]> git.ipfire.org Git - thirdparty/lldpd.git/commitdiff
med: Add configure inventory commands
authorHarshal Gohel <harshaldhruvkumar.gohel@philips.com>
Mon, 11 Apr 2022 12:42:50 +0000 (18:12 +0530)
committerVincent Bernat <vincent@bernat.ch>
Sun, 15 May 2022 09:54:47 +0000 (11:54 +0200)
Default inventory information is fetched from dmi table.
Most of embedded devices do not run EFI bootloader hence dmi information
will not be available in /sys/class/dmi

- Add `configure inventory` commands
- Add `unconfigure inventory` commands
- New code is dependent on enable-lldpmed
- Add write support on lldpctl atoms
- Add support for setting inventory configuration in daemon
- Refactor `lldp_med` to assign `c_med_sw` only once.
  We have the configurability of inventory information, So
  it is not required for daemon to keep assigning `c_med_sw`

12 files changed:
src/client/Makefile.am
src/client/client.h
src/client/conf-inv.c [new file with mode: 0644]
src/client/conf.c
src/ctl.h
src/daemon/client.c
src/daemon/lldpd.c
src/lib/atom.h
src/lib/atoms/chassis.c
src/lib/helpers.c
src/lib/helpers.h
src/lib/lldpctl.h

index d1c168721ae29b6ce54ea94dd27f0268b6562aa7..23a3225c0d8914cc68bd68d7dd0fe65441b72e3b 100644 (file)
@@ -13,7 +13,7 @@ uninstall-local:
        cd $(DESTDIR)$(sbindir) && rm -f lldpctl
 
 lldpcli_SOURCES  = client.h lldpcli.c display.c \
-       conf.c conf-med.c conf-dot3.c conf-power.c \
+       conf.c conf-med.c conf-inv.c conf-dot3.c conf-power.c \
        conf-lldp.c conf-system.c \
        commands.c show.c \
        misc.c tokenizer.c \
index 84e6e6c6d5795e51680ffe16eda1194cddf194e1..78a074e2de9f2021248096287c48752f2781ce1e 100644 (file)
@@ -148,6 +148,7 @@ void register_commands_configure(struct cmd_node *);
 void register_commands_configure_system(struct cmd_node *, struct cmd_node *);
 void register_commands_configure_lldp(struct cmd_node *, struct cmd_node *);
 void register_commands_configure_med(struct cmd_node *, struct cmd_node *);
+void register_commands_configure_inventory(struct cmd_node *, struct cmd_node *);
 void register_commands_configure_dot3(struct cmd_node *);
 void register_commands_medpow(struct cmd_node *);
 void register_commands_dot3pow(struct cmd_node *);
