diff --git a/SOURCES/open-lldp-v1.0.1-31-Rebase-to-open-lldp-branch-1.1.0.patch b/SOURCES/open-lldp-v1.0.1-31-Rebase-to-open-lldp-branch-1.1.0.patch new file mode 100644 index 0000000..bf714f1 --- /dev/null +++ b/SOURCES/open-lldp-v1.0.1-31-Rebase-to-open-lldp-branch-1.1.0.patch @@ -0,0 +1,3849 @@ +From: Aaron Conole +Date: Wed, 09 Jun 2021 15:12:06 +0000 +Subject: [PATCH] lldpad: Rebase to openlldp branch 1.1.0 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Open-LLDP released 1.1.0 which includes a number of important fixes +relevant to customers. The biggest changes are documented in the +changelog. + +This patch updates the lldpad package to 1.1.0 branch as of +4c75fa274230 "tx: rename variable" + +Signed-off-by: Aaron Conole +--- + ChangeLog | 15 +++ + Makefile.am | 26 +++++ + README | 4 + config.c | 45 ++++++--- + configure.ac | 39 ++++++++ + ctrl_iface.c | 4 + dcb_protocol.c | 19 +--- + dcb_rule_chk.c | 2 + dcbtool.c | 2 + dcbtool_cmds.c | 24 ----- + docs/liblldp_clif-vdp22.3 | 2 + docs/lldptool.8 | 4 + event_iface.c | 22 +++- + include/config.h | 3 + include/linux/if_link.h | 100 ++++++++++++++++++++- + include/lldp.h | 13 ++ + include/lldp_basman_clif.h | 6 - + include/lldp_mod.h | 2 + include/lldp_tlv.h | 16 ++- + include/lldp_util.h | 4 + include/lldptool.h | 3 + include/qbg_ecp22.h | 4 + include/qbg_vdpnl.h | 1 + lldp/agent.c | 4 + lldp/l2_packet.h | 7 - + lldp/l2_packet_linux.c | 6 - + lldp/ports.c | 2 + lldp/rx.c | 41 ++++---- + lldp/states.h | 2 + lldp/tx.c | 31 ++++-- + lldp_8021qaz.c | 52 ++++++----- + lldp_8021qaz_clif.c | 80 ++++++++++++----- + lldp_8021qaz_cmds.c | 2 + lldp_8023.c | 14 +-- + lldp_basman.c | 10 -- + lldp_basman_cmds.c | 90 +++++++++++++++++++ + lldp_dcbx.c | 111 +++++++++--------------- + lldp_dcbx_cfg.c | 32 ++++-- + lldp_dcbx_cmds.c | 13 ++ + lldp_dcbx_nl.c | 20 +--- + lldp_evb.c | 8 - + lldp_evb22.c | 8 - + lldp_evb22_cmds.c | 2 + lldp_evb_cmds.c | 2 + lldp_mand.c | 41 +++++--- + lldp_mand_cmds.c | 17 ++- + lldp_med.c | 8 - + lldp_med_cmds.c | 1 + lldp_rtnl.c | 3 + lldp_tlv.c | 12 -- + lldp_util.c | 206 +++++++++++++++++++++++++++++---------------- + lldpad.c | 21 +++- + lldpad.service | 2 + lldpad.socket | 3 + lldpad.spec.in | 36 +++++-- + lldptool.c | 38 ++------ + lldptool_cmds.c | 3 + log.c | 1 + parse_cli.l | 3 + qbg/ecp.c | 8 - + qbg/ecp22.c | 21 +++- + qbg/vdp.c | 16 +-- + qbg/vdp22.c | 12 +- + qbg/vdp22_cmds.c | 7 - + qbg/vdp22sm.c | 4 + qbg/vdp_cmds.c | 2 + qbg/vdpnl.c | 8 - + qbg_utils.c | 3 + tlv_dcbx.c | 33 ++++--- + vdptool.c | 23 ++--- + vdptool_cisco_oui.c | 2 + weak_readline.c | 16 ++- + 72 files changed, 935 insertions(+), 512 deletions(-) + +diff -upr a/ChangeLog b/ChangeLog +--- a/ChangeLog 2015-01-20 13:42:56.000000000 -0500 ++++ b/ChangeLog 2021-06-09 11:00:02.478019444 -0400 +@@ -1,3 +1,18 @@ ++Changes from 1.1.0 to ++Changes from 1.0.1 to 1.1 ++- VDP: introduce vdptool ++- VDP: support retrieving vsi parameter ++- VDP: TLV support ++- VDP: Support OUI infrastructure ++- Switch from SysV to posix shared memory ++- DCBX: ignore PG configurations ++- DCBX: Allow for read-only LLDP configuration ++- Support multicast MAC ++- autoconf: Suport systemd or sysv for init system ++- 802.1qaz: print prio map ++- lldptool: Allow to modify optional TLV content ++- CVE-2018-10932: Don't print raw bytes from mngAddr ++- Misc. bug fixes + Changes from 0.9.46 to 1.0.1 + Mostly fixes and man page updates + Added more testing infrastructure mostly for EVB +diff -upr a/config.c b/config.c +--- a/config.c 2015-01-20 13:42:56.000000000 -0500 ++++ b/config.c 2020-10-23 14:12:58.973289274 -0400 +@@ -56,6 +56,21 @@ + config_t lldpad_cfg; + + /* ++ * config_ifkey - Generates a config key ++ * ++ * Given an interface name this functions generates ++ * a key (based on interface's index) suitable ++ * to pass to libconfig. ++ * ++ */ ++void config_ifkey(const char *name, char *ifkey) { ++ int index = if_nametoindex(name); ++ ++ if(index) ++ sprintf(ifkey, "if%d", index); ++} ++ ++/* + * init_cfg - initialze the global lldpad_cfg via config_init + * + * Returns true (1) for succes and false (0) for failed +@@ -170,7 +185,7 @@ void scan_port(UNUSED void *eloop_data, + LIST_FOREACH(agent, &port->agent_head, entry) { + LLDPAD_DBG("%s: calling ifdown for agent %p.\n", + __func__, agent); +- LIST_FOREACH(np, &lldp_head, lldp) { ++ LIST_FOREACH(np, &lldp_mod_head, lldp) { + ops = np->ops; + if (ops->lldp_mod_ifdown) + ops->lldp_mod_ifdown(ifname, agent); +@@ -219,7 +234,7 @@ int check_cfg_file(void) + } + } else { + retval = errno; +- LLDPAD_ERR("%s is not readable and writeable", ++ LLDPAD_ERR("%s is not readable and writeable\n", + cfg_file_name); + } + } +@@ -295,7 +310,7 @@ int get_int_config(config_setting_t *s, + } + + if (!rval) +- LLDPAD_ERR("invalid value for %s", attr); ++ LLDPAD_ERR("invalid value for %s\n", attr); + + return rval; + } +@@ -339,7 +354,7 @@ int get_array_config(config_setting_t *s + } + + if (!rval) +- LLDPAD_ERR("invalid setting for %s", attr); ++ LLDPAD_ERR("invalid setting for %s\n", attr); + + return rval; + } +@@ -379,7 +394,7 @@ void init_ports(void) + LIST_FOREACH(agent, &port->agent_head, entry) { + LLDPAD_DBG("%s: calling ifup for agent %p.\n", + __func__, agent); +- LIST_FOREACH(np, &lldp_head, lldp) { ++ LIST_FOREACH(np, &lldp_mod_head, lldp) { + if (np->ops->lldp_mod_ifup) + np->ops->lldp_mod_ifup(p->if_name, agent); + } +@@ -451,14 +466,15 @@ static int lookup_config_value(char *pat + int get_config_setting(const char *ifname, int agenttype, char *path, + union cfg_get v, int type) + { +- char p[1024]; ++ char p[1024], ifkey[IFNAMSIZ]; + int rval = CONFIG_FALSE; + const char *section = agent_type2section(agenttype); + + /* look for setting in section->ifname area first */ + if (ifname) { ++ config_ifkey(ifname, ifkey); + snprintf(p, sizeof(p), "%s.%s.%s", +- section, ifname, path); ++ section, ifkey, path); + rval = lookup_config_value(p, v, type); + } + +@@ -475,15 +491,16 @@ int get_config_setting(const char *ifnam + int remove_config_setting(const char *ifname, int agenttype, char *parent, + char *name) + { +- char p[1024]; ++ char p[1024], ifkey[IFNAMSIZ]; + int rval = CONFIG_FALSE; + config_setting_t *setting = NULL; + const char *section = agent_type2section(agenttype); + + /* look for setting in section->ifname area first */ +- if (ifname) { ++ if (ifname) { ++ config_ifkey(ifname, ifkey); + snprintf(p, sizeof(p), "%s.%s.%s", +- section, ifname, parent); ++ section, ifkey, parent); + setting = config_lookup(&lldpad_cfg, p); + } + +@@ -570,15 +587,17 @@ int set_config_setting(const char *ifnam + union cfg_set v, int type) + { + config_setting_t *setting = NULL; +- char p[1024]; ++ char p[1024], ifkey[IFNAMSIZ]; + int rval = cmd_success; + const char *section = agent_type2section(agenttype); + + LLDPAD_DBG("%s(%i): \n", __func__, __LINE__); + +- if (strlen(ifname)) ++ if (strlen(ifname)){ ++ config_ifkey(ifname, ifkey); + snprintf(p, sizeof(p), "%s.%s.%s", +- section, ifname, path); ++ section, ifkey, path); ++ } + else + snprintf(p, sizeof(p), "%s.%s.%s", + section, LLDP_COMMON, path); +diff -upr a/configure.ac b/configure.ac +--- a/configure.ac 2015-01-20 13:42:56.000000000 -0500 ++++ b/configure.ac 2021-06-09 11:00:02.479019457 -0400 +@@ -1,4 +1,4 @@ +-AC_INIT([lldpad], [1.0.1], [lldp-devel@open-lldp.org]) ++AC_INIT([lldpad], [1.1.0], [lldp-devel@open-lldp.org]) + AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects]) + + m4_pattern_allow([AM_PROG_AR]) +@@ -25,6 +25,43 @@ then + AC_MSG_ERROR([no suitable flex found. Please install the 'flex' package.]) + fi + ++dnl Begin determine the systemd use and location ++PKG_CHECK_MODULES([SYSTEMD], [systemd], use_systemd=yes, use_systemd=no) ++ ++dnl Configure developer type flags ++OPENLLDP_CHECK_WARNINGS ++OPENLLDP_CHECK_ERROR ++ ++dnl Set sysvinit values, if system has systemd it will be rewritten ++AC_SUBST(SPEC_BUILD_REQUIRES_POST, "chkconfig") ++AC_SUBST(SPEC_BUILD_REQUIRES_PREUN, "chkconfig initscripts") ++AC_SUBST(SPEC_BUILD_REQUIRES_POSTUN, "initscripts") ++specfile_install="%{_sysconfdir}/init.d/lldpad" ++specfile_install_socket="" ++ ++if test "x$use_systemd" == xyes; then ++ dir="" ++ AC_ARG_WITH([systemdsystemunitdir], ++ AS_HELP_STRING([--with-systemdsystem unitdir=DIR], ++ [Directory for systemd service files default from pkg-config variable systemdsystemunitdir]), ++ [dir=${withval}], ++ [dir="$($PKG_CONFIG --variable=systemdsystemunitdir systemd)"]) ++ ++ systemdsystemunitdir=${dir} ++ AC_SUBST(SYSTEMD_SYSTEM_UNIT_DIR, [$systemdsystemunitdir]) ++ specfile_install="$systemdsystemunitdir/lldpad.service" ++ specfile_install_socket="$systemdsystemunitdir/lldpad.socket" ++ ++ AC_SUBST(SPEC_BUILD_REQUIRES_POST, "systemd") ++ AC_SUBST(SPEC_BUILD_REQUIRES_PREUN, "systemd") ++ AC_SUBST(SPEC_BUILD_REQUIRES_POSTUN, "systemd") ++fi ++ ++AM_CONDITIONAL(SYSTEMD_SYSTEM, test "x$use_systemd" == xyes) ++AC_SUBST(SPEC_FILE_LLDPAD_SERVICE, $specfile_install) ++AC_SUBST(SPEC_FILE_LLDPAD_SOCKET, $specfile_install_socket) ++dnl End systemd stuff ++ + PKG_CHECK_MODULES([LIBCONFIG], [libconfig >= 1.3.2]) + PKG_CHECK_MODULES([LIBNL], [libnl-3.0 >= 3.2]) + +diff -upr a/ctrl_iface.c b/ctrl_iface.c +--- a/ctrl_iface.c 2021-06-09 10:58:59.208200552 -0400 ++++ b/ctrl_iface.c 2020-11-03 09:08:48.057229002 -0500 +@@ -53,8 +53,6 @@ + #include "lldp_util.h" + #include "messages.h" + +-extern struct lldp_head lldp_head; +- + struct ctrl_dst { + struct ctrl_dst *next; + struct sockaddr_un addr; +@@ -116,7 +114,7 @@ int clif_iface_module(struct clif_data * + return cmd_invalid; + } + +- mod = find_module_by_id(&lldp_head, module_id); ++ mod = find_module_by_id(&lldp_mod_head, module_id); + if (mod && mod->ops && mod->ops->client_cmd) + return (mod->ops->client_cmd)(clifd, from, fromlen, + cmd_start, cmd_len, rbuf+strlen(rbuf), rlen); +diff -upr a/dcb_protocol.c b/dcb_protocol.c +--- a/dcb_protocol.c 2015-01-20 13:42:56.000000000 -0500 ++++ b/dcb_protocol.c 2020-09-23 08:50:52.647813847 -0400 +@@ -75,7 +75,7 @@ void pg_insert(struct pghead *head, char + entry = (struct pg_store1 *)malloc(sizeof(struct pg_store1)); + if (!entry) + return; +- strncpy(entry->ifname, ifname, sizeof(entry->ifname)); ++ STRNCPY_TERMINATED(entry->ifname, ifname, sizeof(entry->ifname)); + entry->second = store; + LIST_INSERT_HEAD(head, entry, entries); + } +@@ -1100,7 +1100,7 @@ int dcbx_remove_adapter(char *device_nam + assert(device_name); + not_default = memcmp(DEF_CFG_STORE, device_name, + strlen(DEF_CFG_STORE)); +- strncpy (devName, device_name, MAX_DEVICE_NAME_LEN); ++ STRNCPY_TERMINATED (devName, device_name, MAX_DEVICE_NAME_LEN); + + if (not_default) + handle_opermode_true(device_name); +@@ -2257,13 +2257,8 @@ cmd_status get_bwg_descrpt(char *device_ + + if ((it != NULL) && + (bwgid < it->second->max_pgid_desc)) { +- size = (int)strlen(it->second->pgid_desc[bwgid]) + +- sizeof(char); /* Localization OK */ +- *name = (char*)malloc(size); +- if (*name != NULL) { +- strncpy(*name, it->second->pgid_desc[bwgid], +- size); /* Localization OK */ +- } else { ++ *name = strdup(it->second->pgid_desc[bwgid]); ++ if (*name == NULL) { + goto Error; + } + } else { +@@ -2272,11 +2267,9 @@ cmd_status get_bwg_descrpt(char *device_ + size = (int)strlen( + attribs.descript.pgid_desc[bwgid]) + + sizeof(char); +- *name = (char*)malloc(size); ++ *name = (char*)calloc(size, sizeof(char)); + if (*name != NULL) { +- strncpy(*name, +- attribs.descript.pgid_desc[bwgid], +- size); /* Localization OK */ ++ memcpy(*name, attribs.descript.pgid_desc[bwgid], size - 1); /* Localization OK */ + } else { + goto Error; + } +diff -upr a/dcb_rule_chk.c b/dcb_rule_chk.c +--- a/dcb_rule_chk.c 2015-01-20 13:42:56.000000000 -0500 ++++ b/dcb_rule_chk.c 2020-09-23 08:50:52.647813847 -0400 +@@ -206,6 +206,8 @@ static int dcb_fixup_pg(struct pg_attrib + strict = 0; + if (be == cbe) + be = 0; ++ if (pgid < 0) ++ continue; + } + + if (pg_done[i] == false) { +diff -upr a/dcbtool.c b/dcbtool.c +--- a/dcbtool.c 2015-01-20 13:42:56.000000000 -0500 ++++ b/dcbtool.c 2020-09-23 08:50:52.647813847 -0400 +@@ -47,6 +47,7 @@ + #define UNUSED __attribute__((__unused__)) + + static int show_raw; ++extern void close_history(void); + + static const char *cli_version = + "dcbtool v" DCBTOOL_VERSION "\n" +@@ -460,6 +461,7 @@ static void cli_interactive(int raw) + request(clif_conn, argc, argv, raw); + free(cmd); + } while (!cli_quit); ++ close_history(); + } + + static void cli_terminate(UNUSED int sig) +diff -upr a/dcbtool_cmds.c b/dcbtool_cmds.c +--- a/dcbtool_cmds.c 2015-01-20 13:42:56.000000000 -0500 ++++ b/dcbtool_cmds.c 2020-09-23 08:50:52.647813847 -0400 +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + #include "clif.h" + #include "dcbtool.h" + #include "lldp_dcbx_cmds.h" +@@ -38,7 +39,6 @@ + + static char *print_status(cmd_status status); + static char *get_pgdesc_args(int cmd); +-static int hex2int(char *b); + static void free_cmd_args(char *args); + static char *get_dcb_args(void); + static char *get_dcbx_args(void); +@@ -93,28 +93,6 @@ static char *print_status(cmd_status sta + return str; + } + +-/* assumes input is pointer to two hex digits */ +-/* returns -1 on error */ +-static int hex2int(char *b) +-{ +- int i; +- int n=0; +- int m; +- +- for (i=0,m=1; i<2; i++,m--) { +- if (isxdigit(*(b+i))) { +- if (*(b+i) <= '9') +- n |= (*(b+i) & 0x0f) << (4*m); +- else +- n |= ((*(b+i) & 0x0f) + 9) << (4*m); +- } +- else { +- return -1; +- } +- } +- return n; +-} +- + static char *get_dcb_args(void) + { + char buf[8]; +diff -upr a/docs/liblldp_clif-vdp22.3 b/docs/liblldp_clif-vdp22.3 +--- a/docs/liblldp_clif-vdp22.3 2015-01-20 13:42:56.000000000 -0500 ++++ b/docs/liblldp_clif-vdp22.3 2020-11-03 09:08:48.058229019 -0500 +@@ -1,6 +1,6 @@ + .TH liblldp_clif 3 "February 2014" "open-lldp" "Linux" + .SH NAME +-clif_vsi,clif_vsievt,clif_vsiwait \- Manipulate VDP IEEE 802.1 Ratified Standard Assocications ++clif_vsi,clif_vsievt,clif_vsiwait \- Manipulate VDP IEEE 802.1 Ratified Standard Associations + .SH SYNOPSIS + #include "include/clif.h" + .sp 1 +diff -upr a/docs/lldptool.8 b/docs/lldptool.8 +--- a/docs/lldptool.8 2015-01-20 13:42:56.000000000 -0500 ++++ b/docs/lldptool.8 2020-11-03 09:08:48.058229019 -0500 +@@ -160,9 +160,9 @@ Query the LLDP adminStatus for interface + + .TP + Query the LLDP statistics for interface \fIeth3\fR +-.B lldptool -S -i eth3 adminStatus ++.B lldptool -S -i eth3 + .br +-.B lldptool stats -i eth3 adminStatus ++.B lldptool stats -i eth3 + + .TP + Query the local TLVs which are being transmitted for a given interface: +diff -upr a/event_iface.c b/event_iface.c +--- a/event_iface.c 2015-01-20 13:42:56.000000000 -0500 ++++ b/event_iface.c 2021-01-06 11:05:30.808649405 -0500 +@@ -77,7 +77,7 @@ static void event_if_decode_rta(int type + LLDPAD_DBG(" IFLA_BROADCAST\n"); + break; + case IFLA_IFNAME: +- strncpy(d, (char *)RTA_DATA(rta), IFNAMSIZ); ++ STRNCPY_TERMINATED(d, (char *)RTA_DATA(rta), IFNAMSIZ); + LLDPAD_DBG(" IFLA_IFNAME\n"); + LLDPAD_DBG(" device name is %s\n", d); + break; +@@ -205,6 +205,9 @@ int oper_add_device(char *device_name) + port = newport; + } else if (is_bond(device_name) || !port->portEnabled) + reinit_port(device_name); ++ else if (port->portEnabled) { ++ return 0; ++ } + + lldp_add_agent(device_name, NEAREST_BRIDGE); + lldp_add_agent(device_name, NEAREST_NONTPMR_BRIDGE); +@@ -213,7 +216,7 @@ int oper_add_device(char *device_name) + LIST_FOREACH(agent, &port->agent_head, entry) { + LLDPAD_DBG("%s: calling ifup for agent %p.\n", + __func__, agent); +- LIST_FOREACH(np, &lldp_head, lldp) { ++ LIST_FOREACH(np, &lldp_mod_head, lldp) { + if (np->ops->lldp_mod_ifup) + np->ops->lldp_mod_ifup(device_name, agent); + } +@@ -280,7 +283,7 @@ static void event_if_decode_nlmsg(int ro + LIST_FOREACH(agent, &port->agent_head, entry) { + LLDPAD_DBG("%s: calling ifdown for agent %p.\n", + __func__, agent); +- LIST_FOREACH(np, &lldp_head, lldp) { ++ LIST_FOREACH(np, &lldp_mod_head, lldp) { + ops = np->ops; + if (ops->lldp_mod_ifdown) + ops->lldp_mod_ifdown(device_name, +@@ -415,7 +418,8 @@ event_iface_receive(int sock, UNUSED voi + int event_iface_init() + { + int fd; +- int rcv_size = MAX_PAYLOAD; ++ int rcv_size = 0; ++ socklen_t rcv_len = sizeof(int); + struct sockaddr_nl snl; + + fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); +@@ -423,10 +427,18 @@ int event_iface_init() + if (fd < 0) + return fd; + +- if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &rcv_size, sizeof(int)) < 0) { ++ /* is receive buffer size too small? */ ++ if (getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &rcv_size, &rcv_len) < 0) { + close(fd); + return -EIO; + } ++ if (rcv_size < MIN_RCVBUF_SIZE) { ++ rcv_size = MIN_RCVBUF_SIZE >> 1; /* we get back 2x what we set */ ++ if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &rcv_size, rcv_len) < 0) { ++ close(fd); ++ return -EIO; ++ } ++ } + + memset((void *)&snl, 0, sizeof(struct sockaddr_nl)); + snl.nl_family = AF_NETLINK; +diff -upr a/include/config.h b/include/config.h +--- a/include/config.h 2015-01-20 13:42:56.000000000 -0500 ++++ b/include/config.h 2020-09-23 08:50:52.647813847 -0400 +@@ -111,4 +111,7 @@ void destroy_cfg(void); + int check_cfg_file(void); + int check_for_old_file_format(void); + void init_ports(void); ++ ++void config_ifkey(const char *name, char *ifkey); ++ + #endif /* _CONFIG_H_ */ +diff -upr a/include/linux/if_link.h b/include/linux/if_link.h +--- a/include/linux/if_link.h 2015-01-20 13:42:56.000000000 -0500 ++++ b/include/linux/if_link.h 2020-09-23 08:50:52.648813865 -0400 +@@ -116,15 +116,34 @@ enum { + IFLA_STATS64, + IFLA_VF_PORTS, + IFLA_PORT_SELF, +- IFLA_AF_SPEC, +- IFLA_GROUP, /* Group the device belongs to */ +- IFLA_NET_NS_FD, +- IFLA_EXT_MASK, /* Extended info mask, VFs, etc */ +- IFLA_PROMISCUITY, /* Promiscuity count: > 0 means acts PROMISC */ ++ IFLA_AF_SPEC, ++ IFLA_GROUP, /* Group the device belongs to */ ++ IFLA_NET_NS_FD, ++ IFLA_EXT_MASK, /* Extended info mask, VFs, etc */ ++ IFLA_PROMISCUITY, /* Promiscuity count: > 0 means acts PROMISC */ + #define IFLA_PROMISCUITY IFLA_PROMISCUITY +- IFLA_NUM_TX_QUEUES, +- IFLA_NUM_RX_QUEUES, +- IFLA_CARRIER, ++ IFLA_NUM_TX_QUEUES, ++ IFLA_NUM_RX_QUEUES, ++ IFLA_CARRIER, ++ IFLA_PHYS_PORT_ID, ++ IFLA_CARRIER_CHANGES, ++ IFLA_PHYS_SWITCH_ID, ++ IFLA_LINK_NETNSID, ++ IFLA_PHYS_PORT_NAME, ++ IFLA_PROTO_DOWN, ++ IFLA_GSO_MAX_SEGS, ++ IFLA_GSO_MAX_SIZE, ++ IFLA_PAD, ++ IFLA_XDP, ++ IFLA_EVENT, ++ IFLA_NEW_NETNSID, ++ IFLA_IF_NETNSID, ++ IFLA_TARGET_NETNSID = IFLA_IF_NETNSID, /* new alias */ ++ IFLA_CARRIER_UP_COUNT, ++ IFLA_CARRIER_DOWN_COUNT, ++ IFLA_NEW_IFINDEX, ++ IFLA_MIN_MTU, ++ IFLA_MAX_MTU, + __IFLA_MAX + }; + +@@ -192,6 +211,8 @@ enum { + IFLA_INFO_KIND, + IFLA_INFO_DATA, + IFLA_INFO_XSTATS, ++ IFLA_INFO_SLAVE_KIND, ++ IFLA_INFO_SLAVE_DATA, + __IFLA_INFO_MAX, + }; + +@@ -243,6 +264,69 @@ enum macvlan_mode { + MACVLAN_MODE_BRIDGE = 4, /* talk to bridge ports directly */ + }; + ++/* Bonding section */ ++ ++enum { ++ IFLA_BOND_UNSPEC, ++ IFLA_BOND_MODE, ++ IFLA_BOND_ACTIVE_SLAVE, ++ IFLA_BOND_MIIMON, ++ IFLA_BOND_UPDELAY, ++ IFLA_BOND_DOWNDELAY, ++ IFLA_BOND_USE_CARRIER, ++ IFLA_BOND_ARP_INTERVAL, ++ IFLA_BOND_ARP_IP_TARGET, ++ IFLA_BOND_ARP_VALIDATE, ++ IFLA_BOND_ARP_ALL_TARGETS, ++ IFLA_BOND_PRIMARY, ++ IFLA_BOND_PRIMARY_RESELECT, ++ IFLA_BOND_FAIL_OVER_MAC, ++ IFLA_BOND_XMIT_HASH_POLICY, ++ IFLA_BOND_RESEND_IGMP, ++ IFLA_BOND_NUM_PEER_NOTIF, ++ IFLA_BOND_ALL_SLAVES_ACTIVE, ++ IFLA_BOND_MIN_LINKS, ++ IFLA_BOND_LP_INTERVAL, ++ IFLA_BOND_PACKETS_PER_SLAVE, ++ IFLA_BOND_AD_LACP_RATE, ++ IFLA_BOND_AD_SELECT, ++ IFLA_BOND_AD_INFO, ++ IFLA_BOND_AD_ACTOR_SYS_PRIO, ++ IFLA_BOND_AD_USER_PORT_KEY, ++ IFLA_BOND_AD_ACTOR_SYSTEM, ++ IFLA_BOND_TLB_DYNAMIC_LB, ++ __IFLA_BOND_MAX, ++}; ++ ++#define IFLA_BOND_MAX (__IFLA_BOND_MAX - 1) ++ ++enum { ++ IFLA_BOND_AD_INFO_UNSPEC, ++ IFLA_BOND_AD_INFO_AGGREGATOR, ++ IFLA_BOND_AD_INFO_NUM_PORTS, ++ IFLA_BOND_AD_INFO_ACTOR_KEY, ++ IFLA_BOND_AD_INFO_PARTNER_KEY, ++ IFLA_BOND_AD_INFO_PARTNER_MAC, ++ __IFLA_BOND_AD_INFO_MAX, ++}; ++ ++#define IFLA_BOND_AD_INFO_MAX (__IFLA_BOND_AD_INFO_MAX - 1) ++ ++enum { ++ IFLA_BOND_SLAVE_UNSPEC, ++ IFLA_BOND_SLAVE_STATE, ++ IFLA_BOND_SLAVE_MII_STATUS, ++ IFLA_BOND_SLAVE_LINK_FAILURE_COUNT, ++ IFLA_BOND_SLAVE_PERM_HWADDR, ++ IFLA_BOND_SLAVE_QUEUE_ID, ++ IFLA_BOND_SLAVE_AD_AGGREGATOR_ID, ++ IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE, ++ IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE, ++ __IFLA_BOND_SLAVE_MAX, ++}; ++ ++#define IFLA_BOND_SLAVE_MAX (__IFLA_BOND_SLAVE_MAX - 1) ++ + /* SR-IOV virtual function management section */ + + enum { +diff -upr a/include/lldp_basman_clif.h b/include/lldp_basman_clif.h +--- a/include/lldp_basman_clif.h 2015-01-20 13:42:56.000000000 -0500 ++++ b/include/lldp_basman_clif.h 2020-09-23 08:50:52.648813865 -0400 +@@ -31,7 +31,7 @@ struct lldp_module *basman_cli_register( + void basman_cli_unregister(struct lldp_module *); + int basman_print_tlv(u32, u16, char *); + +-#define ARG_IPV4_ADDR "ipv4" +-#define ARG_IPV6_ADDR "ipv6" +- ++#define ARG_IPV4_ADDR "ipv4" ++#define ARG_IPV6_ADDR "ipv6" ++#define ARG_TLVINFO "info" + #endif +diff -upr a/include/lldp.h b/include/lldp.h +--- a/include/lldp.h 2015-01-20 13:42:56.000000000 -0500 ++++ b/include/lldp.h 2020-09-23 08:50:52.648813865 -0400 +@@ -51,6 +51,13 @@ typedef __u64 u64; + __x > __y ? __x : __y; \ + }) + ++/* Use strncpy with N-1 and ensure the string is terminated. */ ++#define STRNCPY_TERMINATED(DEST, SRC, N) \ ++ do { \ ++ strncpy (DEST, SRC, N - 1); \ ++ DEST[N - 1] = '\0'; \ ++ } while (false) ++ + /* + * Organizationally Unique Identifier (OUI) + * http://standards.ieee.org/regauth/oui/oui.txt +@@ -248,5 +255,11 @@ enum { + #define LLDP_EVB_DEFAULT_RTE 15 + #define LLDP_EVB_DEFAULT_MAX_RTE 31 + ++#ifndef _MSC_VER ++#define STRUCT_PACKED(STRUCT) STRUCT __attribute__((__packed__)) ++#else ++#define STRUCT_PACKED(STRUCT) __pragma(pack(push, 1)) STRUCT __pragma(pack(pop)) ++#endif ++ + void somethingChangedLocal(const char *ifname, int type); + #endif /* _LLDP_H */ +diff -upr a/include/lldp_mod.h b/include/lldp_mod.h +--- a/include/lldp_mod.h 2015-01-20 13:42:56.000000000 -0500 ++++ b/include/lldp_mod.h 2020-10-23 14:12:58.974289292 -0400 +@@ -96,7 +96,7 @@ struct lldp_module { + }; + + LIST_HEAD(lldp_head, lldp_module); +-struct lldp_head lldp_head; ++extern struct lldp_head lldp_mod_head; + + static inline struct lldp_module *find_module_by_id(struct lldp_head *head, int id) + { +diff -upr a/include/lldp_tlv.h b/include/lldp_tlv.h +--- a/include/lldp_tlv.h 2015-01-20 13:42:56.000000000 -0500 ++++ b/include/lldp_tlv.h 2020-09-23 08:50:52.648813865 -0400 +@@ -104,8 +104,8 @@ struct packed_tlv *pack_tlv(struct unpac + struct unpacked_tlv *unpack_tlv(struct packed_tlv *tlv); + int pack_tlv_after(struct unpacked_tlv *, struct packed_tlv *, int); + +-struct unpacked_tlv *free_unpkd_tlv(struct unpacked_tlv *tlv); +-struct packed_tlv *free_pkd_tlv(struct packed_tlv *tlv); ++void free_unpkd_tlv(struct unpacked_tlv *tlv); ++void free_pkd_tlv(struct packed_tlv *tlv); + struct unpacked_tlv *create_tlv(void); + struct packed_tlv *create_ptlv(void); + struct unpacked_tlv *bld_end_tlv(void); +@@ -115,14 +115,18 @@ int tlv_ok(struct unpacked_tlv *tlv); + + #define FREE_UNPKD_TLV(d, f) \ + { \ +- if ((d)->f) \ +- (d)->f = free_unpkd_tlv((d)->f); \ ++ if ((d)->f) { \ ++ free_unpkd_tlv((d)->f); \ ++ (d)->f = NULL; \ ++ } \ + } + + #define FREE_PKD_TLV(d, f) \ + { \ +- if ((d)->f) \ +- (d)->f = free_pkd_tlv((d)->f); \ ++ if ((d)->f) { \ ++ free_pkd_tlv((d)->f); \ ++ (d)->f = NULL; \ ++ } \ + } + + #define PACK_TLV_AFTER(t, p, l, g) \ +diff -upr a/include/lldptool.h b/include/lldptool.h +--- a/include/lldptool.h 2015-01-20 13:42:56.000000000 -0500 ++++ b/include/lldptool.h 2020-09-23 08:50:52.648813865 -0400 +@@ -29,9 +29,8 @@ + + #include "clif.h" + +-struct lldp_head lldp_cli_head; ++extern struct lldp_head lldp_cli_head; + +-int hex2int(char *b); + int clif_command(struct clif *clif, char *cmd, int raw); + void print_raw_message(char *msg, int print); + int parse_print_message(char *msg, int print); +diff -upr a/include/lldp_util.h b/include/lldp_util.h +--- a/include/lldp_util.h 2021-06-09 10:58:59.214200629 -0400 ++++ b/include/lldp_util.h 2021-04-05 12:02:17.318590504 -0400 +@@ -119,6 +119,7 @@ + + int hexstr2bin(const char *hex, u8 *buf, size_t len); + int bin2hexstr(const u8 *hex, size_t hexlen, char *buf, size_t buflen); ++int hex2int(char *b); + + int is_valid_lldp_device(const char *ifname); + int is_active(const char *ifname); +@@ -149,8 +150,7 @@ int get_mautype(const char *); + int get_ifpflags(const char *); + int get_iftype(const char *); + int get_src_mac_from_bond(struct port *bond_port, char *ifname, u8 *addr); +-int get_mac(const char *ifname, u8 mac[]); +-int get_macstr(const char *ifname, char *addr, size_t size); ++int get_mac(const char *ifname, u8 mac[], bool perm_mac); + int get_saddr(const char *ifname, struct sockaddr_in *saddr); + int get_ipaddr(const char *ifname, struct in_addr *); + int get_ipaddrstr(const char *ifname, char *ipaddr, size_t size); +diff -upr a/include/qbg_ecp22.h b/include/qbg_ecp22.h +--- a/include/qbg_ecp22.h 2015-01-20 13:42:56.000000000 -0500 ++++ b/include/qbg_ecp22.h 2020-09-23 08:50:52.649813883 -0400 +@@ -49,10 +49,10 @@ enum { /* ECP Transmit states */ + ECP22_TX_ERROR + }; + +-enum { ++enum ecp22_mode { + ECP22_REQUEST = 0, + ECP22_ACK +-} ecp22_mode; ++}; + + struct ecp22_hdr { /* ECP22 header */ + u16 ver_op_sub; /* ECP22 version, operation, subtype */ +diff -upr a/include/qbg_vdpnl.h b/include/qbg_vdpnl.h +--- a/include/qbg_vdpnl.h 2021-06-09 10:58:59.201200461 -0400 ++++ b/include/qbg_vdpnl.h 2021-01-06 11:05:30.810649436 -0500 +@@ -33,6 +33,7 @@ + #include + + #define MAX_PAYLOAD 4096 /* Maximum Payload Size */ ++#define MIN_RCVBUF_SIZE (MAX_PAYLOAD << 5) /* SO_RCVBUF min */ + + enum { + vdpnl_nlf1 = 1, /* Netlink message format 1 (draft 0.2) */ +diff -upr a/lldp/agent.c b/lldp/agent.c +--- a/lldp/agent.c 2021-06-09 10:58:59.215200642 -0400 ++++ b/lldp/agent.c 2021-01-06 11:05:30.811649451 -0500 +@@ -163,7 +163,7 @@ static void timer(UNUSED void *eloop_dat + run_rx_sm(port, agent); + update_rx_timers(agent); + +- LIST_FOREACH(n, &lldp_head, lldp) { ++ LIST_FOREACH(n, &lldp_mod_head, lldp) { + if (n->ops && n->ops->timer) + n->ops->timer(port, agent); + } +@@ -200,7 +200,7 @@ void clean_lldp_agents(void) + LLDPAD_DBG("Send shutdown frame on port %s\n", + port->ifname); + LIST_FOREACH(agent, &port->agent_head, entry) { +- process_tx_shutdown_frame(port, agent); ++ process_tx_shutdown_frame(port, agent, false); + } + } else { + LLDPAD_DBG("No shutdown frame is sent on port %s\n", +diff -upr a/lldp/l2_packet.h b/lldp/l2_packet.h +--- a/lldp/l2_packet.h 2015-01-20 13:42:56.000000000 -0500 ++++ b/lldp/l2_packet.h 2020-09-23 08:50:52.649813883 -0400 +@@ -37,7 +37,9 @@ + #define IP2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] + #define IPSTR "%02x:%02x:%02x:%02x:%02x:%02x" + ++#ifndef ETH_P_LLDP + #define ETH_P_LLDP 0x88cc ++#endif + + #define ETH_P_ECP 0x88b7 /* Draft 0.2 */ + #define ETH_P_ECP22 0x8940 /* Ratified standard */ +@@ -56,12 +58,11 @@ + */ + struct l2_packet_data; + +- +-struct l2_ethhdr { ++STRUCT_PACKED(struct l2_ethhdr { + u8 h_dest[ETH_ALEN]; + u8 h_source[ETH_ALEN]; + u16 h_proto; +-} STRUCT_PACKED; ++}); + + /** + * l2_packet_init - Initialize l2_packet interface +diff -upr a/lldp/l2_packet_linux.c b/lldp/l2_packet_linux.c +--- a/lldp/l2_packet_linux.c 2015-01-20 13:42:56.000000000 -0500 ++++ b/lldp/l2_packet_linux.c 2020-09-23 08:50:52.649813883 -0400 +@@ -60,7 +60,7 @@ struct l2_packet_data { + + int l2_packet_get_own_src_addr(struct l2_packet_data *l2, u8 *addr) + { +- if (is_san_mac(l2->san_mac_addr)) ++ if (is_valid_mac(l2->san_mac_addr)) + memcpy(addr, l2->san_mac_addr, ETH_ALEN); + else { + /* get an appropriate src MAC to use if the port is +@@ -169,7 +169,7 @@ struct l2_packet_data * l2_packet_init( + if (l2 == NULL) + return NULL; + memset(l2, 0, sizeof(*l2)); +- strncpy(l2->ifname, ifname, sizeof(l2->ifname)); ++ STRNCPY_TERMINATED(l2->ifname, ifname, sizeof(l2->ifname)); + l2->rx_callback = rx_callback; + l2->rx_callback_ctx = rx_callback_ctx; + l2->l2_hdr = l2_hdr; +@@ -183,7 +183,7 @@ struct l2_packet_data * l2_packet_init( + return NULL; + } + +- strncpy(ifr.ifr_name, l2->ifname, sizeof(ifr.ifr_name)); ++ STRNCPY_TERMINATED(ifr.ifr_name, l2->ifname, sizeof(ifr.ifr_name)); + if (ioctl(l2->fd, SIOCGIFINDEX, &ifr) < 0) { + perror("ioctl[SIOCGIFINDEX]"); + close(l2->fd); +diff -upr a/lldp/ports.c b/lldp/ports.c +--- a/lldp/ports.c 2021-06-09 10:58:59.211200590 -0400 ++++ b/lldp/ports.c 2020-12-07 13:15:10.579203256 -0500 +@@ -264,7 +264,7 @@ struct port *add_port(int ifindex, const + memset(newport, 0, sizeof(*newport)); + newport->ifindex = ifindex; + newport->next = NULL; +- strncpy(newport->ifname, ifname, IFNAMSIZ); ++ strncpy(newport->ifname, ifname, IFNAMSIZ - 1); + + newport->bond_master = is_bond(ifname); + /* Initialize relevant port variables */ +diff -upr a/lldp/rx.c b/lldp/rx.c +--- a/lldp/rx.c 2015-01-20 13:42:56.000000000 -0500 ++++ b/lldp/rx.c 2021-06-09 11:00:02.480019469 -0400 +@@ -139,7 +139,16 @@ void rxProcessFrame(struct port *port, s + int err; + struct lldp_module *np; + +- assert(agent->rx.framein && agent->rx.sizein); ++ if (!agent->rx.framein) { ++ LLDPAD_DBG("ERROR - agent framein not set, " ++ "has the neighbour MAC changed? " ++ "Ignoring packet.\n"); ++ return; ++ } ++ if (!agent->rx.sizein) { ++ LLDPAD_DBG("Size-0 packet received, ignoring packet\n"); ++ return; ++ } + agent->lldpdu = 0; + agent->rx.dupTlvs = 0; + +@@ -359,7 +368,7 @@ void rxProcessFrame(struct port *port, s + } + + /* rx per lldp module */ +- LIST_FOREACH(np, &lldp_head, lldp) { ++ LIST_FOREACH(np, &lldp_mod_head, lldp) { + if (!np->ops || !np->ops->lldp_mod_rchange) + continue; + +@@ -377,7 +386,7 @@ void rxProcessFrame(struct port *port, s + if (!tlv_stored) { + LLDPAD_INFO("%s: allocated TLV %u was not stored! %p\n", + __func__, tlv->type, tlv); +- tlv = free_unpkd_tlv(tlv); ++ free_unpkd_tlv(tlv); + agent->stats.statsTLVsUnrecognizedTotal++; + } + tlv = NULL; +@@ -402,7 +411,7 @@ u8 mibDeleteObjects(struct port *port, s + { + struct lldp_module *np; + +- LIST_FOREACH(np, &lldp_head, lldp) { ++ LIST_FOREACH(np, &lldp_mod_head, lldp) { + if (!np->ops || !np->ops->lldp_mod_mibdelete) + continue; + np->ops->lldp_mod_mibdelete(port, agent); +@@ -638,29 +647,21 @@ void rx_change_state(struct lldp_agent * + void clear_manifest(struct lldp_agent *agent) + { + if (agent->rx.manifest->mgmtadd) +- agent->rx.manifest->mgmtadd = +- free_unpkd_tlv(agent->rx.manifest->mgmtadd); ++ free_unpkd_tlv(agent->rx.manifest->mgmtadd); + if (agent->rx.manifest->syscap) +- agent->rx.manifest->syscap = +- free_unpkd_tlv(agent->rx.manifest->syscap); ++ free_unpkd_tlv(agent->rx.manifest->syscap); + if (agent->rx.manifest->sysdesc) +- agent->rx.manifest->sysdesc = +- free_unpkd_tlv(agent->rx.manifest->sysdesc); ++ free_unpkd_tlv(agent->rx.manifest->sysdesc); + if (agent->rx.manifest->sysname) +- agent->rx.manifest->sysname = +- free_unpkd_tlv(agent->rx.manifest->sysname); ++ free_unpkd_tlv(agent->rx.manifest->sysname); + if (agent->rx.manifest->portdesc) +- agent->rx.manifest->portdesc = +- free_unpkd_tlv(agent->rx.manifest->portdesc); ++ free_unpkd_tlv(agent->rx.manifest->portdesc); + if (agent->rx.manifest->ttl) +- agent->rx.manifest->ttl = +- free_unpkd_tlv(agent->rx.manifest->ttl); ++ free_unpkd_tlv(agent->rx.manifest->ttl); + if (agent->rx.manifest->portid) +- agent->rx.manifest->portid = +- free_unpkd_tlv(agent->rx.manifest->portid); ++ free_unpkd_tlv(agent->rx.manifest->portid); + if (agent->rx.manifest->chassis) +- agent->rx.manifest->chassis = +- free_unpkd_tlv(agent->rx.manifest->chassis); ++ free_unpkd_tlv(agent->rx.manifest->chassis); + free(agent->rx.manifest); + agent->rx.manifest = NULL; + } +diff -upr a/lldp/states.h b/lldp/states.h +--- a/lldp/states.h 2021-06-09 10:58:59.211200590 -0400 ++++ b/lldp/states.h 2021-01-06 11:05:30.811649451 -0500 +@@ -85,7 +85,7 @@ u8 txFrame(struct port *port, struct lld + void run_tx_sm(struct port *, struct lldp_agent *); + void process_tx_initialize_sm(struct port *); + void process_tx_idle(struct lldp_agent *); +-void process_tx_shutdown_frame(struct port *, struct lldp_agent *); ++void process_tx_shutdown_frame(struct port *, struct lldp_agent *, bool); + void process_tx_info_frame(struct port *, struct lldp_agent *); + void update_tx_timers(struct lldp_agent *); + void run_tx_timers_sm(struct port *, struct lldp_agent *); +diff -upr a/lldp/tx.c b/lldp/tx.c +--- a/lldp/tx.c 2021-06-09 10:58:59.211200590 -0400 ++++ b/lldp/tx.c 2021-01-06 11:05:30.812649467 -0500 +@@ -71,7 +71,7 @@ bool mibConstrInfoLLDPDU(struct port *po + fb_offset += sizeof(struct l2_ethhdr); + + /* Generic TLV Pack */ +- LIST_FOREACH(np, &lldp_head, lldp) { ++ LIST_FOREACH(np, &lldp_mod_head, lldp) { + if (!np->ops || !np->ops->lldp_mod_gettlv) + continue; + +@@ -83,7 +83,7 @@ bool mibConstrInfoLLDPDU(struct port *po + ptlv->tlv, ptlv->size); + datasize += ptlv->size; + fb_offset += ptlv->size; +- ptlv = free_pkd_tlv(ptlv); ++ free_pkd_tlv(ptlv); + } + } + +@@ -94,7 +94,7 @@ bool mibConstrInfoLLDPDU(struct port *po + memcpy(agent->tx.frameout + fb_offset, ptlv->tlv, ptlv->size); + datasize += ptlv->size; + fb_offset += ptlv->size; +- ptlv = free_pkd_tlv(ptlv); ++ free_pkd_tlv(ptlv); + + if (datasize < ETH_MIN_DATA_LEN) + agent->tx.sizeout = ETH_ZLEN; +@@ -104,7 +104,7 @@ bool mibConstrInfoLLDPDU(struct port *po + return true; + + error: +- ptlv = free_pkd_tlv(ptlv); ++ free_pkd_tlv(ptlv); + if (agent->tx.frameout) + free(agent->tx.frameout); + agent->tx.frameout = NULL; +@@ -206,7 +206,7 @@ bool mibConstrShutdownLLDPDU(struct port + memcpy(agent->tx.frameout, (void *)ð, sizeof(struct l2_ethhdr)); + fb_offset += sizeof(struct l2_ethhdr); + +- np = find_module_by_id(&lldp_head, LLDP_MOD_MAND); ++ np = find_module_by_id(&lldp_mod_head, LLDP_MOD_MAND); + if (!np) + goto error; + if (!np->ops || !np->ops->lldp_mod_gettlv) +@@ -220,7 +220,7 @@ bool mibConstrShutdownLLDPDU(struct port + memcpy(agent->tx.frameout + fb_offset, ptlv->tlv, ptlv->size); + datasize += ptlv->size; + fb_offset += ptlv->size; +- ptlv = free_pkd_tlv(ptlv); ++ free_pkd_tlv(ptlv); + } + + /* The End TLV marks the end of the LLDP PDU */ +@@ -230,7 +230,7 @@ bool mibConstrShutdownLLDPDU(struct port + memcpy(agent->tx.frameout + fb_offset, ptlv->tlv, ptlv->size); + datasize += ptlv->size; + fb_offset += ptlv->size; +- ptlv = free_pkd_tlv(ptlv); ++ free_pkd_tlv(ptlv); + + if (datasize < ETH_MIN_DATA_LEN) + agent->tx.sizeout = ETH_ZLEN; +@@ -239,7 +239,7 @@ bool mibConstrShutdownLLDPDU(struct port + return true; + + error: +- ptlv = free_pkd_tlv(ptlv); ++ free_pkd_tlv(ptlv); + if (agent->tx.frameout) + free(agent->tx.frameout); + agent->tx.frameout = NULL; +@@ -270,7 +270,7 @@ void run_tx_sm(struct port *port, struct + process_tx_idle(agent); + break; + case TX_SHUTDOWN_FRAME: +- process_tx_shutdown_frame(port, agent); ++ process_tx_shutdown_frame(port, agent, true); + break; + case TX_INFO_FRAME: + process_tx_info_frame(port, agent); +@@ -330,8 +330,19 @@ void process_tx_idle(UNUSED struct lldp_ + return; + } + +-void process_tx_shutdown_frame(struct port *port, struct lldp_agent *agent) ++/* we ignore 'adminStatus' in the case that we have recently transitioned ++ * to the shutdown state (in the case of the 'tx' state change) to allow ++ * for transmitting the ttl==0 as required by the IEEE standard. */ ++void process_tx_shutdown_frame(struct port *port, struct lldp_agent *agent, ++ bool ignoreStatus) + { ++ if (agent->adminStatus != enabledRxTx && ++ agent->adminStatus != enabledTxOnly) { ++ if (!ignoreStatus) { ++ return; ++ } ++ } ++ + if (agent->timers.txShutdownWhile == 0) { + if (mibConstrShutdownLLDPDU(port, agent)) + txFrame(port, agent); +diff -upr a/lldp_8021qaz.c b/lldp_8021qaz.c +--- a/lldp_8021qaz.c 2021-06-09 10:58:59.217200668 -0400 ++++ b/lldp_8021qaz.c 2020-11-03 09:08:48.059229036 -0500 +@@ -48,8 +48,8 @@ + #include "lldp_dcbx.h" + + +-struct lldp_head lldp_head; +-struct config_t lldpad_cfg; ++extern config_t lldpad_cfg; ++extern bool read_only_8021qaz; + + static int ieee8021qaz_check_pending(struct port *port, struct lldp_agent *); + static void run_all_sm(struct port *port, struct lldp_agent *agent); +@@ -83,7 +83,7 @@ static int ieee8021qaz_check_pending(str + if (!port->portEnabled) + return 0; + +- iud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_8021QAZ); ++ iud = find_module_user_data_by_id(&lldp_mod_head, LLDP_MOD_8021QAZ); + if (iud) { + LIST_FOREACH(tlv, &iud->head, entry) { + if (!strncmp(port->ifname, tlv->ifname, IFNAMSIZ)) { +@@ -111,14 +111,14 @@ struct lldp_module *ieee8021qaz_register + + mod = malloc(sizeof(*mod)); + if (!mod) { +- LLDPAD_ERR("Failed to malloc LLDP-8021QAZ module data"); ++ LLDPAD_ERR("Failed to malloc LLDP-8021QAZ module data\n"); + goto out_err; + } + + iud = malloc(sizeof(*iud)); + if (!iud) { + free(mod); +- LLDPAD_ERR("Failed to malloc LLDP-8021QAZ module user data"); ++ LLDPAD_ERR("Failed to malloc LLDP-8021QAZ module user data\n"); + goto out_err; + } + memset((void *) iud, 0, sizeof(struct ieee8021qaz_user_data)); +@@ -142,7 +142,7 @@ struct ieee8021qaz_tlvs *ieee8021qaz_dat + struct ieee8021qaz_user_data *iud; + struct ieee8021qaz_tlvs *tlv = NULL; + +- iud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_8021QAZ); ++ iud = find_module_user_data_by_id(&lldp_mod_head, LLDP_MOD_8021QAZ); + if (iud) { + LIST_FOREACH(tlv, &iud->head, entry) { + if (!strncmp(tlv->ifname, ifname, IFNAMSIZ)) +@@ -396,7 +396,7 @@ static int read_cfg_file(char *ifname, s + return 0; + } + +-inline int get_prio_map(u32 prio_map, int prio) ++static int get_prio_map(u32 prio_map, int prio) + { + if (prio > 7) + return 0; +@@ -404,7 +404,7 @@ inline int get_prio_map(u32 prio_map, in + return (prio_map >> (4 * (7-prio))) & 0xF; + } + +-inline void set_prio_map(u32 *prio_map, u8 prio, int tc) ++static void set_prio_map(u32 *prio_map, u8 prio, int tc) + { + u32 mask = ~(0xffffffff & (0xF << (4 * (7-prio)))); + *prio_map &= mask; +@@ -590,7 +590,7 @@ void ieee8021qaz_ifup(char *ifname, stru + memset(tlvs->rx, 0, sizeof(*tlvs->rx)); + + /* Initializing the ieee8021qaz_tlvs struct */ +- strncpy(tlvs->ifname, ifname, IFNAMSIZ); ++ STRNCPY_TERMINATED(tlvs->ifname, ifname, IFNAMSIZ); + tlvs->port = port; + tlvs->ieee8021qazdu = 0; + l2_packet_get_own_src_addr(port->l2, tlvs->local_mac); +@@ -628,7 +628,7 @@ void ieee8021qaz_ifup(char *ifname, stru + LIST_INIT(&tlvs->app_head); + read_cfg_file(port->ifname, agent, tlvs); + +- iud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_8021QAZ); ++ iud = find_module_user_data_by_id(&lldp_mod_head, LLDP_MOD_8021QAZ); + LIST_INSERT_HEAD(&iud->head, tlvs, entry); + + initialized: +@@ -959,6 +959,9 @@ static int del_ieee_hw(const char *ifnam + .dcb_pad = 0 + }; + ++ if (read_only_8021qaz) ++ return 0; ++ + nlsocket = nl_socket_alloc(); + if (!nlsocket) { + LLDPAD_WARN("%s: %s: nl_handle_alloc failed\n", +@@ -1042,6 +1045,9 @@ static int set_ieee_hw(const char *ifnam + .dcb_pad = 0 + }; + ++ if (read_only_8021qaz) ++ return 0; ++ + nlsocket = nl_socket_alloc(); + if (!nlsocket) { + LLDPAD_WARN("%s: %s: nl_handle_alloc failed\n", +@@ -1618,15 +1624,15 @@ static void clear_ieee8021qaz_rx(struct + return; + + if (tlvs->rx->ieee8021qaz) +- tlvs->rx->ieee8021qaz = free_unpkd_tlv(tlvs->rx->ieee8021qaz); ++ free_unpkd_tlv(tlvs->rx->ieee8021qaz); + if (tlvs->rx->etscfg) +- tlvs->rx->etscfg = free_unpkd_tlv(tlvs->rx->etscfg); ++ free_unpkd_tlv(tlvs->rx->etscfg); + if (tlvs->rx->etsrec) +- tlvs->rx->etsrec = free_unpkd_tlv(tlvs->rx->etsrec); ++ free_unpkd_tlv(tlvs->rx->etsrec); + if (tlvs->rx->pfc) +- tlvs->rx->pfc = free_unpkd_tlv(tlvs->rx->pfc); ++ free_unpkd_tlv(tlvs->rx->pfc); + if (tlvs->rx->app) +- tlvs->rx->app = free_unpkd_tlv(tlvs->rx->app); ++ free_unpkd_tlv(tlvs->rx->app); + + free(tlvs->rx); + tlvs->rx = NULL; +@@ -2014,13 +2020,13 @@ static void ieee8021qaz_free_rx(struct i + return; + + if (rx->etscfg) +- rx->etscfg = free_unpkd_tlv(rx->etscfg); ++ free_unpkd_tlv(rx->etscfg); + if (rx->etsrec) +- rx->etsrec = free_unpkd_tlv(rx->etsrec); ++ free_unpkd_tlv(rx->etsrec); + if (rx->pfc) +- rx->pfc = free_unpkd_tlv(rx->pfc); ++ free_unpkd_tlv(rx->pfc); + if (rx->app) +- rx->app = free_unpkd_tlv(rx->app); ++ free_unpkd_tlv(rx->app); + + return; + } +@@ -2106,9 +2112,9 @@ static void ieee8021qaz_free_tlv(struct + return; + + if (tlvs->ets) +- tlvs->ets = free_ets_tlv(tlvs->ets); ++ free_ets_tlv(tlvs->ets); + if (tlvs->pfc) +- tlvs->pfc = free_pfc_tlv(tlvs->pfc); ++ free_pfc_tlv(tlvs->pfc); + + /* Remove _all_ existing application data */ + LIST_FOREACH(np, &tlvs->app_head, entry) +@@ -2172,7 +2178,7 @@ int ieee8021qaz_tlvs_rxed(const char *if + struct ieee8021qaz_user_data *iud; + struct ieee8021qaz_tlvs *tlv = NULL; + +- iud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_8021QAZ); ++ iud = find_module_user_data_by_id(&lldp_mod_head, LLDP_MOD_8021QAZ); + if (iud) { + LIST_FOREACH(tlv, &iud->head, entry) { + if (!strncmp(tlv->ifname, ifname, IFNAMSIZ)) +@@ -2191,7 +2197,7 @@ int ieee8021qaz_check_active(const char + struct ieee8021qaz_user_data *iud; + struct ieee8021qaz_tlvs *tlv = NULL; + +- iud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_8021QAZ); ++ iud = find_module_user_data_by_id(&lldp_mod_head, LLDP_MOD_8021QAZ); + if (iud) { + LIST_FOREACH(tlv, &iud->head, entry) { + if (!strncmp(tlv->ifname, ifname, IFNAMSIZ)) +diff -upr a/lldp_8021qaz_clif.c b/lldp_8021qaz_clif.c +--- a/lldp_8021qaz_clif.c 2015-01-20 13:42:56.000000000 -0500 ++++ b/lldp_8021qaz_clif.c 2020-09-23 08:50:52.650813901 -0400 +@@ -251,40 +251,70 @@ static void ieee8021qaz_print_pfc_tlv(UN + + static void ieee8021qaz_print_app_tlv(u16 len, char *info) + { +- u8 offset = 2; +- u8 app; +- u16 proto; ++ u8 app, app_idx, app_prio, app_sel; ++ u16 proto, offset = 2; ++ u8 dscp[MAX_USER_PRIORITIES][MAX_APP_ENTRIES]; ++ u8 dscp_count[MAX_USER_PRIORITIES] = {0}; ++ u8 i, j; ++ bool first_app = true; + + while (offset < len*2) { + hexstr2bin(info + offset, &app, 1); + hexstr2bin(info + offset + 2, (u8 *)&proto, 2); + +- if (offset > 6) +- printf("\t"); +- printf("App#%i:\n", offset/6); +- printf("\t Priority: %i\n", (app & 0xE0) >> 5); +- printf("\t Sel: %i\n", app & 0x07); +- switch (app & 0x07) { +- case 1: +- printf("\t Ethertype: 0x%04x\n", ntohs(proto)); +- break; +- case 2: +- printf("\t {S}TCP Port: %i\n", ntohs(proto)); +- break; +- case 3: +- printf("\t UDP or DCCP Port: %i\n", ntohs(proto)); +- break; +- case 4: +- printf("\t TCP/STCP/UDP/DCCP Port: %i\n", ntohs(proto)); +- break; +- default: +- printf("\t Reserved Port: %i\n", ntohs(proto)); +- break; ++ app_idx = offset/6; ++ app_prio = (app & 0xE0) >> 5; ++ app_sel = app & 0x07; ++ ++ // Selector five is DSCP. Save value to print table at the end ++ if (app_sel == 5) { ++ dscp[app_prio][dscp_count[app_prio]] = ntohs(proto) & 0x3F; ++ dscp_count[app_prio]++; ++ } else { ++ if (first_app) ++ first_app = false; ++ else ++ printf("\t"); ++ printf("App# %3i \t Prio %1i \t Sel %1i \t P-ID", ++ app_idx, app_prio, app_sel); ++ ++ switch (app_sel) { ++ case 1: ++ printf("\t Ethertype: 0x%04x\n", ntohs(proto)); ++ break; ++ case 2: ++ printf("\t {S}TCP Port: %i\n", ntohs(proto)); ++ break; ++ case 3: ++ printf("\t UDP or DCCP Port: %i\n", ntohs(proto)); ++ break; ++ case 4: ++ printf("\t TCP/STCP/UDP/DCCP Port: %i\n", ntohs(proto)); ++ break; ++ default: ++ printf("\t Reserved Port: %i\n", ntohs(proto)); ++ break; ++ } + } + +- printf("\n"); + offset += 6; + } ++ ++ for(i=0; ihead, entry) { + if (!strncmp(ifname, bd->ifname, IFNAMSIZ) && +@@ -401,7 +399,7 @@ struct packed_tlv *ieee8023_gettlv(struc + PACK_TLV_AFTER(bd->maxfs, ptlv, size, out_free); + return ptlv; + out_free: +- ptlv = free_pkd_tlv(ptlv); ++ free_pkd_tlv(ptlv); + out_err: + LLDPAD_DBG("%s:%s: failed\n", __func__, port->ifname); + return NULL; +@@ -447,7 +445,7 @@ void ieee8023_ifup(char *ifname, struct + goto out_err; + } + memset(bd, 0, sizeof(struct ieee8023_data)); +- strncpy(bd->ifname, ifname, IFNAMSIZ); ++ STRNCPY_TERMINATED(bd->ifname, ifname, IFNAMSIZ); + bd->agenttype = agent->type; + + if (ieee8023_bld_tlv(bd, agent)) { +@@ -456,7 +454,7 @@ void ieee8023_ifup(char *ifname, struct + goto out_err; + } + +- ud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_8023); ++ ud = find_module_user_data_by_id(&lldp_mod_head, LLDP_MOD_8023); + LIST_INSERT_HEAD(&ud->head, bd, entry); + LLDPAD_INFO("%s:port %s added\n", __func__, ifname); + return; +@@ -472,13 +470,13 @@ struct lldp_module *ieee8023_register(vo + + mod = malloc(sizeof(*mod)); + if (!mod) { +- LLDPAD_ERR("failed to malloc LLDP 802.3 module data"); ++ LLDPAD_ERR("failed to malloc LLDP 802.3 module data\n"); + goto out_err; + } + ud = malloc(sizeof(struct ieee8023_user_data)); + if (!ud) { + free(mod); +- LLDPAD_ERR("failed to malloc LLDP 802.3 module user data"); ++ LLDPAD_ERR("failed to malloc LLDP 802.3 module user data\n"); + goto out_err; + } + LIST_INIT(&ud->head); +diff -upr a/lldpad.c b/lldpad.c +--- a/lldpad.c 2021-06-09 10:58:59.208200552 -0400 ++++ b/lldpad.c 2021-04-05 12:02:17.320590536 -0400 +@@ -80,10 +80,13 @@ struct lldp_module *(*register_tlv_table + NULL, + }; + ++struct lldp_head lldp_mod_head; ++ + char *cfg_file_name = NULL; + bool daemonize = 0; + int loglvl = LOG_WARNING; + int omit_tstamp; ++bool read_only_8021qaz = false; + + static const char *lldpad_version = + "lldpad v" VERSION_STR "\n" +@@ -97,7 +100,7 @@ static void init_modules(void) + struct lldp_module *premod = NULL; + int i = 0; + +- LIST_INIT(&lldp_head); ++ LIST_INIT(&lldp_mod_head); + for (i = 0; register_tlv_table[i]; i++) { + module = register_tlv_table[i](); + if (!module) +@@ -105,7 +108,7 @@ static void init_modules(void) + if (premod) + LIST_INSERT_AFTER(premod, module, lldp); + else +- LIST_INSERT_HEAD(&lldp_head, module, lldp); ++ LIST_INSERT_HEAD(&lldp_mod_head, module, lldp); + premod = module; + } + } +@@ -114,9 +117,9 @@ void deinit_modules(void) + { + struct lldp_module *module; + +- while (lldp_head.lh_first != NULL) { +- module = lldp_head.lh_first; +- LIST_REMOVE(lldp_head.lh_first, lldp); ++ while (lldp_mod_head.lh_first != NULL) { ++ module = lldp_mod_head.lh_first; ++ LIST_REMOVE(lldp_mod_head.lh_first, lldp); + module->ops->lldp_mod_unregister(module); + } + } +@@ -136,7 +139,8 @@ static void usage(void) + " -t omit timestamps in log messages\n" + " -v show version\n" + " -f use configfile instead of default\n" +- " -V set syslog level\n"); ++ " -V set syslog level\n" ++ " -R run 8021qaz module in read_only mode\n"); + + exit(1); + } +@@ -236,7 +240,7 @@ int main(int argc, char *argv[]) + int rc = 1; + + for (;;) { +- c = getopt(argc, argv, "hdksptvf:V:"); ++ c = getopt(argc, argv, "hdksptvf:RV:"); + if (c < 0) + break; + switch (c) { +@@ -259,6 +263,9 @@ int main(int argc, char *argv[]) + case 'p': + pid_file = 0; + break; ++ case 'R': ++ read_only_8021qaz = true; ++ break; + case 't': + omit_tstamp = 1; + break; +diff -upr a/lldpad.service b/lldpad.service +--- a/lldpad.service 2015-01-20 13:42:56.000000000 -0500 ++++ b/lldpad.service 2020-09-23 08:50:52.655813990 -0400 +@@ -1,9 +1,11 @@ + [Unit] + Description=Link Layer Discovery Protocol Agent Daemon. + After=syslog.target network.target ++Requires=lldpad.socket + + [Service] + Type=simple ++Restart=always + ExecStart=/usr/sbin/lldpad -t + ExecReload=/bin/kill -HUP $MAINPID + +diff -upr a/lldpad.socket b/lldpad.socket +--- a/lldpad.socket 2015-01-20 13:42:56.000000000 -0500 ++++ b/lldpad.socket 2020-09-23 08:50:52.655813990 -0400 +@@ -1,3 +1,6 @@ ++[Unit] ++Description=Link Layer Discovery Protocol Agent Socket. ++ + [Socket] + ListenDatagram=@/com/intel/lldpad + PassCredentials=true +diff -upr a/lldpad.spec.in b/lldpad.spec.in +--- a/lldpad.spec.in 2015-01-20 13:42:56.000000000 -0500 ++++ b/lldpad.spec.in 2020-09-23 08:50:52.655813990 -0400 +@@ -10,9 +10,9 @@ Source0: http://downloads.sourcef + BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) + + # BuildRequires: +-Requires(post): chkconfig +-Requires(preun): chkconfig initscripts +-Requires(postun): initscripts ++Requires(post): @SPEC_BUILD_REQUIRES_POST@ ++Requires(preun): @SPEC_BUILD_REQUIRES_PREUN@ ++Requires(postun): @SPEC_BUILD_REQUIRES_POSTUN@ + + %description + This package contains the Linux user space daemon and configuration tool for +@@ -46,20 +46,36 @@ rm -rf $RPM_BUILD_ROOT + + + %post +-/sbin/chkconfig --add lldpad ++if [ -e /etc/init.d/%{name} ] && [ -e /sbin/chkconfig ]; then ++ /sbin/chkconfig --add %{name} ++fi ++if type systemctl >/dev/null 2>&1; then ++ # Scriplet only runs preset. Run enable/start manually ++ %systemd_post %{name}.socket %{name}.service ++fi + + %preun + if [ $1 = 0 ]; then +- /sbin/service lldpad stop +- /sbin/chkconfig --del lldpad ++ if [ -e /etc/init.d/%{name} ] && [ -e /sbin/chkconfig ]; then ++ /sbin/service %{name} stop ++ /sbin/chkconfig --del %{name} ++ fi ++ if type systemctl >/dev/null 2>&1; then ++ %systemd_preun %{name}.service %{name}.socket ++ fi + fi + + %postun + if [ $1 = 1 ]; then +- /sbin/service lldpad condrestart ++ # Package upgrade, not uninstall ++ if [ -e /etc/init.d/%{name} ] && [ -e /sbin/chkconfig ]; then ++ /sbin/service %{name} condrestart ++ fi ++ if type systemctl >/dev/null 2>&1; then ++ %systemd_postun_with_restart %{name}.socket %{name}.service ++ fi + fi + +- + %files + %defattr(-,root,root,-) + %doc COPYING +@@ -67,11 +83,13 @@ fi + %doc ChangeLog + %{_sbindir}/* + %dir /var/lib/lldpad +-%{_sysconfdir}/init.d/lldpad ++@SPEC_FILE_LLDPAD_SERVICE@ ++@SPEC_FILE_LLDPAD_SOCKET@ + %{_sysconfdir}/bash_completion.d/lldpad + %{_sysconfdir}/bash_completion.d/lldptool + %{_mandir}/man8/* + %{_libdir}/liblldp_clif.* ++%{_mandir}/man3/liblldp_clif-vdp22.* + + %files devel + %defattr(-,root,root,-) +diff -upr a/lldp_basman.c b/lldp_basman.c +--- a/lldp_basman.c 2015-01-20 13:42:56.000000000 -0500 ++++ b/lldp_basman.c 2020-11-03 09:08:48.059229036 -0500 +@@ -75,8 +75,6 @@ struct tlv_info_manaddr { + struct tlv_info_maoid o; + } __attribute__ ((__packed__)); + +-extern struct lldp_head lldp_head; +- + static const struct lldp_mod_ops basman_ops = { + .lldp_mod_register = basman_register, + .lldp_mod_unregister = basman_unregister, +@@ -91,7 +89,7 @@ static struct basman_data *basman_data(c + struct basman_user_data *bud; + struct basman_data *bd = NULL; + +- bud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_BASIC); ++ bud = find_module_user_data_by_id(&lldp_mod_head, LLDP_MOD_BASIC); + if (bud) { + LIST_FOREACH(bd, &bud->head, entry) { + if (!strncmp(ifname, bd->ifname, IFNAMSIZ) && +@@ -636,7 +634,7 @@ struct packed_tlv *basman_gettlv(struct + PACK_TLV_AFTER(bd->manaddr[i], ptlv, size, out_free); + return ptlv; + out_free: +- ptlv = free_pkd_tlv(ptlv); ++ free_pkd_tlv(ptlv); + out_err: + LLDPAD_DBG("%s:%s: failed\n", __func__, port->ifname); + return NULL; +@@ -679,7 +677,7 @@ void basman_ifup(char *ifname, struct ll + goto out_err; + } + memset(bd, 0, sizeof(struct basman_data)); +- strncpy(bd->ifname, ifname, IFNAMSIZ); ++ STRNCPY_TERMINATED(bd->ifname, ifname, IFNAMSIZ); + bd->agenttype = agent->type; + + if (basman_bld_tlv(bd, agent)) { +@@ -688,7 +686,7 @@ void basman_ifup(char *ifname, struct ll + goto out_err; + } + +- bud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_BASIC); ++ bud = find_module_user_data_by_id(&lldp_mod_head, LLDP_MOD_BASIC); + LIST_INSERT_HEAD(&bud->head, bd, entry); + LLDPAD_DBG("%s:port %s added\n", __func__, ifname); + return; +diff -upr a/lldp_basman_cmds.c b/lldp_basman_cmds.c +--- a/lldp_basman_cmds.c 2015-01-20 13:42:56.000000000 -0500 ++++ b/lldp_basman_cmds.c 2020-09-23 08:50:52.652813936 -0400 +@@ -51,6 +51,9 @@ static int test_arg_ipv6(struct cmd *, c + static int get_arg_tlvtxenable(struct cmd *, char *, char *, char *, int); + static int set_arg_tlvtxenable(struct cmd *, char *, char *, char *, int); + static int test_arg_tlvtxenable(struct cmd *, char *, char *, char *, int); ++static int get_arg_info(struct cmd *, char *, char *, char *, int); ++static int set_arg_info(struct cmd *, char *, char *, char *, int); ++static int test_arg_info(struct cmd *, char *, char *, char *, int); + + static struct arg_handlers arg_handlers[] = { + { .arg = ARG_IPV4_ADDR, .arg_class = TLV_ARG, +@@ -65,6 +68,10 @@ static struct arg_handlers arg_handlers[ + .handle_get = get_arg_tlvtxenable, + .handle_set = set_arg_tlvtxenable, + .handle_test = test_arg_tlvtxenable }, ++ { .arg = ARG_TLVINFO, .arg_class = TLV_ARG, ++ .handle_get = get_arg_info, ++ .handle_set = set_arg_info, ++ .handle_test = test_arg_info }, + { .arg = 0 } + }; + +@@ -166,6 +173,89 @@ static int test_arg_tlvtxenable(struct c + return _set_arg_tlvtxenable(cmd, arg, argvalue, obuf, obuf_len, true); + } + ++static int get_arg_info(struct cmd *cmd, char *arg, UNUSED char *argvalue, ++ char *obuf, int obuf_len) ++{ ++ const char *info_str = NULL; ++ char arg_path[256]; ++ ++ if (cmd->cmd != cmd_gettlv) ++ return cmd_invalid; ++ ++ switch (cmd->tlvid) { ++ case PORT_DESCRIPTION_TLV: ++ case SYSTEM_NAME_TLV: ++ case SYSTEM_DESCRIPTION_TLV: ++ case SYSTEM_CAPABILITIES_TLV: ++ case MANAGEMENT_ADDRESS_TLV: ++ snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", ++ TLVID_PREFIX, cmd->tlvid, arg); ++ ++ get_config_setting(cmd->ifname, cmd->type, arg_path, ++ &info_str, CONFIG_TYPE_STRING); ++ break; ++ case INVALID_TLVID: ++ return cmd_invalid; ++ default: ++ return cmd_not_applicable; ++ } ++ ++ if (info_str) ++ snprintf(obuf, obuf_len, "%02x%s%04x%s", ++ (unsigned int)strlen(arg), arg, ++ (unsigned int)strlen(info_str), info_str); ++ ++ return cmd_success; ++} ++ ++static int _set_arg_info(struct cmd *cmd, UNUSED char *arg, char *argvalue, ++ char *obuf, int obuf_len, bool test) ++{ ++ if (cmd->cmd != cmd_settlv) ++ return cmd_invalid; ++ ++ switch (cmd->tlvid) { ++ case PORT_DESCRIPTION_TLV: ++ case SYSTEM_NAME_TLV: ++ case SYSTEM_DESCRIPTION_TLV: ++ case SYSTEM_CAPABILITIES_TLV: ++ case MANAGEMENT_ADDRESS_TLV: ++ break; ++ case INVALID_TLVID: ++ return cmd_invalid; ++ default: ++ return cmd_not_applicable; ++ } ++ ++ if (strlen(argvalue) < 1) ++ return cmd_invalid; ++ ++ if (test) ++ return cmd_success; ++ ++ if (set_config_tlvinfo_str(cmd->ifname, cmd->type, ++ cmd->tlvid, argvalue)) ++ return cmd_failed; ++ ++ snprintf(obuf, obuf_len, "enableTx = %s\n", argvalue); ++ ++ somethingChangedLocal(cmd->ifname, cmd->type); ++ ++ return cmd_success; ++} ++ ++static int set_arg_info(struct cmd *cmd, char *arg, char *argvalue, ++ char *obuf, int obuf_len) ++{ ++ return _set_arg_info(cmd, arg, argvalue, obuf, obuf_len, false); ++} ++ ++static int test_arg_info(struct cmd *cmd, char *arg, char *argvalue, ++ char *obuf, int obuf_len) ++{ ++ return _set_arg_info(cmd, arg, argvalue, obuf, obuf_len, true); ++} ++ + struct arg_handlers *basman_get_arg_handlers() + { + return &arg_handlers[0]; +diff -upr a/lldp_dcbx.c b/lldp_dcbx.c +--- a/lldp_dcbx.c 2015-01-20 13:42:56.000000000 -0500 ++++ b/lldp_dcbx.c 2020-10-23 14:12:58.975289310 -0400 +@@ -129,7 +129,7 @@ struct dcbx_tlvs *dcbx_data(const char * + struct dcbd_user_data *dud; + struct dcbx_tlvs *tlv = NULL; + +- dud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_DCBX); ++ dud = find_module_user_data_by_id(&lldp_mod_head, LLDP_MOD_DCBX); + if (dud) { + LIST_FOREACH(tlv, &dud->head, entry) { + if (!strncmp(tlv->ifname, ifname, IFNAMSIZ)) +@@ -148,7 +148,7 @@ int dcbx_tlvs_rxed(const char *ifname, s + if (agent->type != NEAREST_BRIDGE) + return 0; + +- dud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_DCBX); ++ dud = find_module_user_data_by_id(&lldp_mod_head, LLDP_MOD_DCBX); + if (dud) { + LIST_FOREACH(tlv, &dud->head, entry) { + if (!strncmp(tlv->ifname, ifname, IFNAMSIZ)) +@@ -172,7 +172,7 @@ int dcbx_check_active(const char *ifname + struct dcbd_user_data *dud; + struct dcbx_tlvs *tlv = NULL; + +- dud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_DCBX); ++ dud = find_module_user_data_by_id(&lldp_mod_head, LLDP_MOD_DCBX); + if (dud) { + LIST_FOREACH(tlv, &dud->head, entry) { + if (!strncmp(tlv->ifname, ifname, IFNAMSIZ)) +@@ -194,6 +194,8 @@ int dcbx_bld_tlv(struct port *newport, s + return 0; + + tlvs = dcbx_data(newport->ifname); ++ if (!tlvs) ++ return 0; + + get_config_setting(newport->ifname, agent->type, ARG_ADMINSTATUS, + &adminstatus, CONFIG_TYPE_INT); +@@ -283,20 +285,20 @@ void dcbx_free_manifest(struct dcbx_mani + return; + + if (manifest->dcbx1) +- manifest->dcbx1 = free_unpkd_tlv(manifest->dcbx1); ++ free_unpkd_tlv(manifest->dcbx1); + if (manifest->dcbx2) +- manifest->dcbx2 = free_unpkd_tlv(manifest->dcbx2); ++ free_unpkd_tlv(manifest->dcbx2); + if (manifest->dcbx_ctrl) +- manifest->dcbx_ctrl = free_unpkd_tlv(manifest->dcbx_ctrl); ++ free_unpkd_tlv(manifest->dcbx_ctrl); + if (manifest->dcbx_pg) +- manifest->dcbx_pg = free_unpkd_tlv(manifest->dcbx_pg); ++ free_unpkd_tlv(manifest->dcbx_pg); + if (manifest->dcbx_pfc) +- manifest->dcbx_pfc = free_unpkd_tlv(manifest->dcbx_pfc); ++ free_unpkd_tlv(manifest->dcbx_pfc); + if (manifest->dcbx_app) +- manifest->dcbx_app = free_unpkd_tlv(manifest->dcbx_app); ++ free_unpkd_tlv(manifest->dcbx_app); + if (manifest->dcbx_llink) +- manifest->dcbx_llink = free_unpkd_tlv(manifest->dcbx_llink); +- ++ free_unpkd_tlv(manifest->dcbx_llink); ++ free(manifest); + return; + } + +@@ -305,44 +307,27 @@ void dcbx_free_tlv(struct dcbx_tlvs *tlv + if (!tlvs) + return; + +- if (tlvs->control != NULL) { +- tlvs->control = free_unpkd_tlv(tlvs->control); +- } +- +- if (tlvs->pg1 != NULL) { +- tlvs->pg1 = free_unpkd_tlv(tlvs->pg1); +- } +- +- if (tlvs->pg2 != NULL) { +- tlvs->pg2 = free_unpkd_tlv(tlvs->pg2); +- } +- +- if (tlvs->pfc1 != NULL) { +- tlvs->pfc1 = free_unpkd_tlv(tlvs->pfc1); +- } +- +- if (tlvs->pfc2 != NULL) { +- tlvs->pfc2 = free_unpkd_tlv(tlvs->pfc2); +- } +- +- if (tlvs->app1 != NULL) { +- tlvs->app1 = free_unpkd_tlv(tlvs->app1); +- } +- +- if (tlvs->app2 != NULL) +- tlvs->app2 = free_unpkd_tlv(tlvs->app2); ++ if (tlvs->control) ++ free_unpkd_tlv(tlvs->control); ++ if (tlvs->pg1) ++ free_unpkd_tlv(tlvs->pg1); ++ if (tlvs->pg2) ++ free_unpkd_tlv(tlvs->pg2); ++ if (tlvs->pfc1) ++ free_unpkd_tlv(tlvs->pfc1); ++ if (tlvs->pfc2) ++ free_unpkd_tlv(tlvs->pfc2); ++ if (tlvs->app1) ++ free_unpkd_tlv(tlvs->app1); ++ if (tlvs->app2) ++ free_unpkd_tlv(tlvs->app2); ++ if (tlvs->llink) ++ free_unpkd_tlv(tlvs->llink); ++ if (tlvs->dcbx1) ++ free_unpkd_tlv(tlvs->dcbx1); ++ if (tlvs->dcbx2) ++ free_unpkd_tlv(tlvs->dcbx2); + +- if (tlvs->llink != NULL) { +- tlvs->llink = free_unpkd_tlv(tlvs->llink); +- } +- +- if (tlvs->dcbx1 != NULL) { +- tlvs->dcbx1 = free_unpkd_tlv(tlvs->dcbx1); +- } +- +- if (tlvs->dcbx2 != NULL) { +- tlvs->dcbx2 = free_unpkd_tlv(tlvs->dcbx2); +- } + return; + } + +@@ -362,6 +347,7 @@ struct packed_tlv* dcbx_gettlv(struct po + return NULL; + + dcbx_free_tlv(tlvs); ++ memset(tlvs, 0, sizeof(struct dcbx_tlvs)); + + dcbx_bld_tlv(port, agent); + if (tlvs->dcbx_st == DCBX_SUBTYPE2) { +@@ -386,7 +372,6 @@ static void dcbx_free_data(struct dcbd_u + LIST_REMOVE(dd, entry); + dcbx_free_tlv(dd); + dcbx_free_manifest(dd->manifest); +- free(dd->manifest); + free(dd); + } + } +@@ -408,7 +393,7 @@ struct lldp_module * dcbx_register(void) + if (get_dcbx_version(&dcbx_version)) { + gdcbx_subtype = dcbx_version; + } else { +- LLDPAD_ERR("failed to get DCBX version"); ++ LLDPAD_ERR("failed to get DCBX version\n"); + goto out_err; + } + +@@ -505,7 +490,7 @@ void dcbx_ifup(char *ifname, struct lldp + ifindex = get_ifidx(ifname); + port = port_find_by_ifindex(ifindex); + +- dud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_DCBX); ++ dud = find_module_user_data_by_id(&lldp_mod_head, LLDP_MOD_DCBX); + tlvs = dcbx_data(ifname); + + if (!port) +@@ -582,7 +567,7 @@ void dcbx_ifup(char *ifname, struct lldp + memset(manifest, 0, sizeof(*manifest)); + + tlvs->manifest = manifest; +- strncpy(tlvs->ifname, ifname, IFNAMSIZ); ++ STRNCPY_TERMINATED(tlvs->ifname, ifname, IFNAMSIZ); + tlvs->port = port; + tlvs->dcbdu = 0; + tlvs->dcbx_st = gdcbx_subtype & MASK_DCBX_FORCE; +@@ -654,7 +639,6 @@ void dcbx_ifdown(char *device_name, stru + LIST_REMOVE(tlvs, entry); + dcbx_free_tlv(tlvs); + dcbx_free_manifest(tlvs->manifest); +- free(tlvs->manifest); + free(tlvs); + } + +@@ -664,26 +648,19 @@ void clear_dcbx_manifest(struct dcbx_tlv + return; + + if (dcbx->manifest->dcbx_llink) +- dcbx->manifest->dcbx_llink = +- free_unpkd_tlv(dcbx->manifest->dcbx_llink); ++ free_unpkd_tlv(dcbx->manifest->dcbx_llink); + if (dcbx->manifest->dcbx_app) +- dcbx->manifest->dcbx_app = +- free_unpkd_tlv(dcbx->manifest->dcbx_app); ++ free_unpkd_tlv(dcbx->manifest->dcbx_app); + if (dcbx->manifest->dcbx_pfc) +- dcbx->manifest->dcbx_pfc = +- free_unpkd_tlv(dcbx->manifest->dcbx_pfc); ++ free_unpkd_tlv(dcbx->manifest->dcbx_pfc); + if (dcbx->manifest->dcbx_pg) +- dcbx->manifest->dcbx_pg = +- free_unpkd_tlv(dcbx->manifest->dcbx_pg); ++ free_unpkd_tlv(dcbx->manifest->dcbx_pg); + if (dcbx->manifest->dcbx_ctrl) +- dcbx->manifest->dcbx_ctrl = +- free_unpkd_tlv(dcbx->manifest->dcbx_ctrl); ++ free_unpkd_tlv(dcbx->manifest->dcbx_ctrl); + if (dcbx->manifest->dcbx1) +- dcbx->manifest->dcbx1 = +- free_unpkd_tlv(dcbx->manifest->dcbx1); ++ free_unpkd_tlv(dcbx->manifest->dcbx1); + if (dcbx->manifest->dcbx2) +- dcbx->manifest->dcbx2 = +- free_unpkd_tlv(dcbx->manifest->dcbx2); ++ free_unpkd_tlv(dcbx->manifest->dcbx2); + free(dcbx->manifest); + dcbx->manifest = NULL; + } +diff -upr a/lldp_dcbx_cfg.c b/lldp_dcbx_cfg.c +--- a/lldp_dcbx_cfg.c 2015-01-20 13:42:56.000000000 -0500 ++++ b/lldp_dcbx_cfg.c 2020-09-23 08:50:52.652813936 -0400 +@@ -99,12 +99,15 @@ static config_setting_t *construct_new_s + config_setting_t *tmp2_setting = NULL; + char abuf[32]; + int i; ++ char device_name_sanitized[IFNAMSIZ]; + + dcbx_setting = config_lookup(&lldpad_cfg, DCBX_SETTING); + if (!dcbx_setting) + return NULL; + +- eth_setting = config_setting_add(dcbx_setting, device_name, ++ config_ifkey(device_name, device_name_sanitized); ++ ++ eth_setting = config_setting_add(dcbx_setting, device_name_sanitized, + CONFIG_TYPE_GROUP); + if (!eth_setting) + goto set_error; +@@ -371,11 +374,13 @@ static int _set_persistent(char *device_ + config_setting_t *setting_value = NULL; + char abuf[2*DCB_MAX_TLV_LENGTH + 1]; + int result, i; ++ char device_name_sanitized[IFNAMSIZ]; + + dcbx_setting = config_lookup(&lldpad_cfg, DCBX_SETTING); ++ config_ifkey(device_name, device_name_sanitized); + if (dcbx_setting) + eth_settings = config_setting_get_member(dcbx_setting, +- device_name); ++ device_name_sanitized); + + /* init the internal data store for device_name */ + if (NULL == eth_settings) { +@@ -698,7 +703,7 @@ static int _set_persistent(char *device_ + return 0; + + set_error: +- LLDPAD_ERR("update of config file %s failed for %s", ++ LLDPAD_ERR("update of config file %s failed for %s\n", + cfg_file_name, device_name); + return cmd_failed; + } +@@ -782,22 +787,20 @@ int get_persistent(char *device_name, fu + int result = cmd_failed, i; + int results[MAX_USER_PRIORITIES]; + int len; +- char abuf[32]; ++ char abuf[32], device_name_sanitized[IFNAMSIZ]; + + memset(attribs, 0, sizeof(*attribs)); + dcbx_setting = config_lookup(&lldpad_cfg, DCBX_SETTING); ++ ++ config_ifkey(device_name, device_name_sanitized); + if (dcbx_setting) +- eth_settings = config_setting_get_member(dcbx_setting, +- device_name); ++ eth_settings = config_setting_get_member(dcbx_setting, ++ device_name_sanitized); + + /* init the internal data store for device_name */ + result = get_default_persistent(device_name, attribs); +- if (NULL == eth_settings) { +- assert(memcmp(device_name, DEF_CFG_STORE, +- strlen(DEF_CFG_STORE))); +- ++ if (NULL == eth_settings) + return result; +- } + + /* Read pfc setting */ + if (get_int_config(eth_settings, "pfc_enable", TYPE_BOOL, +@@ -1071,13 +1074,16 @@ int get_dcb_enable_state(char *ifname, i + int rc = EINVAL; + config_setting_t *settings = NULL; + char path[sizeof(DCBX_SETTING) + IFNAMSIZ + 16]; ++ char ifkey[IFNAMSIZ]; ++ ++ config_ifkey(ifname, ifkey); + + memset(path, 0, sizeof(path)); +- snprintf(path, sizeof(path), "%s.%s.dcb_enable", DCBX_SETTING, ifname); ++ snprintf(path, sizeof(path), "%s.%s.dcb_enable", DCBX_SETTING, ifkey); + settings = config_lookup(&lldpad_cfg, path); + if (!settings) { + LLDPAD_INFO("### %s:%s:failed on %s\n", __func__, ifname, path); +- snprintf(path, sizeof(path), "%s.dcb_enable", ifname); ++ snprintf(path, sizeof(path), "%s.dcb_enable", ifkey); + settings = config_lookup(&lldpad_cfg, path); + if (!settings) { + LLDPAD_INFO("### %s:%s:failed again %s\n", __func__, ifname, path); +diff -upr a/lldp_dcbx_cmds.c b/lldp_dcbx_cmds.c +--- a/lldp_dcbx_cmds.c 2015-01-20 13:42:56.000000000 -0500 ++++ b/lldp_dcbx_cmds.c 2020-09-23 08:50:52.653813954 -0400 +@@ -259,8 +259,12 @@ static cmd_status set_dcb_state(char *po + + if (ilen == (off + CFG_DCB_DLEN)) { + state = (*(ibuf+off+DCB_STATE)) ^ '0'; +- set_hw_state(port_id, state); +- rval = save_dcb_enable_state(port_id, state); ++ ++ if(set_hw_state(port_id, state) < 0) { ++ rval = cmd_not_capable; ++ } else { ++ rval = save_dcb_enable_state(port_id, state); ++ } + } else { + printf("error - setcommand has invalid argument length\n"); + rval = cmd_bad_params; +@@ -943,6 +947,10 @@ static int set_pg_config(pg_attribs *pg_ + bool used[MAX_BANDWIDTH_GROUPS]; + bool uppcts_changed = false; + ++ /* If PG is disabled, skip changing any other attributes */ ++ if (!(pg_data->protocol.Enable)) ++ goto done; ++ + plen=strlen(port_id); + off = DCB_PORT_OFF + plen + CFG_LEN; + +@@ -1067,6 +1075,7 @@ static int set_pg_config(pg_attribs *pg_ + return status; + } + ++done: + is_pfc = get_pfc(port_id, &pfc_data); + if (is_pfc == cmd_success) + status = put_pg(port_id, pg_data, &pfc_data); +diff -upr a/lldp_dcbx_nl.c b/lldp_dcbx_nl.c +--- a/lldp_dcbx_nl.c 2015-01-20 13:42:56.000000000 -0500 ++++ b/lldp_dcbx_nl.c 2020-09-23 08:50:52.653813954 -0400 +@@ -152,16 +152,17 @@ static int send_msg(struct nlmsghdr *nlh + { + struct sockaddr_nl nladdr; + void *buf = (void *)nlh; +- int r, len = nlh->nlmsg_len; ++ int r; + + if (nlh == NULL) + return 1; + + memset(&nladdr, 0, sizeof(nladdr)); + nladdr.nl_family = AF_NETLINK; +- ++ + do { +- r = sendto(nl_sd, buf, len, 0, (struct sockaddr *)&nladdr, ++ r = sendto(nl_sd, buf, nlh->nlmsg_len, 0, ++ (struct sockaddr *)&nladdr, + sizeof(nladdr)); + LLDPAD_DBG("send_msg: sendto = %d\n", r); + +@@ -561,7 +562,7 @@ int get_dcb_numtcs(const char *ifname, u + + seq = nlh->nlmsg_seq; + +- strncpy(name, ifname, sizeof(name)); ++ STRNCPY_TERMINATED (name, ifname, sizeof(name)); + add_rta(nlh, DCB_ATTR_IFNAME, (void *)name, strlen(name) + 1); + rta_parent = add_rta(nlh, DCB_ATTR_NUMTCS, NULL, 0); + +@@ -801,17 +802,6 @@ int set_hw_app(char *ifname, appgroup_at + return(recv_msg(DCB_CMD_SAPP, DCB_ATTR_APP, seq)); + } + +-int run_cmd(char *cmd, ...) +-{ +- char cbuf[128]; +- va_list args; +- +- va_start(args, cmd); +- vsprintf(cbuf, cmd, args); +- va_end(args); +- return system(cbuf); +-} +- + int set_hw_all(char *ifname) + { + struct nlmsghdr *nlh; +diff -upr a/lldp_evb22.c b/lldp_evb22.c +--- a/lldp_evb22.c 2021-06-09 10:58:59.218200681 -0400 ++++ b/lldp_evb22.c 2020-11-03 09:08:48.060229053 -0500 +@@ -37,14 +37,12 @@ + #include "messages.h" + #include "config.h" + +-extern struct lldp_head lldp_head; +- + struct evb22_data *evb22_data(char *ifname, enum agent_type type) + { + struct evb22_user_data *ud; + struct evb22_data *ed = NULL; + +- ud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_EVB22); ++ ud = find_module_user_data_by_id(&lldp_mod_head, LLDP_MOD_EVB22); + if (ud) { + LIST_FOREACH(ed, &ud->head, entry) { + if (!strncmp(ifname, ed->ifname, IFNAMSIZ) && +@@ -450,10 +448,10 @@ static void evb22_ifup(char *ifname, str + __func__, ifname, agent->type, sizeof *ed); + return; + } +- strncpy(ed->ifname, ifname, IFNAMSIZ); ++ STRNCPY_TERMINATED(ed->ifname, ifname, IFNAMSIZ); + ed->agenttype = agent->type; + evb22_init_tlv(ed, agent); +- ud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_EVB22); ++ ud = find_module_user_data_by_id(&lldp_mod_head, LLDP_MOD_EVB22); + LIST_INSERT_HEAD(&ud->head, ed, entry); + LLDPAD_DBG("%s:%s agent %d added\n", __func__, ifname, agent->type); + } +diff -upr a/lldp_evb22_cmds.c b/lldp_evb22_cmds.c +--- a/lldp_evb22_cmds.c 2015-01-20 13:42:56.000000000 -0500 ++++ b/lldp_evb22_cmds.c 2020-09-23 08:50:52.653813954 -0400 +@@ -225,7 +225,7 @@ int evb22_conf_enabletx(char *ifname, en + TLVID(OUI_IEEE_8021Qbg22, LLDP_EVB22_SUBTYPE)); + } + +-static int evb22_cmdok(struct cmd *cmd, cmd_status expected) ++static int evb22_cmdok(struct cmd *cmd, int expected) + { + if (cmd->cmd != expected) + return cmd_invalid; +diff -upr a/lldp_evb.c b/lldp_evb.c +--- a/lldp_evb.c 2021-06-09 10:58:59.217200668 -0400 ++++ b/lldp_evb.c 2021-04-05 12:02:17.318590504 -0400 +@@ -36,14 +36,12 @@ + #include "messages.h" + #include "config.h" + +-extern struct lldp_head lldp_head; +- + struct evb_data *evb_data(char *ifname, enum agent_type type) + { + struct evb_user_data *ud; + struct evb_data *ed = NULL; + +- ud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_EVB); ++ ud = find_module_user_data_by_id(&lldp_mod_head, LLDP_MOD_EVB); + if (ud) { + LIST_FOREACH(ed, &ud->head, entry) { + if (!strncmp(ifname, ed->ifname, IFNAMSIZ) && +@@ -342,12 +340,12 @@ static void evb_ifup(char *ifname, struc + __func__, ifname, agent->type, sizeof(*ed)); + return; + } +- strncpy(ed->ifname, ifname, IFNAMSIZ); ++ STRNCPY_TERMINATED(ed->ifname, ifname, IFNAMSIZ); + ed->agenttype = agent->type; + + evb_init_tlv(ed, agent); + +- ud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_EVB); ++ ud = find_module_user_data_by_id(&lldp_mod_head, LLDP_MOD_EVB); + LIST_INSERT_HEAD(&ud->head, ed, entry); + LLDPAD_DBG("%s:%s agent %d added\n", __func__, ifname, agent->type); + } +diff -upr a/lldp_evb_cmds.c b/lldp_evb_cmds.c +--- a/lldp_evb_cmds.c 2015-01-20 13:42:56.000000000 -0500 ++++ b/lldp_evb_cmds.c 2020-09-23 08:50:52.653813954 -0400 +@@ -163,7 +163,7 @@ int evb_conf_enabletx(char *ifname, enum + return is_tlv_txenabled(ifname, type, TLVID_8021Qbg(LLDP_EVB_SUBTYPE)); + } + +-static int evb_cmdok(struct cmd *cmd, cmd_status expected) ++static int evb_cmdok(struct cmd *cmd, int expected) + { + if (cmd->cmd != expected) + return cmd_invalid; +diff -upr a/lldp_mand.c b/lldp_mand.c +--- a/lldp_mand.c 2021-06-09 10:58:59.211200590 -0400 ++++ b/lldp_mand.c 2020-11-03 09:08:48.061229070 -0500 +@@ -42,8 +42,6 @@ + #include "lldp/l2_packet.h" + #include "lldp_tlv.h" + +-extern struct lldp_head lldp_head; +- + static const struct lldp_mod_ops mand_ops = { + .lldp_mod_register = mand_register, + .lldp_mod_unregister = mand_unregister, +@@ -59,7 +57,7 @@ struct mand_data *mand_data(const char * + struct mand_user_data *mud; + struct mand_data *md = NULL; + +- mud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_MAND); ++ mud = find_module_user_data_by_id(&lldp_mod_head, LLDP_MOD_MAND); + if (mud) { + LIST_FOREACH(md, &mud->head, entry) { + if (!strncmp(ifname, md->ifname, IFNAMSIZ) && +@@ -100,7 +98,7 @@ static int mand_bld_end_tlv(struct mand_ + static int mand_bld_mac_chassis(struct mand_data *md, + struct tlv_info_chassis *chassis) + { +- get_mac(md->ifname, chassis->id.mac); ++ get_mac(md->ifname, chassis->id.mac, false); + if (is_valid_mac(chassis->id.mac)) + chassis->sub = CHASSIS_ID_MAC_ADDRESS; + return sizeof(chassis->id.mac) + sizeof(chassis->sub); +@@ -112,11 +110,13 @@ static int mand_bld_ip_chassis(struct ma + { + unsigned int len; + +- if (!get_ipaddr(md->ifname, &chassis->id.na.ip.v4)) { ++ void *v4_ptr = &chassis->id.na.ip.v4; ++ void *v6_ptr = &chassis->id.na.ip.v6; ++ if (!get_ipaddr(md->ifname, v4_ptr)) { + chassis->sub = CHASSIS_ID_NETWORK_ADDRESS; + chassis->id.na.type = MANADDR_IPV4; + len = sizeof(chassis->id.na.ip.v4); +- } else if (!get_ipaddr6(md->ifname, &chassis->id.na.ip.v6)) { ++ } else if (!get_ipaddr6(md->ifname, v6_ptr)) { + chassis->sub = CHASSIS_ID_NETWORK_ADDRESS; + chassis->id.na.type = MANADDR_IPV6; + len = sizeof(chassis->id.na.ip.v6); +@@ -217,6 +217,7 @@ static int mand_bld_chassis_tlv(struct m + if (length > 0) + break; + /* Fall through on IP error */ ++ /* FALLTHROUGH */ + case CHASSIS_ID_MAC_ADDRESS: + default: + length = mand_bld_mac_chassis(md, &chassis); +@@ -234,6 +235,7 @@ static int mand_bld_chassis_tlv(struct m + if (length > 0) + break; + /* Fall through on IP error */ ++ /* FALLTHROUGH */ + case LLDP_MED_DEVTYPE_NETWORK_CONNECTIVITY: + default: + length = mand_bld_ifname_chassis(md, &chassis); +@@ -361,16 +363,18 @@ static int mand_bld_portid_tlv(struct ma + switch (subtype) { + default: + case PORT_ID_MAC_ADDRESS: +- get_mac(md->ifname, portid.id.mac); ++ get_mac(md->ifname, portid.id.mac, true); + if (is_valid_mac(portid.id.mac)) { + portid.sub = PORT_ID_MAC_ADDRESS; + length = sizeof(portid.id.mac) + + sizeof(portid.sub); + break; + } +- case PORT_ID_NETWORK_ADDRESS: ++ /* FALLTHROUGH */ ++ case PORT_ID_NETWORK_ADDRESS: { + /* uses ipv4 first */ +- if (!get_ipaddr(md->ifname, &portid.id.na.ip.v4)) { ++ void *v4_ptr = &portid.id.na.ip.v4; ++ if (!get_ipaddr(md->ifname, v4_ptr)) { + portid.sub = PORT_ID_NETWORK_ADDRESS; + portid.id.na.type = MANADDR_IPV4; + length = sizeof(portid.id.na.type) + +@@ -379,7 +383,8 @@ static int mand_bld_portid_tlv(struct ma + break; + } + /* ipv4 fails, get ipv6 */ +- if (!get_ipaddr6(md->ifname, &portid.id.na.ip.v6)) { ++ void *v6_ptr = &portid.id.na.ip.v6; ++ if (!get_ipaddr6(md->ifname, v6_ptr)) { + portid.sub = PORT_ID_NETWORK_ADDRESS; + portid.id.na.type = MANADDR_IPV6; + length = sizeof(portid.id.na.type) + +@@ -387,6 +392,8 @@ static int mand_bld_portid_tlv(struct ma + sizeof(portid.sub); + break; + } ++ } ++ /* FALLTHROUGH */ + case PORT_ID_INTERFACE_NAME: + portid.sub = PORT_ID_INTERFACE_NAME; + strncpy((char *)portid.id.ifname, md->ifname, IFNAMSIZ); +@@ -508,9 +515,11 @@ struct packed_tlv *mand_gettlv(struct po + } + + err = mand_bld_tlv(md, agent); +- if (err) ++ if (err) { + LLDPAD_DBG("%s:%s: building mandotory TLV error.\n", + __func__, port->ifname); ++ goto out_err; ++ } + + size = TLVSIZE(md->chassis) + + TLVSIZE(md->portid) +@@ -532,7 +541,7 @@ struct packed_tlv *mand_gettlv(struct po + PACK_TLV_AFTER(md->ttl, ptlv, size, out_free); + return ptlv; + out_free: +- ptlv = free_pkd_tlv(ptlv); ++ free_pkd_tlv(ptlv); + out_err: + LLDPAD_DBG("%s:%s: failed\n", __func__, port->ifname); + return NULL; +@@ -596,10 +605,10 @@ void mand_ifup(char *ifname, struct lldp + return; + } + memset(md, 0, sizeof(struct mand_data)); +- strncpy(md->ifname, ifname, IFNAMSIZ); ++ STRNCPY_TERMINATED(md->ifname, ifname, IFNAMSIZ); + md->agenttype = agent->type; + +- mud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_MAND); ++ mud = find_module_user_data_by_id(&lldp_mod_head, LLDP_MOD_MAND); + LIST_INSERT_HEAD(&mud->head, md, entry); + } + +@@ -627,7 +636,7 @@ struct lldp_module *mand_register(void) + LLDPAD_ERR("failed to malloc LLDP Mandatory module data\n"); + goto out_err; + } +- mud = malloc(sizeof(struct mand_user_data)); ++ mud = malloc(sizeof(struct mand_user_data)); + if (!mud) { + free(mod); + LLDPAD_ERR("failed to malloc LLDP Mandatory module user data\n"); +@@ -635,8 +644,8 @@ struct lldp_module *mand_register(void) + } + LIST_INIT(&mud->head); + mod->id = LLDP_MOD_MAND; ++ mod->data = mud; + mod->ops = &mand_ops; +- mod->data = mud; + LLDPAD_INFO("%s:done\n", __func__); + return mod; + out_err: +diff -upr a/lldp_mand_cmds.c b/lldp_mand_cmds.c +--- a/lldp_mand_cmds.c 2021-06-09 10:58:59.211200590 -0400 ++++ b/lldp_mand_cmds.c 2020-10-23 14:12:58.975289310 -0400 +@@ -44,6 +44,9 @@ + #include "lldp/states.h" + #include "lldp_util.h" + #include "messages.h" ++#include "lldp_8021qaz.h" ++ ++extern bool read_only_8021qaz; + + static int get_arg_adminstatus(struct cmd *, char *, char *, char *, int); + static int set_arg_adminstatus(struct cmd *, char *, char *, char *, int); +@@ -463,7 +466,7 @@ int handle_get_args(struct cmd *cmd, UNU + nbuf = obuf; + nbuf_len = obuf_len; + +- LIST_FOREACH(np, &lldp_head, lldp) { ++ LIST_FOREACH(np, &lldp_mod_head, lldp) { + if (!np->ops->get_arg_handler) + continue; + if (!(ah = np->ops->get_arg_handler())) +@@ -493,7 +496,7 @@ int handle_get_arg(struct cmd *cmd, char + struct arg_handlers *ah; + int rval, status = cmd_not_applicable; + +- LIST_FOREACH(np, &lldp_head, lldp) { ++ LIST_FOREACH(np, &lldp_mod_head, lldp) { + if (!np->ops->get_arg_handler) + continue; + if (!(ah = np->ops->get_arg_handler())) +@@ -590,11 +593,14 @@ int handle_test_arg(struct cmd *cmd, cha + struct arg_handlers *ah; + int rval, status = cmd_not_applicable; + +- LIST_FOREACH(np, &lldp_head, lldp) { ++ LIST_FOREACH(np, &lldp_mod_head, lldp) { + if (!np->ops->get_arg_handler) + continue; + if (!(ah = np->ops->get_arg_handler())) + continue; ++ /* 8021QAZ set operations not allowed in read-only mode */ ++ if (np->id == LLDP_MOD_8021QAZ && read_only_8021qaz) ++ return cmd_no_access; + while (ah->arg) { + if (!strcasecmp(ah->arg, arg) && ah->handle_test) { + rval = ah->handle_test(cmd, ah->arg, argvalue, +@@ -620,11 +626,14 @@ int handle_set_arg(struct cmd *cmd, char + struct arg_handlers *ah; + int rval, status = cmd_not_applicable; + +- LIST_FOREACH(np, &lldp_head, lldp) { ++ LIST_FOREACH(np, &lldp_mod_head, lldp) { + if (!np->ops->get_arg_handler) + continue; + if (!(ah = np->ops->get_arg_handler())) + continue; ++ /* 8021QAZ set operations not allowed in read-only mode */ ++ if (np->id == LLDP_MOD_8021QAZ && read_only_8021qaz) ++ return cmd_no_access; + while (ah->arg) { + if (!strcasecmp(ah->arg, arg) && ah->handle_set) { + rval = ah->handle_set(cmd, ah->arg, argvalue, +diff -upr a/lldp_med.c b/lldp_med.c +--- a/lldp_med.c 2015-01-20 13:42:56.000000000 -0500 ++++ b/lldp_med.c 2020-11-03 09:08:48.061229070 -0500 +@@ -40,8 +40,6 @@ + #include "lldp_mand_clif.h" + #include "lldp_med_cmds.h" + +-extern struct lldp_head lldp_head; +- + struct tlv_info_medcaps { + u8 oui[OUI_SIZE]; + u8 subtype; +@@ -95,7 +93,7 @@ static struct med_data *med_data(const c + struct med_user_data *mud; + struct med_data *md = NULL; + +- mud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_MED); ++ mud = find_module_user_data_by_id(&lldp_mod_head, LLDP_MOD_MED); + if (mud) { + LIST_FOREACH(md, &mud->head, entry) { + if (!strncmp(ifname, md->ifname, IFNAMSIZ) && +@@ -905,7 +903,7 @@ void med_ifup(char *ifname, struct lldp_ + goto out_err; + } + memset(md, 0, sizeof(struct med_data)); +- strncpy(md->ifname, ifname, IFNAMSIZ); ++ STRNCPY_TERMINATED(md->ifname, ifname, IFNAMSIZ); + md->agenttype = agent->type; + + if (med_bld_tlv(md, agent)) { +@@ -914,7 +912,7 @@ void med_ifup(char *ifname, struct lldp_ + free(md); + goto out_err; + } +- mud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_MED); ++ mud = find_module_user_data_by_id(&lldp_mod_head, LLDP_MOD_MED); + LIST_INSERT_HEAD(&mud->head, md, entry); + LLDPAD_INFO("%s:port %s added\n", __func__, ifname); + return; +diff -upr a/lldp_med_cmds.c b/lldp_med_cmds.c +--- a/lldp_med_cmds.c 2015-01-20 13:42:56.000000000 -0500 ++++ b/lldp_med_cmds.c 2020-09-23 08:50:52.654813972 -0400 +@@ -303,6 +303,7 @@ static int _set_arg_med_devtype(struct c + case LLDP_MED_DEVTYPE_ENDPOINT_CLASS_III: + case LLDP_MED_DEVTYPE_ENDPOINT_CLASS_II: + tlv_enabletx(cmd->ifname, cmd->type, (OUI_TIA_TR41 << 8) | LLDP_MED_NETWORK_POLICY); ++ /* FALLTHROUGH */ + case LLDP_MED_DEVTYPE_ENDPOINT_CLASS_I: + case LLDP_MED_DEVTYPE_NETWORK_CONNECTIVITY: + tlv_enabletx(cmd->ifname, cmd->type, (OUI_TIA_TR41 << 8) | LLDP_MED_RESERVED); +diff -upr a/lldp_rtnl.c b/lldp_rtnl.c +--- a/lldp_rtnl.c 2021-06-09 10:58:59.213200616 -0400 ++++ b/lldp_rtnl.c 2021-04-05 12:02:17.319590520 -0400 +@@ -103,7 +103,8 @@ static void add_rtattr(struct nlmsghdr * + + rta->rta_type = type; + rta->rta_len = len; +- memcpy(RTA_DATA(rta), data, alen); ++ if (data) ++ memcpy(RTA_DATA(rta), data, alen); + n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len); + } + +diff -upr a/lldp_tlv.c b/lldp_tlv.c +--- a/lldp_tlv.c 2015-01-20 13:42:56.000000000 -0500 ++++ b/lldp_tlv.c 2020-09-23 08:50:52.654813972 -0400 +@@ -112,13 +112,13 @@ int pack_tlv_after(struct unpacked_tlv * + return -1; + + if (ptlv->size + mtlv->size > length) { +- ptlv = free_pkd_tlv(ptlv); ++ free_pkd_tlv(ptlv); + return -1; + } + + memcpy(&mtlv->tlv[mtlv->size], ptlv->tlv, ptlv->size); + mtlv->size += ptlv->size; +- ptlv = free_pkd_tlv(ptlv); ++ free_pkd_tlv(ptlv); + return 0; + } + +@@ -158,7 +158,7 @@ struct unpacked_tlv *unpack_tlv(struct p + return upkd_tlv; + } + +-struct unpacked_tlv *free_unpkd_tlv(struct unpacked_tlv *tlv) ++void free_unpkd_tlv(struct unpacked_tlv *tlv) + { + if (tlv != NULL) { + if (tlv->info != NULL) { +@@ -166,12 +166,10 @@ struct unpacked_tlv *free_unpkd_tlv(stru + tlv->info = NULL; + } + free(tlv); +- tlv = NULL; + } +- return NULL; + } + +-struct packed_tlv *free_pkd_tlv(struct packed_tlv *tlv) ++void free_pkd_tlv(struct packed_tlv *tlv) + { + if (tlv != NULL) { + if (tlv->tlv != NULL) { +@@ -179,9 +177,7 @@ struct packed_tlv *free_pkd_tlv(struct p + tlv->tlv = NULL; + } + free(tlv); +- tlv = NULL; + } +- return NULL; + } + + struct packed_tlv *create_ptlv() +diff -upr a/lldptool.c b/lldptool.c +--- a/lldptool.c 2015-01-20 13:42:56.000000000 -0500 ++++ b/lldptool.c 2020-10-30 09:35:19.614361934 -0400 +@@ -64,6 +64,9 @@ + #include "lldp_util.h" + #include "lldpad_status.h" + ++struct lldp_head lldp_cli_head; ++struct lldp_head lldp_mod_head; ++extern void close_history(void); + static int show_raw; + + static const char *cli_version = +@@ -199,7 +202,7 @@ static void init_modules(void) + if (premod) + LIST_INSERT_AFTER(premod, module, lldp); + else +- LIST_INSERT_HEAD(&lldp_head, module, lldp); ++ LIST_INSERT_HEAD(&lldp_mod_head, module, lldp); + premod = module; + } + } +@@ -208,9 +211,9 @@ void deinit_modules(void) + { + struct lldp_module *module; + +- while (lldp_head.lh_first != NULL) { +- module = lldp_head.lh_first; +- LIST_REMOVE(lldp_head.lh_first, lldp); ++ while (lldp_mod_head.lh_first != NULL) { ++ module = lldp_mod_head.lh_first; ++ LIST_REMOVE(lldp_mod_head.lh_first, lldp); + module->ops->lldp_mod_unregister(module); + } + } +@@ -222,28 +225,6 @@ static void usage(void) + commands_usage, commands_options, commands_help); + } + +-/* assumes input is pointer to two hex digits */ +-/* returns -1 on error */ +-int hex2int(char *b) +-{ +- int i; +- int n=0; +- int m; +- +- for (i=0,m=1; i<2; i++,m--) { +- if (isxdigit(*(b+i))) { +- if (*(b+i) <= '9') +- n |= (*(b+i) & 0x0f) << (4*m); +- else +- n |= ((*(b+i) & 0x0f) + 9) << (4*m); +- } +- else { +- return -1; +- } +- } +- return n; +-} +- + void print_raw_message(char *msg, int print) + { + if (!print || !(print & SHOW_RAW)) +@@ -368,7 +349,7 @@ cli_cmd_help(UNUSED struct clif *clif, U + printf("%s\n%s\n%s", commands_usage, commands_options, commands_help); + + printf("\nTLV identifiers:\n"); +- LIST_FOREACH(np, &lldp_head, lldp) ++ LIST_FOREACH(np, &lldp_mod_head, lldp) + if (np->ops->print_help) + np->ops->print_help(); + return 0; +@@ -428,7 +409,7 @@ u32 lookup_tlvid(char *tlvid_str) + struct lldp_module *np; + u32 tlvid = INVALID_TLVID; + +- LIST_FOREACH(np, &lldp_head, lldp) { ++ LIST_FOREACH(np, &lldp_mod_head, lldp) { + if (np->ops->lookup_tlv_name) { + tlvid = np->ops->lookup_tlv_name(tlvid_str); + if (tlvid != INVALID_TLVID) +@@ -711,6 +692,7 @@ static void cli_interactive() + } + free(cmd); + } while (!cli_quit); ++ close_history(); + } + + static void cli_terminate(UNUSED int sig) +diff -upr a/lldptool_cmds.c b/lldptool_cmds.c +--- a/lldptool_cmds.c 2015-01-20 13:42:56.000000000 -0500 ++++ b/lldptool_cmds.c 2020-10-23 14:12:58.976289329 -0400 +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + #include "clif.h" + #include "dcb_types.h" + #include "lldptool.h" +@@ -464,7 +465,7 @@ static void print_tlvs(struct cmd *cmd, + offset += 8; + + printed = 0; +- LIST_FOREACH(np, &lldp_head, lldp) { ++ LIST_FOREACH(np, &lldp_mod_head, lldp) { + if (np->ops->print_tlv(tlvid, tlv_len, ibuf+offset)) { + printed = 1; + break; +diff -upr a/lldp_util.c b/lldp_util.c +--- a/lldp_util.c 2021-06-09 10:58:59.215200642 -0400 ++++ b/lldp_util.c 2020-09-23 08:50:52.654813972 -0400 +@@ -24,6 +24,7 @@ + + *******************************************************************************/ + ++#include + #include + #include + #include +@@ -122,6 +123,28 @@ int hexstr2bin(const char *hex, u8 *buf, + return 0; + } + ++/* assumes input is pointer to two hex digits */ ++/* returns -1 on error */ ++int hex2int(char *b) ++{ ++ int i; ++ int n=0; ++ int m; ++ ++ for (i=0,m=1; i<2; i++,m--) { ++ if (isxdigit(*(b+i))) { ++ if (*(b+i) <= '9') ++ n |= (*(b+i) & 0x0f) << (4*m); ++ else ++ n |= ((*(b+i) & 0x0f) + 9) << (4*m); ++ } ++ else { ++ return -1; ++ } ++ } ++ return n; ++} ++ + char *print_mac(char *mac, char *buf) + { + sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x", +@@ -189,26 +212,6 @@ int is_bond(const char *ifname) + } + + /** +- * is_san_mac - check if address is a san mac addr +- * @addr: san mac address +- * +- * Returns 0 if addr is NOT san mac, 1 if it is a san mac. +- * +- * BUG: this does not do anything to prove it's a sanmac!!!! +- * SAN MAC is no different than LAN MAC, no way to tell!!! +- */ +-int is_san_mac(u8 *addr) +-{ +- int i; +- +- for ( i = 0; i < ETH_ALEN; i++) { +- if ( addr[i]!= 0xff ) +- return 1; +- } +- return 0; +-} +- +-/** + * get_src_mac_from_bond - select a source MAC to use for slave + * @bond_port: pointer to port structure for a bond interface + * @ifname: interface name of the slave port +@@ -314,11 +317,24 @@ int get_src_mac_from_bond(struct port *b + */ + int is_valid_mac(const u8 *mac) + { +- if (0 == (mac[0] | mac[1] | mac[2] | mac[3] | mac[4] | mac[5])) +- return 0; +- if (0xff == (mac[0] & mac[1] & mac[2] & mac[3] & mac[4] & mac[5])) +- return 0; +- return 1; ++ static const u8 zero_mac[ETH_ALEN] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; ++ static const u8 ff_mac[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; ++ static const u8 iana_mcast[ETH_ALEN] = {0x01, 0x00, 0x5E}; ++ static const u8 ipv6_mcast[ETH_ALEN] = {0x33, 0x33}; ++ ++ if(memcmp(mac, zero_mac, ETH_ALEN) == 0 || ++ memcmp(mac, ff_mac, ETH_ALEN) == 0) ++ return 0; ++ ++ /* IANA multicast and ipv6 multicast mac address ++ * For reference check document: ++ * https://www.iana.org/assignments/ethernet-numbers/ethernet-numbers.xhtml ++ */ ++ if(memcmp(mac, iana_mcast, 3) == 0 || ++ memcmp(mac, ipv6_mcast, 2) == 0) ++ return 0; ++ ++ return 1; + } + + int read_int(const char *path) +@@ -350,7 +366,7 @@ int get_ifflags(const char *ifname) + fd = get_ioctl_socket(); + if (fd >= 0) { + memset(&ifr, 0, sizeof(ifr)); +- strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); ++ STRNCPY_TERMINATED(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); + if (ioctl(fd, SIOCGIFFLAGS, &ifr) == 0) + flags = ifr.ifr_flags; + } +@@ -386,7 +402,7 @@ int get_ifpflags(const char *ifname) + fd = get_ioctl_socket(); + if (fd >= 0) { + memset(&ifr, 0, sizeof(ifr)); +- strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); ++ STRNCPY_TERMINATED(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); + if (ioctl(fd, SIOCGIFPFLAGS, &ifr) == 0) + flags = ifr.ifr_flags; + } +@@ -470,7 +486,7 @@ int is_slave(const char *ifmaster, const + + memset(&ifr, 0, sizeof(ifr)); + memset(&ifb, 0, sizeof(ifb)); +- strncpy(ifr.ifr_name, ifmaster, IFNAMSIZ); ++ STRNCPY_TERMINATED(ifr.ifr_name, ifmaster, IFNAMSIZ); + ifr.ifr_data = (caddr_t)&ifb; + if (ioctl(fd, SIOCBONDINFOQUERY, &ifr)) + goto out_done; +@@ -500,7 +516,7 @@ int get_ifidx(const char *ifname) + fd = get_ioctl_socket(); + if (fd >= 0) { + memset(&ifreq, 0, sizeof(ifreq)); +- strncpy(ifreq.ifr_name, ifname, IFNAMSIZ); ++ STRNCPY_TERMINATED(ifreq.ifr_name, ifname, IFNAMSIZ); + if (ioctl(fd, SIOCGIFINDEX, &ifreq) == 0) + idx = ifreq.ifr_ifindex; + } +@@ -572,7 +588,7 @@ int is_bridge(const char *ifname) + (unsigned long) &bi, 0, 0 }; + + ifr.ifr_data = (char *)args; +- strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); ++ STRNCPY_TERMINATED(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); + if (ioctl(fd, SIOCDEVPRIVATE, &ifr) == 0) + rc = 1; + } +@@ -610,7 +626,7 @@ int is_vlan(const char *ifname) + if (fd >= 0) { + memset(&ifv, 0, sizeof(ifv)); + ifv.cmd = GET_VLAN_REALDEV_NAME_CMD; +- strncpy(ifv.device1, ifname, sizeof(ifv.device1)); ++ STRNCPY_TERMINATED(ifv.device1, ifname, sizeof(ifv.device1)); + if (ioctl(fd, SIOCGIFVLAN, &ifv) == 0) + rc = 1; + } +@@ -637,7 +653,7 @@ int is_wlan(const char *ifname) + fd = get_ioctl_socket(); + if (fd >= 0) { + memset(&iwreq, 0, sizeof(iwreq)); +- strncpy(iwreq.ifr_name, ifname, sizeof(iwreq.ifr_name)); ++ STRNCPY_TERMINATED(iwreq.ifr_name, ifname, sizeof(iwreq.ifr_name)); + if (ioctl(fd, SIOCGIWNAME, &iwreq) == 0) + rc = 1; + } +@@ -650,6 +666,8 @@ static struct nla_policy ifla_info_polic + { + [IFLA_INFO_KIND] = { .type = NLA_STRING}, + [IFLA_INFO_DATA] = { .type = NLA_NESTED }, ++ [IFLA_INFO_SLAVE_KIND] = { .type = NLA_STRING}, ++ [IFLA_INFO_SLAVE_DATA] = { .type = NLA_NESTED }, + }; + + int is_macvtap(const char *ifname) +@@ -754,7 +772,7 @@ int is_active(const char *ifname) + fd = get_ioctl_socket(); + if (fd >= 0) { + memset(&ifr, 0, sizeof(ifr)); +- strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); ++ STRNCPY_TERMINATED(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); + if (ioctl(fd, SIOCGIFFLAGS, &ifr) == 0) + if (ifr.ifr_flags & IFF_UP) + rc = 1; +@@ -775,7 +793,7 @@ int is_autoneg_supported(const char *ifn + memset(&cmd, 0, sizeof(cmd)); + cmd.cmd = ETHTOOL_GSET; + ifr.ifr_data = &cmd; +- strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); ++ STRNCPY_TERMINATED(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); + if (ioctl(fd, SIOCETHTOOL, &ifr) == 0) + if (cmd.supported & SUPPORTED_Autoneg) + rc = 1; +@@ -796,7 +814,7 @@ int is_autoneg_enabled(const char *ifnam + memset(&cmd, 0, sizeof(cmd)); + cmd.cmd = ETHTOOL_GSET; + ifr.ifr_data = &cmd; +- strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); ++ STRNCPY_TERMINATED(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); + if (ioctl(fd, SIOCETHTOOL, &ifr) == 0) + rc = cmd.autoneg; + } +@@ -833,7 +851,7 @@ int get_maucaps(const char *ifname) + memset(&cmd, 0, sizeof(cmd)); + cmd.cmd = ETHTOOL_GSET; + ifr.ifr_data = &cmd; +- strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); ++ STRNCPY_TERMINATED(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); + if (ioctl(fd, SIOCETHTOOL, &ifr) == 0) { + if (cmd.advertising & ADVERTISED_10baseT_Half) + caps |= MAUCAPADV_b10baseT; +@@ -872,7 +890,7 @@ int get_mautype(const char *ifname) + memset(&cmd, 0, sizeof(cmd)); + cmd.cmd = ETHTOOL_GSET; + ifr.ifr_data = &cmd; +- strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); ++ STRNCPY_TERMINATED(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); + if (ioctl(fd, SIOCETHTOOL, &ifr) == 0) { + /* TODO: too many dot3MauTypes, + * should check duplex, speed, and port */ +@@ -899,7 +917,7 @@ int get_mtu(const char *ifname) + fd = get_ioctl_socket(); + if (fd >= 0) { + memset(&ifr, 0, sizeof(ifr)); +- strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); ++ STRNCPY_TERMINATED(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); + if (ioctl(fd, SIOCGIFMTU, &ifr) == 0) + rc = ifr.ifr_mtu; + } +@@ -921,38 +939,86 @@ int get_mfs(const char *ifname) + return mfs; + } + +-int get_mac(const char *ifname, u8 mac[]) ++int get_mac(const char *ifname, u8 mac[], bool perm_mac) + { +- int fd; +- int rc = EINVAL; +- struct ifreq ifr; ++ int ret, s; ++ struct nlmsghdr *nlh; ++ struct ifinfomsg *ifinfo; ++ struct nlattr *tb[IFLA_MAX+1], ++ *tb2[IFLA_INFO_MAX+1]; + +- memset(mac, 0, 6); +- fd = get_ioctl_socket(); +- if (fd >= 0) { +- ifr.ifr_addr.sa_family = AF_INET; +- strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); +- if (!ioctl(fd, SIOCGIFHWADDR, &ifr)) { +- memcpy(mac, ifr.ifr_hwaddr.sa_data, 6); +- rc = 0; +- } ++ s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE); ++ ++ if (s < 0) { ++ goto out; + } +- return rc; +-} + +-int get_macstr(const char *ifname, char *addr, size_t size) +-{ +- u8 mac[6]; +- int rc; ++ nlh = malloc(NLMSG_SIZE); + +- rc = get_mac(ifname, mac); +- if (rc == 0) { +- snprintf(addr, size, "%02x:%02x:%02x:%02x:%02x:%02x", +- mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); ++ if (!nlh) { ++ goto out; + } +- return rc; +-} + ++ memset(nlh, 0, NLMSG_SIZE); ++ ++ nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); ++ nlh->nlmsg_type = RTM_GETLINK; ++ nlh->nlmsg_flags = NLM_F_REQUEST; ++ ++ ifinfo = NLMSG_DATA(nlh); ++ ifinfo->ifi_family = AF_UNSPEC; ++ ifinfo->ifi_index = get_ifidx(ifname); ++ ++ ret = send(s, nlh, nlh->nlmsg_len, 0); ++ ++ if (ret < 0) { ++ goto out_free; ++ } ++ ++ memset(nlh, 0, NLMSG_SIZE); ++ ++ do { ++ ret = recv(s, (void *) nlh, NLMSG_SIZE, MSG_DONTWAIT); ++ } while ((ret < 0) && errno == EINTR); ++ ++ if (nlmsg_parse(nlh, sizeof(struct ifinfomsg), ++ (struct nlattr **)&tb, IFLA_MAX, NULL)) { ++ goto out_free; ++ } ++ ++ if (tb[IFLA_ADDRESS]) ++ memcpy(mac, (char*)(RTA_DATA(tb[IFLA_ADDRESS])), 6); ++ ++ /* Check for the permanent mac address on bonding slaves */ ++ if (perm_mac && tb[IFLA_LINKINFO]) { ++ char *kind; ++ struct nlattr *tb3; ++ int off = 0; ++ ++ if (nla_parse_nested(tb2, IFLA_INFO_MAX, tb[IFLA_LINKINFO], ++ ifla_info_policy)) { ++ goto out_free; ++ } ++ if (!tb2[IFLA_INFO_SLAVE_KIND]) ++ goto out_free; ++ ++ kind = (char*)(RTA_DATA(tb2[IFLA_INFO_SLAVE_KIND])); ++ if (strcmp(kind, "bond") && !tb2[IFLA_INFO_SLAVE_DATA]) ++ goto out_free; ++ ++ nla_for_each_nested(tb3, tb2[IFLA_INFO_SLAVE_DATA], off) { ++ if (nla_type(tb3) == IFLA_BOND_SLAVE_PERM_HWADDR) { ++ memcpy(mac, nla_data(tb3), nla_len(tb3)); ++ } ++ } ++ } ++ ++out_free: ++ free(nlh); ++out: ++ close(s); ++ return 0; ++} + + u16 get_caps(const char *ifname) + { +@@ -998,7 +1064,7 @@ int get_saddr(const char *ifname, struct + fd = get_ioctl_socket(); + if (fd >= 0) { + ifr.ifr_addr.sa_family = AF_INET; +- strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); ++ STRNCPY_TERMINATED(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); + if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) { + memcpy(saddr, &ifr.ifr_addr, sizeof(*saddr)); + rc = 0; +@@ -1039,9 +1105,11 @@ int get_saddr6(const char *ifname, struc + + rc = getifaddrs(&ifaddr); + if (rc == 0) { ++ rc = -1; + for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { +- if ((ifa->ifa_addr->sa_family == AF_INET6) && +- (strncmp(ifa->ifa_name, ifname, IFNAMSIZ) == 0)) { ++ if (strncmp(ifa->ifa_name, ifname, IFNAMSIZ)) ++ continue; ++ if (ifa->ifa_addr && (ifa->ifa_addr->sa_family == AF_INET6)) { + memcpy(saddr, ifa->ifa_addr, sizeof(*saddr)); + rc = 0; + break; +@@ -1092,7 +1160,7 @@ int get_addr(const char *ifname, int dom + else if (domain == AF_INET6) + return get_ipaddr6(ifname, (struct in6_addr *)buf); + else if (domain == AF_UNSPEC) +- return get_mac(ifname, (u8 *)buf); ++ return get_mac(ifname, (u8 *)buf, false); + else + return -1; + } +@@ -1227,7 +1295,7 @@ int get_arg_val_list(char *ibuf, int ile + } + hexstr2bin(ibuf+*ioff, &arglen, sizeof(arglen)); + *ioff += 2 * (int)sizeof(arglen); +- if (ilen - *ioff >= arglen) { ++ if (ilen - *ioff >= 0) { + args[i] = ibuf+*ioff; + *ioff += arglen; + *(arglens+i) = arglen; +@@ -1237,7 +1305,7 @@ int get_arg_val_list(char *ibuf, int ile + sizeof(argvalue_len)); + argvalue_len = ntohs(argvalue_len); + *ioff += 2*sizeof(argvalue_len); +- if (ilen - *ioff >= argvalue_len) { ++ if (ilen - *ioff >= 0) { + argvals[i] = ibuf+*ioff; + *ioff += argvalue_len; + *(argvallens+i) = argvalue_len; +diff -upr a/log.c b/log.c +--- a/log.c 2015-01-20 13:42:56.000000000 -0500 ++++ b/log.c 2020-09-23 08:50:52.655813990 -0400 +@@ -65,4 +65,5 @@ void log_message(int level, const char * + bypass_time = strchr(format, '\n') == 0; + } + va_end(va); ++ va_end(vb); + } +diff -upr a/Makefile.am b/Makefile.am +--- a/Makefile.am 2021-06-09 10:58:59.212200603 -0400 ++++ b/Makefile.am 2021-04-05 12:02:17.315590455 -0400 +@@ -1,6 +1,9 @@ + # target programs to be installed in ${sbindir} + sbin_PROGRAMS = lldpad dcbtool lldptool vdptool + ++check_PROGRAMS = lldp_clif_test ++TESTS = $(check_PROGRAMS) ++ + # package nltest and vdptest, but do not install it anywhere + if BUILD_DEBUG + noinst_PROGRAMS = nltest vdptest qbg22sim +@@ -16,7 +19,7 @@ ACLOCAL_AMFLAGS = -I m4 + parse_cli.o: CFLAGS+=-U_FORTIFY_SOURCE -Wno-error + + ## system requires a shared libconfig +-AM_CFLAGS = -Wall -Werror -Wextra -Wformat=2 $(LIBCONFIG_CFLAGS) $(LIBNL_CFLAGS) ++AM_CFLAGS = $(LIBCONFIG_CFLAGS) $(LIBNL_CFLAGS) + AM_LDFLAGS = $(LIBCONFIG_LIBS) $(LIBNL_LIBS) -lrt + + ## header files to be installed, for programs using the client interface to lldpad +@@ -86,9 +89,11 @@ vdptool_LDADD = liblldp_clif.la + vdptool_LDFLAGS = -llldp_clif $(LIBNL_LIBS) + + dcbtool_SOURCES = dcbtool.c dcbtool_cmds.c parse_cli.l \ +-weak_readline.c $(lldpad_include_HEADERS) $(noinst_HEADERS) ++ weak_readline.c lldp_rtnl.c lldp_util.c \ ++ $(lldpad_include_HEADERS) $(noinst_HEADERS) ++ + dcbtool_LDADD = liblldp_clif.la +-dcbtool_LDFLAGS = -ldl -llldp_clif ++dcbtool_LDFLAGS = -ldl -llldp_clif $(LIBNL_LIBS) + + lldptool_SOURCES = lldptool.c lldptool_cmds.c lldp_rtnl.c \ + lldp_mand_clif.c lldp_basman_clif.c lldp_med_clif.c \ +@@ -140,3 +145,18 @@ bashcompletiondir = $(sysconfdir)/bash_c + dist_bashcompletion_DATA = contrib/bash_completion/lldpad contrib/bash_completion/lldptool + + AM_DISTCHECK_CONFIGURE_FLAGS = --enable-debug ++ ++lldp_clif_test_SOURCES = test/lldp_clif_test.c lldp_basman_clif.c lldp_util.c \ ++ lldp_rtnl.c ++lldp_clif_test_LDFLAGS = -lrt $(LIBNL_LIBS) ++ ++RPMBUILD_TOP = $(abs_top_builddir)/rpm/rpmbuild ++RPMBUILD_OPT ?= --without check ++ ++# Build user-space RPMs ++rpm: dist $(srcdir)/lldpad.spec ++ ${MKDIR_P} ${RPMBUILD_TOP}/SOURCES ++ cp ${DIST_ARCHIVES} ${RPMBUILD_TOP}/SOURCES ++ rpmbuild ${RPMBUILD_OPT} \ ++ -D "_topdir ${RPMBUILD_TOP}" \ ++ -ba $(srcdir)/lldpad.spec +diff -upr a/parse_cli.l b/parse_cli.l +--- a/parse_cli.l 2015-01-20 13:42:56.000000000 -0500 ++++ b/parse_cli.l 2020-09-23 08:50:52.655813990 -0400 +@@ -494,7 +494,8 @@ gp { if (!cmd) { + yyless(0); + } + +-[0-7] { up2tc_a[up2tc_idx++] = atoi(yytext); ++[0-7] { up2tc_a[up2tc_idx] = atoi(yytext); ++ up2tc_idx++; + if (up2tc_idx == 8) { + BEGIN(getpgargs); + } +diff -upr a/qbg/ecp22.c b/qbg/ecp22.c +--- a/qbg/ecp22.c 2015-01-20 13:42:56.000000000 -0500 ++++ b/qbg/ecp22.c 2020-10-23 14:12:58.976289329 -0400 +@@ -119,7 +119,8 @@ static void ecp22_append(u8 *buffer, u32 + */ + void ecp22_putnode(struct ecp22_freelist *list, struct ecp22_payload_node *elm) + { +- elm->ptlv = free_pkd_tlv(elm->ptlv); ++ free_pkd_tlv(elm->ptlv); ++ elm->ptlv = NULL; + if (list->freecnt > ecp22_maxpayload) + free(elm); + else { +@@ -154,6 +155,7 @@ static bool ecp22_build_ecpdu(struct ecp + memset(ecp->tx.frame, 0, sizeof ecp->tx.frame); + ecp22_append(ecp->tx.frame, &fb_offset, (void *)ð, sizeof eth); + ++ memset(&ecph, 0, sizeof(struct ecp22_hdr)); + ecp22_hdr_set_version(&ecph, 1); + ecp22_hdr_set_op(&ecph, ECP22_REQUEST); + ecp22_hdr_set_subtype(&ecph, ECP22_VDP); +@@ -749,7 +751,7 @@ static struct ecp22 *ecp22_create(char * + ifname); + return NULL; + } +- strncpy(ecp->ifname, ifname, sizeof ecp->ifname); ++ STRNCPY_TERMINATED(ecp->ifname, ifname, sizeof ecp->ifname); + ecp->l2 = l2_packet_init(ecp->ifname, 0, ETH_P_ECP22, + ecp22_rx_receiveframe, ecp, 1); + +@@ -774,7 +776,7 @@ void ecp22_start(char *ifname) + struct ecp22 *ecp; + + LLDPAD_DBG("%s:%s start ecp\n", __func__, ifname); +- eud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_ECP22); ++ eud = find_module_user_data_by_id(&lldp_mod_head, LLDP_MOD_ECP22); + if (!eud) { + LLDPAD_DBG("%s:%s no ECP module\n", __func__, ifname); + return; +@@ -782,6 +784,10 @@ void ecp22_start(char *ifname) + ecp = find_ecpdata(ifname, eud); + if (!ecp) + ecp = ecp22_create(ifname, eud); ++ if (!ecp) { ++ LLDPAD_DBG("%s:%s failed creating ECP22 instance\n", __func__, ifname); ++ return; ++ } + ecp->max_retries = ECP22_MAX_RETRIES_DEFAULT; + ecp->max_rte = ECP22_ACK_TIMER_DEFAULT; + LIST_INIT(&ecp->inuse.head); +@@ -803,7 +809,7 @@ static void ecp22_removelist(ecp22_list + + while ((np = LIST_FIRST(ptr))) { + LIST_REMOVE(np, node); +- np->ptlv = free_pkd_tlv(np->ptlv); ++ free_pkd_tlv(np->ptlv); + free(np); + } + } +@@ -816,6 +822,7 @@ static void ecp22_remove(struct ecp22 *e + ecp22_removelist(&ecp->isfree.head); + ecp->isfree.freecnt = 0; + LIST_REMOVE(ecp, node); ++ l2_packet_deinit(ecp->l2); + free(ecp); + } + +@@ -832,7 +839,7 @@ void ecp22_stop(char *ifname) + struct ecp22 *ecp; + + LLDPAD_DBG("%s:%s stop ecp\n", __func__, ifname); +- eud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_ECP22); ++ eud = find_module_user_data_by_id(&lldp_mod_head, LLDP_MOD_ECP22); + ecp = find_ecpdata(ifname, eud); + if (ecp) + ecp22_remove(ecp); +@@ -847,7 +854,7 @@ static int ecp22_data_from_evb(char *ifn + struct ecp22_user_data *eud; + struct ecp22 *ecp; + +- eud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_ECP22); ++ eud = find_module_user_data_by_id(&lldp_mod_head, LLDP_MOD_ECP22); + ecp = find_ecpdata(ifname, eud); + if (ecp) { + ecp->max_rte = ptr->max_rte; +@@ -925,7 +932,7 @@ static int ecp22_req2send(char *ifname, + + LLDPAD_DBG("%s:%s subtype:%d\n", __func__, ifname, subtype); + +- eud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_ECP22); ++ eud = find_module_user_data_by_id(&lldp_mod_head, LLDP_MOD_ECP22); + ecp = find_ecpdata(ifname, eud); + if (!ecp) { + rc = -ENODEV; +diff -upr a/qbg/ecp.c b/qbg/ecp.c +--- a/qbg/ecp.c 2015-01-20 13:42:56.000000000 -0500 ++++ b/qbg/ecp.c 2020-09-23 08:50:52.656814007 -0400 +@@ -299,7 +299,7 @@ static bool ecp_build_ECPDU(struct vdp_d + + rc = ecp_append(vd->ecp.tx.frame, &fb_offset, ptlv->tlv, + ptlv->size); +- ptlv = free_pkd_tlv(ptlv); ++ free_pkd_tlv(ptlv); + if (rc) + p->seqnr = vd->ecp.lastSequence; + else +@@ -682,7 +682,7 @@ static void ecp_rx_ReceiveFrame(void *ct + } + + if (hdr->h_proto != example_hdr.h_proto) { +- LLDPAD_ERR("%s:%s ERROR ethertype %#x not ECP ethertype", ++ LLDPAD_ERR("%s:%s ERROR ethertype %#x not ECP ethertype\n", + __func__, vd->ecp.ifname, htons(hdr->h_proto)); + frame_error++; + return; +@@ -795,7 +795,7 @@ int ecp_init(char *ifname) + __func__, ifname); + return -1; + } +- strncpy(vd->ecp.ifname, ifname, sizeof vd->ecp.ifname); ++ STRNCPY_TERMINATED(vd->ecp.ifname, ifname, sizeof vd->ecp.ifname); + ecp_rx_change_state(vd, ECP_RX_IDLE); + ecp_rx_run_sm(vd); + ecp_somethingChangedLocal(vd, true); +@@ -969,7 +969,7 @@ static void ecp_rx_ProcessFrame(struct v + if ((tlv->type != TYPE_0) && !tlv_stored) { + LLDPAD_DBG("%s:%s TLV (%u) was not stored (%p)\n", + __func__, vd->ecp.ifname, tlv->type, tlv); +- tlv = free_unpkd_tlv(tlv); ++ free_unpkd_tlv(tlv); + vd->ecp.stats.statsTLVsUnrecognizedTotal++; + } + tlv = NULL; +diff -upr a/qbg/vdp22.c b/qbg/vdp22.c +--- a/qbg/vdp22.c 2021-06-09 10:58:59.210200578 -0400 ++++ b/qbg/vdp22.c 2020-10-23 14:12:58.977289347 -0400 +@@ -455,10 +455,10 @@ static void copy_filter(unsigned char fi + fp->grpid = from->gpid; + if (fif == VDP22_FFMT_GROUPVID) + goto vid; +- /* Fall through intended */ ++ /* FALLTHROUGH */ + case VDP22_FFMT_MACVID: + memcpy(fp->mac, from->mac, sizeof(fp->mac)); +- /* Fall through intended */ ++ /* FALLTHROUGH */ + case VDP22_FFMT_VID: + vid: + fp->vlan = vdp22_set_vlanid(from->vlan) +@@ -694,7 +694,7 @@ static struct vdp22 *vdp22_findif(const + struct vdp22 *vdp = 0; + + if (!ud) { +- ud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_VDP22); ++ ud = find_module_user_data_by_id(&lldp_mod_head, LLDP_MOD_VDP22); + if (!ud) + LLDPAD_DBG("%s:%s no VDP22 module\n", __func__, + ifname); +@@ -794,7 +794,7 @@ void vdp22_stop(char *ifname) + struct vsi22 *vsi; + + LLDPAD_DBG("%s:%s stop vdp\n", __func__, ifname); +- vud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_VDP22); ++ vud = find_module_user_data_by_id(&lldp_mod_head, LLDP_MOD_VDP22); + if (!vud) { + LLDPAD_ERR("%s:%s no VDP22 module\n", __func__, ifname); + return; +@@ -834,7 +834,7 @@ static struct vdp22 *vdp22_create(const + ifname); + return NULL; + } +- strncpy(vdp->ifname, ifname, sizeof vdp->ifname); ++ STRNCPY_TERMINATED(vdp->ifname, ifname, sizeof vdp->ifname); + vdp->myrole = role; + LIST_INIT(&vdp->vsi22_que); + LIST_INSERT_HEAD(&eud->head, vdp, node); +@@ -874,7 +874,7 @@ void vdp22_start(const char *ifname, int + struct vsi22 *vsi; + + LLDPAD_DBG("%s:%s start vdp\n", __func__, ifname); +- vud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_VDP22); ++ vud = find_module_user_data_by_id(&lldp_mod_head, LLDP_MOD_VDP22); + if (!vud) { + LLDPAD_ERR("%s:%s no VDP22 module\n", __func__, ifname); + return; +diff -upr a/qbg/vdp22_cmds.c b/qbg/vdp22_cmds.c +--- a/qbg/vdp22_cmds.c 2021-06-09 10:58:59.201200461 -0400 ++++ b/qbg/vdp22_cmds.c 2020-10-23 14:12:58.977289347 -0400 +@@ -57,7 +57,7 @@ static struct lldp_module *get_my_module + { + struct lldp_module *np = NULL; + +- LIST_FOREACH(np, &lldp_head, lldp) ++ LIST_FOREACH(np, &lldp_mod_head, lldp) + if (thisid == np->id) + break; + return np; +@@ -296,7 +296,7 @@ int vdp22_sendevent(struct vdpnl_vsi *p) + return 0; + } + +-static int vdp22_cmdok(struct cmd *cmd, cmd_status expected) ++static int vdp22_cmdok(struct cmd *cmd, int expected) + { + if (cmd->cmd != expected) + return cmd_invalid; +@@ -473,6 +473,7 @@ static bool vdp22_partial_vsi_equal(stru + if (memcmp(p1->mgrid, p2->mgrid, + sizeof(p2->mgrid))) + return false; ++ /* FALLTHROUGH */ + case VSI_TYPEID_ARG: + if (p1->type_id != p2->type_id) + return false; +@@ -576,7 +577,7 @@ static int get_arg_vsi(struct cmd *cmd, + memset(&vsi, 0, sizeof(vsi)); + memset(vsi_str, 0, sizeof(vsi_str)); + vsi.request = cmd->tlvid; +- strncpy(vsi.ifname, cmd->ifname, sizeof(vsi.ifname) - 1); ++ strncpy(vsi.ifname, cmd->ifname, sizeof(vsi.ifname)); + good_cmd = cmd_failed; + if ((cmd->ops & op_config) && (cmd->ops & op_arg)) { + memset(&mac, 0, sizeof(mac)); +diff -upr a/qbg/vdp22sm.c b/qbg/vdp22sm.c +--- a/qbg/vdp22sm.c 2021-06-09 10:58:59.210200578 -0400 ++++ b/qbg/vdp22sm.c 2020-09-23 08:50:52.657814025 -0400 +@@ -1521,7 +1521,7 @@ static void vdp22br_process(struct vsi22 + case VDP22_RESP_DEASSOC: + if (error > VDP22_STATUS_MASK) + p->status = VDP22_HARDBIT; +- /* Fall through intended */ ++ /* FALLTHROUGH */ + case VDP22_RESP_SUCCESS: + rest: + p->status |= VDP22_ACKBIT | make_status(error); +@@ -1768,7 +1768,7 @@ static void vdp22br_run(struct vsi22 *p) + break; + case VDP22_BR_END: + vdp22br_end(p); +- break; ++ return; + } + } while (vdp22br_move_state(p) == true); + } +diff -upr a/qbg/vdp.c b/qbg/vdp.c +--- a/qbg/vdp.c 2015-01-20 13:42:56.000000000 -0500 ++++ b/qbg/vdp.c 2020-10-23 14:12:58.977289347 -0400 +@@ -188,7 +188,7 @@ struct vdp_data *vdp_data(char *ifname) + struct vdp_user_data *ud; + struct vdp_data *vd = NULL; + +- ud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_VDP02); ++ ud = find_module_user_data_by_id(&lldp_mod_head, LLDP_MOD_VDP02); + if (ud) { + LIST_FOREACH(vd, &ud->head, entry) { + if (!strncmp(ifname, vd->ifname, IFNAMSIZ)) +@@ -879,7 +879,7 @@ static bool vdp_vsi_set_bridge_state(str + { + switch(profile->state) { + case VSI_UNASSOCIATED: +- if ((profile->mode == VDP_MODE_DEASSOCIATE)) /* || (INACTIVE)) */ { ++ if (profile->mode == VDP_MODE_DEASSOCIATE) { + vdp_vsi_change_bridge_state(profile, VSI_DEASSOC_PROCESSING); + return true; + } else if (profile->mode == VDP_MODE_ASSOCIATE) { +@@ -1198,9 +1198,9 @@ int vdp_indicate(struct vdp_data *vd, st + /* put it in the list */ + profile->state = VSI_UNASSOCIATED; + LIST_INSERT_HEAD(&vd->profile_head, profile, profile); +- } + +- vdp_vsi_sm_bridge(profile); ++ vdp_vsi_sm_bridge(profile); ++ } + } + + return 0; +@@ -1357,7 +1357,7 @@ struct packed_tlv *vdp_gettlv(struct vdp + return ptlv; + + out_free: +- ptlv = free_pkd_tlv(ptlv); ++ free_pkd_tlv(ptlv); + out_err: + LLDPAD_ERR("%s: %s failed\n", __func__, vd->ifname); + return NULL; +@@ -1607,7 +1607,7 @@ void vdp_ifup(char *ifname, struct lldp_ + __func__, ifname, sizeof(*vd)); + goto out_err; + } +- strncpy(vd->ifname, ifname, IFNAMSIZ); ++ STRNCPY_TERMINATED(vd->ifname, ifname, IFNAMSIZ); + + vd->role = VDP_ROLE_STATION; + vd->enabletx = enabletx; +@@ -1624,7 +1624,7 @@ void vdp_ifup(char *ifname, struct lldp_ + + LIST_INIT(&vd->profile_head); + +- ud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_VDP02); ++ ud = find_module_user_data_by_id(&lldp_mod_head, LLDP_MOD_VDP02); + LIST_INSERT_HEAD(&ud->head, vd, entry); + + out_start_again: +@@ -1882,7 +1882,7 @@ int vdp_trigger(struct vsi_profile *prof + if (!macp->req_pid) + return 0; + sleep(1); /* Delay message notification */ +- if (!profile->port || !profile->port->ifname) { ++ if (!profile->port || !profile->port->ifname[0]) { + LLDPAD_ERR("%s: no ifname found for profile %p:\n", __func__, + profile); + goto error_exit; +diff -upr a/qbg/vdp_cmds.c b/qbg/vdp_cmds.c +--- a/qbg/vdp_cmds.c 2015-01-20 13:42:56.000000000 -0500 ++++ b/qbg/vdp_cmds.c 2020-09-23 08:50:52.658814043 -0400 +@@ -85,7 +85,7 @@ static char *print_mode(char *s, size_t + return s; + } + +-static int vdp_cmdok(struct cmd *cmd, cmd_status expected) ++static int vdp_cmdok(struct cmd *cmd, int expected) + { + if (cmd->cmd != expected) + return cmd_invalid; +diff -upr a/qbg/vdpnl.c b/qbg/vdpnl.c +--- a/qbg/vdpnl.c 2021-06-09 10:58:59.201200461 -0400 ++++ b/qbg/vdpnl.c 2020-09-23 08:50:52.658814043 -0400 +@@ -233,7 +233,7 @@ static int vdpnl_set(struct nlmsghdr *nl + + vsi->ifindex = ifinfo->ifi_index; + if (tb[IFLA_IFNAME]) +- strncpy(vsi->ifname, (char *)RTA_DATA(tb[IFLA_IFNAME]), ++ STRNCPY_TERMINATED(vsi->ifname, (char *)RTA_DATA(tb[IFLA_IFNAME]), + sizeof vsi->ifname); + else { + if (!if_indextoname(ifinfo->ifi_index, vsi->ifname)) { +@@ -304,9 +304,9 @@ static size_t vdp_nllen(void) + size_t needed; + + needed = nla_total_size(sizeof(struct nlattr)) /* IFLA_VF_PORT */ +- + nla_total_size(4); /* IFLA_PORT_VF */ +- + nla_total_size(PORT_UUID_MAX); /* IFLA_PORT_INSTANCE_UUID */ +- + nla_total_size(2); /* IFLA_PORT_RESPONSE */ ++ + nla_total_size(4) /* IFLA_PORT_VF */ ++ + nla_total_size(PORT_UUID_MAX) /* IFLA_PORT_INSTANCE_UUID */ ++ + nla_total_size(2); /* IFLA_PORT_RESPONSE */ + return needed; + } + +diff -upr a/qbg_utils.c b/qbg_utils.c +--- a/qbg_utils.c 2015-01-20 13:42:56.000000000 -0500 ++++ b/qbg_utils.c 2020-11-03 09:08:48.062229088 -0500 +@@ -36,7 +36,6 @@ + #include "qbg_utils.h" + + extern int loglvl; /* Global lldpad log level */ +-extern struct lldp_head lldp_head; + + /* + * hexdump_frame - print raw evb/ecp/vdp frame +@@ -73,7 +72,7 @@ void hexdump_frame(const char *ifname, c + */ + int modules_notify(int id, int sender_id, char *ifname, void *data) + { +- struct lldp_module *mp = find_module_by_id(&lldp_head, id); ++ struct lldp_module *mp = find_module_by_id(&lldp_mod_head, id); + int rc = 0; + + if (mp && mp->ops->lldp_mod_notify) +diff -upr a/README b/README +--- a/README 2015-01-20 13:42:56.000000000 -0500 ++++ b/README 2020-09-23 08:50:52.646813830 -0400 +@@ -186,7 +186,9 @@ lldpad Application Install + lldpad will create the lldpad.conf file if it does not exist. + + For development purposes, 'lldpad' can be run directly from the build +- directory. ++ directory. To run the unit tests associated with openlldpd, execute: ++ ++ ./bootstrap.sh; ./configure; make check + + Options + ------- +diff -upr a/tlv_dcbx.c b/tlv_dcbx.c +--- a/tlv_dcbx.c 2015-01-20 13:42:56.000000000 -0500 ++++ b/tlv_dcbx.c 2020-09-23 08:50:52.659814061 -0400 +@@ -154,7 +154,8 @@ struct unpacked_tlv *bld_dcbx1_tlv(struc + goto error; + memcpy(&tlv->info[offset], ptlv->tlv, ptlv->size); + offset += ptlv->size; +- ptlv = free_pkd_tlv(ptlv); ++ free_pkd_tlv(ptlv); ++ ptlv = NULL; + } + if (tlv_ok(dcbx->pg1)) { + ptlv = pack_tlv(dcbx->pg1); +@@ -162,7 +163,8 @@ struct unpacked_tlv *bld_dcbx1_tlv(struc + goto error; + memcpy(&tlv->info[offset], ptlv->tlv, ptlv->size); + offset += ptlv->size; +- ptlv = free_pkd_tlv(ptlv); ++ free_pkd_tlv(ptlv); ++ ptlv = NULL; + } + if (tlv_ok(dcbx->pfc1)) { + ptlv = pack_tlv(dcbx->pfc1); +@@ -170,7 +172,8 @@ struct unpacked_tlv *bld_dcbx1_tlv(struc + goto error; + memcpy(&tlv->info[offset], ptlv->tlv, ptlv->size); + offset += ptlv->size; +- ptlv = free_pkd_tlv(ptlv); ++ free_pkd_tlv(ptlv); ++ ptlv = NULL; + } + if (tlv_ok(dcbx->app1)) { + ptlv = pack_tlv(dcbx->app1); +@@ -178,7 +181,8 @@ struct unpacked_tlv *bld_dcbx1_tlv(struc + goto error; + memcpy(&tlv->info[offset], ptlv->tlv, ptlv->size); + offset += ptlv->size; +- ptlv = free_pkd_tlv(ptlv); ++ free_pkd_tlv(ptlv); ++ ptlv = NULL; + } + + if (tlv_ok(dcbx->llink)) { +@@ -187,7 +191,8 @@ struct unpacked_tlv *bld_dcbx1_tlv(struc + goto error; + memcpy(&tlv->info[offset], ptlv->tlv, ptlv->size); + offset += ptlv->size; +- ptlv = free_pkd_tlv(ptlv); ++ free_pkd_tlv(ptlv); ++ ptlv = NULL; + } + + if (offset != tlv->length) +@@ -196,7 +201,8 @@ struct unpacked_tlv *bld_dcbx1_tlv(struc + return tlv; + + error: +- ptlv = free_pkd_tlv(ptlv); ++ if (ptlv) ++ free_pkd_tlv(ptlv); + if (tlv) { + if (tlv->info) + free(tlv->info); +@@ -254,7 +260,8 @@ struct unpacked_tlv *bld_dcbx2_tlv(struc + goto error; + memcpy(&tlv->info[offset], ptlv->tlv, ptlv->size); + offset += ptlv->size; +- ptlv = free_pkd_tlv(ptlv); ++ free_pkd_tlv(ptlv); ++ ptlv = NULL; + } + if (tlv_ok(dcbx->pg2)) { + ptlv = pack_tlv(dcbx->pg2); +@@ -262,7 +269,8 @@ struct unpacked_tlv *bld_dcbx2_tlv(struc + goto error; + memcpy(&tlv->info[offset], ptlv->tlv, ptlv->size); + offset += ptlv->size; +- ptlv = free_pkd_tlv(ptlv); ++ free_pkd_tlv(ptlv); ++ ptlv = NULL; + } + if (tlv_ok(dcbx->pfc2)) { + ptlv = pack_tlv(dcbx->pfc2); +@@ -270,7 +278,8 @@ struct unpacked_tlv *bld_dcbx2_tlv(struc + goto error; + memcpy(&tlv->info[offset], ptlv->tlv, ptlv->size); + offset += ptlv->size; +- ptlv = free_pkd_tlv(ptlv); ++ free_pkd_tlv(ptlv); ++ ptlv = NULL; + } + if (tlv_ok(dcbx->app2)) { + ptlv = pack_tlv(dcbx->app2); +@@ -278,7 +287,8 @@ struct unpacked_tlv *bld_dcbx2_tlv(struc + goto error; + memcpy(&tlv->info[offset], ptlv->tlv, ptlv->size); + offset += ptlv->size; +- ptlv = free_pkd_tlv(ptlv); ++ free_pkd_tlv(ptlv); ++ ptlv = NULL; + } + + if (offset != tlv->length) +@@ -287,7 +297,8 @@ struct unpacked_tlv *bld_dcbx2_tlv(struc + return tlv; + + error: +- ptlv = free_pkd_tlv(ptlv); ++ if (ptlv) ++ free_pkd_tlv(ptlv); + if (tlv) { + if (tlv->info) + free(tlv->info); +diff -upr a/vdptool.c b/vdptool.c +--- a/vdptool.c 2021-06-09 10:58:59.202200474 -0400 ++++ b/vdptool.c 2020-10-23 14:12:58.978289365 -0400 +@@ -36,6 +36,7 @@ + * set and query VSI profile settings. + */ + ++#define _GNU_SOURCE + #include + #include + #include +@@ -60,6 +61,8 @@ + #define OUI_ENCODE_HNDLR(name) name##_oui_encode_hndlr + #define OUI_PRNT_DECODE_HNDLR(name) name##_oui_print_decode_hndlr + ++struct lldp_head lldp_mod_head; ++ + #define EXTERN_OUI_FN(name) \ + extern bool name##_oui_encode_hndlr(char *, char *, size_t); \ + extern void name##_oui_print_decode_hndlr(char *) +@@ -140,7 +143,7 @@ static char *print_status(cmd_status sta + str = "TLV does not support agent type"; + break; + default: +- str = print_vdp_status(status); ++ str = print_vdp_status((enum vdp22_cmd_status)status); + break; + } + return str; +@@ -178,7 +181,7 @@ static char *get_oui_name(char *argvals) + + static void fill_oui_hdr(vdptool_oui_data_t *oui_data, char *oui_name) + { +- strncpy(oui_data->oui_name, oui_name, sizeof(oui_data->oui_name)); ++ STRNCPY_TERMINATED(oui_data->oui_name, oui_name, sizeof(oui_data->oui_name)); + snprintf(oui_data->data, sizeof(oui_data->data), "%02x%s", + (unsigned int)strlen(oui_data->oui_name), oui_data->oui_name); + } +@@ -587,7 +590,7 @@ static void print_all_vsis(char *ibuf, b + size_t ilen = strlen(ibuf); + u16 vsi_len; + int offset = 0, vsi_cnt = 0; +- char tmp_ibuf[strlen(ibuf)]; ++ char tmp_ibuf[strlen(ibuf) + 1]; + + while (ilen > 0) { + vsi_len = hex2u16(ibuf + offset); +@@ -795,13 +798,13 @@ static void init_modules(void) + struct lldp_module *premod = NULL; + int i = 0; + +- LIST_INIT(&lldp_head); ++ LIST_INIT(&lldp_mod_head); + for (i = 0; register_tlv_table[i]; i++) { + module = register_tlv_table[i](); + if (premod) + LIST_INSERT_AFTER(premod, module, lldp); + else +- LIST_INSERT_HEAD(&lldp_head, module, lldp); ++ LIST_INSERT_HEAD(&lldp_mod_head, module, lldp); + premod = module; + } + } +@@ -810,9 +813,9 @@ void deinit_modules(void) + { + struct lldp_module *module; + +- while (lldp_head.lh_first != NULL) { +- module = lldp_head.lh_first; +- LIST_REMOVE(lldp_head.lh_first, lldp); ++ while (lldp_mod_head.lh_first != NULL) { ++ module = lldp_mod_head.lh_first; ++ LIST_REMOVE(lldp_mod_head.lh_first, lldp); + module->ops->lldp_mod_unregister(module); + } + } +@@ -952,7 +955,7 @@ cli_cmd_help(UNUSED struct clif *clif, U + printf("%s\n%s\n%s", commands_usage, commands_options, commands_help); + + printf("\nTLV identifiers:\n"); +- LIST_FOREACH(np, &lldp_head, lldp) ++ LIST_FOREACH(np, &lldp_mod_head, lldp) + if (np->ops->print_help) + np->ops->print_help(); + return 0; +@@ -1005,7 +1008,7 @@ u32 lookup_tlvid(char *tlvid_str) + struct lldp_module *np; + u32 tlvid = INVALID_TLVID; + +- LIST_FOREACH(np, &lldp_head, lldp) { ++ LIST_FOREACH(np, &lldp_mod_head, lldp) { + if (np->ops->lookup_tlv_name) { + tlvid = np->ops->lookup_tlv_name(tlvid_str); + if (tlvid != INVALID_TLVID) +diff -upr a/vdptool_cisco_oui.c b/vdptool_cisco_oui.c +--- a/vdptool_cisco_oui.c 2021-06-09 10:58:59.203200487 -0400 ++++ b/vdptool_cisco_oui.c 2020-09-23 08:50:52.660814079 -0400 +@@ -28,7 +28,7 @@ + #include "lldp_util.h" + #include "vdp_cisco.h" + +-bool cisco_oui_encode_hndlr(char *dst, char *src, int len) ++bool cisco_oui_encode_hndlr(char *dst, char *src, size_t len) + { + char *src_temp = strdup(src); + char *key, *data; +diff -upr a/weak_readline.c b/weak_readline.c +--- a/weak_readline.c 2015-01-20 13:42:56.000000000 -0500 ++++ b/weak_readline.c 2020-09-23 08:50:52.660814079 -0400 +@@ -30,6 +30,9 @@ + #include + + static int inited; ++static void *hist_handle; ++static void *rl_handle; ++ + + static char *(*readline_p)(const char *); + static void (*using_history_p)(void); +@@ -38,9 +41,6 @@ static void (*add_history_p)(const char + + static void weak_readline_init(void) + { +- void *hist_handle; +- void *rl_handle; +- + inited = 1; + hist_handle = dlopen("libhistory.so", RTLD_LAZY | RTLD_GLOBAL); + if (!hist_handle) +@@ -77,6 +77,16 @@ void using_history(void) + using_history_p(); + } + ++void close_history(void) ++{ ++ if (inited) { ++ dlclose(rl_handle); ++ rl_handle = NULL; ++ dlclose(hist_handle); ++ hist_handle = NULL; ++ } ++} ++ + void stifle_history(int max) + { + if (!inited) diff --git a/SPECS/lldpad.spec b/SPECS/lldpad.spec index e98eb6a..0318062 100644 --- a/SPECS/lldpad.spec +++ b/SPECS/lldpad.spec @@ -7,7 +7,7 @@ Name: lldpad Version: 1.0.1 -Release: 14.git%{checkout}%{?dist} +Release: 16.git%{checkout}%{?dist} Summary: Intel LLDP Agent Group: System Environment/Daemons License: GPLv2 @@ -43,6 +43,7 @@ Patch27: open-lldp-v1.0.1-27-fix-build-warnings.patch Patch28: open-lldp-v1.0.1-28-fix-oid-display.patch Patch29: open-lldp-v1.0.1-29-memleak-on-received-TLVs.patch Patch30: open-lldp-v1.0.1-30-support-DSCP-selectors.patch +Patch31: open-lldp-v1.0.1-31-Rebase-to-open-lldp-branch-1.1.0.patch BuildRequires: automake autoconf libtool BuildRequires: flex >= 2.5.33 @@ -116,6 +117,12 @@ rm -f %{buildroot}%{_libdir}/liblldp_clif.la %{_libdir}/liblldp_clif.so %changelog +* Wed Aug 04 2021 Aaron Conole - 1.0.1-16.git036e314 +- Update the changelog + +* Wed Aug 04 2021 Aaron Conole - 1.0.1-15.git036e314 +- Fix the branch compatibility + * Wed Jun 09 2021 Aaron Conole - 1.0.1-14.git036e314 - Update to branch-1.1 compatibility - Fixes to avoid assert in the agent state machine