summaryrefslogtreecommitdiffstats
path: root/dcb/dcb_apptrust.c
diff options
context:
space:
mode:
Diffstat (limited to 'dcb/dcb_apptrust.c')
-rw-r--r--dcb/dcb_apptrust.c307
1 files changed, 307 insertions, 0 deletions
diff --git a/dcb/dcb_apptrust.c b/dcb/dcb_apptrust.c
new file mode 100644
index 0000000..ed1cba7
--- /dev/null
+++ b/dcb/dcb_apptrust.c
@@ -0,0 +1,307 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <errno.h>
+#include <linux/dcbnl.h>
+
+#include "dcb.h"
+#include "utils.h"
+
+static void dcb_apptrust_help_set(void)
+{
+ fprintf(stderr,
+ "Usage: dcb apptrust set dev STRING\n"
+ " [ order [ ethtype | stream-port | dgram-port | port | dscp | pcp ] ]\n"
+ "\n");
+}
+
+static void dcb_apptrust_help_show(void)
+{
+ fprintf(stderr, "Usage: dcb apptrust show dev STRING\n"
+ " [ order ]\n"
+ "\n");
+}
+
+static void dcb_apptrust_help(void)
+{
+ fprintf(stderr, "Usage: dcb apptrust help\n"
+ "\n");
+ dcb_apptrust_help_show();
+ dcb_apptrust_help_set();
+}
+
+static const char *const selector_names[] = {
+ [IEEE_8021QAZ_APP_SEL_ETHERTYPE] = "ethtype",
+ [IEEE_8021QAZ_APP_SEL_STREAM] = "stream-port",
+ [IEEE_8021QAZ_APP_SEL_DGRAM] = "dgram-port",
+ [IEEE_8021QAZ_APP_SEL_ANY] = "port",
+ [IEEE_8021QAZ_APP_SEL_DSCP] = "dscp",
+ [DCB_APP_SEL_PCP] = "pcp",
+};
+
+struct dcb_apptrust_table {
+ __u8 selectors[IEEE_8021QAZ_APP_SEL_MAX + 1];
+ int nselectors;
+};
+
+static bool dcb_apptrust_contains(const struct dcb_apptrust_table *table,
+ __u8 selector)
+{
+ int i;
+
+ for (i = 0; i < table->nselectors; i++)
+ if (table->selectors[i] == selector)
+ return true;
+
+ return false;
+}
+
+static void dcb_apptrust_print_order(const struct dcb_apptrust_table *table)
+{
+ const char *str;
+ __u8 selector;
+ int i;
+
+ open_json_array(PRINT_JSON, "order");
+ print_string(PRINT_FP, NULL, "order: ", NULL);
+
+ for (i = 0; i < table->nselectors; i++) {
+ selector = table->selectors[i];
+ str = selector_names[selector];
+ print_string(PRINT_ANY, NULL, "%s ", str);
+ }
+ print_nl();
+
+ close_json_array(PRINT_JSON, "order");
+}
+
+static void dcb_apptrust_print(const struct dcb_apptrust_table *table)
+{
+ dcb_apptrust_print_order(table);
+ print_nl();
+}
+
+static int dcb_apptrust_get_cb(const struct nlattr *attr, void *data)
+{
+ struct dcb_apptrust_table *table = data;
+ uint16_t type;
+ __u8 selector;
+
+ type = mnl_attr_get_type(attr);
+
+ if (!dcb_app_attr_type_validate(type)) {
+ fprintf(stderr,
+ "Unknown attribute in DCB_ATTR_IEEE_APP_TRUST_TABLE: %d\n",
+ type);
+ return MNL_CB_OK;
+ }
+
+ if (mnl_attr_get_payload_len(attr) < 1) {
+ fprintf(stderr,
+ "DCB_ATTR_IEEE_APP_TRUST payload expected to have size %zd, not %d\n",
+ sizeof(struct dcb_app), mnl_attr_get_payload_len(attr));
+ return MNL_CB_OK;
+ }
+
+ selector = mnl_attr_get_u8(attr);
+
+ /* Check that selector is encapsulated in the right attribute */
+ if (!dcb_app_selector_validate(type, selector)) {
+ fprintf(stderr, "Wrong type for selector: %s\n",
+ selector_names[selector]);
+ return MNL_CB_OK;
+ }
+
+ table->selectors[table->nselectors++] = selector;
+
+ return MNL_CB_OK;
+}
+
+static int dcb_apptrust_get(struct dcb *dcb, const char *dev,
+ struct dcb_apptrust_table *table)
+{
+ uint16_t payload_len;
+ void *payload;
+ int ret;
+
+ ret = dcb_get_attribute_va(dcb, dev, DCB_ATTR_DCB_APP_TRUST_TABLE,
+ &payload, &payload_len);
+ if (ret != 0)
+ return ret;
+
+ ret = mnl_attr_parse_payload(payload, payload_len, dcb_apptrust_get_cb,
+ table);
+ if (ret != MNL_CB_OK)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int dcb_apptrust_set_cb(struct dcb *dcb, struct nlmsghdr *nlh,
+ void *data)
+{
+ const struct dcb_apptrust_table *table = data;
+ enum ieee_attrs_app type;
+ struct nlattr *nest;
+ int i;
+
+ nest = mnl_attr_nest_start(nlh, DCB_ATTR_DCB_APP_TRUST_TABLE);
+
+ for (i = 0; i < table->nselectors; i++) {
+ type = dcb_app_attr_type_get(table->selectors[i]);
+ mnl_attr_put_u8(nlh, type, table->selectors[i]);
+ }
+
+ mnl_attr_nest_end(nlh, nest);
+
+ return 0;
+}
+
+static int dcb_apptrust_set(struct dcb *dcb, const char *dev,
+ const struct dcb_apptrust_table *table)
+{
+ return dcb_set_attribute_va(dcb, DCB_CMD_IEEE_SET, dev,
+ &dcb_apptrust_set_cb, (void *)table);
+}
+
+static __u8 dcb_apptrust_parse_selector(const char *selector, int *err)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(selector_names); i++) {
+ if (selector_names[i] &&
+ strcmp(selector, selector_names[i]) == 0) {
+ *err = 0;
+ return i;
+ }
+ }
+
+ *err = -EINVAL;
+ return 0;
+}
+
+static int dcb_apptrust_parse_selector_list(int *argcp, char ***argvp,
+ struct dcb_apptrust_table *table)
+{
+ int argc = *argcp, err;
+ char **argv = *argvp;
+ __u8 selector;
+
+ /* No trusted selectors ? */
+ if (argc == 0)
+ goto out;
+
+ while (argc > 0) {
+ selector = dcb_apptrust_parse_selector(*argv, &err);
+ if (err < 0)
+ goto out;
+
+ if (table->nselectors > IEEE_8021QAZ_APP_SEL_MAX)
+ return -ERANGE;
+
+ if (dcb_apptrust_contains(table, selector)) {
+ fprintf(stderr, "Duplicate selector: %s\n",
+ selector_names[selector]);
+ return -EINVAL;
+ }
+
+ table->selectors[table->nselectors++] = selector;
+
+ NEXT_ARG_FWD();
+ }
+
+out:
+ *argcp = argc;
+ *argvp = argv;
+
+ return 0;
+}
+
+static int dcb_cmd_apptrust_set(struct dcb *dcb, const char *dev, int argc,
+ char **argv)
+{
+ struct dcb_apptrust_table table = { 0 };
+ int ret;
+
+ if (!argc) {
+ dcb_apptrust_help_set();
+ return 0;
+ }
+
+ do {
+ if (strcmp(*argv, "help") == 0) {
+ dcb_apptrust_help_set();
+ return 0;
+ } else if (strcmp(*argv, "order") == 0) {
+ NEXT_ARG_FWD();
+ ret = dcb_apptrust_parse_selector_list(&argc, &argv,
+ &table);
+ if (ret < 0) {
+ fprintf(stderr, "Invalid list of selectors\n");
+ return -EINVAL;
+ }
+ } else {
+ fprintf(stderr, "What is \"%s\"?\n", *argv);
+ dcb_apptrust_help_set();
+ return -EINVAL;
+ }
+ } while (argc > 0);
+
+ return dcb_apptrust_set(dcb, dev, &table);
+}
+
+static int dcb_cmd_apptrust_show(struct dcb *dcb, const char *dev, int argc,
+ char **argv)
+{
+ struct dcb_apptrust_table table = { 0 };
+ int ret;
+
+ ret = dcb_apptrust_get(dcb, dev, &table);
+ if (ret)
+ return ret;
+
+ open_json_object(NULL);
+
+ if (!argc) {
+ dcb_apptrust_print(&table);
+ goto out;
+ }
+
+ do {
+ if (strcmp(*argv, "help") == 0) {
+ dcb_apptrust_help_show();
+ return 0;
+ } else if (strcmp(*argv, "order") == 0) {
+ dcb_apptrust_print_order(&table);
+ } else {
+ fprintf(stderr, "What is \"%s\"?\n", *argv);
+ dcb_apptrust_help_show();
+ return -EINVAL;
+ }
+
+ NEXT_ARG_FWD();
+ } while (argc > 0);
+
+out:
+ close_json_object();
+ return 0;
+}
+
+int dcb_cmd_apptrust(struct dcb *dcb, int argc, char **argv)
+{
+ if (!argc || strcmp(*argv, "help") == 0) {
+ dcb_apptrust_help();
+ return 0;
+ } else if (strcmp(*argv, "show") == 0) {
+ NEXT_ARG_FWD();
+ return dcb_cmd_parse_dev(dcb, argc, argv, dcb_cmd_apptrust_show,
+ dcb_apptrust_help_show);
+ } else if (strcmp(*argv, "set") == 0) {
+ NEXT_ARG_FWD();
+ return dcb_cmd_parse_dev(dcb, argc, argv, dcb_cmd_apptrust_set,
+ dcb_apptrust_help_set);
+ } else {
+ fprintf(stderr, "What is \"%s\"?\n", *argv);
+ dcb_apptrust_help();
+ return -EINVAL;
+ }
+}