diff --git a/src/client/conf-inv.c b/src/client/conf-inv.c
new file mode 100644 (file)
index 0000000..6b043f2
--- /dev/null
@@ -0,0 +1,215 @@
+/* -*- mode: c; c-file-style: "openbsd" -*- */
+/*
+ * SPDX-FileCopyrightText: 2022 Koninklijke Philips N.V.
+ * SPDX-License-Identifier: ISC
+ */
+
+#include <unistd.h>
+#include <string.h>
+
+#include "client.h"
+#include "../log.h"
+
+static int
+cmd_inventory(struct lldpctl_conn_t *conn, struct writer *w,
+    struct cmd_env *env, void *arg)
+{
+       log_debug("lldpctl", "configure inventory information");
+
+       lldpctl_atom_t *chassis = lldpctl_get_local_chassis(conn);
+
+       if (chassis == NULL) {
+               log_warnx("lldpctl", "unable to get configuration from lldpd. %s",
+                   lldpctl_last_strerror(conn));
+               return 0;
+       }
+
+       char *action = arg;
+       if ((!strcmp(action, "hardware-revision") &&
+               (lldpctl_atom_set_str(chassis,
+                   lldpctl_k_chassis_med_inventory_hw,
+                   cmdenv_get(env, "hardware-revision")) == NULL)) ||
+           (!strcmp(action, "software-revision") &&
+               (lldpctl_atom_set_str(chassis,
+                   lldpctl_k_chassis_med_inventory_sw,
+                   cmdenv_get(env, "software-revision")) == NULL)) ||
+           (!strcmp(action, "firmware-revision") &&
+               (lldpctl_atom_set_str(chassis,
+                   lldpctl_k_chassis_med_inventory_fw,
+                   cmdenv_get(env, "firmware-revision")) == NULL)) ||
+           (!strcmp(action, "serial-number") &&
+               (lldpctl_atom_set_str(chassis,
+                   lldpctl_k_chassis_med_inventory_sn,
+                   cmdenv_get(env, "serial-number")) == NULL)) ||
+           (!strcmp(action, "manufacturer") &&
+               (lldpctl_atom_set_str(chassis,
+                   lldpctl_k_chassis_med_inventory_manuf,
+                   cmdenv_get(env, "manufacturer")) == NULL)) ||
+           (!strcmp(action, "model") &&
+               (lldpctl_atom_set_str(chassis,
+                   lldpctl_k_chassis_med_inventory_model,
+                   cmdenv_get(env, "model")) == NULL)) ||
+           (!strcmp(action, "asset") &&
+               (lldpctl_atom_set_str(chassis,
+                   lldpctl_k_chassis_med_inventory_asset,
+                   cmdenv_get(env, "asset")) == NULL))) {
+               log_warnx("lldpctl", "Unable to setup inventory. %s",
+                   lldpctl_last_strerror(conn));
+               lldpctl_atom_dec_ref(chassis);
+               return 0;
+       }
+
+       log_info("lldpctl", "Configuration for inventory is applied");
+       lldpctl_atom_dec_ref(chassis);
+       return 1;
+}
+
+/**
+ * Register `configure inventory *` commands
+ *
+ */
+static void
+register_commands_inv(struct cmd_node *configure_inv, struct cmd_node *unconfigure_inv)
+{
+       commands_new(
+               commands_new(
+                       commands_new(configure_inv,
+                           "hardware-revision", "Set hardware-revision string",
+                           NULL, NULL, NULL),
+                       NULL, "Inventory hardware-revision string",
+                       NULL, cmd_store_env_value, "hardware-revision"),
+               NEWLINE, "Set hardware-revision string",
+               NULL, cmd_inventory, "hardware-revision");
+
+       commands_new(
+               commands_new(unconfigure_inv,
+                   "hardware-revision", "Unset hardware-revision string",
+                   NULL, NULL, NULL),
+               NEWLINE, "Unset hardware-revision string",
+               NULL, cmd_inventory, "hardware-revision");
+
+       commands_new(
+               commands_new(
+                       commands_new(configure_inv,
+                           "software-revision", "Set software-revision string",
+                           NULL, NULL, NULL),
+                       NULL, "Inventory software-revision string",
+                       NULL, cmd_store_env_value, "software-revision"),
+               NEWLINE, "Set software-revision string",
+               NULL, cmd_inventory, "software-revision");
+
+       commands_new(
+               commands_new(unconfigure_inv,
+                   "software-revision", "Unset software-revision string",
+                   NULL, NULL, NULL),
+               NEWLINE, "Unset software-revision string",
+               NULL, cmd_inventory, "software-revision");
+
+       commands_new(
+               commands_new(
+                       commands_new(configure_inv,
+                           "firmware-revision", "Set firmware-revision string",
+                           NULL, NULL, NULL),
+                       NULL, "Inventory firmware-revision string",
+                       NULL, cmd_store_env_value, "firmware-revision"),
+               NEWLINE, "Set firmware-revision string",
+               NULL, cmd_inventory, "firmware-revision");
+
+       commands_new(
+               commands_new(unconfigure_inv,
+                   "firmware-revision", "Unset firmware-revision string",
+                   NULL, NULL, NULL),
+               NEWLINE, "Unset firmware-revision string",
+               NULL, cmd_inventory, "firmware-revision");
+
+       commands_new(
+               commands_new(
+                       commands_new(configure_inv,
+                           "serial-number", "Set serial-number string",
+                           NULL, NULL, NULL),
+                       NULL, "Inventory serial-number string",
+                       NULL, cmd_store_env_value, "serial-number"),
+               NEWLINE, "Set serial-number string",
+               NULL, cmd_inventory, "serial-number");
+
+       commands_new(
+               commands_new(unconfigure_inv,
+                   "serial-number", "Unset serial-number string",
+                   NULL, NULL, NULL),
+               NEWLINE, "Unset serial-number string",
+               NULL, cmd_inventory, "serial-number");
+
+       commands_new(
+               commands_new(
+                       commands_new(configure_inv,
+                           "manufacturer", "Set manufacturer string",
+                           NULL, NULL, NULL),
+                       NULL, "Inventory manufacturer string",
+                       NULL, cmd_store_env_value, "manufacturer"),
+               NEWLINE, "Set manufacturer string",
+               NULL, cmd_inventory, "manufacturer");
+
+       commands_new(
+               commands_new(unconfigure_inv,
+                   "manufacturer", "Unset manufacturer string",
+                   NULL, NULL, NULL),
+               NEWLINE, "Unset manufacturer string",
+               NULL, cmd_inventory, "manufacturer");
+
+       commands_new(
+               commands_new(
+                       commands_new(configure_inv,
+                           "model", "Set model string",
+                           NULL, NULL, NULL),
+                       NULL, "Inventory model string",
+                       NULL, cmd_store_env_value, "model"),
+               NEWLINE, "Set model string",
+               NULL, cmd_inventory, "model");
+
+       commands_new(
+               commands_new(unconfigure_inv,
+                   "model", "Unset model string",
+                   NULL, NULL, NULL),
+               NEWLINE, "Unset model string",
+               NULL, cmd_inventory, "model");
+
+       commands_new(
+               commands_new(
+                       commands_new(configure_inv,
+                           "asset", "Set asset string",
+                           NULL, NULL, NULL),
+                       NULL, "Inventory asset string",
+                       NULL, cmd_store_env_value, "asset"),
+               NEWLINE, "Set asset string",
+               NULL, cmd_inventory, "asset");
+
+       commands_new(
+               commands_new(unconfigure_inv,
+                   "asset", "Unset asset string",
+                   NULL, NULL, NULL),
+               NEWLINE, "Unset asset string",
+               NULL, cmd_inventory, "asset");
+}
+
+/**
+ * Register `configure inventory *`
+ *
+ */
+void
+register_commands_configure_inventory(struct cmd_node *configure, struct cmd_node *unconfigure) {
+       if(lldpctl_key_get_map(
+                   lldpctl_k_med_policy_type)[0].value <= 0)
+               return;
+
+       struct cmd_node *configure_inv = commands_new(
+               configure,
+               "inventory", "Inventory configuration",
+               NULL, NULL, NULL);
+       struct cmd_node *unconfigure_inv = commands_new(
+               unconfigure,
+               "inventory", "Inventory configuration",
+               NULL, NULL, NULL);
+
+       register_commands_inv(configure_inv, unconfigure_inv);
+}
+
index ba5743f73cc2e59358b78f1cdb50808013d241f3..72688b2abaa395babd50eaadbae718ee5d87af33 100644 (file)
@@ -45,5 +45,6 @@ register_commands_configure(struct cmd_node *root)
        register_commands_configure_system(configure, unconfigure);
        register_commands_configure_lldp(configure, unconfigure);
        register_commands_configure_med(configure, unconfigure);
+       register_commands_configure_inventory(configure, unconfigure);
        register_commands_configure_dot3(configure);
 }
index 86425b62948b176d4439a5e866529f5943e91545..7cb4ced99ad1b030e289042d4cdbbb47c0d6be53 100644 (file)
--- a/src/ctl.h
+++ b/src/ctl.h
@@ -30,6 +30,7 @@ enum hmsg_type {
        GET_CONFIG,             /* Get global configuration */
        SET_CONFIG,             /* Change global configuration */
        GET_INTERFACES,         /* Get list of interfaces */
+       SET_CHASSIS,            /* Set local chassis */
        GET_CHASSIS,            /* Get local chassis */
        GET_INTERFACE,          /* Get all information related to an interface */
        GET_DEFAULT_PORT,       /* Get all information related to default port */
index 0d0f3ea37a19ebee95c1313f27754efe772c0254..56e57590148a0e8f5799e8167df5ba028ff8f50a 100644 (file)
 #include "lldpd.h"
 #include "trace.h"
 
+#ifdef ENABLE_LLDPMED
+#include <sys/utsname.h>
+#endif
+
 static ssize_t
 client_handle_none(struct lldpd *cfg, enum hmsg_type *type,
     void *input, int input_len, void **output, int *subscribed)
@@ -273,6 +277,82 @@ client_handle_get_interfaces(struct lldpd *cfg, enum hmsg_type *type,
        return output_len;
 }
 
+#ifdef ENABLE_LLDPMED
+/**
+ * Set local chassis inventory info
+ * Input: chassis object
+ * Output: updated chassis object
+ */
+static ssize_t
+client_handle_set_local_chassis(struct lldpd *cfg, enum hmsg_type *type,
+    void *input, int input_len, void **output, int *subscribed)
+{
+       struct lldpd_chassis *chassis = NULL;
+       struct lldpd_chassis *local_chassis = NULL;
+       struct utsname un;
+
+       log_debug("rpc", "client request a change in chassis configuration");
+       if (lldpd_chassis_unserialize(input, input_len, &chassis) <= 0) {
+               *type = NONE;
+               return 0;
+       }
+
+       local_chassis = LOCAL_CHASSIS(cfg);
+
+       free(local_chassis->c_med_hw);
+       local_chassis->c_med_hw = (!chassis->c_med_hw) ? dmi_hw() : strdup(chassis->c_med_hw);
+
+       // Follows lldpd.c - only set sw if advertising is enabled
+       if (cfg->g_config.c_advertise_version) {
+               free(local_chassis->c_med_sw);
+
+               if (!chassis->c_med_sw) {
+                       if (uname(&un) < 0) {
+                               log_warn("rpc", "Could not get default uname. Will continue anyway.");
+                               local_chassis->c_med_sw = NULL;
+                       } else {
+                               local_chassis->c_med_sw = strdup(un.release);
+                       }
+               } else {
+                       local_chassis->c_med_sw = strdup(chassis->c_med_sw);
+               }
+       }
+
+       free(local_chassis->c_med_fw);
+       local_chassis->c_med_fw = (!chassis->c_med_fw) ? dmi_fw() : strdup(chassis->c_med_fw);
+
+       free(local_chassis->c_med_sn);
+       local_chassis->c_med_sn = (!chassis->c_med_sn) ? dmi_sn() : strdup(chassis->c_med_sn);
+
+       free(local_chassis->c_med_manuf);
+       local_chassis->c_med_manuf = (!chassis->c_med_manuf) ? dmi_manuf() : strdup(chassis->c_med_manuf);
+
+       free(local_chassis->c_med_model);
+       local_chassis->c_med_model = (!chassis->c_med_model) ? dmi_model() : strdup(chassis->c_med_model);
+
+       free(local_chassis->c_med_asset);
+       local_chassis->c_med_asset = (!chassis->c_med_asset) ? dmi_asset() : strdup(chassis->c_med_asset);
+
+       log_debug("rpc", "change hardware-revision to: %s", local_chassis->c_med_hw);
+       log_debug("rpc", "change software-revision to: %s", local_chassis->c_med_sw);
+       log_debug("rpc", "change firmware-revision to: %s", local_chassis->c_med_fw);
+       log_debug("rpc", "change serial-number to: %s", local_chassis->c_med_sn);
+       log_debug("rpc", "change manufacturer to: %s", local_chassis->c_med_manuf);
+       log_debug("rpc", "change model to: %s", local_chassis->c_med_model);
+       log_debug("rpc", "change asset to: %s", local_chassis->c_med_asset);
+
+       lldpd_chassis_cleanup(chassis, 1);
+
+       ssize_t output_len = lldpd_chassis_serialize(local_chassis, output);
+       if (output_len <= 0) {
+               *type = NONE;
+               return 0;
+       }
+
+       return output_len;
+}
+#endif /* ENABLE_LLDPMED */
+
 /* Return the local chassis.
    Input:  nothing.
    Output: local chassis (lldpd_chassis)
@@ -572,6 +652,9 @@ static struct client_handle client_handles[] = {
        { GET_INTERFACES,       "Get interfaces",    client_handle_get_interfaces },
        { GET_INTERFACE,        "Get interface",     client_handle_get_interface },
        { GET_DEFAULT_PORT,     "Get default port",  client_handle_get_default_port },
+#ifdef ENABLE_LLDPMED
+       { SET_CHASSIS,          "Set local chassis", client_handle_set_local_chassis },
+#endif
        { GET_CHASSIS,          "Get local chassis", client_handle_get_local_chassis },
        { SET_PORT,             "Set port",          client_handle_set_port },
        { SUBSCRIBE,            "Subscribe",         client_handle_subscribe },
index 22ae7463989628eddbe57d07aa759c2a15548c40..6d8853474ffe8c17cdfabe1202c4bfe9246bbbc2 100644 (file)
@@ -1156,16 +1156,25 @@ lldpd_send(struct lldpd_hardware *hardware)
 
 #ifdef ENABLE_LLDPMED
 static void
-lldpd_med(struct lldpd_chassis *chassis)
+lldpd_med(struct lldpd *cfg, struct utsname *un)
 {
        static short int once = 0;
-       if (!once) {
-               chassis->c_med_hw = dmi_hw();
-               chassis->c_med_fw = dmi_fw();
-               chassis->c_med_sn = dmi_sn();
-               chassis->c_med_manuf = dmi_manuf();
-               chassis->c_med_model = dmi_model();
-               chassis->c_med_asset = dmi_asset();
+       if (!once && cfg) {
+               LOCAL_CHASSIS(cfg)->c_med_hw = dmi_hw();
+               LOCAL_CHASSIS(cfg)->c_med_fw = dmi_fw();
+               LOCAL_CHASSIS(cfg)->c_med_sn = dmi_sn();
+               LOCAL_CHASSIS(cfg)->c_med_manuf = dmi_manuf();
+               LOCAL_CHASSIS(cfg)->c_med_model = dmi_model();
+               LOCAL_CHASSIS(cfg)->c_med_asset = dmi_asset();
+               if (un) {
+                       if (LOCAL_CHASSIS(cfg)->c_med_sw)
+                               free(LOCAL_CHASSIS(cfg)->c_med_sw);
+
+                       if (cfg->g_config.c_advertise_version)
+                               LOCAL_CHASSIS(cfg)->c_med_sw = strdup(un->release);
+                       else
+                               LOCAL_CHASSIS(cfg)->c_med_sw = strdup("Unknown");
+               }
                once = 1;
        }
 }
@@ -1242,12 +1251,7 @@ lldpd_update_localchassis(struct lldpd *cfg)
 #ifdef ENABLE_LLDPMED
        if (LOCAL_CHASSIS(cfg)->c_cap_available & LLDP_CAP_TELEPHONE)
                LOCAL_CHASSIS(cfg)->c_cap_enabled |= LLDP_CAP_TELEPHONE;
-       lldpd_med(LOCAL_CHASSIS(cfg));
-       free(LOCAL_CHASSIS(cfg)->c_med_sw);
-       if (cfg->g_config.c_advertise_version)
-               LOCAL_CHASSIS(cfg)->c_med_sw = strdup(un.release);
-       else
-               LOCAL_CHASSIS(cfg)->c_med_sw = strdup("Unknown");
+       lldpd_med(cfg, &un);
 #endif
        if ((LOCAL_CHASSIS(cfg)->c_cap_available & LLDP_CAP_STATION) &&
                (LOCAL_CHASSIS(cfg)->c_cap_enabled == 0))
index 0b1d4bc0002897d01d35eaf140c6e5687d31d330..66bf692aa1a8dddfb6cf2b651c42dd01cf09fa28 100644 (file)
@@ -55,6 +55,9 @@ struct lldpctl_conn_t {
 #define CONN_STATE_GET_DEFAULT_PORT_SEND 15
 #define CONN_STATE_GET_DEFAULT_PORT_RECV 16
 #define CONN_STATE_WATCHING            17
+#define CONN_STATE_SET_CHASSIS_SEND    18
+#define CONN_STATE_SET_CHASSIS_RECV    19
+
        int state;              /* Current state */
        /* Data attached to the state. It is used to check that we are using the
         * same data as a previous call until the state machine goes to
index f0012df70b837e4644218bc97deca71a52eb0e5b..1d2ed27bcd94a3254d394fd4b064299070362aa3 100644 (file)
@@ -99,6 +99,71 @@ _lldpctl_atom_get_atom_chassis(lldpctl_atom_t *atom, lldpctl_key_t key)
        }
 }
 
+#ifdef ENABLE_LLDPMED
+static lldpctl_atom_t*
+_lldpctl_atom_set_str_chassis(lldpctl_atom_t *atom, lldpctl_key_t key,
+    const char *value)
+{
+       struct _lldpctl_atom_chassis_t *p =
+           (struct _lldpctl_atom_chassis_t *) atom;
+       struct lldpd_chassis *chassis = p->chassis;
+
+       char *canary = NULL;
+
+       int rc;
+
+       switch (key) {
+       case lldpctl_k_chassis_med_inventory_hw:
+               free(chassis->c_med_hw);
+               chassis->c_med_hw = xstrdup(value);
+               break;
+       case lldpctl_k_chassis_med_inventory_sw:
+               free(chassis->c_med_sw);
+               chassis->c_med_sw = xstrdup(value);
+               break;
+       case lldpctl_k_chassis_med_inventory_fw:
+               free(chassis->c_med_fw);
+               chassis->c_med_fw = xstrdup(value);
+               break;
+       case lldpctl_k_chassis_med_inventory_sn:
+               free(chassis->c_med_sn);
+               chassis->c_med_sn = xstrdup(value);
+               break;
+       case lldpctl_k_chassis_med_inventory_manuf:
+               free(chassis->c_med_manuf);
+               chassis->c_med_manuf = xstrdup(value);
+               break;
+       case lldpctl_k_chassis_med_inventory_model:
+               free(chassis->c_med_model);
+               chassis->c_med_model = xstrdup(value);
+               break;
+       case lldpctl_k_chassis_med_inventory_asset:
+               free(chassis->c_med_asset);
+               chassis->c_med_asset = xstrdup(value);
+               break;
+       default:
+               SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+               return NULL;
+       }
+
+       if (asprintf(&canary, "%d%s", key, value ? value : "(NULL)") == -1) {
+               SET_ERROR(atom->conn, LLDPCTL_ERR_NOMEM);
+               return NULL;
+       }
+
+       rc = _lldpctl_do_something(atom->conn,
+           CONN_STATE_SET_CHASSIS_SEND, CONN_STATE_SET_CHASSIS_RECV,
+           canary,
+           SET_CHASSIS, chassis, &MARSHAL_INFO(lldpd_chassis),
+           NULL, NULL);
+
+       free(canary);
+       if (rc == 0)
+               return atom;
+       return NULL;
+}
+#endif /* ENABLE_LLDPMED */
+
 static const char*
 _lldpctl_atom_get_str_chassis(lldpctl_atom_t *atom, lldpctl_key_t key)
 {
@@ -222,6 +287,10 @@ static struct atom_builder chassis =
          .get  = _lldpctl_atom_get_atom_chassis,
          .get_str = _lldpctl_atom_get_str_chassis,
          .get_int = _lldpctl_atom_get_int_chassis,
-         .get_buffer = _lldpctl_atom_get_buf_chassis };
+         .get_buffer = _lldpctl_atom_get_buf_chassis,
+#ifdef ENABLE_LLDPMED
+         .set_str = _lldpctl_atom_set_str_chassis,
+#endif
+       };
 
 ATOM_BUILDER_REGISTER(chassis, 3);
index f7ea51d0b479a9c047f9235da834a902e2e81c64..2fa0f78ae8ea78b9965327228c127549eead584d 100644 (file)
@@ -71,3 +71,10 @@ _lldpctl_atom_free_any_list(lldpctl_atom_t *atom)
        lldpctl_atom_dec_ref((lldpctl_atom_t *)plist->parent);
 }
 
+char*
+xstrdup(const char *str)
+{
+       if (!str) return NULL;
+       return strdup(str);
+}
+
index d1b9415a74d6c0e7924bc4d56cd454f5c9713a4c..8d63ec56d7c1621126a07f2bd448a664e586e805 100644 (file)
@@ -21,3 +21,5 @@ int map_reverse_lookup(lldpctl_map_t *list, const char *string);
 int _lldpctl_atom_new_any_list(lldpctl_atom_t *atom, va_list ap);
 void _lldpctl_atom_free_any_list(lldpctl_atom_t *atom);
 
+char *xstrdup(const char *);
+
index d152e2b7700e8a3afd30a2777f0eeb3903f49f1e..56b3bf489648d59a6e5c6537f79934b9c0df7ffc 100644 (file)
@@ -800,13 +800,13 @@ typedef enum {
 
        lldpctl_k_chassis_med_type = 1900, /**< `(IS)` Chassis MED type. See `LLDP_MED_CLASS_*` */
        lldpctl_k_chassis_med_cap,  /**< `(I)` Available MED capabilitied. See `LLDP_MED_CAP_*` */
-       lldpctl_k_chassis_med_inventory_hw, /**< `(S)` LLDP MED inventory "Hardware Revision" */
-       lldpctl_k_chassis_med_inventory_sw, /**< `(S)` LLDP MED inventory "Software Revision" */
-       lldpctl_k_chassis_med_inventory_fw, /**< `(S)` LLDP MED inventory "Firmware Revision" */
-       lldpctl_k_chassis_med_inventory_sn, /**< `(S)` LLDP MED inventory "Serial Number" */
-       lldpctl_k_chassis_med_inventory_manuf, /**< `(S)` LLDP MED inventory "Manufacturer" */
-       lldpctl_k_chassis_med_inventory_model, /**< `(S)` LLDP MED inventory "Model" */
-       lldpctl_k_chassis_med_inventory_asset, /**< `(S)` LLDP MED inventory "Asset ID" */
+       lldpctl_k_chassis_med_inventory_hw, /**< `(S,W)` LLDP MED inventory "Hardware Revision" */
+       lldpctl_k_chassis_med_inventory_sw, /**< `(S,W)` LLDP MED inventory "Software Revision" */
+       lldpctl_k_chassis_med_inventory_fw, /**< `(S,W)` LLDP MED inventory "Firmware Revision" */
+       lldpctl_k_chassis_med_inventory_sn, /**< `(S,W)` LLDP MED inventory "Serial Number" */
+       lldpctl_k_chassis_med_inventory_manuf, /**< `(S,W)` LLDP MED inventory "Manufacturer" */
+       lldpctl_k_chassis_med_inventory_model, /**< `(S,W)` LLDP MED inventory "Model" */
+       lldpctl_k_chassis_med_inventory_asset, /**< `(S,W)` LLDP MED inventory "Asset ID" */
 
        lldpctl_k_port_med_policies = 2000, /**< `(AL,WO)` MED policies attached to a port. */
        lldpctl_k_med_policy_type, /**< `(IS,W)` MED policy app type. See `LLDP_MED_APPTYPE_*`. 0 if a policy is not defined. */