diff --git a/open-lldp-git-update.patch b/open-lldp-git-update.patch deleted file mode 100644 index 1a7c6c9..0000000 --- a/open-lldp-git-update.patch +++ /dev/null @@ -1,23450 +0,0 @@ -diff --git a/COPYING b/COPYING -index 5f297e5..87eef25 100644 ---- a/COPYING -+++ b/COPYING -@@ -8,7 +8,7 @@ GNU General Public License - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc. --59 Temple Place - Suite 330, Boston, MA 02111-1307, USA -+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - - Everyone is permitted to copy and distribute verbatim copies of this license - document, but changing it is not allowed. -diff --git a/Makefile.am b/Makefile.am -index 893fa45..4b07191 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -27,7 +27,7 @@ include/clif.h include/lldp_dcbx_cmds.h \ - include/lldpad.h include/lldp_mand_cmds.h \ - include/clif_msgs.h include/lldp_basman_cmds.h include/lldp_8023_cmds.h \ - include/lldp_med_cmds.h include/lldp_util.h \ --include/lldp_evb_cmds.h include/lldp_vdp_cmds.h include/lldp_8021qaz_cmds.h \ -+include/lldp_evb_cmds.h include/qbg_vdp_cmds.h include/lldp_8021qaz_cmds.h \ - include/clif_sock.h include/linux/dcbnl.h \ - include/linux/netlink.h include/linux/rtnetlink.h \ - include/lldpad_status.h -@@ -40,7 +40,7 @@ include/lldpad_shm.h include/event_iface.h include/messages.h \ - include/parse_cli.h include/version.h include/lldptool_cli.h include/list.h \ - include/lldp_mand_clif.h include/lldp_basman_clif.h include/lldp_med_clif.h \ - include/lldp_8023_clif.h include/lldp_dcbx_clif.h include/lldp_evb_clif.h \ --include/lldp_evb22_clif.h include/lldp_vdp_clif.h include/lldp_vdpnl.h \ -+include/lldp_evb22_clif.h include/qbg_vdp_clif.h include/qbg_vdpnl.h \ - include/lldp_8021qaz_clif.h \ - include/lldp_orgspec_clif.h include/lldp_cisco_clif.h \ - include/lldptool.h include/lldp_rtnl.h include/dcbtool.h include/lldp_dcbx_cfg.h -@@ -56,19 +56,20 @@ lldp_dcbx.c include/lldp_dcbx.h tlv_dcbx.c include/tlv_dcbx.h \ - lldp_dcbx_cfg.c include/lldp_dcbx_cfg.h lldp_util.c \ - lldp_mand.c include/lldp_mand.h \ - lldp_mand_cmds.c lldp_basman_cmds.c lldp_8023_cmds.c lldp_med_cmds.c \ --lldp_evb_cmds.c lldp_evb.c include/lldp_evb.h lldp_vdp_cmds.c \ --include/lldp_vdp_cmds.h \ --include/lldp_ecp.h include/lldp_qbg_utils.h lldp_ecp.c lldp_qbg_utils.c \ --lldp_vdp.c include/lldp_vdp.h \ -+lldp_evb_cmds.c lldp_evb.c include/lldp_evb.h qbg/vdp_cmds.c \ -+include/qbg_vdp_cmds.h \ -+include/qbg_ecp.h include/qbg_utils.h qbg/ecp.c qbg_utils.c \ -+qbg/vdp.c include/qbg_vdp.h \ - lldp_tlv.c include/lldp_tlv.h \ - lldp_basman.c include/lldp_basman.h \ - lldp_med.c include/lldp_med.h \ - lldp_8023.c include/lldp_8023.h \ - lldp_8021qaz.c include/lldp_8021qaz.h \ - lldp_8021qaz_cmds.c include/lldp_8021qaz_cmds.h \ --include/lldp_evb22.h qbg/lldp_evb22.c qbg/lldp_evb22_cmds.c \ --include/lldp_qbg22.h include/lldp_ecp22.h qbg/lldp_ecp22.c \ --include/lldp_vdp22.h qbg/lldp_vdp22.c qbg/lldp_vdpnl.c -+include/lldp_evb22.h lldp_evb22.c lldp_evb22_cmds.c \ -+include/qbg22.h include/qbg_ecp22.h qbg/ecp22.c \ -+include/qbg_vdp22.h qbg/vdp22.c qbg/vdpnl.c qbg/vdp22sm.c qbg/vdp22br.c \ -+include/qbg_vdp22def.h - - lib_LTLIBRARIES = liblldp_clif.la - liblldp_clif_la_LDFLAGS = -version-info 1:0:0 -@@ -83,8 +84,8 @@ dcbtool_LDFLAGS = -ldl -llldp_clif - lldptool_SOURCES = lldptool.c lldptool_cmds.c lldp_rtnl.c \ - lldp_mand_clif.c lldp_basman_clif.c lldp_med_clif.c \ - lldp_8023_clif.c lldp_dcbx_clif.c lldp_util.c \ -- lldp_8021qaz_clif.c lldp_evb_clif.c lldp_vdp_clif.c \ -- lldp_orgspec_clif.c lldp_cisco_clif.c qbg/lldp_evb22_clif.c \ -+ lldp_8021qaz_clif.c lldp_evb_clif.c qbg/vdp_clif.c \ -+ lldp_orgspec_clif.c lldp_cisco_clif.c lldp_evb22_clif.c \ - weak_readline.c $(lldpad_include_HEADERS) $(noinst_HEADERS) - lldptool_LDADD = ${srcdir}/liblldp_clif.la - lldptool_LDFLAGS = -ldl -llldp_clif -@@ -120,25 +121,21 @@ pkgconfig_DATA = lldpad.pc liblldp_clif.pc - ## put a spec file and documentation in the distribution archive - dist_noinst_DATA = lldpad.spec README COPYING ChangeLog - --## lldpad.init is listed here because it gets installed from install-data-local --dist_noinst_SCRIPTS = lldpad.init -- - ## special hooks to handle the init script --install-data-local: lldpad.init -- $(MKDIR_P) $(DESTDIR)/etc/init.d -- $(INSTALL_SCRIPT) lldpad.init $(DESTDIR)/etc/init.d/lldpad -+install-data-local: lldpad.service lldpad.socket -+ $(MKDIR_P) $(DESTDIR)/usr/lib/systemd/system -+ $(INSTALL_DATA) lldpad.service $(DESTDIR)/usr/lib/systemd/system/lldpad.service -+ $(INSTALL_DATA) lldpad.socket $(DESTDIR)/usr/lib/systemd/system/lldpad.socket - - BASH_COMPLETION_DIR=/etc/bash_completion.d/ - - install-data-hook: -- /sbin/chkconfig --add lldpad || true - ## provide support for bash completion - $(MKDIR_P) $(DESTDIR)/$(BASH_COMPLETION_DIR) -- $(INSTALL_SCRIPT) ${srcdir}/contrib/bash_completion/* $(DESTDIR)/$(BASH_COMPLETION_DIR) -+ $(INSTALL_DATA) ${srcdir}/contrib/bash_completion/* $(DESTDIR)/$(BASH_COMPLETION_DIR) - - uninstall-local: -- /sbin/chkconfig --del lldpad || true -- rm -f '$(DESTDIR)/etc/init.d/lldpad' -+ rm -f '$(DESTDIR)/usr/lib/systemd/system/lldpad.*' - rm -f '$(includedir)/dcbd/clif_cmds.h' - rm -f '$(includedir)/dcbd' - -diff --git a/clif.c b/clif.c -index 2984e8e..531305e 100644 ---- a/clif.c -+++ b/clif.c -@@ -240,7 +240,7 @@ pid_t clif_getpid(void) - { - struct clif *clif_conn; - char buf[MAX_CLIF_MSGBUF]; -- size_t len; -+ size_t len = sizeof(buf); - char *ppong; - int ret; - pid_t lldpad = 0; /* LLDPAD process identifier */ -diff --git a/config.c b/config.c -index 7229b91..36130ad 100644 ---- a/config.c -+++ b/config.c -@@ -102,6 +102,7 @@ void destroy_cfg(void) - void scan_port(UNUSED void *eloop_data, UNUSED void *user_ctx) - { - struct port *port; -+ struct port *next; - struct if_nameindex *nameidx, *p; - - LLDPAD_INFO("%s: NLMSG dropped, scan ports.\n", __func__); -@@ -121,24 +122,20 @@ void scan_port(UNUSED void *eloop_data, UNUSED void *user_ctx) - * comes back online we should receive a RTM_NEWLINK event and can - * readd it there. - */ -- port = porthead; -- while (port != NULL) { -+ for (port = porthead; port; port = next) { - int found = 0; -- struct port *del; -- p = nameidx; -- while (p->if_index != 0) { -- if (!strncmp(p->if_name, port->ifname, -- MAX_DEVICE_NAME_LEN)) { -+ -+ for (p = nameidx; p->if_index; ++p) { -+ if ((int)p->if_index == port->ifindex) { - /* Good device exists continue port walk */ - found = 1; -+ memcpy(port->ifname, p->if_name, IFNAMSIZ); - break; - } -- p++; - } -- del = port; -- port = port->next; -+ next = port->next; - if (!found) -- remove_port(del->ifname); -+ remove_port(port->ifname); - } - - /* Walk port list looking for devices that should have been added -@@ -149,43 +146,42 @@ void scan_port(UNUSED void *eloop_data, UNUSED void *user_ctx) - * This is required because we currently do not know if we missed - * IF_OPER_UP, IF_OPER_DOWN or IF_OPER_DORMANT. - */ -- p = nameidx; -- while (p->if_index != 0) { -+ for (p = nameidx; p->if_index; ++p) { - struct lldp_module *np; - const struct lldp_mod_ops *ops; - char *ifname = p->if_name; - struct lldp_agent *agent; - -- if (!is_valid_lldp_device(ifname)) { -- p++; -+ if (!is_valid_lldp_device(ifname)) - continue; -- } - -- port = port_find_by_name(p->if_name); -- if (!port) -- port = add_port(p->if_name); -+ port = port_find_by_ifindex(p->if_index); -+ if (!port) { -+ port = add_port(p->if_index, p->if_name); -+ continue; -+ } - -- if (port && check_link_status(ifname)) { -+ memcpy(port->ifname, ifname, IFNAMSIZ); -+ if (check_link_status(ifname)) { - set_port_oper_delay(ifname); - oper_add_device(ifname); -- } else if (port) { -- LIST_FOREACH(agent, &port->agent_head, entry) { -- LLDPAD_DBG("%s: calling ifdown for agent %p.\n", -- __func__, agent); -- LIST_FOREACH(np, &lldp_head, lldp) { -- ops = np->ops; -- if (ops->lldp_mod_ifdown) -- ops->lldp_mod_ifdown(ifname, -- agent); -- } -+ continue; -+ } -+ LIST_FOREACH(agent, &port->agent_head, entry) { -+ LLDPAD_DBG("%s: calling ifdown for agent %p.\n", -+ __func__, agent); -+ LIST_FOREACH(np, &lldp_head, lldp) { -+ ops = np->ops; -+ if (ops->lldp_mod_ifdown) -+ ops->lldp_mod_ifdown(ifname, agent); - } -- set_lldp_port_enable(ifname, 0); - } -- p++; -+ set_lldp_port_enable(ifname, 0); - } - - if_freenameindex(nameidx); - return; -+ - error_out: - eloop_register_timeout(INI_TIMER, 0, scan_port, NULL, NULL); - return; -@@ -361,36 +357,34 @@ void init_ports(void) - return; - } - -- p = nameidx; -- while (p->if_index != 0) { -+ for (p = nameidx; p->if_index; ++p) { - int valid = is_valid_lldp_device(p->if_name); - -- if (!valid) { -- p++; -+ if (!valid) - continue; -- } - -- port = add_port(p->if_name); -- -- if (port == NULL) { -+ port = add_port(p->if_index, p->if_name); -+ if (!port) { - LLDPAD_ERR("%s: Error adding device %s\n", - __func__, p->if_name); -- } else if (check_link_status(p->if_name)) { -- lldp_add_agent(p->if_name, NEAREST_BRIDGE); -- lldp_add_agent(p->if_name, NEAREST_NONTPMR_BRIDGE); -- lldp_add_agent(p->if_name, NEAREST_CUSTOMER_BRIDGE); -- -- LIST_FOREACH(agent, &port->agent_head, entry) { -- LLDPAD_DBG("%s: calling ifup for agent %p.\n", -- __func__, agent); -- LIST_FOREACH(np, &lldp_head, lldp) { -- if (np->ops->lldp_mod_ifup) -- np->ops->lldp_mod_ifup(p->if_name, agent); -- } -+ continue; -+ } -+ if (!check_link_status(p->if_name)) -+ continue; -+ -+ lldp_add_agent(p->if_name, NEAREST_BRIDGE); -+ lldp_add_agent(p->if_name, NEAREST_NONTPMR_BRIDGE); -+ lldp_add_agent(p->if_name, NEAREST_CUSTOMER_BRIDGE); -+ -+ LIST_FOREACH(agent, &port->agent_head, entry) { -+ LLDPAD_DBG("%s: calling ifup for agent %p.\n", -+ __func__, agent); -+ LIST_FOREACH(np, &lldp_head, lldp) { -+ if (np->ops->lldp_mod_ifup) -+ np->ops->lldp_mod_ifup(p->if_name, agent); - } -- set_lldp_port_enable(p->if_name, 1); - } -- p++; -+ set_lldp_port_enable(p->if_name, 1); - } - - if_freenameindex(nameidx); -diff --git a/ctrl_iface.c b/ctrl_iface.c -index e02f036..7f64b57 100644 ---- a/ctrl_iface.c -+++ b/ctrl_iface.c -@@ -326,7 +326,7 @@ static void process_clif_cmd( struct clif_data *cd, - rsize - strlen(rbuf) - 1); - - /* update status and compute final length */ -- rbuf[CLIF_STAT_OFF] = hexlist[(status & 0x0f1) >> 4]; -+ rbuf[CLIF_STAT_OFF] = hexlist[(status & 0xf0) >> 4]; - rbuf[CLIF_STAT_OFF+1] = hexlist[status & 0x0f]; - *rlen = strlen(rbuf); - } -@@ -411,6 +411,42 @@ int ctrl_iface_register(struct clif_data *clifd) - clifd, NULL); - } - -+int ctrl_iface_systemd_socket() -+{ -+ char *env, *ptr; -+ unsigned int p, l; -+ -+ env = getenv("LISTEN_PID"); -+ if (!env) -+ return -1; -+ -+ p = strtoul(env, &ptr, 10); -+ if (ptr && ptr == env) { -+ LLDPAD_DBG("Invalid value '%s' for LISTEN_PID\n", env); -+ return -1; -+ } -+ if ((pid_t)p != getpid()) { -+ LLDPAD_DBG("Invalid PID '%d' from LISTEN_PID\n", p); -+ return -1; -+ } -+ env = getenv("LISTEN_FDS"); -+ if (!env) { -+ LLDPAD_DBG("LISTEN_FDS is not set\n"); -+ return -1; -+ } -+ l = strtoul(env, &ptr, 10); -+ if (ptr && ptr == env) { -+ LLDPAD_INFO("Invalid value '%s' for LISTEN_FDS\n", env); -+ return -1; -+ } -+ if (l != 1) { -+ LLDPAD_INFO("LISTEN_FDS specified %d fds\n", l); -+ return -1; -+ } -+ /* systemd returns fds with an offset of '3' */ -+ return 3; -+} -+ - int ctrl_iface_init(struct clif_data *clifd) - { - struct sockaddr_un addr; -@@ -421,6 +457,11 @@ int ctrl_iface_init(struct clif_data *clifd) - clifd->ctrl_sock = -1; - clifd->ctrl_dst = NULL; - -+ s = ctrl_iface_systemd_socket(); -+ if (s != -1) { -+ LLDPAD_INFO("using fd %d from systemd\n", s); -+ goto out; -+ } - s = socket(AF_LOCAL, SOCK_DGRAM, 0); - if (s < 0) { - perror("socket(AF_LOCAL)"); -@@ -444,6 +485,7 @@ int ctrl_iface_init(struct clif_data *clifd) - &feature_on, sizeof(feature_on)); - - LLDPAD_INFO("bound ctrl iface to %s\n", &addr.sun_path[1]); -+out: - clifd->ctrl_sock = s; - - return 0; -diff --git a/docs/lldpad.8 b/docs/lldpad.8 -index 62c043f..df1314e 100644 ---- a/docs/lldpad.8 -+++ b/docs/lldpad.8 -@@ -10,11 +10,12 @@ lldpad \- Link Layer Discovery Protocol (LLDP) agent daemon - .SH SYNOPSIS - .B lldpad [-h] - .B [-v] --.B [-V] -+.BI "[-V" " level" "]" - .B [-d] - .B [-k] - .B [-p] - .B [-s] -+.B [-t] - .BI "[-f" " filename" "]" - .SH DESCRIPTION - Executes the LLDP protocol for supported network interfaces. The list of TLVs currently supported are: -@@ -134,7 +135,7 @@ run lldpad as a daemon - .B \-v - show lldpad version - .TP --.B \-V -+.BI "-V" " level" - set lldpad debugging level. Uses syslog debug levels see syslog.2 for details. - .TP - .B \-k -@@ -149,6 +150,9 @@ remove lldpad state records from shared memory - .TP - .B \-p - do not create PID file /var/run/lldpad.pid on startup -+.TP -+.B \-t -+omit timestamps from logging messages - .PP - - .SH NOTE -diff --git a/docs/lldptool-med.8 b/docs/lldptool-med.8 -index 687175c..7932c0d 100644 ---- a/docs/lldptool-med.8 -+++ b/docs/lldptool-med.8 -@@ -14,7 +14,7 @@ LLDP-MED \- Show / manipulate MED TLV configurations - .B lldptool -T -i ethx -V - LLDP-MED - .B devtype = --{ class1 | class2 | class3 } -+{ class1 | class2 | class3 | none } - .sp - .B lldptool -t -i ethx -V - LLDP-MED -diff --git a/docs/lldptool.8 b/docs/lldptool.8 -index d076af8..e70a712 100644 ---- a/docs/lldptool.8 -+++ b/docs/lldptool.8 -@@ -125,7 +125,7 @@ commands. Configures the LLDP adminStatus parameter for the specified interface - .B enableTx - Argument for the - .B get-tlv/set-tlv --commands. May be applied per interface for a specified TLV. Valid values are: \fIyes\fR, \fIno\fR. If the DCBX TLV enableTx is set to \fIno\fR, then all of the DCB feature TLVs DCBX advertise settings will be turned off as well. Setting enableTx to \fIyes\fR for a DCBX TLV will not affect the DCBX advertise settings. -+commands. May be applied per interface for a specified TLV. Valid values are: \fIyes\fR, \fIno\fR. If the DCBX TLV enableTx is set to \fIno\fR, then all of the DCB feature TLVs DCBX advertise settings will be turned off as well. Setting enableTx to \fIyes\fR will enable the DCBX advertise settings. - - .TP - .B ipv4 -@@ -212,7 +212,7 @@ Get all configured attributes for the Management Address TLV on eth3 - - .TP - Enable transmit of the Edge Virtual Bridging TLV for interface eth4 --.B lldptool -i eth4 -T -V evbCfg enableTx=yes -+.B lldptool -i eth4 -T -g ncb -V evbCfg enableTx=yes - - .TP - Enable transmit of VDP for interface eth4 -diff --git a/event_iface.c b/event_iface.c -index 2cd4f0c..297d751 100644 ---- a/event_iface.c -+++ b/event_iface.c -@@ -59,7 +59,7 @@ - #include "lldp/states.h" - #include "messages.h" - #include "lldp_rtnl.h" --#include "lldp_vdpnl.h" -+#include "qbg_vdpnl.h" - #include "lldp_tlv.h" - - extern unsigned int if_nametoindex(const char *); -@@ -186,20 +186,18 @@ int oper_add_device(char *device_name) - struct lldp_module *np; - struct port *port, *newport; - struct lldp_agent *agent; -+ int ifindex; - -- port = porthead; -- while (port != NULL) { -- if (!strncmp(device_name, port->ifname, MAX_DEVICE_NAME_LEN)) -+ ifindex = get_ifidx(device_name); -+ for (port = porthead; port; port = port->next) -+ if (ifindex == port->ifindex) - break; -- port = port->next; -- } - - if (!port) { -- newport = add_port(device_name); -- -- if (newport == NULL) { -+ newport = add_port(ifindex, device_name); -+ if (!newport) { - LLDPAD_INFO("%s: Error adding device %s\n", -- __func__, device_name); -+ __func__, device_name); - return -EINVAL; - } - -@@ -232,6 +230,7 @@ static void event_if_decode_nlmsg(int route_type, void *data, int len) - struct rtattr *rta; - char device_name[IFNAMSIZ]; - struct lldp_agent *agent; -+ int ifindex; - int attrlen; - int valid; - int link_status = IF_OPER_UNKNOWN; -@@ -241,13 +240,13 @@ static void event_if_decode_nlmsg(int route_type, void *data, int len) - case RTM_DELLINK: - case RTM_SETLINK: - case RTM_GETLINK: -+ ifindex = ((struct ifinfomsg *)data)->ifi_index; - LLDPAD_DBG(" IFINFOMSG\n"); - LLDPAD_DBG(" ifi_family = 0x%02x\n", - ((struct ifinfomsg *)data)->ifi_family); - LLDPAD_DBG(" ifi_type = 0x%x\n", - ((struct ifinfomsg *)data)->ifi_type); -- LLDPAD_DBG(" ifi_index = %i\n", -- ((struct ifinfomsg *)data)->ifi_index); -+ LLDPAD_DBG(" ifi_index = %i\n", ifindex); - LLDPAD_DBG(" ifi_flags = 0x%04x\n", - ((struct ifinfomsg *)data)->ifi_flags); - LLDPAD_DBG(" ifi_change = 0x%04x\n", -@@ -274,7 +273,7 @@ static void event_if_decode_nlmsg(int route_type, void *data, int len) - if (!valid) - break; - -- struct port *port = port_find_by_name(device_name); -+ struct port *port = port_find_by_ifindex(ifindex); - if (!port) - break; - -diff --git a/include/linux/dcbnl.h b/include/linux/dcbnl.h -index 66a6723..503bad3 100644 ---- a/include/linux/dcbnl.h -+++ b/include/linux/dcbnl.h -@@ -11,8 +11,8 @@ - * more details. - * - * You should have received a copy of the GNU General Public License along with -- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple -- * Place - Suite 330, Boston, MA 02111-1307 USA. -+ * this program; if not, write to the Free Software Foundation, Inc., -+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Author: Lucy Liu - */ -diff --git a/include/lldp_8021qaz.h b/include/lldp_8021qaz.h -index 461cca2..55353b8 100644 ---- a/include/lldp_8021qaz.h -+++ b/include/lldp_8021qaz.h -@@ -238,5 +238,6 @@ inline int ieee8021qaz_clif_cmd(void *data, struct sockaddr_un *from, - socklen_t fromlen, char *ibuf, int ilen, - char *rbuf); - int ieee8021qaz_check_operstate(void); -+int get_dcbx_hw(const char *ifname, __u8 *dcbx); - - #endif /* _LLDP_8021QAZ_H */ -diff --git a/include/lldp_dcbx_cmds.h b/include/lldp_dcbx_cmds.h -index 9e9603d..39661e7 100644 ---- a/include/lldp_dcbx_cmds.h -+++ b/include/lldp_dcbx_cmds.h -@@ -31,7 +31,7 @@ - #include - #include "clif_msgs.h" - --struct arg_handlers *dcbx_get_arg_handlers(); -+struct arg_handlers *dcbx_get_arg_handlers(void); - void dont_advertise_dcbx_all(char *ifname, bool ad); - - #define CLIF_RSP_MSG_OFF 0 -diff --git a/include/lldp_ecp.h b/include/lldp_ecp.h -deleted file mode 100644 -index aa388c6..0000000 ---- a/include/lldp_ecp.h -+++ /dev/null -@@ -1,106 +0,0 @@ --/******************************************************************************* -- -- Implementation of EVB TLVs for LLDP -- (c) Copyright IBM Corp. 2010, 2012 -- -- Author(s): Jens Osterkamp -- Author(s): Thomas Richter -- -- This program is free software; you can redistribute it and/or modify it -- under the terms and conditions of the GNU General Public License, -- version 2, as published by the Free Software Foundation. -- -- This program is distributed in the hope it will be useful, but WITHOUT -- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -- more details. -- -- You should have received a copy of the GNU General Public License along with -- this program; if not, write to the Free Software Foundation, Inc., -- 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. -- -- The full GNU General Public License is included in this distribution in -- the file called "COPYING". -- --*******************************************************************************/ -- --#ifndef LLDP_ECP_H --#define LLDP_ECP_H -- --#include -- --#include "lldp_mod.h" --#include "lldp_vdp.h" -- --#define ECP_SUBTYPE 0x0 -- --#define ECP_MAX_RETRIES 3 --#define ECP_SEQUENCE_NR_START 0x0 -- --#define MSECS 1000 --#define SECS (1000 * MSECS) -- --#define ECP_ACK_TIMER_DEFAULT (500 * MSECS) /* 500 ms */ --#define ECP_LOCALCHANGE_TIMEOUT (1 * MSECS) /* 1 ms */ -- --#define ECP_ACK_TIMER_STOPPED (-1) -- --typedef enum { -- ECP_REQUEST = 0, -- ECP_ACK --} ecp_mode; -- --struct ecp_buffer { /* ECP payload buffer */ -- u8 frame[ETH_FRAME_LEN]; /* Payload buffer */ -- u16 frame_len; /* # of bytes of valid data */ -- u8 state; /* Buffer state */ -- u8 localChange; /* Status changed */ -- u8 rcvFrame; /* True if new frame received */ --}; -- --struct ecp { -- struct l2_packet_data *l2; -- int sequence; -- int retries; -- int ackReceived; -- int ackTimer; -- u16 lastSequence; -- u16 seqECPDU; -- struct ecp_buffer rx; /* Receive buffer */ -- struct ecp_buffer tx; /* Transmit buffer */ -- struct agentstats stats; -- char ifname[IFNAMSIZ]; /* Interface name */ --}; -- --struct ecp_hdr { -- u8 oui[3]; -- u8 pad1; -- u16 subtype; -- u8 mode; -- u16 seqnr; --} __attribute__ ((__packed__)); -- --enum { -- ECP_TX_INIT_TRANSMIT, -- ECP_TX_TRANSMIT_ECPDU, -- ECP_TX_WAIT_FOR_ACK, -- ECP_TX_REQUEST_PDU --}; -- --enum { -- ECP_RX_IDLE, -- ECP_RX_INIT_RECEIVE, -- ECP_RX_RECEIVE_WAIT, -- ECP_RX_RECEIVE_ECPDU, -- ECP_RX_SEND_ACK, -- ECP_RX_RESEND_ACK, --}; -- --struct vdp_data; -- --void ecp_somethingChangedLocal(struct vdp_data *, bool); --void ecp_rx_send_ack_frame(struct vdp_data *); -- --int ecp_init(char *); --int ecp_deinit(char *); --#endif /* _ECP_H */ -diff --git a/include/lldp_ecp22.h b/include/lldp_ecp22.h -deleted file mode 100644 -index 50a1b44..0000000 ---- a/include/lldp_ecp22.h -+++ /dev/null -@@ -1,172 +0,0 @@ --/******************************************************************************* -- -- Implementation of EVB TLVs for LLDP -- (c) Copyright IBM Corp. 2013 -- -- Author(s): Thomas Richter -- -- This program is free software; you can redistribute it and/or modify it -- under the terms and conditions of the GNU General Public License, -- version 2, as published by the Free Software Foundation. -- -- This program is distributed in the hope it will be useful, but WITHOUT -- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -- more details. -- -- You should have received a copy of the GNU General Public License along with -- this program; if not, write to the Free Software Foundation, Inc., -- 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. -- -- The full GNU General Public License is included in this distribution in -- the file called "COPYING". -- --*******************************************************************************/ -- --#ifndef LLDP_ECP22_H --#define LLDP_ECP22_H -- --#include -- --#include "lldp_mod.h" --#include "lldp_qbg22.h" -- --enum { /* ECP Receive states */ -- ECP22_RX_BEGIN, -- ECP22_RX_WAIT, -- ECP22_RX_WAIT2, -- ECP22_RX_FIRST, -- ECP22_RX_REC_ECPDU, -- ECP22_RX_NEW_ECPDU, -- ECP22_RX_SEND_ACK --}; --enum { /* ECP Transmit states */ -- ECP22_TX_BEGIN, -- ECP22_TX_INIT, -- ECP22_TX_TXMIT_ECPDU, -- ECP22_TX_WAIT_FORREQ, -- ECP22_TX_WAIT_ONDATA, -- ECP22_TX_ERROR --}; -- --enum { -- ECP22_REQUEST = 0, -- ECP22_ACK --} ecp22_mode; -- --struct ecp22_hdr { /* ECP22 header */ -- u16 ver_op_sub; /* ECP22 version, operation, subtype */ -- u16 seqno; /* ECP22 sequence number */ --} __attribute__ ((__packed__)); -- --/* -- * Define maximum ECP protocol payload length. Leave room for END TLV. -- */ --#define ECP22_MAXPAYLOAD_LEN (ETH_DATA_LEN - sizeof(struct ecp22_hdr) - 2) -- --struct ecp22_buffer { /* ECP payload buffer */ -- unsigned char frame[ETH_FRAME_LEN]; /* Payload buffer */ -- unsigned short frame_len; /* # of bytes of valid data */ -- unsigned char state; /* Buffer state machine */ -- unsigned char ecpdu_received; /* True when packet received */ -- unsigned char ack_received; /* True when packet acknowledged */ -- unsigned char retries; /* # of retries */ -- unsigned short last_seqno; /* Seqno last acknowledged packet */ -- unsigned short seqno; /* Seqno this packet */ -- unsigned long errors; /* # of transmit errors */ --}; -- --struct ecp22_payload_node { /* ECP Payload node */ -- struct packed_tlv *ptlv; /* Pointer to packed TLV to send */ -- unsigned short subtype; /* ECP subtype*/ -- unsigned char mac[ETH_ALEN]; /* Destination MAC address */ -- LIST_ENTRY(ecp22_payload_node) node; --}; -- --/* -- * ECP22 payload data -- */ --typedef LIST_HEAD(ecp22_list, ecp22_payload_node) ecp22_list; -- --struct ecp22_usedlist { /* List of valid ecp_payload_nodes */ -- ecp22_list head; /* ECP payload data free list */ -- struct ecp22_payload_node *last; /* Ptr to last entry in list */ --}; -- --struct ecp22_freelist { /* List of free ecp_payload_nodes */ -- ecp22_list head; /* ECP payload data free list */ -- u16 freecnt; /* # of nodes on freelist */ --}; -- --enum { -- ecp22_maxpayload = 64 --}; -- --struct ecp22 { /* ECP protocol data per interface */ -- struct l2_packet_data *l2; -- char ifname[IFNAMSIZ]; /* Interface name */ -- LIST_ENTRY(ecp22) node; /* Successor */ -- struct ecp22_buffer rx; /* Receive buffer */ -- struct ecp22_buffer tx; /* Transmit buffer */ -- struct agentstats stats; -- struct ecp22_usedlist inuse; /* List of payload data */ -- struct ecp22_freelist isfree; /* List of free payload nodes */ -- unsigned char max_retries; /* Max # of retries (via EVB) */ -- unsigned char max_rte; /* Wait time for ack (via EVB) */ --}; -- --struct ecp22_user_data { /* ECP module data per interface */ -- LIST_HEAD(ecp_head, ecp22) head; --}; -- --/* -- * Function prototypes -- */ --struct lldp_module *ecp22_register(void); --void ecp22_unregister(struct lldp_module *); --void ecp22_stop(char *); --void ecp22_start(char *); -- --/* -- * Functions to set and read ecp header operations field. -- */ --static inline void ecp22_hdr_set_op(struct ecp22_hdr *p, unsigned int op) --{ -- p->ver_op_sub &= 0xf3ff; -- p->ver_op_sub |= (op & 0x3) << 10; --} -- --static inline unsigned int ecp22_hdr_read_op(struct ecp22_hdr *p) --{ -- return (p->ver_op_sub >> 10) & 3; --} -- --/* -- * Functions to set and read ecp header subtype field. -- */ --static inline void ecp22_hdr_set_subtype(struct ecp22_hdr *p, unsigned int sub) --{ -- p->ver_op_sub &= 0xfc00; -- p->ver_op_sub |= sub & 0x3ff; --} -- --static inline unsigned int ecp22_hdr_read_subtype(struct ecp22_hdr *p) --{ -- return p->ver_op_sub & 0x3ff; --} -- --/* -- * Functions to set and read ecp header version field. -- */ --static inline void ecp22_hdr_set_version(struct ecp22_hdr *p, unsigned int ver) --{ -- p->ver_op_sub &= 0xfff; -- p->ver_op_sub |= (ver & 0xf) << 12; --} -- --static inline unsigned int ecp22_hdr_read_version(struct ecp22_hdr *p) --{ -- return (p->ver_op_sub >> 12) & 0xf; --} -- --#endif -diff --git a/include/lldp_evb22.h b/include/lldp_evb22.h -index c5255dc..18b72c5 100644 ---- a/include/lldp_evb22.h -+++ b/include/lldp_evb22.h -@@ -27,7 +27,7 @@ - #define _LLDP_EVB22_H - - #include "lldp_mod.h" --#include "lldp_qbg22.h" -+#include "qbg22.h" - - #define LLDP_MOD_EVB22_SUBTYPE 0xd - #define LLDP_MOD_EVB22_OUI { 0x00, 0x80, 0xc2, LLDP_MOD_EVB22_SUBTYPE } -diff --git a/include/lldp_qbg22.h b/include/lldp_qbg22.h -deleted file mode 100644 -index 1007bd9..0000000 ---- a/include/lldp_qbg22.h -+++ /dev/null -@@ -1,87 +0,0 @@ --/******************************************************************************* -- -- Implementation of EVB TLVs for LLDP -- (c) Copyright IBM Corp. 2013 -- -- Author(s): Thomas Richter -- -- This program is free software; you can redistribute it and/or modify it -- under the terms and conditions of the GNU General Public License, -- version 2, as published by the Free Software Foundation. -- -- This program is distributed in the hope it will be useful, but WITHOUT -- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -- more details. -- -- You should have received a copy of the GNU General Public License along with -- this program; if not, write to the Free Software Foundation, Inc., -- 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. -- -- The full GNU General Public License is included in this distribution in -- the file called "COPYING". -- --*******************************************************************************/ -- --/* -- * Define IEEE 802.1Qbg module identification numbers and module interface -- * structures which are exchanged between all the qbg modules. -- * -- * Messages are sent from: -- * EVB --> ECP: Max number of retries (R) and retransmit timeout (RTE). -- * -- * EVB --> VDP: Max number of Reinit-keep-Alive (RKA) Resource wait delay (RWD) -- * and groupid support. -- * -- * VDP --> ECP: VSI Information as payload -- * ECP --> VDP: VSI Information as payload -- * -- * This is used in the module notify call back function. -- */ -- --#ifndef LLDP_QBG22_H --#define LLDP_QBG22_H -- --/* -- * Modules Identifications -- */ --#define LLDP_MOD_EVB22 0x80c2 --#define LLDP_MOD_ECP22 0x80c3 --#define LLDP_MOD_VDP22 0x80c4 -- -- --enum { /* Identify data type in union below */ -- EVB22_TO_ECP22 = 1, /* Data from EVB to ECP */ -- EVB22_TO_VDP22 = 2, /* Data from EVB to VDP */ -- ECP22_TO_ULP = 3, /* Data from ECP to VDP, etc */ -- VDP22_TO_ECP22 = 4, /* Data from VDP to ECP */ -- /* ECP22 subtypes */ -- ECP22_VDP = 1, /* VDP protocol */ -- ECP22_PECSP = 2 /* Port extender control and status protocol */ --}; -- --struct evb22_to_ecp22 { /* Notification from EVB to ECP */ -- unsigned char max_retry;/* Max number of retries */ -- unsigned char max_rte; /* Max number of acknowledgement wait */ --}; -- --struct evb22_to_vdp22 { /* Notification from EVB to VDP */ -- unsigned char max_rwd; /* Max number of resource wait delay */ -- unsigned char max_rka; /* Max number of reinit keep alive */ -- unsigned char gpid; /* Support group ids in VDP */ --}; -- --struct ecp22_to_ulp { /* Notification from ECP to VDP, etc */ -- unsigned short len; /* Size of bytestream */ -- void *data; /* Pointer to data */ --}; -- --struct qbg22_imm { /* Intermodule message data structure */ -- int data_type; /* Identifies union data */ -- union { /* Overlay possible data */ -- struct evb22_to_ecp22 a; -- struct evb22_to_vdp22 b; -- struct ecp22_to_ulp c; -- } u; --}; --#endif -diff --git a/include/lldp_qbg_utils.h b/include/lldp_qbg_utils.h -deleted file mode 100644 -index 9f465c4..0000000 ---- a/include/lldp_qbg_utils.h -+++ /dev/null -@@ -1,43 +0,0 @@ --/******************************************************************************* -- -- Implementation of EVB TLVs for LLDP -- (c) Copyright IBM Corp. 2010, 2013 -- -- Author(s): Thomas Richter -- -- This program is free software; you can redistribute it and/or modify it -- under the terms and conditions of the GNU General Public License, -- version 2, as published by the Free Software Foundation. -- -- This program is distributed in the hope it will be useful, but WITHOUT -- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -- more details. -- -- You should have received a copy of the GNU General Public License along with -- this program; if not, write to the Free Software Foundation, Inc., -- 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. -- -- The full GNU General Public License is included in this distribution in -- the file called "COPYING". -- --*******************************************************************************/ -- --/* -- * Header file for small utility functions called throught qbg modules. -- */ -- --#ifndef LLDP_QBG_UTILS_H --#define LLDP_QBG_UTILS_H -- --void hexdump_frame(const char *, char *, const unsigned char *, size_t); --int modules_notify(int, int, char *, void *); -- --/* -- * Required buffer space to display a UUID. -- * VDP_UUID_STRLEN = strlen("fa9b7fff-b0a0-4893-abcd-beef4ff18f8f") -- */ --#define VDP_UUID_STRLEN 36 -- --int vdp_uuid2str(const u8 *, char *, size_t); --#endif -diff --git a/include/lldp_rtnl.h b/include/lldp_rtnl.h -index 76425e6..2bb09b1 100644 ---- a/include/lldp_rtnl.h -+++ b/include/lldp_rtnl.h -@@ -39,11 +39,25 @@ - void mynla_nest_end(struct nlmsghdr *, struct nlattr *); - struct nlattr *mynla_nest_start(struct nlmsghdr *, int); - void mynla_put(struct nlmsghdr *, int, size_t, void *); -+void mynla_put_u8(struct nlmsghdr *, int, __u8); - void mynla_put_u16(struct nlmsghdr *, int, __u16); - void mynla_put_u32(struct nlmsghdr *, int, __u32); -+void mynla_put_s32(struct nlmsghdr *nlh, int type, __s32); -+__u8 mynla_get_u8(const struct nlattr *); -+__u16 mynla_get_u16(const struct nlattr *); -+__u32 mynla_get_u32(const struct nlattr *); -+__s32 mynla_get_s32(const struct nlattr *); -+void mynla_get(const struct nlattr *, size_t, void *); -+void *mynla_data(const struct nlattr *); -+int mynla_payload(const struct nlattr *); -+int mynla_type(const struct nlattr *); -+int mynla_ok(const struct nlattr *, int); -+int mynla_total_size(int); -+struct nlattr *mynla_next(const struct nlattr *, int *); -+int mynla_parse(struct nlattr **, size_t, struct nlattr *, int); - - int get_operstate(char *ifname); - int set_operstate(char *ifname, __u8 operstate); --int set_linkmode(const char *ifname, __u8 linkmode); -+int set_linkmode(int ifindex, const char *ifname, __u8 linkmode); - - #endif -diff --git a/include/lldp_util.h b/include/lldp_util.h -index ee9e6e6..5767d4e 100644 ---- a/include/lldp_util.h -+++ b/include/lldp_util.h -@@ -142,6 +142,7 @@ int is_autoneg_supported(const char *ifname); - int get_mtu(const char *); - int get_mfs(const char *); - int get_ifflags(const char *); -+int get_ifname(int ifindex, char *ifname); - int get_maucaps(const char *); - int get_mautype(const char *); - int get_ifpflags(const char *); -diff --git a/include/lldp_vdp.h b/include/lldp_vdp.h -deleted file mode 100644 -index 1e2908b..0000000 ---- a/include/lldp_vdp.h -+++ /dev/null -@@ -1,170 +0,0 @@ --/******************************************************************************* -- -- Implementation of EVB TLVs for LLDP -- (c) Copyright IBM Corp. 2010, 2012 -- -- Author(s): Jens Osterkamp -- Author(s): Thomas Richter -- -- This program is free software; you can redistribute it and/or modify it -- under the terms and conditions of the GNU General Public License, -- version 2, as published by the Free Software Foundation. -- -- This program is distributed in the hope it will be useful, but WITHOUT -- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -- more details. -- -- You should have received a copy of the GNU General Public License along with -- this program; if not, write to the Free Software Foundation, Inc., -- 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. -- -- The full GNU General Public License is included in this distribution in -- the file called "COPYING". -- --*******************************************************************************/ -- --#ifndef _LLDP_VDP_H --#define _LLDP_VDP_H -- --#include "lldp_mod.h" --#include "lldp_ecp.h" -- --#define LLDP_MOD_VDP (OUI_IEEE_8021Qbg + 1) -- --#define VDP_MODE_PREASSOCIATE 0x0 --#define VDP_MODE_PREASSOCIATE_WITH_RR 0x1 --#define VDP_MODE_ASSOCIATE 0x2 --#define VDP_MODE_DEASSOCIATE 0x3 -- --#define VDP_RESPONSE_SUCCESS 0x0 --#define VDP_RESPONSE_INVALID_FORMAT 0x1 --#define VDP_RESPONSE_INSUFF_RESOURCES 0x2 --#define VDP_RESPONSE_UNUSED_VTID 0x3 --#define VDP_RESPONSE_VTID_VIOLATION 0x4 --#define VDP_RESPONSE_VTID_VER_VIOLATION 0x5 --#define VDP_RESPONSE_OUT_OF_SYNC 0x6 --#define VDP_RESPONSE_UNKNOWN 0xfe --#define VDP_RESPONSE_NO_RESPONSE 0xff -- --extern const char * const vsi_states[]; -- --#define VDP_FILTER_INFO_FORMAT_VID 0x1 --#define VDP_FILTER_INFO_FORMAT_MACVID 0x2 --#define VDP_FILTER_INFO_FORMAT_GROUPVID 0x3 --#define VDP_FILTER_INFO_FORMAT_GROUPMACVID 0x4 -- --#define VDP_TIMER_GRANULARITY (100 * MSECS) /* 100 ms */ --#define VDP_KEEPALIVE_TIMER_DEFAULT (10 * SECS) /* 10s */ --#define VDP_ACK_TIMER_DEFAULT (2 * ECP_ACK_TIMER_DEFAULT * ECP_MAX_RETRIES) --#define VDP_KEEPALIVE_TIMER_STOPPED (-1) --#define VDP_ACK_TIMER_STOPPED (-1) --#define VDP_LOCALCHANGE_TIMEOUT (1 * MSECS) /* 1 ms */ -- --#define VDP_ROLE_STATION 0 --#define VDP_ROLE_BRIDGE 1 -- --enum { -- VSI_UNASSOCIATED = 0, -- VSI_ASSOC_PROCESSING, -- VSI_ASSOCIATED, -- VSI_PREASSOC_PROCESSING, -- VSI_PREASSOCIATED, -- VSI_DEASSOC_PROCESSING, -- VSI_EXIT, --}; -- --struct mac_vlan_p { -- u8 mac[6]; -- u16 vlan; --} __attribute__ ((__packed__)); -- --struct mac_vlan { /* MAC,VLAN entry anchored by profiles */ -- u8 mac[6]; -- u16 vlan; -- u8 qos; /* QOS field */ -- pid_t req_pid; /* PID of requester for this profile */ -- u32 req_seq; /* Seq # of requester for this profile */ -- LIST_ENTRY(mac_vlan) entry; --}; -- --struct tlv_info_vdp { /* VSI information in packet format */ -- u8 oui[3]; -- u8 sub; -- u8 mode; -- u8 response; -- u8 mgrid; -- u8 id[3]; -- u8 version; -- u8 instance[16]; -- u8 format; -- u16 entries; --} __attribute__ ((__packed__)); -- --struct vsi_profile { -- int mode; /* VSI profile association command */ -- int response; /* Response from switch */ -- u8 no_nlmsg; /* Don't send netlink msg on VSI_EXIT */ -- u8 mgrid; /* Profile mgr id */ -- int id; /* Profile id */ -- u8 version; /* Profile id version number */ -- u8 instance[16]; /* Profile UUID */ -- u8 format; /* Format of MAC,VLAN list */ -- u16 entries; /* Number of MAC,VLAN entries in macvid_head */ -- LIST_HEAD(macvid_head, mac_vlan) macvid_head; -- struct port *port; -- int ackTimer; /* VDP ACK timer interval */ -- int ackReceived; /* VDP ACK received for this profile */ -- int keepaliveTimer; /* VDP keepalive timer interval */ -- int state; /* State of VDP state machine for profile */ -- int seqnr; /* Seqnr of ECP packet this profile was sent */ -- bool localChange; /* True when state needs change */ -- bool remoteChange; /* True when switch caused profile change */ -- bool txmit; /* Profile transmitted */ -- LIST_ENTRY(vsi_profile) profile; --}; -- --struct vdp_data { -- char ifname[IFNAMSIZ]; -- u8 enabletx; -- u8 vdpbit_on; /* Enable VDP Protocol */ -- struct ecp ecp; -- struct unpacked_tlv *vdp; -- int role; -- int keepaliveTimer; -- int ackTimer; -- int nroftimers; -- LIST_HEAD(profile_head, vsi_profile) profile_head; -- LIST_ENTRY(vdp_data) entry; --}; -- --struct vdp_user_data { -- LIST_HEAD(vdp_head, vdp_data) head; --}; -- --struct lldp_module *vdp_register(void); --void vdp_unregister(struct lldp_module *); --struct vdp_data *vdp_data(char *); --struct packed_tlv *vdp_gettlv(struct vdp_data *, struct vsi_profile *); --void vdp_vsi_sm_station(struct vsi_profile *); --struct vsi_profile *vdp_add_profile(struct vdp_data *, struct vsi_profile *); --int vdp_remove_profile(struct vsi_profile *); --void vdp_somethingChangedLocal(struct vsi_profile *, bool); --void vdp_update(char *, u8); --void vdp_ifup(char *, struct lldp_agent *); --void vdp_ifdown(char *, struct lldp_agent *); -- --void vdp_ack_profiles(struct vdp_data *, int); --void vdp_advance_sm(struct vdp_data *); --int vdp_indicate(struct vdp_data *, struct unpacked_tlv *); --int vdp_vsis_pending(struct vdp_data *); --int vdp_vsis(char *); --const char *vdp_response2str(int); --void vdp_trace_profile(struct vsi_profile *); --struct vsi_profile *vdp_alloc_profile(void); --void vdp_delete_profile(struct vsi_profile *); --struct vsi_profile *vdp_find_profile(struct vdp_data *, struct vsi_profile *); -- --#define MAC_ADDR_STRLEN 18 -- --#endif /* _LLDP_VDP_H */ -diff --git a/include/lldp_vdp22.h b/include/lldp_vdp22.h -deleted file mode 100644 -index c29b7fe..0000000 ---- a/include/lldp_vdp22.h -+++ /dev/null -@@ -1,62 +0,0 @@ --/******************************************************************************* -- -- Implementation of EVB TLVs for LLDP -- (c) Copyright IBM Corp. 2013 -- -- Author(s): Thomas Richter -- -- This program is free software; you can redistribute it and/or modify it -- under the terms and conditions of the GNU General Public License, -- version 2, as published by the Free Software Foundation. -- -- This program is distributed in the hope it will be useful, but WITHOUT -- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -- more details. -- -- You should have received a copy of the GNU General Public License along with -- this program; if not, write to the Free Software Foundation, Inc., -- 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. -- -- The full GNU General Public License is included in this distribution in -- the file called "COPYING". -- --*******************************************************************************/ -- --/* -- * External interface definition for the ratified standard VDP protocol. -- */ --#ifndef LLDP_VDP22_H --#define LLDP_VDP22_H -- --#include --#include -- --#include "lldp_mod.h" -- --struct vsi22_profile { -- LIST_ENTRY(vsi22_profile) prof22_entry; --}; -- --struct vdp22 { /* Per interface VSI/VDP data */ -- char ifname[IFNAMSIZ]; /* Interface name */ -- unsigned char max_rwd; /* Max number of resource wait delay */ -- unsigned char max_rka; /* Max number of reinit keep alive */ -- unsigned char gpid; /* Supports group ids in VDP */ -- unsigned short input_len; /* Length of input data from ECP */ -- unsigned char input[ETH_DATA_LEN]; /* Input data from ECP */ -- LIST_HEAD(profile22_head, vsi22_profile) prof22_head; -- LIST_ENTRY(vdp22) entry; --}; -- --struct vdp22_user_data { /* Head for all VDP data */ -- LIST_HEAD(vdp22_head, vdp22) head; --}; -- --struct lldp_module *vdp22_register(void); --void vdp22_unregister(struct lldp_module *); --void vdp22_start(const char *); --void vdp22_stop(char *); --int vdp22_query(const char *); -- --#endif -diff --git a/include/lldp_vdp_clif.h b/include/lldp_vdp_clif.h -deleted file mode 100644 -index ab51426..0000000 ---- a/include/lldp_vdp_clif.h -+++ /dev/null -@@ -1,32 +0,0 @@ --/******************************************************************************* -- -- Implementation of VDP according to IEEE 802.1Qbg -- (c) Copyright IBM Corp. 2010, 2012 -- -- Author(s): Jens Osterkamp -- Author(s): Thomas Richter -- -- This program is free software; you can redistribute it and/or modify it -- under the terms and conditions of the GNU General Public License, -- version 2, as published by the Free Software Foundation. -- -- This program is distributed in the hope it will be useful, but WITHOUT -- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -- more details. -- -- You should have received a copy of the GNU General Public License along with -- this program; if not, write to the Free Software Foundation, Inc., -- 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. -- -- The full GNU General Public License is included in this distribution in -- the file called "COPYING". -- --*******************************************************************************/ -- --#ifndef _LLDP_VDP_CLIF_H --#define _LLDP_VDP_CLIF_H -- --struct lldp_module *vdp_cli_register(void); -- --#endif -diff --git a/include/lldp_vdp_cmds.h b/include/lldp_vdp_cmds.h -deleted file mode 100644 -index ec0d575..0000000 ---- a/include/lldp_vdp_cmds.h -+++ /dev/null -@@ -1,48 +0,0 @@ --/******************************************************************************* -- -- implementation of VDP according to IEEE 802.1Qbg -- (c) Copyright IBM Corp. 2010 -- -- Author(s): Jens Osterkamp -- -- This program is free software; you can redistribute it and/or modify it -- under the terms and conditions of the GNU General Public License, -- version 2, as published by the Free Software Foundation. -- -- This program is distributed in the hope it will be useful, but WITHOUT -- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -- more details. -- -- You should have received a copy of the GNU General Public License along with -- this program; if not, write to the Free Software Foundation, Inc., -- 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. -- -- The full GNU General Public License is included in this distribution in -- the file called "COPYING". -- --*******************************************************************************/ -- --#ifndef _LLDP_VDP_CMDS_H --#define _LLDP_VDP_CMDS_H -- --struct arg_handlers *vdp_get_arg_handlers(); --int vdp_clif_cmd(char *, int, char *, int); -- --enum { -- MODE = 0, -- MGRID, -- TYPEID, -- TYPEIDVERSION, -- INSTANCEID, -- FORMAT, --}; -- --#define VAL_STATION "station" --#define VAL_BRIDGE "bridge" --#define ARG_VDP_MODE "mode" --#define ARG_VDP_ROLE "role" --#define VDP_PREFIX "vdp" --#define VDP_BUF_SIZE 256 -- --#endif -diff --git a/include/lldp_vdpnl.h b/include/lldp_vdpnl.h -deleted file mode 100644 -index d6fdca6..0000000 ---- a/include/lldp_vdpnl.h -+++ /dev/null -@@ -1,64 +0,0 @@ --/******************************************************************************* -- -- Implementation of EVB TLVs for LLDP -- (c) Copyright IBM Corp. 2013 -- -- Author(s): Thomas Richter -- -- This program is free software; you can redistribute it and/or modify it -- under the terms and conditions of the GNU General Public License, -- version 2, as published by the Free Software Foundation. -- -- This program is distributed in the hope it will be useful, but WITHOUT -- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -- more details. -- -- You should have received a copy of the GNU General Public License along with -- this program; if not, write to the Free Software Foundation, Inc., -- 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. -- -- The full GNU General Public License is included in this distribution in -- the file called "COPYING". -- --*******************************************************************************/ -- --/* -- * Definition of the VSI data structure received via netlink interface -- */ --#ifndef LLDP_VDPNL_H --#define LLDP_VDPNL_H -- --#include --#include -- --#define MAX_PAYLOAD 4096 /* Maximum Payload Size */ -- --struct vdpnl_mac { /* MAC-VLAN pair */ -- unsigned short vlan; /* Vlan identifier */ -- unsigned char mac[ETH_ALEN]; /* Mac address */ -- unsigned char qos; /* Quality of service */ --}; -- --struct vdpnl_vsi { /* Data structure for VSI data via netlink */ -- char ifname[IFNAMSIZ]; /* Interface name */ -- int ifindex; /* Index number */ -- unsigned char request; /* VSI request mode */ -- unsigned short response; /* VSI response code */ -- unsigned char vsi_mgrid; -- unsigned char vsi_typeversion; -- unsigned char vsi_uuid[PORT_UUID_MAX]; -- unsigned long vsi_typeid; -- unsigned long req_seq; -- pid_t req_pid; -- int macsz; /* Entries in mac-vlan pair list */ -- struct vdpnl_mac *maclist; /* List of MAC-VLAN pairs */ --}; -- --int vdpnl_recv(unsigned char *, size_t); --int vdpnl_send(struct vdpnl_vsi *); --int vdp_request(struct vdpnl_vsi *); --int vdp22_request(struct vdpnl_vsi *); --int vdp_status(int, struct vdpnl_vsi *); --int event_trigger(struct nlmsghdr *, pid_t); --#endif -diff --git a/include/lldpad_status.h b/include/lldpad_status.h -index 163b5fb..df6e0f7 100644 ---- a/include/lldpad_status.h -+++ b/include/lldpad_status.h -@@ -44,6 +44,7 @@ typedef enum { - cmd_not_capable, - cmd_not_applicable, - cmd_no_access, -+ cmd_agent_not_supported, - } cmd_status; - - #endif /* LLDPAD_STATUS_H */ -diff --git a/include/messages.h b/include/messages.h -index 21e7f1e..d52bdac 100644 ---- a/include/messages.h -+++ b/include/messages.h -@@ -31,6 +31,7 @@ - - extern bool daemonize; - extern int loglvl; -+extern int omit_tstamp; - - void log_message(int loglvl, const char *pFormat, ...) - __attribute__((__format__(__printf__, 2, 3))); -diff --git a/include/qbg22.h b/include/qbg22.h -new file mode 100644 -index 0000000..8ae0154 ---- /dev/null -+++ b/include/qbg22.h -@@ -0,0 +1,89 @@ -+/******************************************************************************* -+ -+ Implementation of EVB TLVs for LLDP -+ (c) Copyright IBM Corp. 2013 -+ -+ Author(s): Thomas Richter -+ -+ This program is free software; you can redistribute it and/or modify it -+ under the terms and conditions of the GNU General Public License, -+ version 2, as published by the Free Software Foundation. -+ -+ This program is distributed in the hope it will be useful, but WITHOUT -+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ more details. -+ -+ You should have received a copy of the GNU General Public License along with -+ this program; if not, write to the Free Software Foundation, Inc., -+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. -+ -+ The full GNU General Public License is included in this distribution in -+ the file called "COPYING". -+ -+*******************************************************************************/ -+ -+/* -+ * Define IEEE 802.1Qbg module identification numbers and module interface -+ * structures which are exchanged between all the qbg modules. -+ * -+ * Messages are sent from: -+ * EVB --> ECP: Max number of retries (R) and retransmit timeout (RTE). -+ * -+ * EVB --> VDP: Max number of Reinit-keep-Alive (RKA) Resource wait delay (RWD) -+ * and groupid support. -+ * -+ * VDP --> ECP: VSI Information as payload -+ * ECP --> VDP: VSI Information as payload -+ * -+ * This is used in the module notify call back function. -+ */ -+ -+#ifndef LLDP_QBG22_H -+#define LLDP_QBG22_H -+ -+/* -+ * Modules Identifications -+ */ -+#define LLDP_MOD_EVB22 0x80c2 -+#define LLDP_MOD_ECP22 0x80c3 -+#define LLDP_MOD_VDP22 0x80c4 -+ -+ -+enum { /* Identify data type in union below */ -+ EVB22_TO_ECP22 = 1, /* Data from EVB to ECP */ -+ EVB22_TO_VDP22 = 2, /* Data from EVB to VDP */ -+ ECP22_TO_ULP = 3, /* Data from ECP to VDP, etc */ -+ VDP22_TO_ECP22 = 4, /* Data from VDP to ECP */ -+ /* ECP22 subtypes */ -+ ECP22_VDP = 1, /* VDP protocol */ -+ ECP22_PECSP = 2 /* Port extender control and status protocol */ -+}; -+ -+struct evb22_to_ecp22 { /* Notification from EVB to ECP */ -+ unsigned char max_retry;/* Max number of retries */ -+ unsigned char max_rte; /* Max number of acknowledgement wait */ -+}; -+ -+struct evb22_to_vdp22 { /* Notification from EVB to VDP */ -+ unsigned char max_retry;/* Max number of retries */ -+ unsigned char max_rte; /* Max number of acknowledgement wait */ -+ unsigned char max_rwd; /* Max number of resource wait delay */ -+ unsigned char max_rka; /* Max number of reinit keep alive */ -+ unsigned char gpid; /* Support group ids in VDP */ -+}; -+ -+struct ecp22_to_ulp { /* Notification from ECP to VDP, etc */ -+ unsigned short len; /* Size of bytestream */ -+ void *data; /* Pointer to data */ -+}; -+ -+struct qbg22_imm { /* Intermodule message data structure */ -+ int data_type; /* Identifies union data */ -+ union { /* Overlay possible data */ -+ struct evb22_to_ecp22 a; -+ struct evb22_to_vdp22 b; -+ struct ecp22_to_ulp c; -+ } u; -+}; -+#endif -diff --git a/include/qbg_ecp.h b/include/qbg_ecp.h -new file mode 100644 -index 0000000..a67385b ---- /dev/null -+++ b/include/qbg_ecp.h -@@ -0,0 +1,106 @@ -+/******************************************************************************* -+ -+ Implementation of EVB TLVs for LLDP -+ (c) Copyright IBM Corp. 2010, 2012 -+ -+ Author(s): Jens Osterkamp -+ Author(s): Thomas Richter -+ -+ This program is free software; you can redistribute it and/or modify it -+ under the terms and conditions of the GNU General Public License, -+ version 2, as published by the Free Software Foundation. -+ -+ This program is distributed in the hope it will be useful, but WITHOUT -+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ more details. -+ -+ You should have received a copy of the GNU General Public License along with -+ this program; if not, write to the Free Software Foundation, Inc., -+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. -+ -+ The full GNU General Public License is included in this distribution in -+ the file called "COPYING". -+ -+*******************************************************************************/ -+ -+#ifndef QBG_ECP_H -+#define QBG_ECP_H -+ -+#include -+ -+#include "lldp_mod.h" -+#include "qbg_vdp.h" -+ -+#define ECP_SUBTYPE 0x0 -+ -+#define ECP_MAX_RETRIES 3 -+#define ECP_SEQUENCE_NR_START 0x0 -+ -+#define MSECS 1000 -+#define SECS (1000 * MSECS) -+ -+#define ECP_ACK_TIMER_DEFAULT (500 * MSECS) /* 500 ms */ -+#define ECP_LOCALCHANGE_TIMEOUT (1 * MSECS) /* 1 ms */ -+ -+#define ECP_ACK_TIMER_STOPPED (-1) -+ -+typedef enum { -+ ECP_REQUEST = 0, -+ ECP_ACK -+} ecp_mode; -+ -+struct ecp_buffer { /* ECP payload buffer */ -+ u8 frame[ETH_FRAME_LEN]; /* Payload buffer */ -+ u16 frame_len; /* # of bytes of valid data */ -+ u8 state; /* Buffer state */ -+ u8 localChange; /* Status changed */ -+ u8 rcvFrame; /* True if new frame received */ -+}; -+ -+struct ecp { -+ struct l2_packet_data *l2; -+ int sequence; -+ int retries; -+ int ackReceived; -+ int ackTimer; -+ u16 lastSequence; -+ u16 seqECPDU; -+ struct ecp_buffer rx; /* Receive buffer */ -+ struct ecp_buffer tx; /* Transmit buffer */ -+ struct agentstats stats; -+ char ifname[IFNAMSIZ]; /* Interface name */ -+}; -+ -+struct ecp_hdr { -+ u8 oui[3]; -+ u8 pad1; -+ u16 subtype; -+ u8 mode; -+ u16 seqnr; -+} __attribute__ ((__packed__)); -+ -+enum { -+ ECP_TX_INIT_TRANSMIT, -+ ECP_TX_TRANSMIT_ECPDU, -+ ECP_TX_WAIT_FOR_ACK, -+ ECP_TX_REQUEST_PDU -+}; -+ -+enum { -+ ECP_RX_IDLE, -+ ECP_RX_INIT_RECEIVE, -+ ECP_RX_RECEIVE_WAIT, -+ ECP_RX_RECEIVE_ECPDU, -+ ECP_RX_SEND_ACK, -+ ECP_RX_RESEND_ACK, -+}; -+ -+struct vdp_data; -+ -+void ecp_somethingChangedLocal(struct vdp_data *, bool); -+void ecp_rx_send_ack_frame(struct vdp_data *); -+ -+int ecp_init(char *); -+int ecp_deinit(char *); -+#endif /* _ECP_H */ -diff --git a/include/qbg_ecp22.h b/include/qbg_ecp22.h -new file mode 100644 -index 0000000..567f6df ---- /dev/null -+++ b/include/qbg_ecp22.h -@@ -0,0 +1,172 @@ -+/******************************************************************************* -+ -+ Implementation of EVB TLVs for LLDP -+ (c) Copyright IBM Corp. 2013 -+ -+ Author(s): Thomas Richter -+ -+ This program is free software; you can redistribute it and/or modify it -+ under the terms and conditions of the GNU General Public License, -+ version 2, as published by the Free Software Foundation. -+ -+ This program is distributed in the hope it will be useful, but WITHOUT -+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ more details. -+ -+ You should have received a copy of the GNU General Public License along with -+ this program; if not, write to the Free Software Foundation, Inc., -+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. -+ -+ The full GNU General Public License is included in this distribution in -+ the file called "COPYING". -+ -+*******************************************************************************/ -+ -+#ifndef QBG_ECP22_H -+#define QBG_ECP22_H -+ -+#include -+ -+#include "lldp_mod.h" -+#include "qbg22.h" -+ -+enum { /* ECP Receive states */ -+ ECP22_RX_BEGIN, -+ ECP22_RX_WAIT, -+ ECP22_RX_WAIT2, -+ ECP22_RX_FIRST, -+ ECP22_RX_REC_ECPDU, -+ ECP22_RX_NEW_ECPDU, -+ ECP22_RX_SEND_ACK -+}; -+enum { /* ECP Transmit states */ -+ ECP22_TX_BEGIN, -+ ECP22_TX_INIT, -+ ECP22_TX_TXMIT_ECPDU, -+ ECP22_TX_WAIT_FORREQ, -+ ECP22_TX_WAIT_ONDATA, -+ ECP22_TX_ERROR -+}; -+ -+enum { -+ ECP22_REQUEST = 0, -+ ECP22_ACK -+} ecp22_mode; -+ -+struct ecp22_hdr { /* ECP22 header */ -+ u16 ver_op_sub; /* ECP22 version, operation, subtype */ -+ u16 seqno; /* ECP22 sequence number */ -+} __attribute__ ((__packed__)); -+ -+/* -+ * Define maximum ECP protocol payload length. Leave room for END TLV. -+ */ -+#define ECP22_MAXPAYLOAD_LEN (ETH_DATA_LEN - sizeof(struct ecp22_hdr) - 2) -+ -+struct ecp22_buffer { /* ECP payload buffer */ -+ unsigned char frame[ETH_FRAME_LEN]; /* Payload buffer */ -+ unsigned short frame_len; /* # of bytes of valid data */ -+ unsigned char state; /* Buffer state machine */ -+ unsigned char ecpdu_received; /* True when packet received */ -+ unsigned char ack_received; /* True when packet acknowledged */ -+ unsigned char retries; /* # of retries */ -+ unsigned short last_seqno; /* Seqno last acknowledged packet */ -+ unsigned short seqno; /* Seqno this packet */ -+ unsigned long errors; /* # of transmit errors */ -+}; -+ -+struct ecp22_payload_node { /* ECP Payload node */ -+ struct packed_tlv *ptlv; /* Pointer to packed TLV to send */ -+ unsigned short subtype; /* ECP subtype*/ -+ unsigned char mac[ETH_ALEN]; /* Destination MAC address */ -+ LIST_ENTRY(ecp22_payload_node) node; -+}; -+ -+/* -+ * ECP22 payload data -+ */ -+typedef LIST_HEAD(ecp22_list, ecp22_payload_node) ecp22_list; -+ -+struct ecp22_usedlist { /* List of valid ecp_payload_nodes */ -+ ecp22_list head; /* ECP payload data free list */ -+ struct ecp22_payload_node *last; /* Ptr to last entry in list */ -+}; -+ -+struct ecp22_freelist { /* List of free ecp_payload_nodes */ -+ ecp22_list head; /* ECP payload data free list */ -+ u16 freecnt; /* # of nodes on freelist */ -+}; -+ -+enum { -+ ecp22_maxpayload = 64 -+}; -+ -+struct ecp22 { /* ECP protocol data per interface */ -+ struct l2_packet_data *l2; -+ char ifname[IFNAMSIZ]; /* Interface name */ -+ LIST_ENTRY(ecp22) node; /* Successor */ -+ struct ecp22_buffer rx; /* Receive buffer */ -+ struct ecp22_buffer tx; /* Transmit buffer */ -+ struct agentstats stats; -+ struct ecp22_usedlist inuse; /* List of payload data */ -+ struct ecp22_freelist isfree; /* List of free payload nodes */ -+ unsigned char max_retries; /* Max # of retries (via EVB) */ -+ unsigned char max_rte; /* Wait time for ack (via EVB) */ -+}; -+ -+struct ecp22_user_data { /* ECP module data per interface */ -+ LIST_HEAD(ecp_head, ecp22) head; -+}; -+ -+/* -+ * Function prototypes -+ */ -+struct lldp_module *ecp22_register(void); -+void ecp22_unregister(struct lldp_module *); -+void ecp22_stop(char *); -+void ecp22_start(char *); -+ -+/* -+ * Functions to set and read ecp header operations field. -+ */ -+static inline void ecp22_hdr_set_op(struct ecp22_hdr *p, unsigned int op) -+{ -+ p->ver_op_sub &= 0xf3ff; -+ p->ver_op_sub |= (op & 0x3) << 10; -+} -+ -+static inline unsigned int ecp22_hdr_read_op(struct ecp22_hdr *p) -+{ -+ return (p->ver_op_sub >> 10) & 3; -+} -+ -+/* -+ * Functions to set and read ecp header subtype field. -+ */ -+static inline void ecp22_hdr_set_subtype(struct ecp22_hdr *p, unsigned int sub) -+{ -+ p->ver_op_sub &= 0xfc00; -+ p->ver_op_sub |= sub & 0x3ff; -+} -+ -+static inline unsigned int ecp22_hdr_read_subtype(struct ecp22_hdr *p) -+{ -+ return p->ver_op_sub & 0x3ff; -+} -+ -+/* -+ * Functions to set and read ecp header version field. -+ */ -+static inline void ecp22_hdr_set_version(struct ecp22_hdr *p, unsigned int ver) -+{ -+ p->ver_op_sub &= 0xfff; -+ p->ver_op_sub |= (ver & 0xf) << 12; -+} -+ -+static inline unsigned int ecp22_hdr_read_version(struct ecp22_hdr *p) -+{ -+ return (p->ver_op_sub >> 12) & 0xf; -+} -+ -+#endif -diff --git a/include/qbg_utils.h b/include/qbg_utils.h -new file mode 100644 -index 0000000..9de3984 ---- /dev/null -+++ b/include/qbg_utils.h -@@ -0,0 +1,45 @@ -+/******************************************************************************* -+ -+ Implementation of EVB TLVs for LLDP -+ (c) Copyright IBM Corp. 2010, 2013 -+ -+ Author(s): Thomas Richter -+ -+ This program is free software; you can redistribute it and/or modify it -+ under the terms and conditions of the GNU General Public License, -+ version 2, as published by the Free Software Foundation. -+ -+ This program is distributed in the hope it will be useful, but WITHOUT -+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ more details. -+ -+ You should have received a copy of the GNU General Public License along with -+ this program; if not, write to the Free Software Foundation, Inc., -+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. -+ -+ The full GNU General Public License is included in this distribution in -+ the file called "COPYING". -+ -+*******************************************************************************/ -+ -+/* -+ * Header file for small utility functions called throught qbg modules. -+ */ -+ -+#ifndef QBG_UTILS_H -+#define QBG_UTILS_H -+ -+void hexdump_frame(const char *, char *, const unsigned char *, size_t); -+int modules_notify(int, int, char *, void *); -+ -+/* -+ * Required buffer space to display a VSI ID (as UUID or other formats). -+ * VDP_UUID_STRLEN = strlen("fa9b7fff-b0a0-4893-abcd-beef4ff18f8f") -+ * or strlen("fa9b:7fff:b0a0:4893:abcd:beef:4ff1:8f8f") -+ */ -+#define VDP_UUID_STRLEN 40 -+ -+/* Convert VSI IDs to strings */ -+int vdp_uuid2str(const u8 *, char *, size_t); -+#endif -diff --git a/include/qbg_vdp.h b/include/qbg_vdp.h -new file mode 100644 -index 0000000..e7de693 ---- /dev/null -+++ b/include/qbg_vdp.h -@@ -0,0 +1,170 @@ -+/******************************************************************************* -+ -+ Implementation of EVB TLVs for LLDP -+ (c) Copyright IBM Corp. 2010, 2012 -+ -+ Author(s): Jens Osterkamp -+ Author(s): Thomas Richter -+ -+ This program is free software; you can redistribute it and/or modify it -+ under the terms and conditions of the GNU General Public License, -+ version 2, as published by the Free Software Foundation. -+ -+ This program is distributed in the hope it will be useful, but WITHOUT -+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ more details. -+ -+ You should have received a copy of the GNU General Public License along with -+ this program; if not, write to the Free Software Foundation, Inc., -+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. -+ -+ The full GNU General Public License is included in this distribution in -+ the file called "COPYING". -+ -+*******************************************************************************/ -+ -+#ifndef QBG_VDP_H -+#define QBG_VDP_H -+ -+#include "lldp_mod.h" -+#include "qbg_ecp.h" -+ -+#define LLDP_MOD_VDP (OUI_IEEE_8021Qbg + 1) -+ -+#define VDP_MODE_PREASSOCIATE 0x0 -+#define VDP_MODE_PREASSOCIATE_WITH_RR 0x1 -+#define VDP_MODE_ASSOCIATE 0x2 -+#define VDP_MODE_DEASSOCIATE 0x3 -+ -+#define VDP_RESPONSE_SUCCESS 0x0 -+#define VDP_RESPONSE_INVALID_FORMAT 0x1 -+#define VDP_RESPONSE_INSUFF_RESOURCES 0x2 -+#define VDP_RESPONSE_UNUSED_VTID 0x3 -+#define VDP_RESPONSE_VTID_VIOLATION 0x4 -+#define VDP_RESPONSE_VTID_VER_VIOLATION 0x5 -+#define VDP_RESPONSE_OUT_OF_SYNC 0x6 -+#define VDP_RESPONSE_UNKNOWN 0xfe -+#define VDP_RESPONSE_NO_RESPONSE 0xff -+ -+extern const char * const vsi_states[]; -+ -+#define VDP_FILTER_INFO_FORMAT_VID 0x1 -+#define VDP_FILTER_INFO_FORMAT_MACVID 0x2 -+#define VDP_FILTER_INFO_FORMAT_GROUPVID 0x3 -+#define VDP_FILTER_INFO_FORMAT_GROUPMACVID 0x4 -+ -+#define VDP_TIMER_GRANULARITY (100 * MSECS) /* 100 ms */ -+#define VDP_KEEPALIVE_TIMER_DEFAULT (10 * SECS) /* 10s */ -+#define VDP_ACK_TIMER_DEFAULT (2 * ECP_ACK_TIMER_DEFAULT * ECP_MAX_RETRIES) -+#define VDP_KEEPALIVE_TIMER_STOPPED (-1) -+#define VDP_ACK_TIMER_STOPPED (-1) -+#define VDP_LOCALCHANGE_TIMEOUT (1 * MSECS) /* 1 ms */ -+ -+#define VDP_ROLE_STATION 0 -+#define VDP_ROLE_BRIDGE 1 -+ -+enum { -+ VSI_UNASSOCIATED = 0, -+ VSI_ASSOC_PROCESSING, -+ VSI_ASSOCIATED, -+ VSI_PREASSOC_PROCESSING, -+ VSI_PREASSOCIATED, -+ VSI_DEASSOC_PROCESSING, -+ VSI_EXIT, -+}; -+ -+struct mac_vlan_p { -+ u8 mac[6]; -+ u16 vlan; -+} __attribute__ ((__packed__)); -+ -+struct mac_vlan { /* MAC,VLAN entry anchored by profiles */ -+ u8 mac[6]; -+ u16 vlan; -+ u8 qos; /* QOS field */ -+ pid_t req_pid; /* PID of requester for this profile */ -+ u32 req_seq; /* Seq # of requester for this profile */ -+ LIST_ENTRY(mac_vlan) entry; -+}; -+ -+struct tlv_info_vdp { /* VSI information in packet format */ -+ u8 oui[3]; -+ u8 sub; -+ u8 mode; -+ u8 response; -+ u8 mgrid; -+ u8 id[3]; -+ u8 version; -+ u8 instance[16]; -+ u8 format; -+ u16 entries; -+} __attribute__ ((__packed__)); -+ -+struct vsi_profile { -+ int mode; /* VSI profile association command */ -+ int response; /* Response from switch */ -+ u8 no_nlmsg; /* Don't send netlink msg on VSI_EXIT */ -+ u8 mgrid; /* Profile mgr id */ -+ int id; /* Profile id */ -+ u8 version; /* Profile id version number */ -+ u8 instance[16]; /* Profile UUID */ -+ u8 format; /* Format of MAC,VLAN list */ -+ u16 entries; /* Number of MAC,VLAN entries in macvid_head */ -+ LIST_HEAD(macvid_head, mac_vlan) macvid_head; -+ struct port *port; -+ int ackTimer; /* VDP ACK timer interval */ -+ int ackReceived; /* VDP ACK received for this profile */ -+ int keepaliveTimer; /* VDP keepalive timer interval */ -+ int state; /* State of VDP state machine for profile */ -+ int seqnr; /* Seqnr of ECP packet this profile was sent */ -+ bool localChange; /* True when state needs change */ -+ bool remoteChange; /* True when switch caused profile change */ -+ bool txmit; /* Profile transmitted */ -+ LIST_ENTRY(vsi_profile) profile; -+}; -+ -+struct vdp_data { -+ char ifname[IFNAMSIZ]; -+ u8 enabletx; -+ u8 vdpbit_on; /* Enable VDP Protocol */ -+ struct ecp ecp; -+ struct unpacked_tlv *vdp; -+ int role; -+ int keepaliveTimer; -+ int ackTimer; -+ int nroftimers; -+ LIST_HEAD(profile_head, vsi_profile) profile_head; -+ LIST_ENTRY(vdp_data) entry; -+}; -+ -+struct vdp_user_data { -+ LIST_HEAD(vdp_head, vdp_data) head; -+}; -+ -+struct lldp_module *vdp_register(void); -+void vdp_unregister(struct lldp_module *); -+struct vdp_data *vdp_data(char *); -+struct packed_tlv *vdp_gettlv(struct vdp_data *, struct vsi_profile *); -+void vdp_vsi_sm_station(struct vsi_profile *); -+struct vsi_profile *vdp_add_profile(struct vdp_data *, struct vsi_profile *); -+int vdp_remove_profile(struct vsi_profile *); -+void vdp_somethingChangedLocal(struct vsi_profile *, bool); -+void vdp_update(char *, u8); -+void vdp_ifup(char *, struct lldp_agent *); -+void vdp_ifdown(char *, struct lldp_agent *); -+ -+void vdp_ack_profiles(struct vdp_data *, int); -+void vdp_advance_sm(struct vdp_data *); -+int vdp_indicate(struct vdp_data *, struct unpacked_tlv *); -+int vdp_vsis_pending(struct vdp_data *); -+int vdp_vsis(char *); -+const char *vdp_response2str(int); -+void vdp_trace_profile(struct vsi_profile *); -+struct vsi_profile *vdp_alloc_profile(void); -+void vdp_delete_profile(struct vsi_profile *); -+struct vsi_profile *vdp_find_profile(struct vdp_data *, struct vsi_profile *); -+ -+#define MAC_ADDR_STRLEN 18 -+ -+#endif /* _LLDP_VDP_H */ -diff --git a/include/qbg_vdp22.h b/include/qbg_vdp22.h -new file mode 100644 -index 0000000..aa3d5c5 ---- /dev/null -+++ b/include/qbg_vdp22.h -@@ -0,0 +1,206 @@ -+/******************************************************************************* -+ -+ Implementation of VDP protocol for IEEE 802.1 Qbg Ratified Standard -+ (c) Copyright IBM Corp. 2013 -+ -+ Author(s): Thomas Richter -+ -+ This program is free software; you can redistribute it and/or modify it -+ under the terms and conditions of the GNU General Public License, -+ version 2, as published by the Free Software Foundation. -+ -+ This program is distributed in the hope it will be useful, but WITHOUT -+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ more details. -+ -+ You should have received a copy of the GNU General Public License along with -+ this program; if not, write to the Free Software Foundation, Inc., -+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. -+ -+ The full GNU General Public License is included in this distribution in -+ the file called "COPYING". -+ -+*******************************************************************************/ -+ -+#ifndef QBG_VDP22_H -+#define QBG_VDP22_H -+ -+/* -+ * Defintion of VDP22 data structures: -+ * For IEEE 802.1Qbg ratified standard the Virtual Station Information (VSI) -+ * in the VDP22 protocol is maintained as a queue with one entry per interface -+ * supporting VDP22. -+ * Each interface is the anchor for a list of active VSI manager identifiers. -+ * All VSIs with the same -+ * - manager-id -+ * - type-id and type version -+ * - VSI format type and VSI id -+ * - filter info format -+ * are grouped into one entry. This means if two VSIs differ only in the -+ * filter info format (for example), two seperate VSI list elements will be -+ * allocated and queued in the VSI queue of that interface name. -+ * -+ * Each VSI node maintains the VDP22 state machine for that association. -+ * -+ * Supported operations: -+ * - Find a VSI entry given the search criterias: -+ * manager-id, type-id, type-version, VSI-format, VSI-ID and filter-info -+ * (data and format). -+ * - Add new filter data to a matching VSI entry (and filter not already -+ * active). -+ * - Remove filter data from a matching VSI entry. -+ * - Add a new VSI node when no VSI match is found. -+ * - Remove a VSI node when no filter entry is active anymore. -+ */ -+ -+#include -+#include -+#include -+ -+#include -+ -+enum vdp22_role { /* State for VDP22 bridge processing */ -+ VDP22_BRIDGE = 1, /* Bridge role */ -+ VDP22_STATION /* State role */ -+}; -+ -+enum vdp22_cmdresp { /* VDP22 Protocol command responses */ -+ VDP22_RESP_SUCCESS = 0, /* Success */ -+ VDP22_RESP_INVALID_FORMAT = 1, -+ VDP22_RESP_NO_RESOURCES = 2, -+ VDP22_RESP_NO_VSIMGR = 3, /* No contact to VSI manager */ -+ VDP22_RESP_OTHER = 4, /* Other reasons */ -+ VDP22_RESP_NOADDR = 5, /* Invalid VID, MAC, GROUP etc */ -+ VDP22_RESP_DEASSOC = 252, /* Deassoc response */ -+ VDP22_RESP_TIMEOUT = 253, /* Timeout response */ -+ VDP22_RESP_KEEP = 254, /* Keep response */ -+ VDP22_RESP_NONE = 255 /* No response returned so far */ -+}; -+ -+enum { -+ VDP22_MGRIDSZ = 16, /* Size of manager identifier */ -+ VDP22_IDSZ = 16 /* Size of vsi identifier */ -+}; -+ -+struct vsi_origin { /* Originator of VSI request */ -+ pid_t req_pid; /* PID of requester for VSI */ -+ unsigned long req_seq; /* Seq # of requester for VSI */ -+}; -+ -+/* -+ * Generic filter data. Some field are unused, this depends -+ * on the filter info format value (see enum above). -+ */ -+struct fid22 { /* Filter data: GROUP,MAC,VLAN entry */ -+ unsigned long grpid; /* Group identifier */ -+ unsigned char mac[ETH_ALEN]; /* MAC address */ -+ unsigned short vlan; /* VLAN idenfier */ -+ struct vsi_origin requestor; -+}; -+ -+/* -+ * VSI information. One node per matching entry (same mgrid, type_id, type_ver, -+ * id_fmt, id and fif). Filter data can be added and removed. -+ */ -+enum vsi22_flags { /* Flags (or'ed in) */ -+ VDP22_BUSY = 1, /* This node is under work */ -+ VDP22_DELETE_ME = 2, /* Deallocate this node */ -+ VDP22_RETURN_VID = 4, /* Return wildcard vlan id */ -+ VDP22_NOTIFY = 8, /* Send netlink message to requestor */ -+ VDP22_NLCMD = 16 /* Netlink command pending */ -+}; -+ -+struct vdp22smi { /* Data structure for VDP22 state machine */ -+ int state; /* State of VDP state machine for VSI */ -+ bool kato; /* VSI KA ACK timeout hit for this VSI */ -+ bool ackreceived; /* VSI ACK received for this VSI */ -+ bool acktimeout; /* VSI ACK timeout hit for this VSI */ -+ bool localchg; /* True when state needs change */ -+ bool deassoc; /* True when deassoc received from switch */ -+ bool txmit; /* True when packed TLV transmitted */ -+ bool resp_ok; /* True when acked TLV received and match ok */ -+ int txmit_error; /* != 0 error code from transmit via ECP */ -+}; -+ -+struct vsi22 { -+ LIST_ENTRY(vsi22) node; /* Node element */ -+ unsigned char mgrid[VDP22_MGRIDSZ]; /* Manager identifier */ -+ unsigned char cc_vsi_mode; /* currently confirmed VSI mode */ -+ unsigned char vsi_mode; /* VSI mode: ASSOC, PREASSOC, etc */ -+ unsigned char resp_vsi_mode; /* Responsed VSI mode: ASSOC, etc */ -+ unsigned char status; /* Status, Request/Response */ -+ unsigned char hints; /* Indicate migration/suspend */ -+ unsigned long type_id; /* Type identifier */ -+ unsigned char type_ver; /* Type version */ -+ unsigned char vsi_fmt; /* Format of VSI identifier */ -+ unsigned char vsi[VDP22_IDSZ]; /* VSI identifier */ -+ unsigned char fif; /* Filter info format */ -+ unsigned short no_fdata; /* Entries in filter data */ -+ struct fid22 *fdata; /* Filter data variable length */ -+ struct vdp22 *vdp; /* Back pointer to VDP head */ -+ unsigned long flags; /* Flags, see above */ -+ struct vdp22smi smi; /* State machine information */ -+}; -+ -+struct vdp22 { /* Per interface VSI/VDP data */ -+ LIST_ENTRY(vdp22) node; /* Node element */ -+ char ifname[IFNAMSIZ + 1]; /* Interface name */ -+ unsigned char ecp_retries; /* # of ECP module retries */ -+ unsigned char ecp_rte; /* ECP module retry timeout exponent */ -+ unsigned char vdp_rwd; /* Resource wait delay exponent */ -+ unsigned char vdp_rka; /* Reinit keep alive exponent */ -+ unsigned char gpid; /* Supports group ids in VDP */ -+ unsigned char myrole; /* Station or bridge role */ -+ unsigned char br_down; /* True when bridge down */ -+ unsigned short input_len; /* Length of input data from ECP */ -+ unsigned char input[ETH_DATA_LEN]; /* Input data from ECP */ -+ LIST_HEAD(vsi22_head, vsi22) vsi22_que; /* Active VSIs */ -+}; -+ -+struct vdp22_user_data { /* Head for all VDP data */ -+ LIST_HEAD(vdp22_head, vdp22) head; -+}; -+ -+struct lldp_module *vdp22_register(void); -+void vdp22_unregister(struct lldp_module *); -+void vdp22_start(const char *, int); -+void vdp22_showvsi(struct vsi22 *p); -+void vdp22_stop(char *); -+int vdp22_from_ecp22(struct vdp22 *); -+int vdp22_query(const char *); -+int vdp22_addreq(struct vsi22 *, struct vdp22 *); -+int vdp22_nlback(struct vsi22 *); -+struct vsi22 *vdp22_copy_vsi(struct vsi22 *); -+void vdp22_listdel_vsi(struct vsi22 *); -+int vdp22br_resources(struct vsi22 *, int *); -+int vdp22_local2str(const u8 *, char *, size_t); -+ -+/* -+ * Functions to get and set vlan identifier and qos. -+ */ -+static inline unsigned short vdp22_get_ps(unsigned short x) -+{ -+ return (x >> 15) & 0x1; -+} -+ -+static inline unsigned short vdp22_get_qos(unsigned short x) -+{ -+ return (x >> 12) & 0xf; -+} -+ -+static inline unsigned short vdp22_set_qos(unsigned short x) -+{ -+ return (x & 0xf) << 12; -+} -+ -+static inline unsigned short vdp22_get_vlanid(unsigned short x) -+{ -+ return x & 0xfff; -+} -+ -+static inline unsigned short vdp22_set_vlanid(unsigned short x) -+{ -+ return (x & 0xfff); -+} -+#endif -diff --git a/include/qbg_vdp22def.h b/include/qbg_vdp22def.h -new file mode 100644 -index 0000000..52f4502 ---- /dev/null -+++ b/include/qbg_vdp22def.h -@@ -0,0 +1,75 @@ -+/******************************************************************************* -+ -+ Implementation of EVB TLVs for LLDP -+ (c) Copyright IBM Corp. 2013 -+ -+ Author(s): Thomas Richter -+ -+ This program is free software; you can redistribute it and/or modify it -+ under the terms and conditions of the GNU General Public License, -+ version 2, as published by the Free Software Foundation. -+ -+ This program is distributed in the hope it will be useful, but WITHOUT -+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ more details. -+ -+ You should have received a copy of the GNU General Public License along with -+ this program; if not, write to the Free Software Foundation, Inc., -+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. -+ -+ The full GNU General Public License is included in this distribution in -+ the file called "COPYING". -+ -+*******************************************************************************/ -+ -+/* -+ * External interface definition for the ratified standard VDP protocol. -+ */ -+#ifndef QBG_VDP22DEF_H -+#define QBG_VDP22DEF_H -+ -+/* -+ * Define VDP22 filter formats. -+ */ -+enum vdp22_ffmt { /* Format of filter information */ -+ VDP22_FFMT_VID = 1, /* Vlan Identifier */ -+ VDP22_FFMT_MACVID, /* MAC address and Vlan Identifier */ -+ VDP22_FFMT_GROUPVID, /* Group and Vlan Identifier */ -+ VDP22_FFMT_GROUPMACVID /* Group, MAC and Vlan Identifier */ -+}; -+ -+/* -+ * Define VDP22 VSI Profile modes. -+ */ -+enum vdp22_modes { -+ VDP22_ENDTLV = 0, -+ VDP22_PREASSOC = 1, -+ VDP22_PREASSOC_WITH_RR, -+ VDP22_ASSOC, -+ VDP22_DEASSOC, -+ VDP22_MGRID, -+ VDP22_OUI = 0x7f -+}; -+ -+/* -+ * Define VDP22 VSI identifier format -+ */ -+enum vdp22_vsiid_fmt { -+ VDP22_ID_IP4 = 1, /* VSI ID is IPv4 address */ -+ VDP22_ID_IP6, /* VSI ID is IPv6 address */ -+ VDP22_ID_MAC, /* VSI ID is IEEE 802 MAC address */ -+ VDP22_ID_LOCAL, /* VSI ID is locally defined */ -+ VDP22_ID_UUID /* VSI ID is RFC4122 UUID */ -+}; -+ -+ -+/* -+ * Define VDP22 Migiration hints -+ */ -+enum vdp22_migration_hints { -+ VDP22_MIGTO = 16, /* M-bit migrate to hint */ -+ VDP22_MIGFROM = 32 /* S-bit migrate from hint */ -+}; -+ -+#endif -diff --git a/include/qbg_vdp_clif.h b/include/qbg_vdp_clif.h -new file mode 100644 -index 0000000..e4f9f78 ---- /dev/null -+++ b/include/qbg_vdp_clif.h -@@ -0,0 +1,32 @@ -+/******************************************************************************* -+ -+ Implementation of VDP according to IEEE 802.1Qbg -+ (c) Copyright IBM Corp. 2010, 2012 -+ -+ Author(s): Jens Osterkamp -+ Author(s): Thomas Richter -+ -+ This program is free software; you can redistribute it and/or modify it -+ under the terms and conditions of the GNU General Public License, -+ version 2, as published by the Free Software Foundation. -+ -+ This program is distributed in the hope it will be useful, but WITHOUT -+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ more details. -+ -+ You should have received a copy of the GNU General Public License along with -+ this program; if not, write to the Free Software Foundation, Inc., -+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. -+ -+ The full GNU General Public License is included in this distribution in -+ the file called "COPYING". -+ -+*******************************************************************************/ -+ -+#ifndef QBG_VDP_CLIF_H -+#define QBG_VDP_CLIF_H -+ -+struct lldp_module *vdp_cli_register(void); -+ -+#endif -diff --git a/include/qbg_vdp_cmds.h b/include/qbg_vdp_cmds.h -new file mode 100644 -index 0000000..2bbcb1c ---- /dev/null -+++ b/include/qbg_vdp_cmds.h -@@ -0,0 +1,48 @@ -+/******************************************************************************* -+ -+ implementation of VDP according to IEEE 802.1Qbg -+ (c) Copyright IBM Corp. 2010 -+ -+ Author(s): Jens Osterkamp -+ -+ This program is free software; you can redistribute it and/or modify it -+ under the terms and conditions of the GNU General Public License, -+ version 2, as published by the Free Software Foundation. -+ -+ This program is distributed in the hope it will be useful, but WITHOUT -+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ more details. -+ -+ You should have received a copy of the GNU General Public License along with -+ this program; if not, write to the Free Software Foundation, Inc., -+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. -+ -+ The full GNU General Public License is included in this distribution in -+ the file called "COPYING". -+ -+*******************************************************************************/ -+ -+#ifndef QBG_VDP_CMDS_H -+#define QBG_VDP_CMDS_H -+ -+struct arg_handlers *vdp_get_arg_handlers(); -+int vdp_clif_cmd(char *, int, char *, int); -+ -+enum { -+ MODE = 0, -+ MGRID, -+ TYPEID, -+ TYPEIDVERSION, -+ INSTANCEID, -+ FORMAT, -+}; -+ -+#define VAL_STATION "station" -+#define VAL_BRIDGE "bridge" -+#define ARG_VDP_MODE "mode" -+#define ARG_VDP_ROLE "role" -+#define VDP_PREFIX "vdp" -+#define VDP_BUF_SIZE 256 -+ -+#endif -diff --git a/include/qbg_vdpnl.h b/include/qbg_vdpnl.h -new file mode 100644 -index 0000000..ece030d ---- /dev/null -+++ b/include/qbg_vdpnl.h -@@ -0,0 +1,78 @@ -+/******************************************************************************* -+ -+ Implementation of EVB TLVs for LLDP -+ (c) Copyright IBM Corp. 2013 -+ -+ Author(s): Thomas Richter -+ -+ This program is free software; you can redistribute it and/or modify it -+ under the terms and conditions of the GNU General Public License, -+ version 2, as published by the Free Software Foundation. -+ -+ This program is distributed in the hope it will be useful, but WITHOUT -+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ more details. -+ -+ You should have received a copy of the GNU General Public License along with -+ this program; if not, write to the Free Software Foundation, Inc., -+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. -+ -+ The full GNU General Public License is included in this distribution in -+ the file called "COPYING". -+ -+*******************************************************************************/ -+ -+/* -+ * Definition of the VSI data structure received via netlink interface -+ */ -+#ifndef QBG_VDPNL_H -+#define QBG_VDPNL_H -+ -+#include -+#include -+ -+#define MAX_PAYLOAD 4096 /* Maximum Payload Size */ -+ -+enum { -+ vdpnl_nlf1 = 1, /* Netlink message format 1 (draft 0.2) */ -+ vdpnl_nlf2 /* Netlink message format 2 (ratified) */ -+}; -+ -+struct vdpnl_mac { /* MAC-VLAN pair */ -+ unsigned short vlan; /* Vlan identifier */ -+ unsigned char mac[ETH_ALEN]; /* Mac address */ -+ unsigned char qos; /* Quality of service */ -+ unsigned char changed; /* Vlan changed by switch */ -+ unsigned long gpid; /* Group identifer */ -+}; -+ -+struct vdpnl_vsi { /* Data structure for VSI data via netlink */ -+ char ifname[IFNAMSIZ + 1]; /* Interface name */ -+ int ifindex; /* Index number */ -+ int vf; /* Virtual function number */ -+ unsigned char hints; /* VSI request mode migrition hints */ -+ unsigned char request; /* VSI request mode */ -+ unsigned short response; /* VSI response code */ -+ unsigned char vsi_mgrid; -+ unsigned char vsi_typeversion; -+ unsigned char vsiid_fmt; -+ unsigned char vsi_uuid[PORT_UUID_MAX]; -+ unsigned char vsi_mgrid2[PORT_UUID_MAX]; -+ unsigned char nl_version; /* Netlink message format version */ -+ unsigned long vsi_typeid; -+ unsigned long req_seq; -+ pid_t req_pid; -+ unsigned char filter_fmt; /* Filter format type */ -+ int macsz; /* Entries in mac-vlan pair list */ -+ struct vdpnl_mac *maclist; /* List of MAC-VLAN pairs */ -+}; -+ -+int vdpnl_recv(unsigned char *, size_t); -+int vdpnl_send(struct vdpnl_vsi *); -+int vdp_request(struct vdpnl_vsi *); -+int vdp22_request(struct vdpnl_vsi *); -+int vdp_status(int, struct vdpnl_vsi *); -+int vdp22_status(int, struct vdpnl_vsi *); -+int event_trigger(struct nlmsghdr *, pid_t); -+#endif -diff --git a/lldp/agent.c b/lldp/agent.c -index 2e85aa5..4bc5394 100644 ---- a/lldp/agent.c -+++ b/lldp/agent.c -@@ -51,12 +51,10 @@ static const char *agent_sections[AGENT_MAX] = { - struct lldp_agent * - lldp_agent_find_by_type(const char *ifname, enum agent_type type) - { -- struct port *port; -+ struct port *port = port_find_by_ifindex(get_ifidx(ifname)); - struct lldp_agent *agent; - -- port = port_find_by_name(ifname); -- -- if (port == NULL) -+ if (!port) - return NULL; - - LIST_FOREACH(agent, &port->agent_head, entry) { -@@ -109,12 +107,10 @@ void lldp_init_agent(struct port *port, struct lldp_agent *agent, int type) - int lldp_add_agent(const char *ifname, enum agent_type type) - { - int count; -- struct port *port; -+ struct port *port = port_find_by_ifindex(get_ifidx(ifname)); - struct lldp_agent *agent, *newagent; - -- port = port_find_by_name(ifname); -- -- if (port == NULL) -+ if (!port) - return -1; - - /* check if lldp_agents for this if already exist */ -@@ -123,17 +119,15 @@ int lldp_add_agent(const char *ifname, enum agent_type type) - count++; - if (agent->type != type) - continue; -- else -- return -1; -+ return -1; - } - - /* if not, create one and initialize it */ -- LLDPAD_DBG("%s(%i): creating new agent for port %s.\n", __func__, -- __LINE__, ifname); -- newagent = (struct lldp_agent *)malloc(sizeof(struct lldp_agent)); -- if (newagent == NULL) { -- LLDPAD_DBG("%s(%i): creation of new agent failed !.\n", -- __func__, __LINE__); -+ LLDPAD_DBG("%s: creating new agent for port %s.\n", __func__, -+ ifname); -+ newagent = malloc(sizeof(*newagent)); -+ if (!newagent) { -+ LLDPAD_DBG("%s: creation of new agent failed !.\n", __func__); - return -1; - } - -diff --git a/lldp/l2_packet_linux.c b/lldp/l2_packet_linux.c -index a5fe8bf..08f1e55 100644 ---- a/lldp/l2_packet_linux.c -+++ b/lldp/l2_packet_linux.c -@@ -33,6 +33,7 @@ - #include - #include - #include -+#include - #include "eloop.h" - #include "ports.h" - #include "messages.h" -@@ -144,8 +145,9 @@ static void l2_packet_receive(int sock, void *eloop_ctx, UNUSED void *sock_ctx) - &fromlen); - - if (res < 0) { -- LLDPAD_INFO("receive ERROR = %d\n", res); -- perror("l2_packet_receive - recvfrom"); -+ LLDPAD_INFO("receive if %s ERROR = %d\n", l2->ifname, errno); -+ if (errno != ENETDOWN) -+ perror("l2_packet_receive - recvfrom"); - return; - } - -diff --git a/lldp/ports.c b/lldp/ports.c -index 0652ce8..3bd6a2a 100644 ---- a/lldp/ports.c -+++ b/lldp/ports.c -@@ -124,56 +124,43 @@ int get_lldp_agent_admin(const char *ifname, int type) - - void set_lldp_agent_admin(const char *ifname, int type, int admin) - { -- struct port *port = NULL; -+ struct port *port; - struct lldp_agent *agent; -- int all = 0; -- int tmp; -- -- all = !strlen(ifname); -- -- port = porthead; -- while (port != NULL) { -- if (all || !strncmp(ifname, port->ifname, IFNAMSIZ)) { -- /* don't change a port which has an explicit setting -- * on a global setting change -- */ -- if (all && (!get_config_setting(port->ifname, -- type, -- ARG_ADMINSTATUS, -- (void *)&tmp, -- CONFIG_TYPE_INT))) { -- port = port->next; -- continue; -- } -- -- agent = lldp_agent_find_by_type(port->ifname, type); -- if (!agent) { -- port = port->next; -- continue; -- } -- -- if (agent->adminStatus != admin) { -- agent->adminStatus = admin; -- somethingChangedLocal(ifname, type); -- run_tx_sm(port, agent); -- run_rx_sm(port, agent); -- } -- -- if (!all) -- break; -- } -- port = port->next; -+ int ifindex = get_ifidx(ifname); -+ -+ if (!ifindex) -+ return; -+ -+ for (port = porthead; port; port = port->next) { -+ if (ifindex == port->ifindex) -+ break; -+ } -+ -+ if (!port) -+ return; -+ -+ agent = lldp_agent_find_by_type(port->ifname, type); -+ if (!agent) -+ return; -+ -+ /* Set ifname with ifindex reported ifname */ -+ if (strncmp(port->ifname, ifname, IFNAMSIZ) != 0) -+ memcpy(port->ifname, ifname, IFNAMSIZ); -+ -+ if (agent->adminStatus != admin) { -+ agent->adminStatus = admin; -+ somethingChangedLocal(port->ifname, type); -+ run_tx_sm(port, agent); -+ run_rx_sm(port, agent); - } - } - - void set_lldp_port_enable(const char *ifname, int enable) - { -- struct port *port = NULL; -+ struct port *port = port_find_by_ifindex(get_ifidx(ifname)); - struct lldp_agent *agent = NULL; - -- port = port_find_by_name(ifname); -- -- if (port == NULL) -+ if (!port) - return; - - port->portEnabled = (u8)enable; -@@ -192,9 +179,9 @@ void set_lldp_port_enable(const char *ifname, int enable) - - void set_port_oper_delay(const char *ifname) - { -- struct port *port = port_find_by_name(ifname); -+ struct port *port = port_find_by_ifindex(get_ifidx(ifname)); - -- if (port == NULL) -+ if (!port) - return; - - port->dormantDelay = DORMANT_DELAY; -@@ -204,11 +191,9 @@ void set_port_oper_delay(const char *ifname) - - int set_port_hw_resetting(const char *ifname, int resetting) - { -- struct port *port = NULL; -- -- port = port_find_by_name(ifname); -+ struct port *port = port_find_by_ifindex(get_ifidx(ifname)); - -- if (port == NULL) -+ if (!port) - return -1; - - port->hw_resetting = (u8)resetting; -@@ -218,22 +203,18 @@ int set_port_hw_resetting(const char *ifname, int resetting) - - int get_port_hw_resetting(const char *ifname) - { -- struct port *port = NULL; -- -- port = port_find_by_name(ifname); -+ struct port *port = port_find_by_ifindex(get_ifidx(ifname)); - - if (port) - return port->hw_resetting; -- else -- return 0; -+ -+ return 0; - } - - int reinit_port(const char *ifname) - { -+ struct port *port = port_find_by_ifindex(get_ifidx(ifname)); - struct lldp_agent *agent; -- struct port *port; -- -- port = port_find_by_name(ifname); - - if (!port) - return -1; -@@ -268,29 +249,23 @@ int reinit_port(const char *ifname) - return 0; - } - --struct port *add_port(const char *ifname) -+struct port *add_port(int ifindex, const char *ifname) - { - struct port *newport; - -- newport = porthead; -- while (newport != NULL) { -- if (!strncmp(ifname, newport->ifname, IFNAMSIZ)) -- return 0; -- newport = newport->next; -- } -+ for (newport = porthead; newport; newport = newport->next) -+ if (ifindex == newport->ifindex) -+ return NULL; - -- newport = (struct port *)malloc(sizeof(struct port)); -- if (newport == NULL) { -+ newport = malloc(sizeof(*newport)); -+ if (!newport) { - LLDPAD_DBG("new port malloc failed\n"); - goto fail; - } -- memset(newport,0,sizeof(struct port)); -+ memset(newport, 0, sizeof(*newport)); -+ newport->ifindex = ifindex; - newport->next = NULL; -- newport->ifname = strdup(ifname); -- if (newport->ifname == NULL) { -- LLDPAD_DBG("new port name malloc failed\n"); -- goto fail; -- } -+ strncpy(newport->ifname, ifname, IFNAMSIZ); - - newport->bond_master = is_bond(ifname); - /* Initialize relevant port variables */ -@@ -318,16 +293,14 @@ struct port *add_port(const char *ifname) - return newport; - - fail: -- if(newport) { -- if(newport->ifname) -- free(newport->ifname); -+ if (newport) - free(newport); -- } - return NULL; - } - --int remove_port(char *ifname) -+int remove_port(const char *ifname) - { -+ int ifindex = get_ifidx(ifname); - struct port *port; /* Pointer to port to remove */ - struct port *parent = NULL; /* Pointer to previous on port stack */ - struct lldp_agent *agent; -@@ -348,7 +321,7 @@ int remove_port(char *ifname) - LLDPAD_DBG("In %s: Found port %s\n", __func__, port->ifname); - - /* Set linkmode to off */ -- set_linkmode(ifname, 0); -+ set_linkmode(ifindex, port->ifname, 0); - - /* Close down the socket */ - l2_packet_deinit(port->l2); -@@ -394,9 +367,6 @@ int remove_port(char *ifname) - else - return -1; - -- if (port->ifname) -- free(port->ifname); -- - free(port); - - return 0; -diff --git a/lldp/ports.h b/lldp/ports.h -index 2aa15c9..21280e0 100644 ---- a/lldp/ports.h -+++ b/lldp/ports.h -@@ -76,7 +76,8 @@ enum portEnableStatus { - - /* lldp port specific structure */ - struct port { -- char *ifname; -+ struct port *next; -+ int ifindex; - u8 hw_resetting; - u8 portEnabled; - u8 prevPortEnabled; -@@ -87,8 +88,7 @@ struct port { - - LIST_HEAD(agent_head, lldp_agent) agent_head; - struct l2_packet_data *l2; -- -- struct port *next; -+ char ifname[IFNAMSIZ]; - }; - - extern struct port *porthead; -@@ -96,8 +96,8 @@ extern struct port *porthead; - #ifdef __cplusplus - extern "C" { - #endif --struct port *add_port(const char *); --int remove_port(char *); -+struct port *add_port(int ifindex, const char *); -+int remove_port(const char *); - #ifdef __cplusplus - } - #endif -@@ -118,15 +118,13 @@ void set_port_oper_delay(const char *ifname); - int reinit_port(const char *ifname); - void set_agent_oper_delay(const char *ifname, int type); - --static inline struct port *port_find_by_name(const char *ifname) -+static inline struct port *port_find_by_ifindex(int ifindex) - { - struct port *port = porthead; - -- while (port) { -- if (!strncmp(ifname, port->ifname, IFNAMSIZ)) -+ for (port = porthead; port; port = port->next) -+ if (ifindex == port->ifindex) - return port; -- port = port->next; -- } - return NULL; - } - -diff --git a/lldp_8021qaz.c b/lldp_8021qaz.c -index b3da01b..cab1fd5 100644 ---- a/lldp_8021qaz.c -+++ b/lldp_8021qaz.c -@@ -419,7 +419,7 @@ inline void set_prio_map(u32 *prio_map, u8 prio, int tc) - * - * Returns 0 on success, error value otherwise. - */ --static int get_dcbx_hw(const char *ifname, __u8 *dcbx) -+int get_dcbx_hw(const char *ifname, __u8 *dcbx) - { - int err = 0; - struct nlattr *attr; -@@ -492,6 +492,7 @@ static int get_dcbx_hw(const char *ifname, __u8 *dcbx) - if (!attr) { - LLDPAD_DBG("%s: %s: nlmsg_find_attr failed, no GDCBX support\n", - __func__, ifname); -+ err = -EOPNOTSUPP; - goto out; - } - -@@ -540,8 +541,7 @@ void ieee8021qaz_ifup(char *ifname, struct lldp_agent *agent) - /* If hardware is not DCBX IEEE compliant or it is managed - * by an LLD agent most likely a firmware agent abort - */ -- if (!(dcbx & DCB_CAP_DCBX_VER_IEEE) || -- (dcbx & DCB_CAP_DCBX_LLD_MANAGED)) -+ if (dcbx & DCB_CAP_DCBX_LLD_MANAGED) - return; - - /* If 802.1Qaz is already configured no need to continue */ -@@ -557,12 +557,7 @@ void ieee8021qaz_ifup(char *ifname, struct lldp_agent *agent) - set_lldp_agent_admin(ifname, agent->type, enabledRxOnly); - - /* lookup port data */ -- port = porthead; -- while (port != NULL) { -- if (!strncmp(ifname, port->ifname, MAX_DEVICE_NAME_LEN)) -- break; -- port = port->next; -- } -+ port = port_find_by_ifindex(get_ifidx(ifname)); - - /* - * Check if link down and/or tlvs exist for current port. -@@ -633,8 +628,10 @@ initialized: - /* Query hardware and set maximum number of TCs with hardware values */ - len = get_ieee_hw(ifname, &ets, &pfc, &data, &cnt); - if (len > 0) { -- tlvs->ets->cfgl->max_tcs = ets->ets_cap; -- tlvs->pfc->local.pfc_cap = pfc->pfc_cap; -+ if (ets) -+ tlvs->ets->cfgl->max_tcs = ets->ets_cap; -+ if (pfc) -+ tlvs->pfc->local.pfc_cap = pfc->pfc_cap; - - free(ets); - free(pfc); -@@ -644,7 +641,7 @@ initialized: - /* if the dcbx field is filled in by the dcbx query then the - * kernel is supports IEEE mode, so make IEEE DCBX active by default. - */ -- if (!dcbx || (dcbx_get_legacy_version(ifname) & ~MASK_DCBX_FORCE)) { -+ if (dcbx_get_legacy_version(ifname) & ~MASK_DCBX_FORCE) { - tlvs->active = false; - } else { - tlvs->active = true; -@@ -2146,29 +2143,18 @@ void ieee8021qaz_unregister(struct lldp_module *mod) - */ - void ieee8021qaz_ifdown(char *device_name, struct lldp_agent *agent) - { -- struct port *port = NULL; - struct ieee8021qaz_tlvs *tlvs; - - if (agent->type != NEAREST_BRIDGE) - return; - -- port = porthead; -- while (port != NULL) { -- if (!strncmp(device_name, port->ifname, MAX_DEVICE_NAME_LEN)) -- break; -- port = port->next; -- } -- - tlvs = ieee8021qaz_data(device_name); -- - if (!tlvs) - return; - -- if (tlvs) { -- ieee8021qaz_free_rx(tlvs->rx); -- free(tlvs->rx); -- tlvs->rx = NULL; -- } -+ ieee8021qaz_free_rx(tlvs->rx); -+ free(tlvs->rx); -+ tlvs->rx = NULL; - } - - /* -diff --git a/lldp_8021qaz_cmds.c b/lldp_8021qaz_cmds.c -index 1414a78..fb6ba85 100644 ---- a/lldp_8021qaz_cmds.c -+++ b/lldp_8021qaz_cmds.c -@@ -132,7 +132,6 @@ static int - get_arg_dcbx_mode(struct cmd *cmd, char *args, UNUSED char *arg_value, - char *obuf, int obuf_len) - { -- struct ieee8021qaz_tlvs *tlvs; - char buf[250] = ""; - - if (cmd->cmd != cmd_gettlv) -@@ -147,10 +146,6 @@ get_arg_dcbx_mode(struct cmd *cmd, char *args, UNUSED char *arg_value, - return cmd_not_applicable; - } - -- tlvs = ieee8021qaz_data(cmd->ifname); -- if (!tlvs) -- return cmd_device_not_found; -- - switch (lldpad_shm_get_dcbx(cmd->ifname)) { - case dcbx_subtype0: - snprintf(buf, sizeof(buf), "auto"); -@@ -173,11 +168,32 @@ get_arg_dcbx_mode(struct cmd *cmd, char *args, UNUSED char *arg_value, - return cmd_success; - } - -+#define MAX_DCBX_HW_RETRIES 5 -+ -+static bool is_dcbx_hw(const char *ifname) -+{ -+ __u8 dcbx = 0; -+ int err, tries = 0; -+ -+query_retry: -+ err = get_dcbx_hw(ifname, &dcbx); -+ -+ if (err == -ENOMEM && tries < MAX_DCBX_HW_RETRIES) { -+ tries++; -+ goto query_retry; -+ } -+ -+ if (err < 0 || -+ !(dcbx & DCB_CAP_DCBX_VER_IEEE) || -+ dcbx & DCB_CAP_DCBX_LLD_MANAGED) -+ return false; -+ -+ return true; -+} -+ - static int set_arg_dcbx_mode(struct cmd *cmd, UNUSED char *args, - char *arg_value, char *obuf, int obuf_len) - { -- struct ieee8021qaz_tlvs *tlvs; -- - if (cmd->cmd != cmd_settlv) - return cmd_invalid; - -@@ -190,12 +206,12 @@ static int set_arg_dcbx_mode(struct cmd *cmd, UNUSED char *args, - return cmd_not_applicable; - } - -+ if (!is_dcbx_hw(cmd->ifname)) -+ return cmd_not_capable; -+ - if (strcmp(arg_value, "reset")) - return cmd_invalid; - -- tlvs = ieee8021qaz_data(cmd->ifname); -- if (!tlvs) -- return cmd_device_not_found; - - lldpad_shm_set_dcbx(cmd->ifname, dcbx_subtype0); - snprintf(obuf, obuf_len, "mode = %s\n", arg_value); -@@ -214,8 +230,8 @@ test_arg_dcbx_mode(UNUSED struct cmd *cmd, UNUSED char *args, - static int get_arg_willing(struct cmd *cmd, char *args, - UNUSED char *arg_value, char *obuf, int obuf_len) - { -- int willing = 0; -- struct ieee8021qaz_tlvs *tlvs; -+ char arg_path[256]; -+ int willing, err; - - if (cmd->cmd != cmd_gettlv) - return cmd_invalid; -@@ -230,26 +246,20 @@ static int get_arg_willing(struct cmd *cmd, char *args, - return cmd_not_applicable; - } - -- tlvs = ieee8021qaz_data(cmd->ifname); -- if (!tlvs) -- return cmd_device_not_found; -- switch (cmd->tlvid) { -- case (OUI_IEEE_8021 << 8) | LLDP_8021QAZ_ETSCFG: -- willing = tlvs->ets->cfgl->willing; -- break; -- case (OUI_IEEE_8021 << 8) | LLDP_8021QAZ_PFC: -- willing = tlvs->pfc->local.willing; -- break; -- } -+ snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", TLVID_PREFIX, -+ cmd->tlvid, args); -+ err = get_config_setting(cmd->ifname, cmd->type, arg_path, &willing, -+ CONFIG_TYPE_INT); - -- if (willing) -- snprintf(obuf, obuf_len, "%02x%s%04x%s", -- (unsigned int) strlen(args), args, -- (unsigned int) strlen(VAL_YES), VAL_YES); -+ if (err) -+ snprintf(obuf, obuf_len, "%02x%s%04d", -+ (unsigned int) strlen(args), args, 0); - else - snprintf(obuf, obuf_len, "%02x%s%04x%s", - (unsigned int) strlen(args), args, -- (unsigned int) strlen(VAL_NO), VAL_NO); -+ willing ? (unsigned int)strlen(VAL_YES) : -+ (unsigned int)strlen(VAL_NO), -+ willing ? VAL_YES : VAL_NO); - - return cmd_success; - } -@@ -264,8 +274,6 @@ static int _set_arg_willing(struct cmd *cmd, char *args, - if (cmd->cmd != cmd_settlv) - return cmd_invalid; - -- -- - /* To remain backward compatible and make it easier - * for everyone use to {0|1} notation we still support - * this but also support english variants as well -@@ -297,20 +305,23 @@ static int _set_arg_willing(struct cmd *cmd, char *args, - return cmd_not_applicable; - } - -- if (test) -+ -+ if (test) { -+ if (!is_dcbx_hw(cmd->ifname)) -+ return cmd_not_capable; - return cmd_success; -+ } - - tlvs = ieee8021qaz_data(cmd->ifname); -- if (!tlvs) -- return cmd_device_not_found; -- -- switch (cmd->tlvid) { -- case (OUI_IEEE_8021 << 8) | LLDP_8021QAZ_ETSCFG: -- tlvs->ets->cfgl->willing = !!willing; -- break; -- case (OUI_IEEE_8021 << 8) | LLDP_8021QAZ_PFC: -- tlvs->pfc->local.willing = !!willing; -- break; -+ if (tlvs) { -+ switch (cmd->tlvid) { -+ case (OUI_IEEE_8021 << 8) | LLDP_8021QAZ_ETSCFG: -+ tlvs->ets->cfgl->willing = !!willing; -+ break; -+ case (OUI_IEEE_8021 << 8) | LLDP_8021QAZ_PFC: -+ tlvs->pfc->local.willing = !!willing; -+ break; -+ } - } - - snprintf(obuf, obuf_len, "willing = %s\n", -@@ -340,7 +351,9 @@ static int test_arg_willing(struct cmd *cmd, char *args, - static int get_arg_numtc(struct cmd *cmd, char *args, - UNUSED char *arg_value, char *obuf, int obuf_len) - { -- struct ieee8021qaz_tlvs *tlvs; -+ char arg_path[256]; -+ int max_tcs = 0; -+ int err = 0; - - if (cmd->cmd != cmd_gettlv) - return cmd_invalid; -@@ -356,12 +369,18 @@ static int get_arg_numtc(struct cmd *cmd, char *args, - return cmd_not_applicable; - } - -- tlvs = ieee8021qaz_data(cmd->ifname); -- if (!tlvs) -- return cmd_device_not_found; - -- snprintf(obuf, obuf_len, "%02x%s%04x%i", -- (unsigned int) strlen(args), args, 1, tlvs->ets->cfgl->max_tcs); -+ snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", TLVID_PREFIX, -+ cmd->tlvid, args); -+ err = get_config_setting(cmd->ifname, cmd->type, -+ arg_path, &max_tcs, CONFIG_TYPE_INT); -+ -+ if (!err) -+ snprintf(obuf, obuf_len, "%02x%s%04x%i", -+ (unsigned int) strlen(args), args, 1, max_tcs); -+ else -+ snprintf(obuf, obuf_len, "%02x%s%04d", -+ (unsigned int) strlen(args), args, 0); - - return cmd_success; - } -@@ -377,10 +396,9 @@ static int get_arg_up2tc(struct cmd *cmd, char *args, - UNUSED char *arg_value, - char *obuf, UNUSED int obuf_len) - { -- struct ieee8021qaz_tlvs *tlvs; -- char buf[250] = ""; -- u32 *pmap = NULL; -- int i; -+ char arg_path[256] = ""; -+ const char *buf = ""; -+ int err; - - if (cmd->cmd != cmd_gettlv) - return cmd_invalid; -@@ -395,33 +413,18 @@ static int get_arg_up2tc(struct cmd *cmd, char *args, - return cmd_not_applicable; - } - -- tlvs = ieee8021qaz_data(cmd->ifname); -- if (!tlvs) -- return cmd_device_not_found; -- switch (cmd->tlvid) { -- case (OUI_IEEE_8021 << 8) | LLDP_8021QAZ_ETSCFG: -- pmap = &tlvs->ets->cfgl->prio_map; -- break; -- case (OUI_IEEE_8021 << 8) | LLDP_8021QAZ_ETSREC: -- pmap = &tlvs->ets->recl->prio_map; -- break; -- } -- -- for (i = 0; i < 8; i++) { -- char cat[5]; -- -- if (i) -- snprintf(cat, sizeof(cat), ",%i:%i", i, -- get_prio_map(*pmap, i)); -- else -- snprintf(cat, sizeof(cat), "%i:%i", i, -- get_prio_map(*pmap, i)); -- strncat(buf, cat, sizeof(buf) - strlen(buf) - 1); -- } -+ snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", TLVID_PREFIX, -+ cmd->tlvid, args); -+ err = get_config_setting(cmd->ifname, cmd->type, -+ arg_path, &buf, CONFIG_TYPE_STRING); - -- snprintf(obuf, obuf_len, "%02x%s%04x%s", -- (unsigned int) strlen(args), args, -- (unsigned int) strlen(buf), buf); -+ if (!err) -+ snprintf(obuf, obuf_len, "%02x%s%04x%s", -+ (unsigned int) strlen(args), args, -+ (unsigned int) strlen(buf), buf); -+ else -+ snprintf(obuf, obuf_len, "%02x%s%04d", -+ (unsigned int) strlen(args), args, 0); - - return cmd_success; - } -@@ -433,35 +436,33 @@ _set_arg_up2tc(struct cmd *cmd, char *args, const char *arg_value, - struct ieee8021qaz_tlvs *tlvs; - char arg_path[256]; - char *toked_maps, *parse; -- u32 *pmap; -- u32 save_pmap; -- u8 max; -- int i, err = cmd_success; -+ u32 *pmap = NULL; -+ u8 max = MAX_TCS; -+ int err = cmd_success; - - if (cmd->cmd != cmd_settlv) - return cmd_invalid; - -+ tlvs = ieee8021qaz_data(cmd->ifname); -+ - switch (cmd->tlvid) { - case (OUI_IEEE_8021 << 8) | LLDP_8021QAZ_ETSCFG: -- tlvs = ieee8021qaz_data(cmd->ifname); -- if (!tlvs) -- return cmd_device_not_found; -- pmap = &tlvs->ets->cfgl->prio_map; -- max = tlvs->ets->cfgl->max_tcs; -+ if (tlvs) { -+ pmap = &tlvs->ets->cfgl->prio_map; -+ max = tlvs->ets->cfgl->max_tcs; -+ } - break; - case (OUI_IEEE_8021 << 8) | LLDP_8021QAZ_ETSREC: -- tlvs = ieee8021qaz_data(cmd->ifname); -- if (!tlvs) -- return cmd_device_not_found; -- pmap = &tlvs->ets->recl->prio_map; -- max = MAX_TCS; -+ if (tlvs) { -+ pmap = &tlvs->ets->recl->prio_map; -+ max = MAX_TCS; -+ } - break; - case INVALID_TLVID: - return cmd_invalid; - default: - return cmd_not_applicable; - } -- save_pmap = *pmap; - - parse = strdup(arg_value); - if (!parse) -@@ -526,29 +527,25 @@ _set_arg_up2tc(struct cmd *cmd, char *args, const char *arg_value, - } - - mask = ~(0xffffffff & (0xF << (4 * (7-prio)))); -- *pmap &= mask; -- *pmap |= tc << (4 * (7-prio)); -+ if (pmap && !test) { -+ *pmap &= mask; -+ *pmap |= tc << (4 * (7-prio)); -+ } - toked_maps = strtok(NULL, ","); - } -- } else { -+ } else if (pmap && !test) { - *pmap = 0; - } - - if (test) { -- *pmap = save_pmap; -+ if (!is_dcbx_hw(cmd->ifname)) -+ return cmd_not_capable; - free(parse); - return cmd_success; - } - - /* Build output buffer */ -- strncat(obuf, "up2tc = ", obuf_len - strlen(obuf) - 1); -- for (i = 0; i < 8; i++) { -- char cat[5]; -- -- snprintf(cat, sizeof(cat), "%i:%i ", i, get_prio_map(*pmap, i)); -- strncat(obuf, cat, obuf_len - strlen(obuf) - 1); -- } -- strncat(obuf, "\n", obuf_len - strlen(obuf) - 1); -+ snprintf(obuf, obuf_len, "up2tc = %s\n", arg_value); - - /* Update configuration file with new attribute */ - snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", TLVID_PREFIX, -@@ -576,26 +573,17 @@ static int test_arg_up2tc(struct cmd *cmd, char *args, - static int get_arg_tcbw(struct cmd *cmd, char *args, - UNUSED char *arg_value, char *obuf, UNUSED int obuf_len) - { -- struct ieee8021qaz_tlvs *tlvs; -- char buf[250] = ""; -- int i; -- u8 *bmap; -+ char arg_path[250] = ""; -+ const char *buf = ""; -+ int err; - - if (cmd->cmd != cmd_gettlv) - return cmd_invalid; - - switch (cmd->tlvid) { - case (OUI_IEEE_8021 << 8) | LLDP_8021QAZ_ETSCFG: -- tlvs = ieee8021qaz_data(cmd->ifname); -- if (!tlvs) -- return cmd_device_not_found; -- bmap = tlvs->ets->cfgl->tc_bw; - break; - case (OUI_IEEE_8021 << 8) | LLDP_8021QAZ_ETSREC: -- tlvs = ieee8021qaz_data(cmd->ifname); -- if (!tlvs) -- return cmd_device_not_found; -- bmap = tlvs->ets->recl->tc_bw; - break; - case INVALID_TLVID: - return cmd_invalid; -@@ -603,17 +591,18 @@ static int get_arg_tcbw(struct cmd *cmd, char *args, - return cmd_not_applicable; - } - -- for (i = 0; i < 8; i++) { -- char cat[6]; -- if (i) -- snprintf(cat, sizeof(cat), ",%i", bmap[i]); -- else -- snprintf(cat, sizeof(cat), "%i", bmap[i]); -- strncat(buf, cat, sizeof(buf) - strlen(buf) - 1); -- } -+ snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", TLVID_PREFIX, -+ cmd->tlvid, args); -+ err = get_config_setting(cmd->ifname, cmd->type, arg_path, &buf, -+ CONFIG_TYPE_STRING); - -- snprintf(obuf, obuf_len, "%02x%s%04x%s", (unsigned int) strlen(args), -- args, (unsigned int) strlen(buf), buf); -+ if (!err) -+ snprintf(obuf, obuf_len, "%02x%s%04x%s", -+ (unsigned int) strlen(args), args, -+ (unsigned int) strlen(buf), buf); -+ else -+ snprintf(obuf, obuf_len, "%02x%s%04d", -+ (unsigned int) strlen(args), args, 0); - - return cmd_success; - } -@@ -626,7 +615,7 @@ _set_arg_tcbw(struct cmd *cmd, char *args, const char *arg_value, - char arg_path[256]; - char *toked_bw, *parse; - int i, err = cmd_success; -- u8 *tcbw, percent[8] = {0}, total = 0; -+ u8 *tcbw = NULL, percent[8] = {0}, total = 0; - - if (cmd->cmd != cmd_settlv) - return cmd_invalid; -@@ -634,15 +623,13 @@ _set_arg_tcbw(struct cmd *cmd, char *args, const char *arg_value, - switch (cmd->tlvid) { - case (OUI_IEEE_8021 << 8) | LLDP_8021QAZ_ETSCFG: - tlvs = ieee8021qaz_data(cmd->ifname); -- if (!tlvs) -- return cmd_device_not_found; -- tcbw = tlvs->ets->cfgl->tc_bw; -+ if (tlvs) -+ tcbw = tlvs->ets->cfgl->tc_bw; - break; - case (OUI_IEEE_8021 << 8) | LLDP_8021QAZ_ETSREC: - tlvs = ieee8021qaz_data(cmd->ifname); -- if (!tlvs) -- return cmd_device_not_found; -- tcbw = tlvs->ets->recl->tc_bw; -+ if (tlvs) -+ tcbw = tlvs->ets->recl->tc_bw; - break; - case INVALID_TLVID: - return cmd_invalid; -@@ -668,9 +655,11 @@ _set_arg_tcbw(struct cmd *cmd, char *args, const char *arg_value, - err = cmd_invalid; - goto invalid; - } else if (test) { -+ if (!is_dcbx_hw(cmd->ifname)) -+ return cmd_not_capable; - free(parse); - return cmd_success; -- } else { -+ } else if (tcbw) { - memcpy(tcbw, percent, sizeof(*tcbw) * MAX_TCS); - } - -@@ -708,26 +697,17 @@ static int test_arg_tcbw(struct cmd *cmd, char *args, - static int get_arg_tsa(struct cmd *cmd, char *args, UNUSED char *arg_value, - char *obuf, UNUSED int obuf_len) - { -- struct ieee8021qaz_tlvs *tlvs; -- char buf[250] = ""; -- int i; -- u8 *tsa; -+ const char *buf = ""; -+ char arg_path[250] = ""; -+ int err; - - if (cmd->cmd != cmd_gettlv) - return cmd_invalid; - - switch (cmd->tlvid) { - case (OUI_IEEE_8021 << 8) | LLDP_8021QAZ_ETSCFG: -- tlvs = ieee8021qaz_data(cmd->ifname); -- if (!tlvs) -- return cmd_device_not_found; -- tsa = tlvs->ets->cfgl->tsa_map; - break; - case (OUI_IEEE_8021 << 8) | LLDP_8021QAZ_ETSREC: -- tlvs = ieee8021qaz_data(cmd->ifname); -- if (!tlvs) -- return cmd_device_not_found; -- tsa = tlvs->ets->recl->tsa_map; - break; - case INVALID_TLVID: - return cmd_invalid; -@@ -735,40 +715,18 @@ static int get_arg_tsa(struct cmd *cmd, char *args, UNUSED char *arg_value, - return cmd_not_applicable; - } - -- for (i = 0; i < 8; i++) { -- char cnt[4]; -- int space_left; -- -- if (i) -- snprintf(cnt, sizeof(cnt), ",%i:", i); -- else -- snprintf(cnt, sizeof(cnt), "%i:", i); -- strncat(buf, cnt, sizeof(buf) - strlen(buf) - 1); -- -- space_left = sizeof(buf) - strlen(buf) - 1; -- switch (tsa[i]) { -- case IEEE8021Q_TSA_STRICT: -- strncat(buf, "strict", space_left); -- break; -- case IEEE8021Q_TSA_CBSHAPER: -- strncat(buf, "cb_shaper", space_left); -- break; -- case IEEE8021Q_TSA_ETS: -- strncat(buf, "ets", space_left); -- break; -- case IEEE8021Q_TSA_VENDOR: -- strncat(buf, "vendor", space_left); -- break; -- default: -- strncat(buf, "unknown", space_left); -- break; -- } -- } -- -- snprintf(obuf, obuf_len, "%02x%s%04x%s", -- (unsigned int) strlen(args), args, -- (unsigned int) strlen(buf), buf); -+ snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", -+ TLVID_PREFIX, cmd->tlvid, args); -+ err = get_config_setting(cmd->ifname, cmd->type, arg_path, &buf, -+ CONFIG_TYPE_STRING); - -+ if (!err) -+ snprintf(obuf, obuf_len, "%02x%s%04x%s", -+ (unsigned int) strlen(args), args, -+ (unsigned int) strlen(buf), buf); -+ else -+ snprintf(obuf, obuf_len, "%02x%s%04d", -+ (unsigned int) strlen(args), args, 0); - - return cmd_success; - } -@@ -781,7 +739,7 @@ _set_arg_tsa(struct cmd *cmd, char *args, const char *arg_value, - char arg_path[256]; - char *toked_maps, *parse; - int i, err = cmd_success; -- u8 *tsa; -+ u8 *tsa = NULL; - - if (cmd->cmd != cmd_settlv) - return cmd_invalid; -@@ -789,15 +747,13 @@ _set_arg_tsa(struct cmd *cmd, char *args, const char *arg_value, - switch (cmd->tlvid) { - case (OUI_IEEE_8021 << 8) | LLDP_8021QAZ_ETSCFG: - tlvs = ieee8021qaz_data(cmd->ifname); -- if (!tlvs) -- return cmd_device_not_found; -- tsa = tlvs->ets->cfgl->tsa_map; -+ if (tlvs) -+ tsa = tlvs->ets->cfgl->tsa_map; - break; - case (OUI_IEEE_8021 << 8) | LLDP_8021QAZ_ETSREC: - tlvs = ieee8021qaz_data(cmd->ifname); -- if (!tlvs) -- return cmd_device_not_found; -- tsa = tlvs->ets->recl->tsa_map; -+ if (tlvs) -+ tsa = tlvs->ets->recl->tsa_map; - break; - case INVALID_TLVID: - return cmd_invalid; -@@ -840,15 +796,17 @@ _set_arg_tsa(struct cmd *cmd, char *args, const char *arg_value, - goto invalid; - } - -- if (!test) -+ if (!test && tsa) - tsa[tc] = type; - toked_maps = strtok(NULL, ","); - } -- } else if (!test) { -+ } else if (!test && tsa) { - memset(tsa, 0, MAX_TCS); - } - - if (test) { -+ if (!is_dcbx_hw(cmd->ifname)) -+ return cmd_not_capable; - free(parse); - return cmd_success; - } -@@ -862,22 +820,24 @@ _set_arg_tsa(struct cmd *cmd, char *args, const char *arg_value, - strncat(obuf, cnt, obuf_len - strlen(obuf) - 1); - - space_left = obuf_len - strlen(obuf) - 1; -- switch (tsa[i]) { -- case IEEE8021Q_TSA_STRICT: -- strncat(obuf, "strict ", space_left); -- break; -- case IEEE8021Q_TSA_CBSHAPER: -- strncat(obuf, "cb_shaper ", space_left); -- break; -- case IEEE8021Q_TSA_ETS: -- strncat(obuf, "ets ", space_left); -- break; -- case IEEE8021Q_TSA_VENDOR: -- strncat(obuf, "vendor ", space_left); -- break; -- default: -- strncat(obuf, "unknown ", space_left); -- break; -+ if (tsa) { -+ switch (tsa[i]) { -+ case IEEE8021Q_TSA_STRICT: -+ strncat(obuf, "strict ", space_left); -+ break; -+ case IEEE8021Q_TSA_CBSHAPER: -+ strncat(obuf, "cb_shaper ", space_left); -+ break; -+ case IEEE8021Q_TSA_ETS: -+ strncat(obuf, "ets ", space_left); -+ break; -+ case IEEE8021Q_TSA_VENDOR: -+ strncat(obuf, "vendor ", space_left); -+ break; -+ default: -+ strncat(obuf, "unknown ", space_left); -+ break; -+ } - } - } - strncat(obuf, "\n", obuf_len - strlen(obuf) - 1); -@@ -907,11 +867,8 @@ static int test_arg_tsa(struct cmd *cmd, char *args, char *arg_value, - static int get_arg_enabled(struct cmd *cmd, char *args, UNUSED char *arg_value, - char *obuf, UNUSED int obuf_len) - { -- struct ieee8021qaz_tlvs *tlvs; -- char buf[20] = ""; -- int i; -- bool first; -- u8 pfc; -+ char arg_path[256]; -+ int err, pfc; - - if (cmd->cmd != cmd_gettlv) - return cmd_invalid; -@@ -925,33 +882,17 @@ static int get_arg_enabled(struct cmd *cmd, char *args, UNUSED char *arg_value, - return cmd_not_applicable; - } - -- tlvs = ieee8021qaz_data(cmd->ifname); -- if (!tlvs) -- return cmd_device_not_found; -- -- pfc = tlvs->pfc->local.pfc_enable; -- -- first = true; -- for (i = 0; i < 8; i++) { -- if (pfc & (1 << i)) { -- char val[3]; -- -- if (first) { -- snprintf(val, sizeof(val), "%i", i); -- first = false; -- } else { -- snprintf(val, sizeof(val), ",%i", i); -- } -- strncat(buf, val, sizeof(buf) - strlen(buf) - 1); -- } -- } -- -- if (first) -- strncpy(buf, "none", sizeof(buf)); -+ snprintf(arg_path, sizeof(arg_path), -+ "%s%08x.%s", TLVID_PREFIX, cmd->tlvid, args); -+ err = get_config_setting(cmd->ifname, cmd->type, arg_path, &pfc, -+ CONFIG_TYPE_INT); - -- snprintf(obuf, obuf_len, "%02x%s%04x%s", -- (unsigned int) strlen(args), args, -- (unsigned int) strlen(buf), buf); -+ if (!err) -+ snprintf(obuf, obuf_len, "%02x%s%04x%i", -+ (unsigned int) strlen(args), args, 2, pfc); -+ else -+ snprintf(obuf, obuf_len, "%02x%s%04d", -+ (unsigned int) strlen(args), args, 0); - - - return cmd_success; -@@ -979,10 +920,6 @@ static int _set_arg_enabled(struct cmd *cmd, char *args, - return cmd_not_applicable; - } - -- tlvs = ieee8021qaz_data(cmd->ifname); -- if (!tlvs) -- return cmd_device_not_found; -- - parse = strdup(arg_value); - if (!parse) - return cmd_failed; -@@ -1014,6 +951,8 @@ static int _set_arg_enabled(struct cmd *cmd, char *args, - } - - if (test) { -+ if (!is_dcbx_hw(cmd->ifname)) -+ return cmd_not_capable; - free(parse); - return cmd_success; - } -@@ -1040,7 +979,10 @@ static int _set_arg_enabled(struct cmd *cmd, char *args, - "%s%08x.%s", TLVID_PREFIX, cmd->tlvid, args); - set_config_setting(cmd->ifname, cmd->type, arg_path, &mask, - CONFIG_TYPE_INT); -- tlvs->pfc->local.pfc_enable = mask; -+ -+ tlvs = ieee8021qaz_data(cmd->ifname); -+ if (tlvs) -+ tlvs->pfc->local.pfc_enable = mask; - somethingChangedLocal(cmd->ifname, cmd->type); - invalid: - free(parse); -@@ -1062,7 +1004,9 @@ static int test_arg_enabled(struct cmd *cmd, char *args, - static int get_arg_delay(struct cmd *cmd, char *args, - UNUSED char *arg_value, char *obuf, int obuf_len) - { -- struct ieee8021qaz_tlvs *tlvs; -+ unsigned int delay; -+ char arg_path[256]; -+ int err; - - if (cmd->cmd != cmd_gettlv) - return cmd_invalid; -@@ -1076,13 +1020,17 @@ static int get_arg_delay(struct cmd *cmd, char *args, - return cmd_not_applicable; - } - -- tlvs = ieee8021qaz_data(cmd->ifname); -- if (!tlvs) -- return cmd_device_not_found; -+ snprintf(arg_path, sizeof(arg_path), -+ "%s%08x.%s", TLVID_PREFIX, cmd->tlvid, args); -+ err = get_config_setting(cmd->ifname, cmd->type, arg_path, &delay, -+ CONFIG_TYPE_INT); - -- snprintf(obuf, obuf_len, "%02x%s%04x%02x", -- (unsigned int) strlen(args), args, 2, -- tlvs->pfc->local.delay); -+ if (!err) -+ snprintf(obuf, obuf_len, "%02x%s%04x%02x", -+ (unsigned int) strlen(args), args, 2, delay); -+ else -+ snprintf(obuf, obuf_len, "%02x%s%04d", -+ (unsigned int) strlen(args), args, 0); - - return cmd_success; - } -@@ -1106,14 +1054,15 @@ static int _set_arg_delay(struct cmd *cmd, char *args, - return cmd_not_applicable; - } - -- tlvs = ieee8021qaz_data(cmd->ifname); -- if (!tlvs) -- return cmd_device_not_found; -- -- if (test) -+ if (test) { -+ if (!is_dcbx_hw(cmd->ifname)) -+ return cmd_not_capable; - return cmd_success; -+ } - -- tlvs->pfc->local.delay = delay; -+ tlvs = ieee8021qaz_data(cmd->ifname); -+ if (tlvs) -+ tlvs->pfc->local.delay = delay; - - snprintf(obuf, obuf_len, "delay = %i\n", delay); - -@@ -1140,13 +1089,38 @@ static int test_arg_delay(struct cmd *cmd, char *args, - return _set_arg_delay(cmd, args, arg_value, obuf, obuf_len, true); - } - -+static void arg_app_strncat_hw(char *new_app, int hw) -+{ -+ switch (hw) { -+ case IEEE_APP_SET: -+ strncat(new_app, "hw (pending set)\n", -+ sizeof(new_app) - strlen(new_app) - 2); -+ break; -+ case IEEE_APP_DEL: -+ strncat(new_app, "hw (pending delete)\n", -+ sizeof(new_app) - strlen(new_app) - 2); -+ break; -+ case IEEE_APP_DONE: -+ strncat(new_app, "hw (set)\n", -+ sizeof(new_app) - strlen(new_app) - 2); -+ break; -+ default: -+ strncat(new_app, " hw (unknown)\n", -+ sizeof(new_app) - strlen(new_app) - 2); -+ break; -+ } -+} -+ - static int get_arg_app(struct cmd *cmd, char *args, UNUSED char *arg_value, - char *obuf, int obuf_len) - { - struct ieee8021qaz_tlvs *tlvs; -- int i = 0; - struct app_obj *np; - char app_buf[2048] = "(prio,sel,proto)\n"; -+ char new_app[80] = ""; -+ const char *app; -+ u8 prio, sel; -+ int proto, hw = -1, i; - - if (cmd->cmd != cmd_gettlv) - return cmd_invalid; -@@ -1161,55 +1135,93 @@ static int get_arg_app(struct cmd *cmd, char *args, UNUSED char *arg_value, - } - - tlvs = ieee8021qaz_data(cmd->ifname); -- if (!tlvs) -- return cmd_device_not_found; -+ for (i = 0; i < MAX_APP_ENTRIES; i++) { -+ char arg_path[256]; -+ char *parse, *app_tuple; -+ int err; - -- LIST_FOREACH(np, &tlvs->app_head, entry) { -- char new_app[80]; -- char state[15]; -- struct dcb_app *dcb_app = &np->app; -+ snprintf(arg_path, sizeof(arg_path), "%s%08x.%s%i", -+ TLVID_PREFIX, TLVID_8021(LLDP_8021QAZ_APP), -+ ARG_APP, i); -+ errno = 0; -+ err = get_config_setting(cmd->ifname, cmd->type, arg_path, -+ &app, CONFIG_TYPE_STRING); -+ if (err) -+ continue; - -- switch (np->hw) { -- case IEEE_APP_SET: -- strcpy(state, "pending set"); -+ /* Parse cfg file input, bounds checking done on set app cmd */ -+ parse = strdup(app); -+ if (!parse) - break; -- case IEEE_APP_DEL: -- strcpy(state, "pending delete"); -+ app_tuple = strtok(parse, ","); -+ if (!app_tuple) - break; -- case IEEE_APP_DONE: -- strcpy(state, "set"); -+ prio = atoi(app_tuple); -+ app_tuple = strtok(NULL, ","); -+ if (!app_tuple) - break; -- default: -- strcpy(state, "unknown"); -+ sel = atoi(app_tuple); -+ -+ app_tuple = strtok(NULL, ","); -+ if (!app_tuple) - break; -- } - -- if (dcb_app->selector == 1) { -+ /* APP Data can be in hex or integer form */ -+ errno = 0; -+ proto = (int) strtol(app_tuple, NULL, 0); -+ if (sel == 1) { - snprintf(new_app, sizeof(new_app), -- "%i:(%i,%i,0x%04x) %s (%s)\n", i, -- dcb_app->priority, -- dcb_app->selector, -- dcb_app->protocol, -- np->peer ? "peer" : "local", -- state); -+ "%i:(%i,%i,0x%04x) local ", i, -+ prio, sel, proto); - } else { - snprintf(new_app, sizeof(new_app), -- "%i:(%i,%i,%i) %s hw (%s)\n", i, -- dcb_app->priority, -- dcb_app->selector, -- dcb_app->protocol, -- np->peer ? "peer" : "local", -- state); -+ "%i:(%i,%i,%i) local ", i, -+ prio, sel, proto); - } -+ -+ if (tlvs) { -+ LIST_FOREACH(np, &tlvs->app_head, entry) { -+ if (np->app.selector == sel && -+ np->app.protocol == proto && -+ np->app.priority == prio && -+ !np->peer) -+ hw = np->hw; -+ } -+ } -+ -+ arg_app_strncat_hw(new_app, hw); - strncat(app_buf, new_app, sizeof(app_buf) - strlen(app_buf) - 2); -- i++; -+ } -+ -+ if (tlvs) { -+ LIST_FOREACH(np, &tlvs->app_head, entry) { -+ if (!np->peer) -+ continue; -+ -+ if (np->app.selector == 1) { -+ snprintf(new_app, sizeof(new_app), -+ "%i:(%i,%i,0x%04x) peer ", i, -+ np->app.priority, -+ np->app.selector, -+ np->app.protocol); -+ } else { -+ snprintf(new_app, sizeof(new_app), -+ "%i:(%i,%i,%i) peer ", i, -+ np->app.priority, -+ np->app.selector, -+ np->app.protocol); -+ } -+ -+ arg_app_strncat_hw(new_app, np->hw); -+ strncat(app_buf, new_app, -+ sizeof(app_buf) - strlen(app_buf) - 2); -+ } - } - - snprintf(obuf, obuf_len, "%02x%s%04x%s", - (unsigned int) strlen(args), args, - (unsigned int) strlen(app_buf), app_buf); - -- - return cmd_success; - } - -@@ -1242,8 +1254,6 @@ static int _set_arg_app(struct cmd *cmd, char *args, char *arg_value, - } - - tlvs = ieee8021qaz_data(cmd->ifname); -- if (!tlvs) -- return cmd_device_not_found; - - parse = strdup(arg_value); - if (!parse) -@@ -1298,8 +1308,11 @@ static int _set_arg_app(struct cmd *cmd, char *args, char *arg_value, - - free(parse); - -- if (test) -+ if (test) { -+ if (!is_dcbx_hw(cmd->ifname)) -+ return cmd_not_capable; - return cmd_success; -+ } - - snprintf(new_argval, sizeof(new_argval), - "%1u,%1u,%5u", (u8) prio, (u8) sel, (u16)pid); -@@ -1341,6 +1354,9 @@ static int _set_arg_app(struct cmd *cmd, char *args, char *arg_value, - return cmd_failed; - - /* Build app noting we verified prio, sel, and pid inputs */ -+ if (!tlvs) -+ goto write_app_config; -+ - ieee8021qaz_mod_app(&tlvs->app_head, 0, (u8) prio, (u8) sel, (u16) pid, - (cmd->ops & op_delete) ? op_delete : 0); - ieee8021qaz_app_sethw(cmd->ifname, &tlvs->app_head); -@@ -1348,45 +1364,28 @@ static int _set_arg_app(struct cmd *cmd, char *args, char *arg_value, - i = 0; - LIST_FOREACH(np, &tlvs->app_head, entry) { - char new_app[80]; -- char state[15]; -- struct dcb_app *dcb_app = &np->app; -- -- switch (np->hw) { -- case IEEE_APP_SET: -- strcpy(state, "pending set"); -- break; -- case IEEE_APP_DEL: -- strcpy(state, "pending delete"); -- break; -- case IEEE_APP_DONE: -- strcpy(state, "set"); -- break; -- default: -- strcpy(state, "unknown"); -- break; -- } - -- if (dcb_app->selector == 1) { -+ if (np->app.selector == 1) { - snprintf(new_app, sizeof(new_app), -- "%i:(%i,%i,0x%04x) %s (%s)\n", i, -- dcb_app->priority, -- dcb_app->selector, -- dcb_app->protocol, -- np->peer ? "peer" : "local", -- state); -+ "%i:(%i,%i,0x%04x) %s ", i, -+ np->app.priority, -+ np->app.selector, -+ np->app.protocol, -+ np->peer ? "peer" : "local"); - } else { - snprintf(new_app, sizeof(new_app), -- "%i:(%i,%i,%i) %s (%s)\n", i, -- dcb_app->priority, -- dcb_app->selector, -- dcb_app->protocol, -- np->peer ? "peer" : "local", -- state); -+ "%i:(%i,%i,%i) %s ", i, -+ np->app.priority, -+ np->app.selector, -+ np->app.protocol, -+ np->peer ? "peer" : "local"); - } -+ arg_app_strncat_hw(new_app, np->hw); - strncat(obuf, new_app, obuf_len - strlen(obuf) - 2); - i++; - } - -+write_app_config: - somethingChangedLocal(cmd->ifname, cmd->type); - - if (cmd->ops & op_delete) -@@ -1434,7 +1433,7 @@ get_arg_tlvtxenable(struct cmd *cmd, char *arg, UNUSED char *argvalue, - snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", - TLVID_PREFIX, cmd->tlvid, arg); - -- if (!is_tlv_txdisabled(cmd->ifname, cmd->type, cmd->tlvid)) -+ if (is_tlv_txenabled(cmd->ifname, cmd->type, cmd->tlvid)) - value = true; - else - value = false; -@@ -1500,8 +1499,11 @@ static int _set_arg_tlvtxenable(struct cmd *cmd, char *arg, char *argvalue, - err = get_config_setting(cmd->ifname, cmd->type, arg_path, - &curr, CONFIG_TYPE_BOOL); - -- if (test) -+ if (test) { -+ if (!is_dcbx_hw(cmd->ifname)) -+ return cmd_not_capable; - return cmd_success; -+ } - - snprintf(obuf, obuf_len, "enabled = %s\n", value ? "yes" : "no"); - -diff --git a/lldp_8023.c b/lldp_8023.c -index e8e3f31..eea4bc7 100644 ---- a/lldp_8023.c -+++ b/lldp_8023.c -@@ -320,40 +320,32 @@ static void ieee8023_free_tlv(struct ieee8023_data *bd) - } - } - --static int ieee8023_bld_tlv(struct ieee8023_data *bd, -- struct lldp_agent *agent) -+static int ieee8023_bld_tlv(struct ieee8023_data *bd, struct lldp_agent *agent) - { -- int rc = 0; -- -- if (!port_find_by_name(bd->ifname)) { -- rc = EEXIST; -- goto out_err; -- } -+ if (!port_find_by_ifindex(get_ifidx(bd->ifname))) -+ return -EEXIST; - - if (ieee8023_bld_maccfg_tlv(bd, agent)) { - LLDPAD_DBG("%s:%s:ieee8023_bld_macfg_tlv() failed\n", -- __func__, bd->ifname); -- goto out_err; -+ __func__, bd->ifname); -+ return 0; - } - if (ieee8023_bld_powvmdi_tlv(bd, agent)) { - LLDPAD_DBG("%s:%s:ieee8023_bld_powvmdi_tlv() failed\n", -- __func__, bd->ifname); -- goto out_err; -+ __func__, bd->ifname); -+ return 0; - } - if (ieee8023_bld_linkagg_tlv(bd, agent)) { - LLDPAD_DBG("%s:%s:ieee8023_bld_linkagg_tlv() failed\n", -- __func__, bd->ifname); -- goto out_err; -+ __func__, bd->ifname); -+ return 0; - } - if (ieee8023_bld_maxfs_tlv(bd, agent)) { - LLDPAD_DBG("%s:%s:ieee8023_bld_maxfs_tlv() failed\n", -- __func__, bd->ifname); -- goto out_err; -+ __func__, bd->ifname); -+ return 0; - } -- rc = 0; -- --out_err: -- return rc; -+ return 0; - } - - static void ieee8023_free_data(struct ieee8023_user_data *ud) -diff --git a/lldp_basman.c b/lldp_basman.c -index 4916e19..824dd9a 100644 ---- a/lldp_basman.c -+++ b/lldp_basman.c -@@ -541,42 +541,35 @@ static void basman_free_tlv(struct basman_data *bd) - /* build unpacked tlvs */ - static int basman_bld_tlv(struct basman_data *bd, struct lldp_agent *agent) - { -- int rc = EPERM; -- -- if (!port_find_by_name(bd->ifname)) { -- rc = EEXIST; -- goto out_err; -- } -+ if (!port_find_by_ifindex(get_ifidx(bd->ifname))) -+ return -EEXIST; - - if (basman_bld_portdesc_tlv(bd, agent)) { - LLDPAD_DBG("%s:%s:basman_bld_portdesc_tlv() failed\n", -- __func__, bd->ifname); -- goto out_err; -+ __func__, bd->ifname); -+ return -EPERM; - } - if (basman_bld_sysname_tlv(bd, agent)) { - LLDPAD_DBG("%s:%s:basman_bld_sysname_tlv() failed\n", -- __func__, bd->ifname); -- goto out_err; -+ __func__, bd->ifname); -+ return -EPERM; - } - if (basman_bld_sysdesc_tlv(bd, agent)) { - LLDPAD_DBG("%s:%s:basman_bld_sysdesc_tlv() failed\n", -- __func__, bd->ifname); -- goto out_err; -+ __func__, bd->ifname); -+ return -EPERM; - } - if (basman_bld_syscaps_tlv(bd, agent)) { - LLDPAD_DBG("%s:%s:basman_bld_syscaps_tlv() failed\n", -- __func__, bd->ifname); -- goto out_err; -+ __func__, bd->ifname); -+ return -EPERM; - } - if (basman_bld_manaddr_tlv(bd, agent)) { - LLDPAD_DBG("%s:%s:basman_bld_manaddr_tlv() failed\n", -- __func__, bd->ifname); -- goto out_err; -+ __func__, bd->ifname); -+ return -EPERM; - } -- rc = 0; -- --out_err: -- return rc; -+ return 0; - } - - static void basman_free_data(struct basman_user_data *bud) -diff --git a/lldp_dcbx.c b/lldp_dcbx.c -index e9f41a8..53a5e01 100644 ---- a/lldp_dcbx.c -+++ b/lldp_dcbx.c -@@ -484,7 +484,8 @@ void dcbx_unregister(struct lldp_module *mod) - - void dcbx_ifup(char *ifname, struct lldp_agent *agent) - { -- struct port *port = NULL; -+ int ifindex; -+ struct port *port; - struct dcbx_tlvs *tlvs; - struct dcbd_user_data *dud; - struct dcbx_manifest *manifest; -@@ -501,14 +502,15 @@ void dcbx_ifup(char *ifname, struct lldp_agent *agent) - if (agent->type != NEAREST_BRIDGE) - return; - -- port = port_find_by_name(ifname); -+ ifindex = get_ifidx(ifname); -+ port = port_find_by_ifindex(ifindex); - - dud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_DCBX); - tlvs = dcbx_data(ifname); - - if (!port) - return; -- else if (tlvs) -+ if (tlvs) - goto initialized; - - /* Abort initialization on hardware that does not support -@@ -634,7 +636,6 @@ initialized: - - void dcbx_ifdown(char *device_name, struct lldp_agent *agent) - { -- struct port *port = NULL; - struct dcbx_tlvs *tlvs; - - if (agent->type != NEAREST_BRIDGE) -@@ -644,30 +645,19 @@ void dcbx_ifdown(char *device_name, struct lldp_agent *agent) - if (is_bond(device_name)) - return; - -- port = porthead; -- while (port != NULL) { -- if (!strncmp(device_name, port->ifname, MAX_DEVICE_NAME_LEN)) -- break; -- port = port->next; -- } -- - tlvs = dcbx_data(device_name); -- - if (!tlvs) - return; - - /* remove dcb port */ -- if (check_port_dcb_mode(device_name)) { -+ if (check_port_dcb_mode(device_name)) - dcbx_remove_adapter(device_name); -- } - -- if (tlvs) { -- LIST_REMOVE(tlvs, entry); -- dcbx_free_tlv(tlvs); -- dcbx_free_manifest(tlvs->manifest); -- free(tlvs->manifest); -- free(tlvs); -- } -+ LIST_REMOVE(tlvs, entry); -+ dcbx_free_tlv(tlvs); -+ dcbx_free_manifest(tlvs->manifest); -+ free(tlvs->manifest); -+ free(tlvs); - } - - void clear_dcbx_manifest(struct dcbx_tlvs *dcbx) -diff --git a/lldp_dcbx_cmds.c b/lldp_dcbx_cmds.c -index 1ce4d4c..0329910 100644 ---- a/lldp_dcbx_cmds.c -+++ b/lldp_dcbx_cmds.c -@@ -229,7 +229,7 @@ static int test_arg_tlvtxenable(struct cmd *cmd, char *arg, char *argvalue, - return _set_arg_tlvtxenable(cmd, arg, argvalue, obuf, obuf_len, true); - } - --struct arg_handlers *dcbx_get_arg_handlers() -+struct arg_handlers *dcbx_get_arg_handlers(void) - { - return &arg_handlers[0]; - } -@@ -533,7 +533,7 @@ static int handle_dcbx_cmd(u8 cmd, u8 feature, char *ibuf, int ilen, char *rbuf) - return status; - } - --int dcbx_clif_cmd(void *data, -+int dcbx_clif_cmd(UNUSED void *data, - UNUSED struct sockaddr_un *from, - UNUSED socklen_t fromlen, - char *ibuf, int ilen, -@@ -549,10 +549,8 @@ int dcbx_clif_cmd(void *data, - pfc_attribs pfc_data; - app_attribs app_data; - llink_attribs llink_data; -- struct port *port; - struct dcbx_tlvs *dcbx; -- -- data = (struct clif_data *) data; -+ int dcb_enable; - - if (hexstr2bin(ibuf+DCB_CMD_OFF, &cmd, sizeof(cmd)) || - hexstr2bin(ibuf+DCB_FEATURE_OFF, &feature, sizeof(feature))) -@@ -586,17 +584,13 @@ int dcbx_clif_cmd(void *data, - memcpy(port_id, ibuf+DCB_PORT_OFF, plen); - port_id[plen] = '\0'; - -- /* Confirm port is a lldpad managed port */ -- port = port_find_by_name(port_id); -- if (!port) -- return cmd_device_not_found; -- -- dcbx = dcbx_data(port->ifname); -- if (!dcbx) -- return cmd_device_not_found; -+ if (get_hw_state(port_id, &dcb_enable) < 0) -+ return cmd_not_capable; - -+ dcbx = dcbx_data(port_id); - /* OPER and PEER cmd not applicable while in IEEE-DCBX modes */ -- if (dcbx->active == 0 && (cmd == CMD_GET_PEER || cmd == CMD_GET_OPER)) -+ if ((!dcbx || dcbx->active == 0) && -+ (cmd == CMD_GET_PEER || cmd == CMD_GET_OPER)) - return cmd_not_applicable; - - switch(feature) { -diff --git a/lldp_dcbx_nl.c b/lldp_dcbx_nl.c -index 33cf257..0f267dd 100644 ---- a/lldp_dcbx_nl.c -+++ b/lldp_dcbx_nl.c -@@ -39,6 +39,7 @@ - #include "linux/rtnetlink.h" - #include "linux/dcbnl.h" - #include "lldp.h" -+#include "lldp_util.h" - #include "dcb_types.h" - #include "dcb_protocol.h" - #include "dcb_driver_interface.h" -@@ -641,9 +642,10 @@ int get_hw_state(char *ifname, int *dcb_state) - - int set_hw_state(char *ifname, int dcb_state) - { -- int err = 0; -+ int err; -+ int ifindex = get_ifidx(ifname); - -- err = set_linkmode(ifname, dcb_state); -+ err = set_linkmode(ifindex, ifname, dcb_state); - - if (err) - LLDPAD_DBG("ERROR %s: set_linkmode dcbstate %i\n", -diff --git a/lldp_ecp.c b/lldp_ecp.c -deleted file mode 100644 -index 8e92253..0000000 ---- a/lldp_ecp.c -+++ /dev/null -@@ -1,1093 +0,0 @@ --/****************************************************************************** -- -- Implementation of ECP according to 802.1Qbg -- (c) Copyright IBM Corp. 2010, 2012 -- -- Author(s): Jens Osterkamp -- Author(s): Thomas Richter -- -- This program is free software; you can redistribute it and/or modify it -- under the terms and conditions of the GNU General Public License, -- version 2, as published by the Free Software Foundation. -- -- This program is distributed in the hope it will be useful, but WITHOUT -- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -- more details. -- -- You should have received a copy of the GNU General Public License along with -- this program; if not, write to the Free Software Foundation, Inc., -- 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. -- -- The full GNU General Public License is included in this distribution in -- the file called "COPYING". -- --******************************************************************************/ -- --#include --#include --#include --#include --#include --#include --#include -- --#include "eloop.h" --#include "lldp.h" --#include "lldp_evb.h" --#include "lldp_qbg_utils.h" --#include "lldp_vdp.h" --#include "messages.h" --#include "config.h" --#include "lldp/l2_packet.h" -- --#include "lldp_tlv.h" -- --static void ecp_tx_run_sm(struct vdp_data *); --static void ecp_rx_run_sm(struct vdp_data *); -- --/* ecp_localchange_handler - triggers the processing of a local change -- * @eloop_data: data structure of event loop -- * @user_ctx: user context, vdp_data here -- * -- * no return value -- * -- * called from ecp_somethingchangedlocal when a change is pending. Calls -- * the ECP tx station state machine. A oneshot handler. This detour is taken -- * to not having to call the ecp code from the vdp state machine. Instead, we -- * return to the event loop, giving other code a chance to do work. -- */ --static void ecp_localchange_handler(UNUSED void *eloop_data, void *user_ctx) --{ -- struct vdp_data *vd; -- -- vd = (struct vdp_data *) user_ctx; -- if (vd->ecp.tx.localChange) { -- LLDPAD_DBG("%s:%s ecp.tx.localChange %i\n", -- __func__, vd->ecp.ifname, vd->ecp.tx.localChange); -- ecp_tx_run_sm(vd); -- } --} -- --/* ecp_start_localchange_timer - starts the ECP localchange timer -- * @vd: vdp_data for the interface -- * -- * returns 0 on success, -1 on error -- * -- * starts the ECP localchange timer when a localchange has been signaled from -- * the VDP state machine. -- */ --static int ecp_start_localchange_timer(struct vdp_data *vd) --{ -- return eloop_register_timeout(0, ECP_LOCALCHANGE_TIMEOUT, -- ecp_localchange_handler, -- NULL, (void *) vd); --} -- --/* ecp_stop_localchange_timer - stop the ECP localchange timer -- * @vd: vdp_data for the interface -- * -- * returns the number of removed handlers -- * -- * stops the ECP localchange timer. Used e.g. when the host interface goes down. -- */ --static int ecp_stop_localchange_timer(struct vdp_data *vd) --{ -- LLDPAD_DBG("%s:%s stopping ecp localchange timer\n", __func__, -- vd->ecp.ifname); -- return eloop_cancel_timeout(ecp_localchange_handler, NULL, (void *) vd); --} -- --/* ecp_ackTimer_expired - checks for expired ack timer -- * @vd: vdp_data for interface -- * -- * returns true or false -- * -- * returns true if ack timer has expired, false otherwise. -- */ --static bool ecp_ackTimer_expired(struct vdp_data *vd) --{ -- return (vd->ecp.ackTimer == 0); --} -- --/* ecp_ack_timeout_handler - handles the ack timer expiry -- * @eloop_data: data structure of event loop -- * @user_ctx: user context, vdp_data here -- * -- * no return value -- * -- * called when the ECP timer has expired. Calls the ECP station state machine. -- */ --static void ecp_ack_timeout_handler(UNUSED void *eloop_data, void *user_ctx) --{ -- struct vdp_data *vd; -- -- vd = (struct vdp_data *) user_ctx; -- if (vd->ecp.ackTimer > 0) -- vd->ecp.ackTimer -= ECP_ACK_TIMER_DEFAULT; -- -- if (ecp_ackTimer_expired(vd) == true) { -- LLDPAD_DBG("%s:%s ecp_ackTimer_expired (%i)\n", -- __func__, vd->ecp.ifname, vd->ecp.ackTimer); -- ecp_tx_run_sm(vd); -- } else { -- LLDPAD_DBG("%s:%s BUG! handler called but" -- "vdp->ecp.ackTimer not expired (%i)\n", -- __func__, vd->ecp.ifname, vd->ecp.ackTimer); -- } --} -- --/* ecp_start_ack_timer - starts the ECP ack timer -- * @vd: vdp_data for the interface -- * -- * returns 0 on success, -1 on error -- * -- * starts the ECP ack timer when a frame has been sent out. -- */ --static int ecp_start_ack_timer(struct vdp_data *vd) --{ -- return eloop_register_timeout(0, ECP_ACK_TIMER_DEFAULT, -- ecp_ack_timeout_handler, -- NULL, (void *) vd); --} -- --/* ecp_stop_ack_timer - stop the ECP ack timer -- * @vd: vdp_data for the interface -- * -- * returns the number of removed handlers -- * -- * stops the ECP ack timer. Used e.g. when the host interface goes down. -- */ --static int ecp_stop_ack_timer(struct vdp_data *vd) --{ -- LLDPAD_DBG("%s:%s stopping ecp ack timer\n", __func__, vd->ecp.ifname); -- return eloop_cancel_timeout(ecp_ack_timeout_handler, NULL, (void *) vd); --} -- --/* ecp_tx_stop_ackTimer - stop the ECP ack timer -- * @vd: currently used port -- * -- * returns the number of removed handlers -- * -- * stops the ECP ack timer. used when a ack frame for the port has been -- * received. -- */ --static void ecp_tx_stop_ackTimer(struct vdp_data *vd) --{ -- vd->ecp.ackTimer = ECP_ACK_TIMER_STOPPED; -- LLDPAD_DBG("%s:%s stopped ecp ack timer\n", __func__, vd->ecp.ifname); -- ecp_stop_ack_timer(vd); --} -- --int ecp_deinit(char *ifname) --{ -- struct vdp_data *vd; -- -- LLDPAD_DBG("%s:%s stopping ECP\n", __func__, ifname); -- vd = vdp_data(ifname); -- if (!vd) { -- LLDPAD_ERR("%s:%s unable to find vd\n", __func__, ifname); -- return -1; -- } -- -- ecp_stop_ack_timer(vd); -- ecp_stop_localchange_timer(vd); -- ecp_tx_stop_ackTimer(vd); -- return 0; --} -- --static const char *ecp_tx_states[] = { -- "ECP_TX_INIT_TRANSMIT", -- "ECP_TX_TRANSMIT_ECPDU", -- "ECP_TX_WAIT_FOR_ACK", -- "ECP_TX_REQUEST_PDU" --}; -- --/* ecp_somethingChangedLocal - set flag if port has changed -- * @vd: port to set the flag for -- * @mode: mode to set the flag to -- * -- * no return value -- * -- * set the localChange flag with a mode to indicate a port has changed. -- * used to signal an ecpdu needs to be sent out. -- */ -- --void ecp_somethingChangedLocal(struct vdp_data *vd, bool flag) --{ -- if (!vd) -- return; -- -- LLDPAD_DBG("%s:%s vd->ecp.tx.localChange to %s\n", __func__, -- vd->ecp.ifname, (flag == true) ? "true" : "false"); -- vd->ecp.tx.localChange = flag; -- ecp_start_localchange_timer(vd); --} -- --/* -- * Append some data at the end of the transmit data buffer. Make sure the -- * End TLV always fits into the buffer. -- */ --static u8 end_tlv[2] = { 0x0, 0x0 }; /* END TLV */ -- --static int ecp_append(u8 *buffer, u32 *pos, void *data, u32 len) --{ -- if (*pos + len > ETH_FRAME_LEN - sizeof end_tlv) -- return 0; -- memcpy(buffer + *pos, data, len); -- *pos += len; -- return 1; --} -- --/* ecp_build_ECPDU - create an ecp protocol data unit -- * @vd: currently used port -- * -- * returns true on success, false on failure -- * -- * creates the frame header with the ports mac address, the ecp header with REQ -- * plus a list of packed TLVs created from the profiles on this -- * port. -- */ --static bool ecp_build_ECPDU(struct vdp_data *vd) --{ -- struct l2_ethhdr eth; -- struct ecp_hdr ecp_hdr; -- u8 own_addr[ETH_ALEN]; -- u32 fb_offset = 0; -- struct packed_tlv *ptlv = NULL; -- struct vsi_profile *p; -- int rc; -- -- /* TODO: use LLDP group MAC addresses to support -- * S-channels/multichannel -- */ -- memcpy(eth.h_dest, nearest_bridge, ETH_ALEN); -- l2_packet_get_own_src_addr(vd->ecp.l2,(u8 *)&own_addr); -- memcpy(eth.h_source, &own_addr, ETH_ALEN); -- eth.h_proto = htons(ETH_P_ECP); -- memset(vd->ecp.tx.frame, 0, sizeof vd->ecp.tx.frame); -- ecp_append(vd->ecp.tx.frame, &fb_offset, (void *)ð, sizeof eth); -- -- ecp_hdr.oui[0] = 0x0; -- ecp_hdr.oui[1] = 0x1b; -- ecp_hdr.oui[2] = 0x3f; -- ecp_hdr.pad1 = 0x0; -- ecp_hdr.subtype = ECP_SUBTYPE; -- ecp_hdr.mode = ECP_REQUEST; -- -- vd->ecp.lastSequence++; -- ecp_hdr.seqnr = htons(vd->ecp.lastSequence); -- ecp_append(vd->ecp.tx.frame, &fb_offset, (void *)&ecp_hdr, -- sizeof ecp_hdr); -- -- /* create packed_tlvs for all profiles on this interface */ -- LIST_FOREACH(p, &vd->profile_head, profile) { -- -- if (!p->localChange) { -- LLDPAD_DBG("%s:%s skipping unchanged profile\n", -- __func__, vd->ecp.ifname); -- continue; -- } -- -- ptlv = vdp_gettlv(vd, p); -- -- if (!ptlv) { -- LLDPAD_DBG("%s:%s ptlv not created\n", __func__, -- vd->ecp.ifname); -- continue; -- } -- -- rc = ecp_append(vd->ecp.tx.frame, &fb_offset, ptlv->tlv, -- ptlv->size); -- ptlv = free_pkd_tlv(ptlv); -- if (rc) -- p->seqnr = vd->ecp.lastSequence; -- else -- break; -- } -- ecp_append(vd->ecp.tx.frame, &fb_offset, end_tlv, sizeof end_tlv); -- vd->ecp.tx.frame_len = MAX(fb_offset, (unsigned)ETH_ZLEN); -- return true; --} -- --/* ecp_tx_Initialize - initializes the ecp tx state machine -- * @vd: currently used port -- * -- * no return value -- * -- * initializes some variables for the ecp tx state machine. -- */ --static void ecp_tx_Initialize(struct vdp_data *vd) --{ -- memset(vd->ecp.tx.frame, 0, sizeof vd->ecp.tx.frame); -- ecp_somethingChangedLocal(vd, true); -- vd->ecp.lastSequence = ECP_SEQUENCE_NR_START; -- vd->ecp.stats.statsFramesOutTotal = 0; -- vd->ecp.ackTimer = ECP_ACK_TIMER_STOPPED; -- vd->ecp.retries = 0; --} -- --/* ecp_txFrame - transmit ecp frame -- * @vd: currently used port -- * -- * returns the number of characters sent on success, -1 on failure -- * -- * sends out the frame stored in the frame structure using l2_packet_send. -- */ --static u8 ecp_txFrame(struct vdp_data *vd) --{ -- int status = 0; -- -- status = l2_packet_send(vd->ecp.l2, (u8 *)&nearest_bridge, -- htons(ETH_P_ECP), vd->ecp.tx.frame, vd->ecp.tx.frame_len); -- vd->ecp.stats.statsFramesOutTotal++; -- vd->ecp.tx.frame_len = 0; -- return status; --} -- --/* ecp_tx_create_frame - create ecp frame -- * @vd: currently used port -- * -- * no return value -- */ --static void ecp_tx_create_frame(struct vdp_data *vd) --{ -- /* send REQs */ -- if (vd->ecp.tx.localChange) { -- int ret; -- -- LLDPAD_DBG("%s:%s sending REQs\n", __func__, vd->ecp.ifname); -- ret = ecp_build_ECPDU(vd); -- -- /* ECPDU construction succesful, send out frame */ -- if (ret == true) { -- hexdump_frame(vd->ecp.ifname, "frame-out", -- vd->ecp.tx.frame, vd->ecp.tx.frame_len); -- ecp_txFrame(vd); -- } -- } -- -- ecp_somethingChangedLocal(vd, false); --} -- --/* ecp_tx_start_ackTimer - starts the ECP ack timer -- * @vd: vdp_data to process -- * -- * returns 0 on success, -1 on error -- * -- * starts the ack timer when a frame has been sent out. -- */ --static void ecp_tx_start_ackTimer(struct vdp_data *vd) --{ -- vd->ecp.ackTimer = ECP_ACK_TIMER_DEFAULT; -- LLDPAD_DBG("%s-%s: starting ecp ack timer\n", __func__, vd->ifname); -- ecp_start_ack_timer(vd); --} -- --/* ecp_tx_change_state - changes the ecp tx sm state -- * @vd: currently used port -- * @newstate: new state for the sm -- * -- * no return value -- * -- * checks state transistion for consistency and finally changes the state of -- * the profile. -- */ --static void ecp_tx_change_state(struct vdp_data *vd, u8 newstate) --{ -- switch(newstate) { -- case ECP_TX_INIT_TRANSMIT: -- break; -- case ECP_TX_TRANSMIT_ECPDU: -- assert((vd->ecp.tx.state == ECP_TX_INIT_TRANSMIT) || -- (vd->ecp.tx.state == ECP_TX_WAIT_FOR_ACK) || -- (vd->ecp.tx.state == ECP_TX_REQUEST_PDU)); -- break; -- case ECP_TX_WAIT_FOR_ACK: -- assert(vd->ecp.tx.state == ECP_TX_TRANSMIT_ECPDU); -- break; -- case ECP_TX_REQUEST_PDU: -- assert(vd->ecp.tx.state == ECP_TX_WAIT_FOR_ACK); -- break; -- default: -- LLDPAD_ERR("%s: LLDP TX state machine invalid state %d\n", -- vd->ifname, newstate); -- } -- LLDPAD_DBG("%s-%s: state change %s -> %s\n", __func__, -- vd->ifname, ecp_tx_states[vd->ecp.tx.state], -- ecp_tx_states[newstate]); -- vd->ecp.tx.state = newstate; -- return; --} -- --/* ecp_set_tx_state - sets the ecp tx sm state -- * @vd: currently used port -- * -- * returns true or false -- * -- * switches the state machine to the next state depending on the input -- * variables. returns true or false depending on wether the state machine -- * can be run again with the new state or can stop at the current state. -- */ --static bool ecp_set_tx_state(struct vdp_data *vd) --{ -- struct port *port = port_find_by_name(vd->ifname); -- -- if (!port) { -- LLDPAD_ERR("%s: port not found\n", __func__); -- return 0; -- } -- -- if ((port->portEnabled == false) && (port->prevPortEnabled == true)) { -- LLDPAD_ERR("set_tx_state: port was disabled\n"); -- ecp_tx_change_state(vd, ECP_TX_INIT_TRANSMIT); -- } -- port->prevPortEnabled = port->portEnabled; -- -- switch (vd->ecp.tx.state) { -- case ECP_TX_INIT_TRANSMIT: -- if (port->portEnabled && (vd->enabletx == true) -- && vd->ecp.tx.localChange) { -- ecp_tx_change_state(vd, ECP_TX_TRANSMIT_ECPDU); -- return true; -- } -- return false; -- case ECP_TX_TRANSMIT_ECPDU: -- if (vd->enabletx == false) { -- ecp_tx_change_state(vd, ECP_TX_INIT_TRANSMIT); -- return true; -- } -- ecp_tx_change_state(vd, ECP_TX_WAIT_FOR_ACK); -- return false; -- case ECP_TX_WAIT_FOR_ACK: -- if (ecp_ackTimer_expired(vd)) { -- vd->ecp.retries++; -- if (vd->ecp.retries < ECP_MAX_RETRIES) { -- ecp_somethingChangedLocal(vd, true); -- ecp_tx_change_state(vd, ECP_TX_TRANSMIT_ECPDU); -- return true; -- } -- if (vd->ecp.retries == ECP_MAX_RETRIES) { -- LLDPAD_DBG("%s-%s: retries expired\n", -- __func__, vd->ifname); -- ecp_tx_stop_ackTimer(vd); -- ecp_tx_change_state(vd, ECP_TX_REQUEST_PDU); -- return true; -- } -- } -- if (vd->ecp.ackReceived && -- vd->ecp.seqECPDU == vd->ecp.lastSequence) { -- vd->ecp.ackReceived = false; -- if (vdp_vsis_pending(vd)) { -- LLDPAD_DBG("%s-%s: still work pending\n", -- __func__, vd->ifname); -- ecp_somethingChangedLocal(vd, true); -- } -- ecp_tx_change_state(vd, ECP_TX_REQUEST_PDU); -- return true; -- } -- return false; -- case ECP_TX_REQUEST_PDU: -- if (vd->ecp.tx.localChange) { -- ecp_tx_change_state(vd, ECP_TX_TRANSMIT_ECPDU); -- return true; -- } -- return false; -- default: -- LLDPAD_ERR("%s: LLDP TX state machine in invalid state %d\n", -- vd->ifname, vd->ecp.tx.state); -- return false; -- } --} -- --/* ecp_tx_run_sm - state machine for ecp tx -- * @vd: currently used vdp_data -- * -- * no return value -- * -- * runs the state machine for ecp tx. -- */ --void ecp_tx_run_sm(struct vdp_data *vd) --{ -- do { -- LLDPAD_DBG("%s-%s: ecp_tx - %s\n", __func__, -- vd->ifname, ecp_tx_states[vd->ecp.tx.state]); -- -- switch(vd->ecp.tx.state) { -- case ECP_TX_INIT_TRANSMIT: -- ecp_tx_Initialize(vd); -- break; -- case ECP_TX_TRANSMIT_ECPDU: -- ecp_tx_create_frame(vd); -- ecp_tx_start_ackTimer(vd); -- ecp_somethingChangedLocal(vd, false); -- break; -- case ECP_TX_WAIT_FOR_ACK: -- if (vd->ecp.ackReceived) { -- LLDPAD_DBG("%s-%s: ECP_TX_WAIT_FOR_ACK " -- "ackReceived seqECPDU %#x " -- "lastSequence %#x\n", __func__, -- vd->ifname, vd->ecp.seqECPDU, -- vd->ecp.lastSequence); -- ecp_somethingChangedLocal(vd, false); -- ecp_tx_stop_ackTimer(vd); -- } -- break; -- case ECP_TX_REQUEST_PDU: -- vd->ecp.retries = 0; -- LLDPAD_DBG("%s-%s: ECP_TX_REQUEST_PDU lastSeq %#x\n", -- __func__, vd->ifname, vd->ecp.lastSequence); -- break; -- default: -- LLDPAD_ERR("%s: LLDP TX state machine in invalid state %d\n", -- vd->ifname, vd->ecp.tx.state); -- } -- } while (ecp_set_tx_state(vd) == true); --} -- --static const char *ecp_rx_states[] = { -- "ECP_RX_IDLE", -- "ECP_RX_INIT_RECEIVE", -- "ECP_RX_RECEIVE_WAIT", -- "ECP_RX_RECEIVE_ECPDU", -- "ECP_RX_SEND_ACK", -- "ECP_RX_RESEND_ACK", --}; -- --/* ecp_rx_Initialize - initializes the ecp rx state machine -- * @vd: vd for the state machine -- * -- * no return value -- * -- * initialize some variables, get rid of old frame if necessary -- */ --static void ecp_rx_Initialize(struct vdp_data *vd) --{ -- vd->ecp.rx.rcvFrame = false; -- vd->ecp.ackReceived = false; -- vd->ecp.rx.frame_len = 0; --} -- --/* ecp_rx_SendAckFrame - send ack frame -- * @vd: port used by ecp -- * -- * currently always returns 0 -- * -- * copies current received frame over to frame out, fills in address of this -- * port and set mode field to ACK. used by ecp_rx_send_ack_frame. -- */ --static int ecp_rx_SendAckFrame(struct vdp_data *vd) --{ -- u16 tlv_offset = 0; -- struct ecp_hdr *ecp_hdr; -- struct l2_ethhdr *hdr; -- u8 own_addr[ETH_ALEN]; -- -- LLDPAD_DBG("%s:%s acking frame\n", __func__, vd->ecp.ifname); -- /* copy over to transmit buffer */ -- memcpy(vd->ecp.tx.frame, vd->ecp.rx.frame, vd->ecp.rx.frame_len); -- vd->ecp.tx.frame_len = vd->ecp.rx.frame_len; -- -- /* use my own addr to send ACK */ -- hdr = (struct l2_ethhdr *)vd->ecp.tx.frame; -- l2_packet_get_own_src_addr(vd->ecp.l2,(u8 *)&own_addr); -- memcpy(hdr->h_source, &own_addr, ETH_ALEN); -- -- tlv_offset = sizeof(struct l2_ethhdr); -- ecp_hdr = (struct ecp_hdr *)&vd->ecp.tx.frame[tlv_offset]; -- ecp_hdr->mode = ECP_ACK; -- -- tlv_offset = sizeof(struct l2_ethhdr) + sizeof(struct ecp_hdr); -- LLDPAD_DBG("%s:%s zeroing out rest of ack frame from %i to %i\n", -- __func__, vd->ecp.ifname, tlv_offset, vd->ecp.rx.frame_len); -- memset(&vd->ecp.tx.frame[tlv_offset], 0, -- vd->ecp.rx.frame_len - tlv_offset); -- return 0; --} -- --/* ecp_rx_send_ack_frame - send out ack frame for received frame -- * @vd: vd for the state machine -- * -- * no return value -- * -- * creates an ack frame for a just received frame, prints the about to be -- * sent frame and finally transmits it. -- */ --void ecp_rx_send_ack_frame(struct vdp_data *vd) --{ -- ecp_rx_SendAckFrame(vd); -- hexdump_frame(vd->ecp.ifname, "frame-ack", vd->ecp.tx.frame, -- vd->ecp.tx.frame_len); -- ecp_txFrame(vd); --} -- --/* ecp_rx_ReceiveFrame - receive ecp frame -- * @ctx: rx callback context, struct vd * in this case -- * @ifindex: index of interface -- * @buf: buffer which contains the frame just received -- * @len: size of buffer (frame) -- * -- * no return value -- * -- * creates a local copy of the buffer and checks the header. keeps some -- * statistics about ecp frames. Checks if it is a request or an ack frame -- * and branches to ecp rx or ecp tx state machine. -- */ --static void ecp_rx_ReceiveFrame(void *ctx, UNUSED int ifindex, const u8 *buf, -- size_t len) --{ -- struct vdp_data *vd; -- struct port *port; -- u8 frame_error = 0; -- u16 tlv_offset; -- struct l2_ethhdr *hdr; -- struct l2_ethhdr example_hdr,*ex; -- struct ecp_hdr *ecp_hdr; -- -- if (!ctx) { -- LLDPAD_WARN("%s: no ctx - can't process frame\n", __func__); -- return; -- } -- -- vd = (struct vdp_data *)ctx; -- port = port_find_by_name(vd->ifname); -- if (port == NULL) -- return; -- -- LLDPAD_DBG("%s:%s received packet with size %i\n", __func__, -- vd->ecp.ifname, (int)len); -- if (vd->enabletx == false) -- return; -- -- if (vd->ecp.rx.frame_len == len && -- (memcmp(buf, vd->ecp.rx.frame, len) == 0)) { -- vd->ecp.stats.statsFramesInTotal++; -- return; -- } -- -- memset(vd->ecp.rx.frame, 0, len); -- memcpy(vd->ecp.rx.frame, buf, len); -- -- vd->ecp.rx.frame_len = (u16)len; -- ex = &example_hdr; -- memcpy(ex->h_dest, nearest_bridge, ETH_ALEN); -- ex->h_proto = htons(ETH_P_ECP); -- hdr = (struct l2_ethhdr *)vd->ecp.rx.frame; -- -- if ((memcmp(hdr->h_dest, ex->h_dest, ETH_ALEN) != 0)) { -- LLDPAD_ERR("%s:%s ERROR multicast address error in incoming frame." -- " Dropping frame.\n", __func__, vd->ecp.ifname); -- frame_error++; -- return; -- } -- -- if (hdr->h_proto != example_hdr.h_proto) { -- LLDPAD_ERR("%s:%s ERROR ethertype %#x not ECP ethertype", -- __func__, vd->ecp.ifname, htons(hdr->h_proto)); -- frame_error++; -- return; -- } -- -- if (!frame_error) { -- vd->ecp.stats.statsFramesInTotal++; -- vd->ecp.rx.rcvFrame = true; -- } -- -- tlv_offset = sizeof(struct l2_ethhdr); -- ecp_hdr = (struct ecp_hdr *)&vd->ecp.rx.frame[tlv_offset]; -- vd->ecp.seqECPDU = ntohs(ecp_hdr->seqnr); -- hexdump_frame(vd->ecp.ifname, "frame-in", vd->ecp.rx.frame, -- vd->ecp.rx.frame_len); -- -- switch(ecp_hdr->mode) { -- case ECP_REQUEST: -- LLDPAD_DBG("%s:%s received REQ frame\n", __func__, -- vd->ecp.ifname); -- vd->ecp.ackReceived = false; -- ecp_rx_run_sm(vd); -- break; -- case ECP_ACK: -- LLDPAD_DBG("%s:%s received ACK frame\n", __func__, -- vd->ecp.ifname); -- vd->ecp.ackReceived = true; -- vdp_ack_profiles(vd, vd->ecp.seqECPDU); -- ecp_tx_run_sm(vd); -- vd->ecp.ackReceived = false; -- break; -- default: -- LLDPAD_ERR("%s:%s ERROR: unknown mode %i\n", __func__, -- vd->ecp.ifname, ecp_hdr->mode); -- return; -- } -- --} -- --/* ecp_rx_change_state - changes the ecp rx sm state -- * @vd: currently used port -- * @newstate: new state for the sm -- * -- * no return value -- * -- * checks state transistion for consistency and finally changes the state of -- * the profile. -- */ --static void ecp_rx_change_state(struct vdp_data *vd, u8 newstate) --{ -- switch(newstate) { -- case ECP_RX_IDLE: -- break; -- case ECP_RX_INIT_RECEIVE: -- break; -- case ECP_RX_RECEIVE_WAIT: -- assert((vd->ecp.rx.state == ECP_RX_INIT_RECEIVE) || -- (vd->ecp.rx.state == ECP_RX_IDLE) || -- (vd->ecp.rx.state == ECP_RX_SEND_ACK) || -- (vd->ecp.rx.state == ECP_RX_RESEND_ACK)); -- break; -- case ECP_RX_RECEIVE_ECPDU: -- assert(vd->ecp.rx.state == ECP_RX_RECEIVE_WAIT); -- break; -- case ECP_RX_SEND_ACK: -- assert(vd->ecp.rx.state == ECP_RX_RECEIVE_ECPDU); -- break; -- case ECP_RX_RESEND_ACK: -- assert(vd->ecp.rx.state == ECP_RX_RECEIVE_ECPDU); -- break; -- default: -- LLDPAD_ERR("%s:%s LLDP RX state machine invalid state %d\n", -- __func__, vd->ecp.ifname, newstate); -- } -- -- LLDPAD_DBG("%s:%s state change %s -> %s\n", __func__, -- vd->ecp.ifname, ecp_rx_states[vd->ecp.rx.state], -- ecp_rx_states[newstate]); -- -- vd->ecp.rx.state = newstate; --} -- --/* ecp_init - initialize ecp module -- * @ifname: interface for which the module is initialized -- * -- * returns 0 on success, -1 on error -- * -- * finds the port to the interface name, sets up the receive handle for -- * incoming ecp frames and initializes the ecp rx and tx state machines. -- * should usually be called when a successful exchange of EVB TLVs has been -- * made and ECP and VDP protocols are supported by both sides. -- */ --int ecp_init(char *ifname) --{ -- struct vdp_data *vd; -- -- LLDPAD_DBG("%s:%s starting ECP\n", __func__, ifname); -- vd = vdp_data(ifname); -- if (!vd) { -- LLDPAD_ERR("%s:%s unable to find vd\n", __func__, ifname); -- return -1; -- } -- -- if (!vd->ecp.l2) -- vd->ecp.l2 = l2_packet_init(vd->ifname, NULL, ETH_P_ECP, -- ecp_rx_ReceiveFrame, vd, 1); -- -- if (!vd->ecp.l2) { -- LLDPAD_ERR("%s:%s failed to access layer 2 access ETH_P_ECP\n", -- __func__, ifname); -- return -1; -- } -- strncpy(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); -- return 0; --} -- --/* ecp_rx_validate_frame - validates received frame -- * @vd: vdp_data used by ecp -- * -- * no return value -- * -- * checks wether received frame has correct subtype and mode -- */ -- --static void ecp_rx_validate_frame(struct vdp_data *vd) --{ -- u16 tlv_offset = 0; -- struct ecp_hdr *ecp_hdr; -- -- LLDPAD_DBG("%s:%s validating frame\n", __func__, vd->ecp.ifname); -- tlv_offset = sizeof(struct l2_ethhdr); -- ecp_hdr = (struct ecp_hdr *)&vd->ecp.rx.frame[tlv_offset]; -- LLDPAD_DBG("%s:%s ecp packet with subtype %#x mode %#x seq %#04x\n", -- __func__, vd->ecp.ifname, ecp_hdr->subtype, ecp_hdr->mode, -- ntohs(ecp_hdr->seqnr)); -- -- if (ecp_hdr->subtype != ECP_SUBTYPE) { -- LLDPAD_ERR("%s:%s ERROR: unknown subtype\n", __func__, -- vd->ecp.ifname); -- return; -- } -- -- if ((ecp_hdr->oui[0] != 0x0) || (ecp_hdr->oui[1] != 0x1b) || -- (ecp_hdr->oui[2] != 0x3f)) { -- LLDPAD_ERR("%s:%s ERROR: incorrect OUI 0x%02x%02x%02x\n", -- __func__, vd->ecp.ifname, ecp_hdr->oui[0], -- ecp_hdr->oui[1], ecp_hdr->oui[2]); -- return; -- } -- -- switch(ecp_hdr->mode) { -- case ECP_REQUEST: -- break; -- case ECP_ACK: -- break; -- default: -- LLDPAD_ERR("%s:%s ERROR: unknown mode %i\n", __func__, -- vd->ecp.ifname, ecp_hdr->mode); -- return; -- } -- -- /* FIXME: also done in ecp_rx_ReceiveFrame, -- * are both necessary ? */ -- vd->ecp.seqECPDU = ntohs(ecp_hdr->seqnr); --} -- --/* ecp_rx_ProcessFrame - process received ecp frames -- * @vd: currently used port -- * -- * no return value -- * -- * walks through the packed vsi tlvs in an ecp frame, extracts them -- * and passes them to the VDP ULP with vdp_indicate. -- */ --static void ecp_rx_ProcessFrame(struct vdp_data *vd) --{ -- u16 tlv_cnt = 0; -- u8 tlv_type = 0; -- u16 tlv_length = 0; -- u16 tlv_offset = 0; -- u16 *tlv_head_ptr = NULL; -- u8 frame_error = 0; -- bool tlv_stored = false; -- struct ecp_hdr *ecp_hdr; -- int vdp_called; -- -- LLDPAD_DBG("%s:%s processing frame\n", __func__, vd->ecp.ifname); -- tlv_offset = sizeof(struct l2_ethhdr); -- -- ecp_hdr = (struct ecp_hdr *)&vd->ecp.rx.frame[tlv_offset]; -- LLDPAD_DBG("%s:%s ecp packet with subtype %#x mode %#x seq %#04x\n", -- __func__, vd->ifname, ecp_hdr->subtype, -- ecp_hdr->mode, ntohs(ecp_hdr->seqnr)); -- if (ecp_hdr->mode == ECP_ACK) -- return; -- -- /* processing of VSI_TLVs starts here */ -- tlv_offset += sizeof(struct ecp_hdr); -- vdp_called = 0; -- do { -- tlv_cnt++; -- -- if (tlv_offset > vd->ecp.rx.frame_len) { -- LLDPAD_ERR("%s:%s ERROR: Frame overrun! tlv_offset %i" -- " frame_len %i cnt %i\n", __func__, -- vd->ecp.ifname, tlv_offset, -- vd->ecp.rx.frame_len, tlv_cnt); -- frame_error++; -- goto out; -- } -- -- if (tlv_offset + 2 > vd->ecp.rx.frame_len) { -- LLDPAD_DBG("%s:%s tlv EOF problem size=%d offset=%d\n", -- __func__, vd->ecp.ifname, -- vd->ecp.rx.frame_len, tlv_offset); -- frame_error++; -- goto out; -- } -- -- tlv_head_ptr = (u16 *)&vd->ecp.rx.frame[tlv_offset]; -- tlv_length = htons(*tlv_head_ptr) & 0x01FF; -- tlv_type = (u8)(htons(*tlv_head_ptr) >> 9); -- -- u16 tmp_offset = tlv_offset + tlv_length; -- if (tmp_offset > vd->ecp.rx.frame_len) { -- LLDPAD_ERR("%s:%s ERROR: Frame overflow: offset=%d " -- "rx.size=%d\n", __func__, vd->ecp.ifname, -- tmp_offset, vd->ecp.rx.frame_len); -- frame_error++; -- goto out; -- } -- -- u8 *info = (u8 *)&vd->ecp.rx.frame[tlv_offset + -- sizeof(*tlv_head_ptr)]; -- -- struct unpacked_tlv *tlv = create_tlv(); -- -- if (!tlv) { -- LLDPAD_DBG("%s:%s failed malloc for incoming TLV\n", -- __func__, vd->ecp.ifname); -- goto out; -- } -- -- if ((tlv_length == 0) && (tlv->type != TYPE_0)) { -- LLDPAD_DBG("%s:%s tlv_length == 0\n", __func__, -- vd->ecp.ifname); -- free_unpkd_tlv(tlv); -- goto out; -- } -- -- tlv->type = tlv_type; -- tlv->length = tlv_length; -- tlv->info = (u8 *)malloc(tlv_length); -- if (tlv->info) { -- memset(tlv->info,0, tlv_length); -- memcpy(tlv->info, info, tlv_length); -- } else { -- LLDPAD_DBG("%s:%s failed malloc for incoming TLV info\n", -- __func__, vd->ecp.ifname); -- free_unpkd_tlv(tlv); -- goto out; -- } -- -- /* Validate the TLV */ -- tlv_offset += sizeof(*tlv_head_ptr) + tlv_length; -- -- if (tlv->type == TYPE_127) { /* private TLV */ -- /* give VSI TLV to VDP */ -- if (!vdp_indicate(vd, tlv)) { -- tlv_stored = true; -- ++vdp_called; -- } else { -- /* TODO -- * put it in a list and try again later until -- * timer and retries have expired -- */ -- tlv_stored = false; -- } -- } -- -- 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); -- vd->ecp.stats.statsTLVsUnrecognizedTotal++; -- } -- tlv = NULL; -- tlv_stored = false; -- } while (tlv_offset < vd->ecp.rx.frame_len); --out: -- if (frame_error) { -- vd->ecp.stats.statsFramesDiscardedTotal++; -- vd->ecp.stats.statsFramesInErrorsTotal++; -- } -- if (vdp_called) -- vdp_advance_sm(vd); --} -- --/* ecp_set_rx_state - sets the ecp rx sm state -- * @vd: currently used port -- * -- * returns true or false -- * -- * switches the state machine to the next state depending on the input -- * variables. returns true or false depending on wether the state machine -- * can be run again with the new state or can stop at the current state. -- */ --static bool ecp_set_rx_state(struct vdp_data *vd) --{ -- struct port *port = port_find_by_name(vd->ifname); -- -- if (!port) -- return false; -- -- if (port->portEnabled == false) -- ecp_rx_change_state(vd, ECP_RX_IDLE); -- -- switch(vd->ecp.rx.state) { -- case ECP_RX_IDLE: -- if (port->portEnabled == true) { -- ecp_rx_change_state(vd, ECP_RX_INIT_RECEIVE); -- return true; -- } -- return false; -- case ECP_RX_INIT_RECEIVE: -- if (vd->enabletx == true) { -- ecp_rx_change_state(vd, ECP_RX_RECEIVE_WAIT); -- return true; -- } -- return false; -- case ECP_RX_RECEIVE_WAIT: -- if (vd->enabletx == false) { -- ecp_rx_change_state(vd, ECP_RX_IDLE); -- return true; -- } -- if (vd->ecp.rx.rcvFrame == true) { -- ecp_rx_change_state(vd, ECP_RX_RECEIVE_ECPDU); -- return true; -- } -- return false; -- case ECP_RX_RECEIVE_ECPDU: -- if (vd->ecp.seqECPDU == vd->ecp.lastSequence) { -- LLDPAD_DBG("%s:%s seqECPDU %x, lastSequence %x\n", -- __func__, vd->ecp.ifname, vd->ecp.seqECPDU, -- vd->ecp.lastSequence); -- ecp_rx_change_state(vd, ECP_RX_RESEND_ACK); -- return true; -- } -- if (vd->ecp.seqECPDU != vd->ecp.lastSequence) { -- ecp_rx_change_state(vd, ECP_RX_RESEND_ACK); -- return true; -- } -- return false; -- case ECP_RX_SEND_ACK: -- case ECP_RX_RESEND_ACK: -- ecp_rx_change_state(vd, ECP_RX_RECEIVE_WAIT); -- return false; -- default: -- LLDPAD_DBG("%s:%s ECP RX state machine in invalid state %d\n", -- __func__, vd->ecp.ifname, vd->ecp.rx.state); -- return false; -- } --} -- --/* ecp_rx_run_sm - state machine for ecp rx -- * @vd: currently used port -- * -- * no return value -- * -- * runs the state machine for ecp rx. -- */ --static void ecp_rx_run_sm(struct vdp_data *vd) --{ -- ecp_set_rx_state(vd); -- do { -- LLDPAD_DBG("%s:%s ecp_rx - %s\n", __func__, vd->ecp.ifname, -- ecp_rx_states[vd->ecp.tx.state]); -- -- switch(vd->ecp.rx.state) { -- case ECP_RX_IDLE: -- break; -- case ECP_RX_INIT_RECEIVE: -- ecp_rx_Initialize(vd); -- break; -- case ECP_RX_RECEIVE_WAIT: -- break; -- case ECP_RX_RECEIVE_ECPDU: -- vd->ecp.rx.rcvFrame = false; -- ecp_rx_validate_frame(vd); -- break; -- case ECP_RX_SEND_ACK: -- ecp_rx_ProcessFrame(vd); -- break; -- case ECP_RX_RESEND_ACK: -- ecp_rx_ProcessFrame(vd); -- if (!vd->ecp.ackReceived) { -- ecp_rx_send_ack_frame(vd); -- } -- break; -- default: -- LLDPAD_DBG("%s:%s ECP RX state machine in invalid state %d\n", -- __func__, vd->ecp.ifname, vd->ecp.rx.state); -- } -- } while (ecp_set_rx_state(vd) == true); --} -diff --git a/lldp_evb.c b/lldp_evb.c -index c5c52bb..4b3752e 100644 ---- a/lldp_evb.c -+++ b/lldp_evb.c -@@ -32,7 +32,7 @@ - #include "lldp_tlv.h" - #include "lldp_evb.h" - #include "lldp_evb_cmds.h" --#include "lldp_vdp.h" -+#include "qbg_vdp.h" - #include "messages.h" - #include "config.h" - -diff --git a/lldp_evb22.c b/lldp_evb22.c -new file mode 100644 -index 0000000..1b1dc4f ---- /dev/null -+++ b/lldp_evb22.c -@@ -0,0 +1,559 @@ -+/****************************************************************************** -+ -+ Implementation of EVB TLVs for LLDP -+ (c) Copyright IBM Corp. 2012 -+ -+ Author(s): Thomas Richter -+ -+ This program is free software; you can redistribute it and/or modify it -+ under the terms and conditions of the GNU General Public License, -+ version 2, as published by the Free Software Foundation. -+ -+ This program is distributed in the hope it will be useful, but WITHOUT -+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ more details. -+ -+ You should have received a copy of the GNU General Public License along with -+ this program; if not, write to the Free Software Foundation, Inc., -+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. -+ -+ The full GNU General Public License is included in this distribution in -+ the file called "COPYING". -+ -+******************************************************************************/ -+ -+#define _GNU_SOURCE -+#include -+#include -+ -+#include "lldp.h" -+#include "lldp_tlv.h" -+#include "lldp_evb22.h" -+#include "qbg_ecp22.h" -+#include "qbg_vdp22.h" -+#include "qbg_utils.h" -+#include "lldp_evb_cmds.h" -+#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); -+ if (ud) { -+ LIST_FOREACH(ed, &ud->head, entry) { -+ if (!strncmp(ifname, ed->ifname, IFNAMSIZ) && -+ (type == ed->agenttype)) -+ break; -+ } -+ } -+ return ed; -+} -+ -+static void evb22_format_tlv(char *buf, size_t len, struct evb22_tlv *tlv) -+{ -+ int comma = 0; -+ char bridge_txt[32], station_txt[32]; -+ -+ memset(bridge_txt, 0, sizeof bridge_txt); -+ if (evb_ex_bgid(tlv->bridge_s)) { -+ strcat(bridge_txt, "bgid"); -+ comma = 1; -+ } -+ if (evb_ex_rrcap(tlv->bridge_s)) { -+ if (comma) -+ strcat(bridge_txt, ","); -+ strcat(bridge_txt, "rrcap"); -+ comma = 1; -+ } -+ if (evb_ex_rrctr(tlv->bridge_s)) { -+ if (comma) -+ strcat(bridge_txt, ","); -+ strcat(bridge_txt, "rrctr"); -+ } -+ -+ comma = 0; -+ memset(station_txt, 0, sizeof station_txt); -+ if (evb_ex_sgid(tlv->station_s)) { -+ strcat(station_txt, "sgid"); -+ comma = 1; -+ } -+ if (evb_ex_rrreq(tlv->station_s)) { -+ if (comma) -+ strcat(station_txt, ","); -+ strcat(station_txt, "rrreq"); -+ comma = 1; -+ } -+ if (evb_ex_rrstat(tlv->station_s)) { -+ if (comma) -+ strcat(station_txt, ","); -+ strcat(station_txt, "rrstat"); -+ } -+ snprintf(buf, len, "bridge:%s(%#02x) station:%s(%#02x) " -+ "retries:%d rte:%d mode:%d r/l:%d rwd:%d " -+ "r/l:%d rka:%d", bridge_txt, tlv->bridge_s, -+ station_txt, tlv->station_s, -+ evb_ex_retries(tlv->r_rte), evb_ex_rte(tlv->r_rte), -+ evb_ex_evbmode(tlv->evb_mode), evb_ex_rol(tlv->evb_mode), -+ evb_ex_rwd(tlv->evb_mode), -+ evb_ex_rol(tlv->rl_rka), evb_ex_rka(tlv->rl_rka)); -+} -+ -+static void evb22_print_tlvinfo(char *ifname, struct evb22_tlv *tlv) -+{ -+ char buf[256]; -+ -+ evb22_format_tlv(buf, sizeof buf, tlv); -+ LLDPAD_DBG("%s evb %s\n", ifname, buf); -+} -+ -+static void evb22_dump_tlv(char *ifname, struct unpacked_tlv *tlv) -+{ -+ int i, left = 0; -+ char buffer[256]; -+ -+ for (i = 0; i < tlv->length; i++) { -+ int c; -+ -+ c = snprintf(buffer + left, -+ sizeof buffer - left, -+ "%02x ", tlv->info[i]); -+ -+ if (c < 0 || (c >= (int)sizeof buffer - left)) -+ break; -+ else -+ left += c; -+ } -+ -+ LLDPAD_DBG("%s:%s type %i length %i info %s\n", -+ __func__, ifname, tlv->type, tlv->length, buffer); -+} -+ -+static void common_tlv(struct evb22_data *ed) -+{ -+ struct evb22_tlv *recv = &ed->last; -+ struct evb22_tlv *mine = &ed->policy; -+ u8 val; -+ -+ /* Set retries and rte value */ -+ val = evb_ex_retries(recv->r_rte); -+ if (evb_ex_retries(mine->r_rte) > val) -+ val = evb_ex_retries(mine->r_rte); -+ ed->out.r_rte = evb_set_retries(val); -+ val = evb_ex_rte(recv->r_rte); -+ if (evb_ex_rte(mine->r_rte) > val) -+ val = evb_ex_rte(mine->r_rte); -+ ed->out.r_rte |= evb_set_rte(val); -+ -+ /* Set evbmode */ -+ ed->out.evb_mode = evb_set_evbmode(evb_ex_evbmode(mine->evb_mode)); -+ val = evb_ex_rwd(recv->evb_mode); -+ if (evb_ex_rwd(mine->evb_mode) > val) -+ val = evb_ex_rwd(mine->evb_mode); -+ else -+ ed->out.evb_mode |= evb_set_rol(1); -+ ed->out.evb_mode |= evb_set_rwd(val); -+ -+ /* Set rka */ -+ ed->out.rl_rka = 0; -+ val = evb_ex_rka(recv->rl_rka); -+ if (evb_ex_rka(mine->rl_rka) > val) -+ val = evb_ex_rka(mine->rl_rka); -+ else -+ ed->out.rl_rka = evb_set_rol(1); -+ ed->out.rl_rka |= evb_set_rka(val); -+} -+ -+/* -+ * Fill the EVB DU for LLDP transmition. Sender is bridge. -+ */ -+static void bridge_tlv(struct evb22_data *ed) -+{ -+ struct evb22_tlv *recv = &ed->last; -+ struct evb22_tlv *mine = &ed->policy; -+ -+ /* Copy my last station status */ -+ ed->out.station_s = recv->station_s; -+ -+ /* Set bridge status */ -+ ed->out.bridge_s = mine->bridge_s; -+ if (evb_ex_rrreq(recv->station_s) && evb_ex_rrcap(mine->bridge_s)) -+ ed->out.bridge_s |= evb_set_rrctr(1); -+ common_tlv(ed); -+} -+ -+/* -+ * Fill the EVB DU for LLDP transmition. Sender is station. -+ */ -+static void station_tlv(struct evb22_data *ed) -+{ -+ struct evb22_tlv *recv = &ed->last; -+ struct evb22_tlv *mine = &ed->policy; -+ u8 val; -+ -+ /* Copy my last bridge status */ -+ ed->out.bridge_s = recv->bridge_s; -+ -+ /* -+ * Set station status, 2nd byte of OUI is 0x80. If 0x00 -+ * nothing received from bridge. -+ */ -+ if (recv->oui[1] == 0) -+ val = EVB_RRSTAT_DONT; -+ else if (evb_ex_rrctr(recv->bridge_s)) -+ val = EVB_RRSTAT_YES; -+ else -+ val = EVB_RRSTAT_NO; -+ ed->out.station_s = evb_maskoff_rrstat(mine->station_s) -+ | evb_set_rrstat(val); -+ common_tlv(ed); -+} -+ -+/* -+ * Checks values received in TLV and takes over some values. -+ * Sets the new suggestion in member tie to be send out to switch. -+ * -+ * Also notify depending modules about the new values. -+ */ -+static void evb22_update_tlv(struct evb22_data *ed) -+{ -+ struct qbg22_imm qbg; -+ -+ if (evb_ex_evbmode(ed->policy.evb_mode) == EVB_STATION) -+ station_tlv(ed); -+ else -+ bridge_tlv(ed); -+ -+ qbg.data_type = EVB22_TO_ECP22; -+ qbg.u.a.max_rte = evb_ex_rte(ed->out.r_rte); -+ qbg.u.a.max_retry = evb_ex_retries(ed->out.r_rte); -+ modules_notify(LLDP_MOD_ECP22, LLDP_MOD_EVB22, ed->ifname, &qbg); -+ -+ qbg.data_type = EVB22_TO_VDP22; -+ qbg.u.b.max_rka = evb_ex_rka(ed->out.rl_rka); -+ qbg.u.b.max_rwd = evb_ex_rwd(ed->out.evb_mode); -+ qbg.u.b.max_rte = evb_ex_rte(ed->out.r_rte); -+ qbg.u.b.max_retry = evb_ex_retries(ed->out.r_rte); -+ /* Support group identifiers when advertised by both sides */ -+ qbg.u.b.gpid = evb_ex_bgid(ed->out.bridge_s) -+ && evb_ex_sgid(ed->out.station_s); -+ modules_notify(LLDP_MOD_VDP22, LLDP_MOD_EVB22, ed->ifname, &qbg); -+} -+ -+/* -+ * Build the packed EVB TLV. -+ * Returns a pointer to the packed tlv or 0 on failure. -+ */ -+static struct packed_tlv *evb22_build_tlv(struct evb22_data *ed) -+{ -+ struct packed_tlv *ptlv = 0; -+ u8 infobuf[sizeof(struct evb22_tlv)]; -+ struct unpacked_tlv tlv = { -+ .type = ORG_SPECIFIC_TLV, -+ .length = sizeof(struct evb22_tlv), -+ .info = infobuf -+ }; -+ -+ evb22_update_tlv(ed); -+ memcpy(tlv.info, &ed->out, tlv.length); -+ ptlv = pack_tlv(&tlv); -+ if (ptlv) { -+ LLDPAD_DBG("%s:%s TLV about to be sent out:\n", __func__, -+ ed->ifname); -+ evb22_dump_tlv(ed->ifname, &tlv); -+ } else -+ LLDPAD_DBG("%s:%s failed to pack EVB TLV\n", __func__, -+ ed->ifname); -+ return ptlv; -+} -+ -+/* -+ * Function call to build and return module specific packed EVB TLV. -+ * Returned packed_tlv is free'ed by caller of this function. -+ */ -+static struct packed_tlv *evb22_gettlv(struct port *port, -+ struct lldp_agent *agent) -+{ -+ struct evb22_data *ed; -+ -+ if (agent->type != NEAREST_CUSTOMER_BRIDGE) -+ return 0; -+ ed = evb22_data(port->ifname, agent->type); -+ if (!ed) { -+ LLDPAD_ERR("%s:%s agent %d failed\n", __func__, port->ifname, -+ agent->type); -+ return 0; -+ } -+ return (ed->txmit) ? evb22_build_tlv(ed) : 0; -+} -+ -+/* -+ * evb_rchange: process received EVB TLV LLDPDU -+ * -+ * TLV not consumed on error -+ */ -+static int evb22_rchange(struct port *port, struct lldp_agent *agent, -+ struct unpacked_tlv *tlv) -+{ -+ struct evb22_data *ed; -+ u8 oui_subtype[OUI_SUB_SIZE] = LLDP_MOD_EVB22_OUI; -+ -+ if (agent->type != NEAREST_CUSTOMER_BRIDGE) -+ return 0; -+ ed = evb22_data(port->ifname, agent->type); -+ -+ if (!ed) -+ return SUBTYPE_INVALID; -+ -+ if (tlv->type == TYPE_127) { -+ /* check for length */ -+ if (tlv->length < OUI_SUB_SIZE) -+ return TLV_ERR; -+ -+ /* check for oui */ -+ if (memcmp(tlv->info, &oui_subtype, OUI_SUB_SIZE)) -+ return SUBTYPE_INVALID; -+ -+ /* disable rx if tx has been disabled by administrator */ -+ if (!ed->txmit) { -+ LLDPAD_WARN("%s:%s agent %d EVB Config disabled\n", -+ __func__, ed->ifname, agent->type); -+ return TLV_OK; -+ } -+ -+ LLDPAD_DBG("%s:%s agent %d received tlv:\n", __func__, -+ port->ifname, agent->type); -+ evb22_dump_tlv(ed->ifname, tlv); -+ memcpy(&ed->last, tlv->info, tlv->length); -+ evb22_print_tlvinfo(ed->ifname, &ed->last); -+ -+ evb22_update_tlv(ed); -+ somethingChangedLocal(ed->ifname, agent->type); -+ -+ LLDPAD_DBG("%s:%s agent %d new tlv:\n", __func__, port->ifname, -+ agent->type); -+ evb22_print_tlvinfo(ed->ifname, &ed->out); -+ /* TODO vdp_update(port->ifname, ed->tie.ccap); */ -+ } -+ return TLV_OK; -+} -+ -+/* -+ * Stop all modules which depend on EVB capabilities. -+ */ -+static void evb22_stop_modules(char *ifname) -+{ -+ LLDPAD_DBG("%s:%s STOP\n", __func__, ifname); -+ ecp22_stop(ifname); -+ vdp22_stop(ifname); -+} -+ -+static void evb22_ifdown(char *ifname, struct lldp_agent *agent) -+{ -+ struct evb22_data *ed; -+ -+ if (agent->type != NEAREST_CUSTOMER_BRIDGE) -+ return; -+ LLDPAD_DBG("%s:%s agent %d called\n", __func__, ifname, agent->type); -+ -+ ed = evb22_data(ifname, agent->type); -+ if (!ed) { -+ LLDPAD_DBG("%s:%s agent %d does not exist.\n", __func__, -+ ifname, agent->type); -+ return; -+ } -+ if (ed->vdp_start) -+ evb22_stop_modules(ifname); -+ LIST_REMOVE(ed, entry); -+ free(ed); -+ LLDPAD_INFO("%s:%s agent %d removed\n", __func__, ifname, agent->type); -+} -+ -+/* -+ * Fill up evb structure with reasonable info from the configuration file. -+ */ -+static void evb22_init_tlv(struct evb22_data *ed, struct lldp_agent *agent) -+{ -+ u8 mode; -+ -+ memset(&ed->last, 0, sizeof ed->last); -+ memset(&ed->out, 0, sizeof ed->out); -+ memset(&ed->policy, 0, sizeof ed->policy); -+ -+ ed->txmit = evb22_conf_enabletx(ed->ifname, agent->type); -+ if (!ed->txmit) -+ LLDPAD_DBG("%s:%s agent %d EVB tx is currently disabled\n", -+ __func__, ed->ifname, agent->type); -+ -+ hton24(ed->policy.oui, LLDP_MOD_EVB22); -+ ed->policy.sub = LLDP_MOD_EVB22_SUBTYPE; -+ hton24(ed->out.oui, LLDP_MOD_EVB22); -+ ed->out.sub = LLDP_MOD_EVB22_SUBTYPE; -+ -+ mode = evb22_conf_evbmode(ed->ifname, agent->type); -+ ed->policy.evb_mode = evb_set_rol(0) -+ | evb_set_rwd(evb22_conf_rwd(ed->ifname, agent->type)) -+ | evb_set_evbmode(mode); -+ if (mode == EVB_STATION) { -+ mode = evb22_conf_rrreq(ed->ifname, agent->type); -+ ed->policy.station_s = evb_set_rrstat(EVB_RRSTAT_DONT) -+ | evb_set_sgid(evb22_conf_gid(ed->ifname, agent->type)) -+ | evb_set_rrreq(mode); -+ ed->policy.bridge_s = 0; -+ } else { -+ mode = evb22_conf_rrcap(ed->ifname, agent->type); -+ ed->policy.bridge_s = evb_set_rrcap(mode) -+ | evb_set_bgid(evb22_conf_gid(ed->ifname, agent->type)); -+ ed->policy.station_s = 0; -+ } -+ ed->policy.r_rte = -+ evb_set_retries(evb22_conf_retries(ed->ifname, agent->type)) -+ | evb_set_rte(evb22_conf_rte(ed->ifname, agent->type)); -+ ed->policy.rl_rka = evb_set_rol(0) -+ | evb_set_rka(evb22_conf_rka(ed->ifname, agent->type)); -+} -+ -+static void evb22_ifup(char *ifname, struct lldp_agent *agent) -+{ -+ struct evb22_data *ed; -+ struct evb22_user_data *ud; -+ -+ if (agent->type != NEAREST_CUSTOMER_BRIDGE) -+ return; -+ LLDPAD_DBG("%s:%s agent %d called\n", __func__, ifname, agent->type); -+ -+ ed = evb22_data(ifname, agent->type); -+ if (ed) { -+ LLDPAD_DBG("%s:%s agent %d already exists\n", __func__, ifname, -+ agent->type); -+ return; -+ } -+ -+ /* not found, alloc/init per-port tlv data */ -+ ed = (struct evb22_data *) calloc(1, sizeof *ed); -+ if (!ed) { -+ LLDPAD_ERR("%s:%s agent %d malloc %zu failed\n", -+ __func__, ifname, agent->type, sizeof *ed); -+ return; -+ } -+ strncpy(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); -+ LIST_INSERT_HEAD(&ud->head, ed, entry); -+ LLDPAD_DBG("%s:%s agent %d added\n", __func__, ifname, agent->type); -+} -+ -+/* -+ * Start all modules which depend on EVB capabilities: ECP, VDP, CDCP. -+ */ -+static void evb22_start_modules(char *ifname, int role) -+{ -+ LLDPAD_DBG("%s:%s START role:%d\n", __func__, ifname, role); -+ ecp22_start(ifname); -+ vdp22_start(ifname, role); -+} -+ -+/* -+ * Check for stable interfaces. When an interface goes up the carrier might -+ * come and go during a start up time. Define a window during which the port -+ * is considered unstable for EVB/VDP protocols. -+ * -+ * Use the dormantDelay counter of the port to determine a stable interface. -+ */ -+static int evb22_timer(struct port *port, struct lldp_agent *agent) -+{ -+ struct evb22_data *ed; -+ -+ if (agent->type != NEAREST_CUSTOMER_BRIDGE) -+ return 0; -+ ed = evb22_data(port->ifname, agent->type); -+ if (!ed) -+ return 0; -+ if (!ed->vdp_start -+ && evb_ex_rrstat(ed->out.station_s) == EVB_RRSTAT_YES) { -+ ed->vdp_start = true; -+ evb22_start_modules(port->ifname, -+ evb_ex_evbmode(ed->policy.evb_mode)); -+ } -+ return 0; -+} -+ -+static u8 evb22_mibdelete(struct port *port, struct lldp_agent *agent) -+{ -+ struct evb22_data *ed; -+ -+ ed = evb22_data(port->ifname, agent->type); -+ if (ed && (agent->type == ed->agenttype)) { -+ memset(&ed->last, 0, sizeof ed->last); -+ /* TODO vdp_update(port->ifname, 0); */ -+ } -+ return 0; -+} -+ -+/* -+ * Remove all interface/agent specific evb data. -+ */ -+static void evb22_free_data(struct evb22_user_data *ud) -+{ -+ struct evb22_data *ed; -+ -+ if (ud) { -+ while (!LIST_EMPTY(&ud->head)) { -+ ed = LIST_FIRST(&ud->head); -+ LIST_REMOVE(ed, entry); -+ free(ed); -+ } -+ } -+} -+ -+void evb22_unregister(struct lldp_module *mod) -+{ -+ if (mod->data) { -+ evb22_free_data((struct evb22_user_data *) mod->data); -+ free(mod->data); -+ } -+ free(mod); -+ LLDPAD_DBG("%s:done\n", __func__); -+} -+ -+static const struct lldp_mod_ops evb22_ops = { -+ .lldp_mod_gettlv = evb22_gettlv, -+ .lldp_mod_rchange = evb22_rchange, -+ .lldp_mod_mibdelete = evb22_mibdelete, -+ .timer = evb22_timer, -+ .lldp_mod_ifdown = evb22_ifdown, -+ .lldp_mod_ifup = evb22_ifup, -+ .lldp_mod_register = evb22_register, -+ .lldp_mod_unregister = evb22_unregister, -+ .get_arg_handler = evb22_get_arg_handlers -+}; -+ -+struct lldp_module *evb22_register(void) -+{ -+ struct lldp_module *mod; -+ struct evb22_user_data *ud; -+ -+ mod = calloc(1, sizeof *mod); -+ if (!mod) { -+ LLDPAD_ERR("%s: failed to malloc module data\n", __func__); -+ return NULL; -+ } -+ ud = calloc(1, sizeof *ud); -+ if (!ud) { -+ free(mod); -+ LLDPAD_ERR("%s failed to malloc module user data\n", __func__); -+ return NULL; -+ } -+ LIST_INIT(&ud->head); -+ mod->id = LLDP_MOD_EVB22; -+ mod->ops = &evb22_ops; -+ mod->data = ud; -+ LLDPAD_DBG("%s:done\n", __func__); -+ return mod; -+} -diff --git a/lldp_evb22_clif.c b/lldp_evb22_clif.c -new file mode 100644 -index 0000000..336273f ---- /dev/null -+++ b/lldp_evb22_clif.c -@@ -0,0 +1,201 @@ -+/****************************************************************************** -+ -+ Implementation of EVB TLVs for LLDP -+ (c) Copyright IBM Corp. 2010, 2012 -+ -+ Author(s): Thomas Richter -+ -+ This program is free software; you can redistribute it and/or modify it -+ under the terms and conditions of the GNU General Public License, -+ version 2, as published by the Free Software Foundation. -+ -+ This program is distributed in the hope it will be useful, but WITHOUT -+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ more details. -+ -+ You should have received a copy of the GNU General Public License along with -+ this program; if not, write to the Free Software Foundation, Inc., -+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. -+ -+ The full GNU General Public License is included in this distribution in -+ the file called "COPYING". -+ -+******************************************************************************/ -+ -+#include -+#include -+ -+#include "lldp_tlv.h" -+#include "clif_msgs.h" -+#include "lldp_mod.h" -+#include "lldptool.h" -+#include "lldp.h" -+#include "lldp_evb22.h" -+#include "lldp_evb22_clif.h" -+ -+static void show_tlv(char *buf, size_t len, struct evb22_tlv *tlv) -+{ -+ int comma = 0; -+ char bridge_txt[32], station_txt[32]; -+ -+ memset(bridge_txt, 0, sizeof bridge_txt); -+ if (evb_ex_bgid(tlv->bridge_s)) { -+ strcat(bridge_txt, "bgid"); -+ comma = 1; -+ } -+ if (evb_ex_rrcap(tlv->bridge_s)) { -+ if (comma) -+ strcat(bridge_txt, ","); -+ strcat(bridge_txt, "rrcap"); -+ comma = 1; -+ } -+ if (evb_ex_rrctr(tlv->bridge_s)) { -+ if (comma) -+ strcat(bridge_txt, ","); -+ strcat(bridge_txt, "rrctr"); -+ } -+ -+ comma = 0; -+ memset(station_txt, 0, sizeof station_txt); -+ if (evb_ex_sgid(tlv->station_s)) { -+ strcat(station_txt, "sgid"); -+ comma = 1; -+ } -+ if (evb_ex_rrreq(tlv->station_s)) { -+ if (comma) -+ strcat(station_txt, ","); -+ strcat(station_txt, "rrreq"); -+ comma = 1; -+ } -+ if (evb_ex_rrstat(tlv->station_s)) { -+ if (comma) -+ strcat(station_txt, ","); -+ strcat(station_txt, "rrstat"); -+ } -+ -+ snprintf(buf, len, "bridge:%s(%#02x)\n" -+ "\tstation:%s(%#02x)\n" -+ "\tretries:%d rte:%d\n" -+ "\tmode:%s r/l:%d rwd:%d\n" -+ "\tr/l:%d rka:%d\n", -+ bridge_txt, tlv->bridge_s, -+ station_txt, tlv->station_s, -+ evb_ex_retries(tlv->r_rte), evb_ex_rte(tlv->r_rte), -+ evb_ex_evbmode(tlv->evb_mode) == EVB_STATION ? -+ "station" : "bridge", -+ evb_ex_rol(tlv->evb_mode), -+ evb_ex_rwd(tlv->evb_mode), -+ evb_ex_rol(tlv->rl_rka), evb_ex_rka(tlv->rl_rka)); -+} -+ -+static void evb22_print_cfg_tlv(u16 len, char *info) -+{ -+ struct evb22_tlv tlv; -+ char buf[256]; -+ -+ if (len != 5) { -+ printf("Bad evbcfg TLV: %s\n", info); -+ return; -+ } -+ memset(&tlv, 0, sizeof tlv); -+ memset(buf, 0, sizeof buf); -+ hexstr2bin(&info[0], &tlv.bridge_s, sizeof tlv.bridge_s); -+ hexstr2bin(&info[2], &tlv.station_s, sizeof tlv.station_s); -+ hexstr2bin(&info[4], &tlv.r_rte, sizeof tlv.r_rte); -+ hexstr2bin(&info[6], &tlv.evb_mode, sizeof tlv.evb_mode); -+ hexstr2bin(&info[8], &tlv.rl_rka, sizeof tlv.rl_rka); -+ show_tlv(buf, sizeof buf, &tlv); -+ printf("%s", buf); -+} -+ -+static struct type_name_info evb22_tlv_names[] = { -+ { -+ .type = TLVID(OUI_IEEE_8021Qbg22, LLDP_EVB22_SUBTYPE), -+ .name = "EVB Configuration TLV", -+ .key = "evb", -+ .print_info = evb22_print_cfg_tlv -+ }, -+ { -+ .type = INVALID_TLVID -+ } -+}; -+ -+static int evb22_print_help() -+{ -+ struct type_name_info *tn = &evb22_tlv_names[0]; -+ -+ while (tn->type != INVALID_TLVID) { -+ if (tn->key && strlen(tn->key) && tn->name) { -+ printf(" %s", tn->key); -+ if (strlen(tn->key)+3 < 8) -+ printf("\t"); -+ printf("\t: %s\n", tn->name); -+ } -+ tn++; -+ } -+ -+ return 0; -+} -+ -+static void evb22_cli_unregister(struct lldp_module *mod) -+{ -+ free(mod); -+} -+ -+/* return 1: if it printed the TLV -+ * 0: if it did not -+ */ -+static int evb22_print_tlv(u32 tlvid, u16 len, char *info) -+{ -+ struct type_name_info *tn = &evb22_tlv_names[0]; -+ -+ while (tn->type != INVALID_TLVID) { -+ if (tlvid == tn->type) { -+ printf("%s\n", tn->name); -+ if (tn->print_info) { -+ printf("\t"); -+ tn->print_info(len-4, info); -+ } -+ return 1; -+ } -+ tn++; -+ } -+ -+ return 0; -+} -+ -+static u32 evb22_lookup_tlv_name(char *tlvid_str) -+{ -+ struct type_name_info *tn = &evb22_tlv_names[0]; -+ -+ while (tn->type != INVALID_TLVID) { -+ if (!strcasecmp(tn->key, tlvid_str)) -+ return tn->type; -+ tn++; -+ } -+ return INVALID_TLVID; -+} -+ -+static const struct lldp_mod_ops evb22_ops_clif = { -+ .lldp_mod_register = evb22_cli_register, -+ .lldp_mod_unregister = evb22_cli_unregister, -+ .print_tlv = evb22_print_tlv, -+ .lookup_tlv_name = evb22_lookup_tlv_name, -+ .print_help = evb22_print_help -+}; -+ -+struct lldp_module *evb22_cli_register(void) -+{ -+ struct lldp_module *mod; -+ -+ mod = calloc(1, sizeof(*mod)); -+ if (!mod) { -+ fprintf(stderr, "%s failed to malloc module data\n", __func__); -+ return NULL; -+ } -+ mod->id = LLDP_MOD_EVB22; -+ mod->ops = &evb22_ops_clif; -+ -+ return mod; -+} -diff --git a/lldp_evb22_cmds.c b/lldp_evb22_cmds.c -new file mode 100644 -index 0000000..51b7ba1 ---- /dev/null -+++ b/lldp_evb22_cmds.c -@@ -0,0 +1,738 @@ -+/****************************************************************************** -+ -+ Implementation of EVB TLVs for LLDP -+ (c) Copyright IBM Corp. 2012 -+ -+ Author(s): Thomas Richter -+ -+ This program is free software; you can redistribute it and/or modify it -+ under the terms and conditions of the GNU General Public License, -+ version 2, as published by the Free Software Foundation. -+ -+ This program is distributed in the hope it will be useful, but WITHOUT -+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ more details. -+ -+ You should have received a copy of the GNU General Public License along with -+ this program; if not, write to the Free Software Foundation, Inc., -+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. -+ -+ The full GNU General Public License is included in this distribution in -+ the file called "COPYING". -+ -+******************************************************************************/ -+ -+#define _GNU_SOURCE -+ -+#include -+#include -+#include -+ -+#include "lldp.h" -+#include "lldp_evb22.h" -+#include "lldp_tlv.h" -+#include "lldp_mand_clif.h" -+#include "config.h" -+#include "clif_msgs.h" -+#include "messages.h" -+ -+/* -+ * Defines for configuration file name tags. -+ */ -+#define EVB_BUF_SIZE 256 -+#define EVB_CONF_MODE "evbmode" -+#define EVB_CONF_RRREQ "evbrrreq" -+#define EVB_CONF_RRCAP "evbrrcap" -+#define EVB_CONF_GPID "evbgpid" -+#define EVB_CONF_RETRIES "ecpretries" -+#define EVB_CONF_RTE "ecprte" -+#define EVB_CONF_RWD "vdprwd" -+#define EVB_CONF_RKA "vdprka" -+#define EVB_CONF_BRIDGE "bridge" -+#define EVB_CONF_STATION "station" -+ -+/* -+ * Read EVB specific data from the configuration file. -+ */ -+static const char *evb22_conf_string(char *ifname, enum agent_type type, -+ char *ext, int def) -+{ -+ char arg_path[EVB_BUF_SIZE]; -+ const char *param = NULL; -+ -+ snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", -+ TLVID_PREFIX, TLVID(OUI_IEEE_8021Qbg22, LLDP_EVB22_SUBTYPE), -+ ext); -+ if (get_cfg(ifname, type, arg_path, ¶m, CONFIG_TYPE_STRING)) -+ LLDPAD_INFO("%s:%s agent %d loading EVB policy for %s" -+ " failed, using default (%d)\n", __func__, -+ ifname, type, ext, def); -+ return param; -+} -+ -+static int evb22_conf_int(char *ifname, enum agent_type type, -+ char *ext, int def, int cfgtype) -+{ -+ char arg_path[EVB_BUF_SIZE]; -+ int param; -+ -+ snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", -+ TLVID_PREFIX, TLVID(OUI_IEEE_8021Qbg22, LLDP_EVB22_SUBTYPE), -+ ext); -+ if (get_cfg(ifname, type, arg_path, ¶m, cfgtype)) { -+ LLDPAD_INFO("%s:%s agent %d loading EVB policy for %s" -+ " failed, using default (%d)\n", __func__, -+ ifname, type, ext, def); -+ return def; -+ } -+ return param; -+} -+ -+/* -+ * Read EXP parameter. Defaults to 8 --> 10 * 2 ^ 8 = 2560us > 2ms. -+ */ -+static int exponent(char *ifname, enum agent_type type, char *txt, int def) -+{ -+ int value; -+ -+ value = evb22_conf_int(ifname, type, txt, def, CONFIG_TYPE_INT); -+ if (value > 31) { -+ LLDPAD_DBG("%s:%s agent %d invalid %s %d\n", __func__, -+ ifname, type, txt, value); -+ value = def; -+ } -+ LLDPAD_DBG("%s:%s agent %d policy %s %d\n", __func__, -+ ifname, type, txt, value); -+ return value; -+} -+ -+/* -+ * Read retransmission exponent parameter. -+ */ -+int evb22_conf_rte(char *ifname, enum agent_type type) -+{ -+ return exponent(ifname, type, EVB_CONF_RTE, 8); -+} -+ -+/* -+ * Read reinit keep alive parameter. Same as RTE. -+ */ -+int evb22_conf_rka(char *ifname, enum agent_type type) -+{ -+ return exponent(ifname, type, EVB_CONF_RKA, 20); -+} -+ -+/* -+ * Read resource wait delay parameter. Same as RTE. -+ */ -+int evb22_conf_rwd(char *ifname, enum agent_type type) -+{ -+ return exponent(ifname, type, EVB_CONF_RWD, 20); -+} -+ -+/* -+ * Read max retries parameter. Defaults to 3. -+ */ -+int evb22_conf_retries(char *ifname, enum agent_type type) -+{ -+ int value; -+ -+ value = evb22_conf_int(ifname, type, EVB_CONF_RETRIES, 3, -+ CONFIG_TYPE_INT); -+ if (value > 7) { -+ LLDPAD_DBG("%s:%s agent %d invalid %s %d\n", __func__, -+ ifname, type, EVB_CONF_RETRIES, value); -+ value = 3; -+ } -+ LLDPAD_DBG("%s:%s agent %d policy %s %d\n", __func__, -+ ifname, type, EVB_CONF_RETRIES, value); -+ return value; -+} -+ -+/* -+ * Read station group id parameter. Defaults to false. -+ */ -+int evb22_conf_gid(char *ifname, enum agent_type type) -+{ -+ int value; -+ -+ value = evb22_conf_int(ifname, type, EVB_CONF_GPID, false, -+ CONFIG_TYPE_BOOL); -+ LLDPAD_DBG("%s:%s agent %d policy %s %s\n", __func__, -+ ifname, type, EVB_CONF_GPID, value ? "true" : "false"); -+ return value; -+} -+ -+/* -+ * Read reflective-relay bridge capability parameter. Defaults to false. -+ */ -+int evb22_conf_rrcap(char *ifname, enum agent_type type) -+{ -+ int value; -+ -+ value = evb22_conf_int(ifname, type, EVB_CONF_RRCAP, false, -+ CONFIG_TYPE_BOOL); -+ LLDPAD_DBG("%s:%s agent %d policy %s %s\n", __func__, -+ ifname, type, EVB_CONF_RRCAP, value ? "true" : "false"); -+ return value; -+} -+ -+/* -+ * Read reflective-relay station request parameter. Defaults to false. -+ */ -+int evb22_conf_rrreq(char *ifname, enum agent_type type) -+{ -+ int value; -+ -+ value = evb22_conf_int(ifname, type, EVB_CONF_RRREQ, false, -+ CONFIG_TYPE_BOOL); -+ LLDPAD_DBG("%s:%s agent %d policy %s %s\n", __func__, -+ ifname, type, EVB_CONF_RRREQ, value ? "true" : "false"); -+ return value; -+} -+ -+/* -+ * Read station/bridge role from configuration file. Defaults to station -+ */ -+int evb22_conf_evbmode(char *ifname, enum agent_type type) -+{ -+ int mode = EVB_STATION; -+ const char *value; -+ -+ value = evb22_conf_string(ifname, type, EVB_CONF_MODE, mode); -+ if (value) { -+ if (!strcasecmp(value, EVB_CONF_BRIDGE)) -+ mode = EVB_BRIDGE; -+ else if (strcasecmp(value, EVB_CONF_STATION)) { -+ LLDPAD_ERR("%s:%s agent %d invalid evbmode %s\n", -+ __func__, ifname, type, value); -+ value = EVB_CONF_STATION; -+ } -+ } else -+ value = EVB_CONF_STATION; -+ LLDPAD_DBG("%s:%s agent %d policy %s %s(%#x)\n", __func__, -+ ifname, type, EVB_CONF_MODE, value, mode); -+ return mode; -+} -+ -+/* -+ * Read transmit status from configuration file. -+ */ -+int evb22_conf_enabletx(char *ifname, enum agent_type type) -+{ -+ return is_tlv_txenabled(ifname, type, -+ TLVID(OUI_IEEE_8021Qbg22, LLDP_EVB22_SUBTYPE)); -+} -+ -+static int evb22_cmdok(struct cmd *cmd, cmd_status expected) -+{ -+ if (cmd->cmd != expected) -+ return cmd_invalid; -+ switch (cmd->tlvid) { -+ case TLVID(OUI_IEEE_8021Qbg22, LLDP_EVB22_SUBTYPE): -+ return cmd_success; -+ case INVALID_TLVID: -+ return cmd_invalid; -+ default: -+ return cmd_not_applicable; -+ } -+} -+ -+static int get_arg_evbmode(struct cmd *cmd, char *arg, UNUSED char *argvalue, -+ char *obuf, int obuf_len) -+{ -+ struct evb22_data *ed; -+ char *s; -+ cmd_status good_cmd = evb22_cmdok(cmd, cmd_gettlv); -+ -+ if (good_cmd != cmd_success) -+ return good_cmd; -+ ed = evb22_data((char *) &cmd->ifname, cmd->type); -+ if (!ed) -+ return cmd_invalid; -+ if (evb_ex_evbmode(ed->policy.evb_mode) == EVB_STATION) -+ s = EVB_CONF_STATION; -+ else -+ s = EVB_CONF_BRIDGE; -+ snprintf(obuf, obuf_len, "%02x%s%04x%s", -+ (unsigned int)strlen(arg), arg, (unsigned int)strlen(s), s); -+ return cmd_success; -+} -+ -+static int set2_arg_evbmode(struct cmd *cmd, char *arg, const char *argvalue, -+ bool test) -+{ -+ char arg_path[EVB_BUF_SIZE]; -+ struct evb22_data *ed; -+ cmd_status good_cmd = evb22_cmdok(cmd, cmd_settlv); -+ u8 mode; -+ -+ if (good_cmd != cmd_success) -+ return good_cmd; -+ if (strcasecmp(argvalue, EVB_CONF_BRIDGE) -+ && strcasecmp(argvalue, EVB_CONF_STATION)) -+ return cmd_bad_params; -+ ed = evb22_data((char *) &cmd->ifname, cmd->type); -+ if (!ed) -+ return cmd_invalid; -+ if (test) -+ return cmd_success; -+ snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", -+ TLVID_PREFIX, cmd->tlvid, arg); -+ -+ if (set_cfg(cmd->ifname, cmd->type, arg_path, &argvalue, -+ CONFIG_TYPE_STRING)) { -+ LLDPAD_ERR("%s: error saving EVB mode (%s)\n", ed->ifname, -+ argvalue); -+ return cmd_failed; -+ } -+ mode = strcasecmp(argvalue, EVB_CONF_BRIDGE) ? EVB_STATION : EVB_BRIDGE; -+ ed->policy.evb_mode = evb_maskoff_evbmode(ed->policy.evb_mode) | -+ evb_set_evbmode(mode); -+ LLDPAD_INFO("%s: changed EVB mode (%s)\n", ed->ifname, argvalue); -+ return cmd_success; -+} -+ -+static int set_arg_evbmode(struct cmd *cmd, char *arg, char *argvalue, -+ UNUSED char *obuf, UNUSED int obuf_len) -+{ -+ return set2_arg_evbmode(cmd, arg, argvalue, false); -+} -+ -+static int test_arg_evbmode(struct cmd *cmd, char *arg, char *argvalue, -+ UNUSED char *obuf, UNUSED int obuf_len) -+{ -+ return set2_arg_evbmode(cmd, arg, argvalue, true); -+} -+ -+static int get_txmit(struct evb22_data *ed) -+{ -+ return ed->txmit; -+} -+ -+static void set_txmit(struct evb22_data *ed, int value) -+{ -+ ed->txmit = value; -+} -+ -+static int get_gpid(struct evb22_data *ed) -+{ -+ int mode = evb_ex_evbmode(ed->policy.evb_mode); -+ -+ if (mode == EVB_STATION && evb_ex_sgid(ed->policy.station_s)) -+ return 1; -+ if (mode == EVB_BRIDGE && evb_ex_bgid(ed->policy.bridge_s)) -+ return 1; -+ return 0; -+} -+ -+static void set_gpid(struct evb22_data *ed, int value) -+{ -+ if (evb_ex_evbmode(ed->policy.evb_mode) == EVB_STATION) -+ ed->policy.station_s = evb_maskoff_sgid(ed->policy.station_s) -+ | evb_set_sgid(value); -+ else -+ ed->policy.bridge_s = evb_maskoff_bgid(ed->policy.bridge_s) -+ | evb_set_bgid(value); -+} -+ -+static void set_rrcap(struct evb22_data *ed, int value) -+{ -+ ed->policy.bridge_s = evb_maskoff_rrcap(ed->policy.bridge_s) -+ | evb_set_rrcap(value); -+} -+ -+static int get_rrcap(struct evb22_data *ed) -+{ -+ return evb_ex_rrcap(ed->policy.bridge_s); -+} -+ -+static void set_rrreq(struct evb22_data *ed, int value) -+{ -+ ed->policy.station_s = evb_maskoff_rrreq(ed->policy.station_s) -+ | evb_set_rrreq(value); -+} -+ -+static int get_rrreq(struct evb22_data *ed) -+{ -+ return evb_ex_rrreq(ed->policy.station_s); -+} -+ -+/* -+ * Read a boolean value from the command line argument and apply the new -+ * value to parameter. -+ */ -+static int scan_bool(struct cmd *cmd, char *arg, char *argvalue, bool test, -+ void (*fct)(struct evb22_data *, int)) -+{ -+ int value; -+ char arg_path[EVB_BUF_SIZE]; -+ struct evb22_data *ed; -+ cmd_status good_cmd = evb22_cmdok(cmd, cmd_settlv); -+ -+ if (good_cmd != cmd_success) -+ return good_cmd; -+ if (!strcasecmp(argvalue, VAL_YES)) -+ value = 1; -+ else if (!strcasecmp(argvalue, VAL_NO)) -+ value = 0; -+ else -+ return cmd_bad_params; -+ ed = evb22_data((char *) &cmd->ifname, cmd->type); -+ if (!ed) -+ return cmd_invalid; -+ if (test) -+ return cmd_success; -+ snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", -+ TLVID_PREFIX, cmd->tlvid, arg); -+ if (set_cfg(cmd->ifname, cmd->type, arg_path, &value, -+ CONFIG_TYPE_BOOL)){ -+ LLDPAD_ERR("%s: error saving EVB enabletx (%s)\n", ed->ifname, -+ argvalue); -+ return cmd_failed; -+ } -+ LLDPAD_INFO("%s: changed EVB %s (%s)\n", ed->ifname, arg, argvalue); -+ (*fct)(ed, value); -+ somethingChangedLocal(cmd->ifname, cmd->type); -+ return cmd_success; -+} -+ -+static int show_bool(struct cmd *cmd, char *arg, UNUSED char *argvalue, -+ char *obuf, int obuf_len, -+ int (*fct)(struct evb22_data *)) -+{ -+ struct evb22_data *ed; -+ char *s; -+ cmd_status good_cmd = evb22_cmdok(cmd, cmd_gettlv); -+ -+ if (good_cmd != cmd_success) -+ return good_cmd; -+ ed = evb22_data((char *) &cmd->ifname, cmd->type); -+ if (!ed) -+ return cmd_invalid; -+ if ((*fct)(ed)) -+ s = VAL_YES; -+ else -+ s = VAL_NO; -+ snprintf(obuf, obuf_len, "%02x%s%04x%s", -+ (unsigned int)strlen(arg), arg, (unsigned int)strlen(s), s); -+ return cmd_success; -+} -+ -+static int get_arg_tlvtxenable(struct cmd *cmd, char *arg, -+ UNUSED char *argvalue, char *obuf, int obuf_len) -+{ -+ return show_bool(cmd, arg, argvalue, obuf, obuf_len, get_txmit); -+} -+ -+static int set_arg_tlvtxenable(struct cmd *cmd, char *arg, char *argvalue, -+ UNUSED char *obuf, UNUSED int obuf_len) -+{ -+ return scan_bool(cmd, arg, argvalue, false, set_txmit); -+} -+ -+static int test_arg_tlvtxenable(struct cmd *cmd, char *arg, char *argvalue, -+ UNUSED char *obuf, UNUSED int obuf_len) -+{ -+ return scan_bool(cmd, arg, argvalue, true, 0); -+} -+ -+static int get_arg_gpid(struct cmd *cmd, char *arg, UNUSED char *argvalue, -+ char *obuf, int obuf_len) -+{ -+ return show_bool(cmd, arg, argvalue, obuf, obuf_len, get_gpid); -+} -+ -+static int set_arg_gpid(struct cmd *cmd, char *arg, char *argvalue, -+ UNUSED char *obuf, UNUSED int obuf_len) -+{ -+ return scan_bool(cmd, arg, argvalue, false, set_gpid); -+} -+ -+static int test_arg_gpid(struct cmd *cmd, char *arg, char *argvalue, -+ UNUSED char *obuf, UNUSED int obuf_len) -+{ -+ return scan_bool(cmd, arg, argvalue, true, 0); -+} -+ -+static int get_arg_rrcap(struct cmd *cmd, char *arg, UNUSED char *argvalue, -+ char *obuf, int obuf_len) -+{ -+ return show_bool(cmd, arg, argvalue, obuf, obuf_len, get_rrcap); -+} -+ -+static int set_arg_rrcap(struct cmd *cmd, char *arg, char *argvalue, -+ UNUSED char *obuf, UNUSED int obuf_len) -+{ -+ return scan_bool(cmd, arg, argvalue, false, set_rrcap); -+} -+ -+static int test_arg_rrcap(struct cmd *cmd, char *arg, char *argvalue, -+ UNUSED char *obuf, UNUSED int obuf_len) -+{ -+ return scan_bool(cmd, arg, argvalue, true, 0); -+} -+ -+static int get_arg_rrreq(struct cmd *cmd, char *arg, UNUSED char *argvalue, -+ char *obuf, int obuf_len) -+{ -+ return show_bool(cmd, arg, argvalue, obuf, obuf_len, get_rrreq); -+} -+ -+static int set_arg_rrreq(struct cmd *cmd, char *arg, char *argvalue, -+ UNUSED char *obuf, UNUSED int obuf_len) -+{ -+ return scan_bool(cmd, arg, argvalue, false, set_rrreq); -+} -+ -+static int test_arg_rrreq(struct cmd *cmd, char *arg, char *argvalue, -+ UNUSED char *obuf, UNUSED int obuf_len) -+{ -+ return scan_bool(cmd, arg, argvalue, true, 0); -+} -+ -+ -+static void set_retries(struct evb22_data *ed, int value) -+{ -+ ed->policy.r_rte = evb_maskoff_retries(ed->policy.r_rte) -+ | evb_set_retries(value); -+} -+ -+static int get_retries(struct evb22_data *ed) -+{ -+ return evb_ex_retries(ed->policy.r_rte); -+} -+ -+static void set_rte(struct evb22_data *ed, int value) -+{ -+ ed->policy.r_rte = evb_maskoff_rte(ed->policy.r_rte) -+ | evb_set_rte(value); -+} -+ -+static int get_rte(struct evb22_data *ed) -+{ -+ return evb_ex_rte(ed->policy.r_rte); -+} -+ -+static void set_rwd(struct evb22_data *ed, int value) -+{ -+ ed->policy.evb_mode = evb_maskoff_rwd(ed->policy.evb_mode) -+ | evb_set_rwd(value); -+} -+ -+static int get_rwd(struct evb22_data *ed) -+{ -+ return evb_ex_rwd(ed->policy.evb_mode); -+} -+ -+static void set_rka(struct evb22_data *ed, int value) -+{ -+ ed->policy.rl_rka = evb_maskoff_rka(ed->policy.rl_rka) -+ | evb_set_rka(value); -+} -+ -+static int get_rka(struct evb22_data *ed) -+{ -+ return evb_ex_rka(ed->policy.rl_rka); -+} -+ -+static int scan_31bit(struct cmd *cmd, char *arg, const char *argvalue, -+ bool test, void (*fct)(struct evb22_data *, int), -+ int limit) -+{ -+ char arg_path[EVB_BUF_SIZE]; -+ struct evb22_data *ed; -+ int value; -+ char *endp; -+ cmd_status good_cmd = evb22_cmdok(cmd, cmd_settlv); -+ -+ if (good_cmd != cmd_success) -+ return good_cmd; -+ value = strtoul(argvalue, &endp, 0); -+ if (*endp != '\0' || value > limit) -+ return cmd_bad_params; -+ ed = evb22_data((char *) &cmd->ifname, cmd->type); -+ if (!ed) -+ return cmd_invalid; -+ if (test) -+ return cmd_success; -+ snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", -+ TLVID_PREFIX, cmd->tlvid, arg); -+ if (set_cfg(ed->ifname, cmd->type, arg_path, &value, -+ CONFIG_TYPE_INT)){ -+ LLDPAD_ERR("%s: error saving EVB %s (%d)\n", ed->ifname, arg, -+ value); -+ return cmd_failed; -+ } -+ LLDPAD_INFO("%s: changed EVB %s (%s)\n", ed->ifname, arg, argvalue); -+ (*fct)(ed, value); -+ somethingChangedLocal(cmd->ifname, cmd->type); -+ return cmd_success; -+} -+ -+static int show_31bit(struct cmd *cmd, char *arg, UNUSED char *argvalue, -+ char *obuf, int obuf_len, -+ int (*fct)(struct evb22_data *)) -+{ -+ struct evb22_data *ed; -+ char s[EVB_BUF_SIZE]; -+ cmd_status good_cmd = evb22_cmdok(cmd, cmd_gettlv); -+ -+ if (good_cmd != cmd_success) -+ return good_cmd; -+ ed = evb22_data((char *) &cmd->ifname, cmd->type); -+ if (!ed) -+ return cmd_invalid; -+ if (sprintf(s, "%i", (*fct)(ed)) <= 0) -+ return cmd_invalid; -+ snprintf(obuf, obuf_len, "%02x%s%04x%s", -+ (unsigned int)strlen(arg), arg, (unsigned int)strlen(s), s); -+ return cmd_success; -+} -+ -+static int get_arg_retries(struct cmd *cmd, char *arg, UNUSED char *argvalue, -+ char *obuf, int obuf_len) -+{ -+ return show_31bit(cmd, arg, argvalue, obuf, obuf_len, get_retries); -+} -+ -+static int set_arg_retries(struct cmd *cmd, char *arg, char *argvalue, -+ UNUSED char *obuf, UNUSED int obuf_len) -+{ -+ return scan_31bit(cmd, arg, argvalue, false, set_retries, 7); -+} -+ -+static int test_arg_retries(struct cmd *cmd, char *arg, char *argvalue, -+ UNUSED char *obuf, UNUSED int obuf_len) -+{ -+ return scan_31bit(cmd, arg, argvalue, true, 0, 7); -+} -+ -+static int get_arg_rte(struct cmd *cmd, char *arg, UNUSED char *argvalue, -+ char *obuf, int obuf_len) -+{ -+ return show_31bit(cmd, arg, argvalue, obuf, obuf_len, get_rte); -+} -+ -+static int set_arg_rte(struct cmd *cmd, char *arg, char *argvalue, -+ UNUSED char *obuf, UNUSED int obuf_len) -+{ -+ return scan_31bit(cmd, arg, argvalue, false, set_rte, 31); -+} -+ -+static int test_arg_rte(struct cmd *cmd, char *arg, char *argvalue, -+ UNUSED char *obuf, UNUSED int obuf_len) -+{ -+ return scan_31bit(cmd, arg, argvalue, true, 0, 31); -+} -+ -+static int get_arg_rwd(struct cmd *cmd, char *arg, UNUSED char *argvalue, -+ char *obuf, int obuf_len) -+{ -+ return show_31bit(cmd, arg, argvalue, obuf, obuf_len, get_rwd); -+} -+ -+static int set_arg_rwd(struct cmd *cmd, char *arg, char *argvalue, -+ UNUSED char *obuf, UNUSED int obuf_len) -+{ -+ return scan_31bit(cmd, arg, argvalue, false, set_rwd, 31); -+} -+ -+static int test_arg_rwd(struct cmd *cmd, char *arg, char *argvalue, -+ UNUSED char *obuf, UNUSED int obuf_len) -+{ -+ return scan_31bit(cmd, arg, argvalue, true, 0, 31); -+} -+ -+static int get_arg_rka(struct cmd *cmd, char *arg, UNUSED char *argvalue, -+ char *obuf, int obuf_len) -+{ -+ return show_31bit(cmd, arg, argvalue, obuf, obuf_len, get_rka); -+} -+ -+static int set_arg_rka(struct cmd *cmd, char *arg, char *argvalue, -+ UNUSED char *obuf, UNUSED int obuf_len) -+{ -+ return scan_31bit(cmd, arg, argvalue, false, set_rka, 31); -+} -+ -+static int test_arg_rka(struct cmd *cmd, char *arg, char *argvalue, -+ UNUSED char *obuf, UNUSED int obuf_len) -+{ -+ return scan_31bit(cmd, arg, argvalue, true, 0, 31); -+} -+ -+static struct arg_handlers arg_handlers[] = { -+ { -+ .arg = EVB_CONF_RKA, -+ .arg_class = TLV_ARG, -+ .handle_get = get_arg_rka, -+ .handle_set = set_arg_rka, -+ .handle_test = test_arg_rka -+ }, -+ { -+ .arg = EVB_CONF_RWD, -+ .arg_class = TLV_ARG, -+ .handle_get = get_arg_rwd, -+ .handle_set = set_arg_rwd, -+ .handle_test = test_arg_rwd -+ }, -+ { -+ .arg = EVB_CONF_RTE, -+ .arg_class = TLV_ARG, -+ .handle_get = get_arg_rte, -+ .handle_set = set_arg_rte, -+ .handle_test = test_arg_rte -+ }, -+ { -+ .arg = EVB_CONF_RETRIES, -+ .arg_class = TLV_ARG, -+ .handle_get = get_arg_retries, -+ .handle_set = set_arg_retries, -+ .handle_test = test_arg_retries -+ }, -+ { -+ .arg = EVB_CONF_RRREQ, -+ .arg_class = TLV_ARG, -+ .handle_get = get_arg_rrreq, -+ .handle_set = set_arg_rrreq, -+ .handle_test = test_arg_rrreq -+ }, -+ { -+ .arg = EVB_CONF_RRCAP, -+ .arg_class = TLV_ARG, -+ .handle_get = get_arg_rrcap, -+ .handle_set = set_arg_rrcap, -+ .handle_test = test_arg_rrcap -+ }, -+ { -+ .arg = EVB_CONF_GPID, -+ .arg_class = TLV_ARG, -+ .handle_get = get_arg_gpid, -+ .handle_set = set_arg_gpid, -+ .handle_test = test_arg_gpid -+ }, -+ { -+ .arg = EVB_CONF_MODE, -+ .arg_class = TLV_ARG, -+ .handle_get = get_arg_evbmode, -+ .handle_set = set_arg_evbmode, -+ .handle_test = test_arg_evbmode -+ }, -+ { -+ .arg = ARG_TLVTXENABLE, -+ .arg_class = TLV_ARG, -+ .handle_get = get_arg_tlvtxenable, -+ .handle_set = set_arg_tlvtxenable, -+ .handle_test = test_arg_tlvtxenable -+ }, -+ { -+ .arg = 0 -+ } -+}; -+ -+struct arg_handlers *evb22_get_arg_handlers() -+{ -+ return &arg_handlers[0]; -+} -diff --git a/lldp_evb_cmds.c b/lldp_evb_cmds.c -index 923d56d..3baba61 100644 ---- a/lldp_evb_cmds.c -+++ b/lldp_evb_cmds.c -@@ -32,7 +32,7 @@ - - #include "lldp.h" - #include "lldp_evb.h" --#include "lldp_vdp.h" -+#include "qbg_vdp.h" - #include "lldp_tlv.h" - #include "lldp_mand_clif.h" - #include "config.h" -@@ -167,8 +167,12 @@ static int evb_cmdok(struct cmd *cmd, cmd_status expected) - { - if (cmd->cmd != expected) - return cmd_invalid; -+ - switch (cmd->tlvid) { - case TLVID_8021Qbg(LLDP_EVB_SUBTYPE): -+ if (cmd->type != NEAREST_CUSTOMER_BRIDGE) -+ return cmd_agent_not_supported; -+ - return cmd_success; - case INVALID_TLVID: - return cmd_invalid; -@@ -181,17 +185,19 @@ static int - get_arg_tlvtxenable(struct cmd *cmd, char *arg, UNUSED char *argvalue, - char *obuf, int obuf_len) - { -- struct evb_data *ed; -- char *s; - cmd_status good_cmd = evb_cmdok(cmd, cmd_gettlv); -+ char *s, arg_path[EVB_BUF_SIZE]; -+ int value; - - if (good_cmd != cmd_success) - return good_cmd; - -- ed = evb_data((char *) &cmd->ifname, cmd->type); -- if (!ed) -- return cmd_invalid; -- if (ed->txmit) -+ snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", -+ TLVID_PREFIX, cmd->tlvid, arg); -+ if (get_cfg(cmd->ifname, cmd->type, arg_path, &value, CONFIG_TYPE_BOOL)) -+ value = false; -+ -+ if (value) - s = VAL_YES; - else - s = VAL_NO; -@@ -221,10 +227,11 @@ static int _set_arg_tlvtxenable(struct cmd *cmd, char *arg, char *argvalue, - return cmd_bad_params; - - ed = evb_data((char *) &cmd->ifname, cmd->type); -- if (!ed) -- return cmd_invalid; -- if (vdp_vsis(ed->ifname)) -- return cmd_failed; -+ if (ed) { -+ if (vdp_vsis(ed->ifname)) -+ return cmd_failed; -+ } -+ - if (test) - return cmd_success; - -@@ -233,12 +240,14 @@ static int _set_arg_tlvtxenable(struct cmd *cmd, char *arg, char *argvalue, - - if (set_cfg(cmd->ifname, cmd->type, arg_path, &value, - CONFIG_TYPE_BOOL)){ -- LLDPAD_ERR("%s: error saving EVB enabletx (%s)\n", ed->ifname, -+ LLDPAD_ERR("%s: error saving EVB enabletx (%s)\n", cmd->ifname, - argvalue); - return cmd_failed; - } -- ed->txmit = value; -- LLDPAD_INFO("%s: changed EVB enabletx (%s)\n", ed->ifname, argvalue); -+ if (ed) -+ ed->txmit = value; -+ -+ LLDPAD_INFO("%s: changed EVB enabletx (%s)\n", cmd->ifname, argvalue); - somethingChangedLocal(cmd->ifname, cmd->type); - - return cmd_success; -@@ -259,20 +268,19 @@ static int test_arg_tlvtxenable(struct cmd *cmd, char *arg, char *argvalue, - static int get_arg_fmode(struct cmd *cmd, char *arg, UNUSED char *argvalue, - char *obuf, int obuf_len) - { -- char *s; -- struct evb_data *ed; - cmd_status good_cmd = evb_cmdok(cmd, cmd_gettlv); -+ char *s; -+ u8 mode; - - if (good_cmd != cmd_success) - return good_cmd; - -- ed = evb_data((char *) &cmd->ifname, cmd->type); -- if (!ed) -- return cmd_invalid; -- if (ed->policy.smode & LLDP_EVB_CAPABILITY_FORWARD_REFLECTIVE_RELAY) -+ mode = evb_conf_fmode(cmd->ifname, cmd->type); -+ if (mode & LLDP_EVB_CAPABILITY_FORWARD_REFLECTIVE_RELAY) - s = VAL_EVB_FMODE_REFLECTIVE_RELAY; - else - s = VAL_EVB_FMODE_BRIDGE; -+ - snprintf(obuf, obuf_len, "%02x%s%04x%s", - (unsigned int)strlen(arg), arg, (unsigned int)strlen(s), s); - return cmd_success; -@@ -296,25 +304,28 @@ static int _set_arg_fmode(struct cmd *cmd, const char *argvalue, bool test) - return cmd_bad_params; - - ed = evb_data((char *) &cmd->ifname, cmd->type); -- if (!ed) -- return cmd_invalid; -- if (vdp_vsis(ed->ifname)) -- return cmd_failed; -+ if (ed) { -+ if (vdp_vsis(ed->ifname)) -+ return cmd_failed; -+ } -+ - if (test) - return cmd_success; - - snprintf(arg_path, sizeof(arg_path), "%s%08x.fmode", - TLVID_PREFIX, cmd->tlvid); - -- if (set_cfg(ed->ifname, cmd->type, arg_path, &argvalue, -+ if (set_cfg(cmd->ifname, cmd->type, arg_path, &argvalue, - CONFIG_TYPE_STRING)) { - LLDPAD_ERR("%s: saving EVB forwarding mode failed\n", -- ed->ifname); -+ cmd->ifname); - return cmd_failed; - } - -- ed->policy.smode = smode; -- LLDPAD_INFO("%s: changed EVB forwarding mode (%s)\n", ed->ifname, -+ if (ed) -+ ed->policy.smode = smode; -+ -+ LLDPAD_INFO("%s: changed EVB forwarding mode (%s)\n", cmd->ifname, - argvalue); - somethingChangedLocal(cmd->ifname, cmd->type); - return cmd_success; -@@ -338,27 +349,25 @@ get_arg_capabilities(struct cmd *cmd, char *arg, UNUSED char *argvalue, - { - int comma = 0; - char t[EVB_BUF_SIZE]; -- struct evb_data *ed; -+ u8 scap; - cmd_status good_cmd = evb_cmdok(cmd, cmd_gettlv); - - if (good_cmd != cmd_success) - return good_cmd; -- ed = evb_data((char *) &cmd->ifname, cmd->type); -- if (!ed) -- return cmd_invalid; - -+ scap = evb_conf_capa(cmd->ifname, cmd->type); - memset(t, 0, sizeof t); -- if (ed->policy.scap & LLDP_EVB_CAPABILITY_PROTOCOL_RTE) { -+ if (scap & LLDP_EVB_CAPABILITY_PROTOCOL_RTE) { - strcat(t, VAL_EVB_CAPA_RTE); - comma = 1; - } -- if (ed->policy.scap & LLDP_EVB_CAPABILITY_PROTOCOL_ECP) { -+ if (scap & LLDP_EVB_CAPABILITY_PROTOCOL_ECP) { - if (comma) - strcat(t, " "); - strcat(t, VAL_EVB_CAPA_ECP); - comma = 1; - } -- if (ed->policy.scap & LLDP_EVB_CAPABILITY_PROTOCOL_VDP) { -+ if (scap & LLDP_EVB_CAPABILITY_PROTOCOL_VDP) { - if (comma) - strcat(t, " "); - strcat(t, VAL_EVB_CAPA_VDP); -@@ -415,25 +424,25 @@ _set_arg_capabilities(struct cmd *cmd, const char *argvalue, bool test) - return cmd_bad_params; - - ed = evb_data((char *) &cmd->ifname, cmd->type); -- if (!ed) -- return cmd_invalid; -- if (vdp_vsis(ed->ifname)) -- return cmd_failed; -+ if (ed) -+ if (vdp_vsis(ed->ifname)) -+ return cmd_failed; - if (test) - return cmd_success; - - snprintf(arg_path, sizeof(arg_path), "%s%08x.capabilities", - TLVID_PREFIX, cmd->tlvid); - -- if (set_cfg(ed->ifname, cmd->type, arg_path, &argvalue, -+ if (set_cfg(cmd->ifname, cmd->type, arg_path, &argvalue, - CONFIG_TYPE_STRING)) { - LLDPAD_ERR("%s: saving EVB capabilities (%#x) failed\n", -- ed->ifname, scap); -+ cmd->ifname, scap); - return cmd_failed; - } - -- ed->policy.scap = scap; -- LLDPAD_INFO("%s: changed EVB capabilities (%#x)\n", ed->ifname, scap); -+ if (ed) -+ ed->policy.scap = scap; -+ LLDPAD_INFO("%s: changed EVB capabilities (%#x)\n", cmd->ifname, scap); - somethingChangedLocal(cmd->ifname, cmd->type); - - return cmd_success; -@@ -457,17 +466,15 @@ static int get_arg_rte(struct cmd *cmd, char *arg, UNUSED char *argvalue, - char *obuf, int obuf_len) - { - char s[EVB_BUF_SIZE]; -- struct evb_data *ed; -+ u8 rte; - cmd_status good_cmd = evb_cmdok(cmd, cmd_gettlv); - - if (good_cmd != cmd_success) - return good_cmd; - -- ed = evb_data((char *) &cmd->ifname, cmd->type); -- if (!ed) -- return cmd_invalid; -+ rte = evb_conf_rte(cmd->ifname, cmd->type); - -- if (sprintf(s, "%i", ed->policy.rte) <= 0) -+ if (sprintf(s, "%i", rte) <= 0) - return cmd_invalid; - - snprintf(obuf, obuf_len, "%02x%s%04x%s", -@@ -491,24 +498,24 @@ static int _set_arg_rte(struct cmd *cmd, const char *argvalue, bool test) - return cmd_bad_params; - - ed = evb_data((char *) &cmd->ifname, cmd->type); -- if (!ed) -- return cmd_invalid; -- if (vdp_vsis(ed->ifname)) -- return cmd_failed; -+ if (ed) -+ if (vdp_vsis(ed->ifname)) -+ return cmd_failed; - if (test) - return cmd_success; - - snprintf(arg_path, sizeof(arg_path), "%s%08x.rte", TLVID_PREFIX, - cmd->tlvid); -- if (set_cfg(ed->ifname, cmd->type, arg_path, &argvalue, -+ if (set_cfg(cmd->ifname, cmd->type, arg_path, &argvalue, - CONFIG_TYPE_STRING)){ -- LLDPAD_ERR("%s: error saving EVB rte (%d)\n", ed->ifname, -+ LLDPAD_ERR("%s: error saving EVB rte (%d)\n", cmd->ifname, - value); - return cmd_failed; - } - -- ed->policy.rte = value; -- LLDPAD_INFO("%s: changed EVB rte (%#x)\n", ed->ifname, value); -+ if (ed) -+ ed->policy.rte = value; -+ LLDPAD_INFO("%s: changed EVB rte (%#x)\n", cmd->ifname, value); - somethingChangedLocal(cmd->ifname, cmd->type); - - return cmd_success; -@@ -530,16 +537,15 @@ static int get_arg_vsis(struct cmd *cmd, char *arg, UNUSED char *argvalue, - char *obuf, int obuf_len) - { - char s[EVB_BUF_SIZE]; -- struct evb_data *ed; -+ u16 svsi; - cmd_status good_cmd = evb_cmdok(cmd, cmd_gettlv); - - if (good_cmd != cmd_success) - return good_cmd; - -- ed = evb_data((char *) &cmd->ifname, cmd->type); -- if (!ed) -- return cmd_invalid; -- if (sprintf(s, "%04i", ed->policy.svsi) <= 0) -+ svsi = evb_conf_vsis(cmd->ifname, cmd->type); -+ -+ if (sprintf(s, "%04i", svsi) <= 0) - return cmd_invalid; - snprintf(obuf, obuf_len, "%02x%s%04x%s", - (unsigned int)strlen(arg), arg, (unsigned int)strlen(s), s); -@@ -561,24 +567,24 @@ static int _set_arg_vsis(struct cmd *cmd, const char *argvalue, bool test) - return cmd_bad_params; - - ed = evb_data((char *) &cmd->ifname, cmd->type); -- if (!ed) -- return cmd_invalid; -- if (vdp_vsis(ed->ifname)) -- return cmd_failed; -+ if (ed) -+ if (vdp_vsis(ed->ifname)) -+ return cmd_failed; - if (test) - return cmd_success; - - snprintf(arg_path, sizeof(arg_path), "%s%08x.vsis", TLVID_PREFIX, - cmd->tlvid); -- if (set_cfg(ed->ifname, cmd->type, arg_path, &argvalue, -+ if (set_cfg(cmd->ifname, cmd->type, arg_path, &argvalue, - CONFIG_TYPE_STRING)){ -- LLDPAD_ERR("%s: error saving EVB vsi (%d)\n", ed->ifname, -+ LLDPAD_ERR("%s: error saving EVB vsi (%d)\n", cmd->ifname, - value); - return cmd_failed; - } - -- ed->policy.svsi = htons(value); -- LLDPAD_INFO("%s: changed EVB vsis (%#x)\n", ed->ifname, value); -+ if (ed) -+ ed->policy.svsi = htons(value); -+ LLDPAD_INFO("%s: changed EVB vsis (%#x)\n", cmd->ifname, value); - somethingChangedLocal(cmd->ifname, cmd->type); - - return cmd_success; -diff --git a/lldp_mand.c b/lldp_mand.c -index 943070f..b269d3f 100644 ---- a/lldp_mand.c -+++ b/lldp_mand.c -@@ -464,8 +464,9 @@ out_err: - static int mand_bld_tlv(struct mand_data *md, struct lldp_agent *agent) - { - int rc = EPERM; -+ int ifindex = get_ifidx(md->ifname); - -- if (!port_find_by_name(md->ifname)) { -+ if (!port_find_by_ifindex(ifindex)) { - rc = EEXIST; - goto out_err; - } -@@ -655,13 +656,13 @@ void mand_unregister(struct lldp_module *mod) - struct mand_data *md; - - nameidx = if_nameindex(); -- if (nameidx == NULL) { -+ if (!nameidx) { - LLDPAD_DBG("error calling if_nameindex()\n"); - return; - } - - for (p = nameidx; p->if_index != 0; p++) { -- port = port_find_by_name(p->if_name); -+ port = port_find_by_ifindex(p->if_index); - if (!port) - continue; - -diff --git a/lldp_mand_cmds.c b/lldp_mand_cmds.c -index aedb8dc..532337b 100644 ---- a/lldp_mand_cmds.c -+++ b/lldp_mand_cmds.c -@@ -78,17 +78,12 @@ static struct arg_handlers arg_handlers[] = { - static int get_mand_subtype(struct cmd *cmd, char *arg, UNUSED char *argvalue, - char *obuf, int obuf_len) - { -- struct mand_data *md; - int subtype; - char *string, arg_path[256]; - - if (cmd->cmd != cmd_gettlv) - return cmd_invalid; - -- md = mand_data(cmd->ifname, cmd->type); -- if (!md) -- return cmd_device_not_found; -- - switch (cmd->tlvid) { - case CHASSIS_ID_TLV: - snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", -@@ -183,8 +178,6 @@ static int _set_mand_subtype(struct cmd *cmd, char *arg, char *argvalue, - return cmd_invalid; - - md = mand_data(cmd->ifname, cmd->type); -- if (!md) -- return cmd_device_not_found; - - switch (cmd->tlvid) { - case CHASSIS_ID_TLV: -@@ -261,9 +254,11 @@ static int _set_mand_subtype(struct cmd *cmd, char *arg, char *argvalue, - if (test) - return cmd_success; - -- md->read_shm = 1; -- md->rebuild_chassis = 1; -- md->rebuild_portid = 1; -+ if (md) { -+ md->read_shm = 1; -+ md->rebuild_chassis = 1; -+ md->rebuild_portid = 1; -+ } - - snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", TLVID_PREFIX, - cmd->tlvid, arg); -@@ -570,6 +565,10 @@ int get_tlvs(struct cmd *cmd, char *rbuf, int rlen) - u16 type, len; - int res; - -+ /* VDP 0.2 protocol for nearest customer bridge only */ -+ if (cmd->tlvid == (OUI_IEEE_8021Qbg << 8) -+ && cmd->type != NEAREST_CUSTOMER_BRIDGE) -+ return cmd_agent_not_supported; - if (cmd->ops & op_local) { - res = get_local_tlvs(cmd->ifname, cmd->type, &tlvs[0], &size); - if (res) -@@ -652,7 +651,6 @@ int mand_clif_cmd(UNUSED void *data, - char *rbuf, int rlen) - { - struct cmd cmd; -- struct port *port; - u8 len, version; - int ioff, roff; - int rstatus = cmd_invalid; -@@ -727,9 +725,8 @@ int mand_clif_cmd(UNUSED void *data, - (unsigned int)strlen(cmd.ifname), cmd.ifname); - roff = strlen(rbuf); - -- /* Confirm port is a lldpad managed port */ -- port = port_find_by_name(cmd.ifname); -- if (!port) { -+ /* Confirm port is a valid LLDP port */ -+ if (!get_ifidx(cmd.ifname) || !is_valid_lldp_device(cmd.ifname)) { - free(argvals); - free(args); - return cmd_device_not_found; -diff --git a/lldp_med.c b/lldp_med.c -index db83eaf..77ec20d 100644 ---- a/lldp_med.c -+++ b/lldp_med.c -@@ -686,39 +686,32 @@ out_err: - * @md: the med data struct - * - * Returns 0 for success or error code for failure -- * - */ --static int med_bld_tlv(struct med_data *md, -- struct lldp_agent *agent) -+static int med_bld_tlv(struct med_data *md, struct lldp_agent *agent) - { -- int rc = EPERM; -- -- if (!port_find_by_name(md->ifname)) { -- rc = EEXIST; -- goto out_err; -- } -+ if (!port_find_by_ifindex(get_ifidx(md->ifname))) -+ return -EEXIST; - - /* no build if not enabled */ - if (!is_tlv_txenabled(md->ifname, agent->type, - TLVID_MED(LLDP_MED_RESERVED))) { - LLDPAD_DBG("%s:%s:LLDP-MED is not enabled\n", -- __func__, md->ifname); -- rc = 0; -- goto out_err; -+ __func__, md->ifname); -+ return 0; - } - - /* no build if enabled no devtype is given */ - if (!LLDP_MED_DEVTYPE_DEFINED(get_med_devtype(md->ifname, agent->type))) { - LLDPAD_DBG("%s:%s:LLDP-MED devtype is not defined\n", -- __func__, md->ifname); -- goto out_err; -+ __func__, md->ifname); -+ return -EPERM; - } - - /* MED Cap is always mandatory for MED */ - if (med_bld_medcaps_tlv(md, agent)) { - LLDPAD_DBG("%s:%s:MED Capabilities TLV is mandatory!\n", -- __func__, md->ifname); -- goto out_err; -+ __func__, md->ifname); -+ return -EPERM; - } - - /* MAC PHY TLV is mandatory for MED */ -@@ -726,8 +719,7 @@ static int med_bld_tlv(struct med_data *md, - TLVID_8023(LLDP_8023_MACPHY_CONFIG_STATUS))) { - LLDPAD_DBG("%s:%s MAC PHY Config is mandatory for MED\n", - __func__, md->ifname); -- rc = ENOTTY; -- goto out_err; -+ return -ENOTTY; - } - - /* Build optional and conditional ones based on device type: -@@ -757,32 +749,28 @@ static int med_bld_tlv(struct med_data *md, - * - Extended Power-via-MDI: mandatory only for - * 802.3.af PSE - * - Inventory: optional -- * - */ - if (med_bld_netpoli_tlv(md, agent)) { - LLDPAD_DBG("%s:%s:med_bld_netpoli_tlv() failed\n", -- __func__, md->ifname); -- goto out_err; -+ __func__, md->ifname); -+ return -EPERM; - } - if (med_bld_locid_tlv(md, agent)) { - LLDPAD_DBG("%s:%s:med_bld_locid_tlv() failed\n", -- __func__, md->ifname); -- goto out_err; -+ __func__, md->ifname); -+ return -EPERM; - } - if (med_bld_powvmdi_tlv(md, agent)) { - LLDPAD_DBG("%s:%s:med_bld_powvmdi_tlv() failed\n", -- __func__, md->ifname); -- goto out_err; -+ __func__, md->ifname); -+ return -EPERM; - } - if (med_bld_inventory_tlv(md, agent)) { - LLDPAD_DBG("%s:%s:med_bld_inventory_tlv() failed\n", -- __func__, md->ifname); -- goto out_err; -+ __func__, md->ifname); -+ return -EPERM; - } -- rc = 0; -- --out_err: -- return rc; -+ return 0; - } - - /* -diff --git a/lldp_qbg_utils.c b/lldp_qbg_utils.c -deleted file mode 100644 -index 04491de..0000000 ---- a/lldp_qbg_utils.c -+++ /dev/null -@@ -1,95 +0,0 @@ --/****************************************************************************** -- -- Implementation of ECP according to 802.1Qbg -- (c) Copyright IBM Corp. 2010, 2013 -- -- Author(s): Thomas Richter -- -- This program is free software; you can redistribute it and/or modify it -- under the terms and conditions of the GNU General Public License, -- version 2, as published by the Free Software Foundation. -- -- This program is distributed in the hope it will be useful, but WITHOUT -- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -- more details. -- -- You should have received a copy of the GNU General Public License along with -- this program; if not, write to the Free Software Foundation, Inc., -- 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. -- -- The full GNU General Public License is included in this distribution in -- the file called "COPYING". -- --******************************************************************************/ -- --/* -- * This file contains common support utilities for the ECP protocols. -- */ -- --#include --#include -- --#include "lldp.h" --#include "lldp_mod.h" --#include "messages.h" --#include "lldp_qbg_utils.h" -- --extern int loglvl; /* Global lldpad log level */ --extern struct lldp_head lldp_head; -- --/* -- * hexdump_frame - print raw evb/ecp/vdp frame -- */ --void hexdump_frame(const char *ifname, char *txt, const unsigned char *buf, -- size_t len) --{ -- size_t i; -- int left = 0; -- char buffer[ETH_FRAME_LEN * 3]; -- -- /* Only collect data when the loglvl ensures data printout */ -- if (LOG_DEBUG < loglvl) -- return; -- for (i = 0; i < len; i++) { -- int c; -- c = snprintf(buffer + left, sizeof buffer - left, "%02x%c", -- buf[i], !((i + 1) % 16) ? '\n' : ' '); -- if (c > 0 && (c < (int)sizeof buffer - left)) -- left += c; -- } -- LLDPAD_DBG("%s:%s %s\n%s\n", __func__, ifname, txt, buffer); --} -- --/* -- * Function to advertise changed variables to other modules. -- * -- * Parameters are interface name, target module id and data. -- * When sending the data, the module call back function contains the -- * module id of the sender. -- * -- * Return 0 when no addressee found or addressess found but addressee was -- * unable to handle data. -- */ --int modules_notify(int id, int sender_id, char *ifname, void *data) --{ -- struct lldp_module *mp = find_module_by_id(&lldp_head, id); -- int rc = 0; -- -- if (mp && mp->ops->lldp_mod_notify) -- rc = mp->ops->lldp_mod_notify(sender_id, ifname, data); -- LLDPAD_DBG("%s:%s target-id:%#x rc:%d\n", __func__, ifname, id, rc); -- return rc; --} -- --int vdp_uuid2str(const u8 *p, char *dst, size_t size) --{ -- if (dst && size > VDP_UUID_STRLEN) { -- snprintf(dst, size, "%02x%02x%02x%02x-%02x%02x-%02x%02x" -- "-%02x%02x-%02x%02x%02x%02x%02x%02x", -- p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], -- p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); -- return 0; -- } -- return -1; --} -diff --git a/lldp_rtnl.c b/lldp_rtnl.c -index 0c57e62..dffc0ba 100644 ---- a/lldp_rtnl.c -+++ b/lldp_rtnl.c -@@ -75,6 +75,11 @@ void mynla_put(struct nlmsghdr *nlh, int type, size_t len, void *data) - nlh->nlmsg_len += NLA_HDRLEN + NLA_ALIGN(len); - } - -+void mynla_put_u8(struct nlmsghdr *nlh, int type, __u8 data) -+{ -+ mynla_put(nlh, type, sizeof data, &data); -+} -+ - void mynla_put_u16(struct nlmsghdr *nlh, int type, __u16 data) - { - mynla_put(nlh, type, sizeof data, &data); -@@ -85,6 +90,94 @@ void mynla_put_u32(struct nlmsghdr *nlh, int type, __u32 data) - mynla_put(nlh, type, sizeof data, &data); - } - -+void mynla_put_s32(struct nlmsghdr *nlh, int type, __s32 data) -+{ -+ mynla_put(nlh, type, sizeof data, &data); -+} -+ -+void mynla_get(const struct nlattr *nla, size_t len, void *data) -+{ -+ memcpy(data, mynla_data(nla), len); -+} -+ -+__s32 mynla_get_s32(const struct nlattr *nla) -+{ -+ return *(__u32 *)mynla_data(nla); -+} -+ -+__u32 mynla_get_u32(const struct nlattr *nla) -+{ -+ return *(__u32 *)mynla_data(nla); -+} -+ -+__u16 mynla_get_u16(const struct nlattr *nla) -+{ -+ return *(__u16 *)mynla_data(nla); -+} -+ -+__u8 mynla_get_u8(const struct nlattr *nla) -+{ -+ return *(__u8 *)mynla_data(nla); -+} -+ -+void *mynla_data(const struct nlattr *nla) -+{ -+ return (char *)nla + NLA_HDRLEN; -+} -+ -+int mynla_payload(const struct nlattr *nla) -+{ -+ return nla->nla_len - NLA_HDRLEN; -+} -+ -+int mynla_type(const struct nlattr *nla) -+{ -+ return nla->nla_type & ~NLA_F_NESTED; -+} -+ -+int mynla_ok(const struct nlattr *nla, int rest) -+{ -+ return rest >= (int) sizeof(*nla) && -+ nla->nla_len >= sizeof(*nla) && nla->nla_len <= rest; -+} -+ -+struct nlattr *mynla_next(const struct nlattr *nla, int *rest) -+{ -+ int len = NLA_ALIGN(nla->nla_len); -+ -+ *rest -= len; -+ return (struct nlattr *)((char *)nla + len); -+} -+ -+static inline int mynla_attr_size(int payload) -+{ -+ return NLA_HDRLEN + payload; -+} -+ -+int mynla_total_size(int payload) -+{ -+ return NLA_ALIGN(mynla_attr_size(payload)); -+} -+ -+/* -+ * Parse a list of netlink attributes. -+ * Return 0 on success and errno when the parsing fails. -+ */ -+int mynla_parse(struct nlattr **tb, size_t tb_len, struct nlattr *pos, -+ int attrlen) -+{ -+ unsigned short nla_type; -+ -+ while (mynla_ok(pos, attrlen)) { -+ nla_type = mynla_type(pos); -+ if (nla_type < tb_len) -+ tb[nla_type] = (struct nlattr *)pos; -+ pos = mynla_next(pos, &attrlen); -+ } -+ return (attrlen) ? -EINVAL : 0; -+} -+ -+ - typedef int rtnl_handler(struct nlmsghdr *nh, void *arg); - - /** -@@ -173,7 +266,7 @@ static ssize_t rtnl_send_linkmode(int s, int ifindex, - return send(s, &req, req.nh.nlmsg_len, 0); - } - --static int rtnl_set_linkmode(int ifindex, const char *ifname, __u8 linkmode) -+int set_linkmode(int ifindex, const char *ifname, __u8 linkmode) - { - int s; - int rc; -@@ -301,11 +394,6 @@ int get_operstate(char *ifname) - return operstate; - } - --int set_linkmode(const char *ifname, __u8 linkmode) --{ -- return rtnl_set_linkmode(0, ifname, linkmode); --} -- - int get_perm_hwaddr(const char *ifname, u8 *buf_perm, u8 *buf_san) - { - int s; -diff --git a/lldp_util.c b/lldp_util.c -index 4a1cc4a..754b0cd 100644 ---- a/lldp_util.c -+++ b/lldp_util.c -@@ -308,9 +308,17 @@ int get_src_mac_from_bond(struct port *bond_port, char *ifname, u8 *addr) - return 1; - } - -+/* -+ * Return true if the mac address is valid (non-zero and no hardware -+ * broadcast address) -+ */ - int is_valid_mac(const u8 *mac) - { -- return !!(mac[0] | mac[1] | mac[2] | mac[3] | mac[4] | mac[5]); -+ 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; - } - - int read_int(const char *path) -@@ -349,6 +357,25 @@ int get_ifflags(const char *ifname) - return flags; - } - -+int get_ifname(int ifindex, char *ifname) -+{ -+ int fd; -+ int rc; -+ struct ifreq ifr; -+ -+ memset(&ifr, 0, sizeof(ifr)); -+ fd = get_ioctl_socket(); -+ if (fd < 0) -+ return -1; -+ -+ ifr.ifr_ifindex = ifindex; -+ rc = ioctl(fd, SIOCGIFNAME, &ifr); -+ if (rc >= 0) -+ memcpy(ifname, ifr.ifr_name, IFNAMSIZ); -+ -+ return rc; -+} -+ - int get_ifpflags(const char *ifname) - { - int fd; -@@ -1185,7 +1212,7 @@ int get_arg_val_list(char *ibuf, int ilen, int *ioff, - *ioff += arglen; - *(arglens+i) = arglen; - -- if (ilen - *ioff > 2 * (int)sizeof(argvalue_len)) { -+ if (ilen - *ioff >= 2 * (int)sizeof(argvalue_len)) { - hexstr2bin(ibuf+*ioff, (u8 *)&argvalue_len, - sizeof(argvalue_len)); - argvalue_len = ntohs(argvalue_len); -diff --git a/lldp_vdp.c b/lldp_vdp.c -deleted file mode 100644 -index 57133d1..0000000 ---- a/lldp_vdp.c -+++ /dev/null -@@ -1,1916 +0,0 @@ --/****************************************************************************** -- -- Implementation of VDP according to IEEE 802.1Qbg -- (c) Copyright IBM Corp. 2010, 2012 -- -- Author(s): Jens Osterkamp -- Author(s): Thomas Richter -- -- This program is free software; you can redistribute it and/or modify it -- under the terms and conditions of the GNU General Public License, -- version 2, as published by the Free Software Foundation. -- -- This program is distributed in the hope it will be useful, but WITHOUT -- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -- more details. -- -- You should have received a copy of the GNU General Public License along with -- this program; if not, write to the Free Software Foundation, Inc., -- 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. -- -- The full GNU General Public License is included in this distribution in -- the file called "COPYING". -- --******************************************************************************/ -- --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include "lldp.h" --#include "lldp_vdp.h" --#include "lldp_vdpnl.h" --#include "eloop.h" --#include "lldp_evb.h" --#include "messages.h" --#include "config.h" --#include "lldp_tlv.h" --#include "lldp_vdp_cmds.h" --#include "lldp_qbg_utils.h" --#include "lldp_mand_clif.h" -- --/* Define Module id. Must match with value in lldp_vdp_clif.c */ --#define LLDP_MOD_VDP02 ((LLDP_MOD_VDP << 8) | LLDP_VDP_SUBTYPE) -- --static const char * const vsi_responses[] = { -- [VDP_RESPONSE_SUCCESS] = "success", -- [VDP_RESPONSE_INVALID_FORMAT] = "invalid format", -- [VDP_RESPONSE_INSUFF_RESOURCES] = "insufficient resources", -- [VDP_RESPONSE_UNUSED_VTID] = "unused VTID", -- [VDP_RESPONSE_VTID_VIOLATION] = "VTID violation", -- [VDP_RESPONSE_VTID_VER_VIOLATION] = "VTID version violation", -- [VDP_RESPONSE_OUT_OF_SYNC] = "out of sync", -- [VDP_RESPONSE_UNKNOWN] = "unknown response", -- [VDP_RESPONSE_NO_RESPONSE] = "no response", --}; -- --const char * const vsi_states[] = { -- [VSI_UNASSOCIATED] = "VSI_UNASSOCIATED", -- [VSI_ASSOC_PROCESSING] = "VSI_ASSOC_PROCESSING", -- [VSI_ASSOCIATED] = "VSI_ASSOCIATED", -- [VSI_PREASSOC_PROCESSING] = "VSI_PREASSOC_PROCESSING", -- [VSI_PREASSOCIATED] = "VSI_PREASSOCIATED", -- [VSI_DEASSOC_PROCESSING] = "VSI_DEASSOC_PROCESSING", -- [VSI_EXIT] = "VSI_EXIT", --}; -- --int vdp_start_localchange_timer(struct vsi_profile *p); --int vdp_remove_profile(struct vsi_profile *profile); --int vdp_trigger(struct vsi_profile *profile); -- --void vdp_trace_profile(struct vsi_profile *p) --{ -- char instance[VDP_UUID_STRLEN + 2]; -- struct mac_vlan *mac_vlan; -- -- vdp_uuid2str(p->instance, instance, sizeof(instance)); -- -- LLDPAD_DBG("profile:%p mode:%d response:%d state:%d (%s) no_nlmsg:%d" -- " txmit:%i" -- " mgrid:%d id:%d(%#x) version:%d %s format:%d entries:%d\n", -- p, p->mode, p->response, p->state, vsi_states[p->state], -- p->no_nlmsg, p->txmit, -- p->mgrid, p->id, p->id, p->version, instance, p->format, -- p->entries); -- LIST_FOREACH(mac_vlan, &p->macvid_head, entry) { -- char macbuf[MAC_ADDR_STRLEN + 1]; -- -- mac2str(mac_vlan->mac, macbuf, MAC_ADDR_STRLEN); -- LLDPAD_DBG("profile:%p mac:%s vlan:%d qos:%d pid:%d seq:%d\n", -- p, macbuf, mac_vlan->vlan, mac_vlan->qos, -- mac_vlan->req_pid, mac_vlan->req_seq); -- } --} -- --struct vsi_profile *vdp_alloc_profile() --{ -- struct vsi_profile *prof; -- -- prof = calloc(1, sizeof *prof); -- if (prof) -- LIST_INIT(&prof->macvid_head); -- return prof; --} -- --/* -- * vdp_remove_macvlan - remove all mac/vlan pairs in the profile -- * @profile: profile to remove -- * -- * Remove all allocated pairs on the profile. -- */ --static void vdp_remove_macvlan(struct vsi_profile *profile) --{ -- struct mac_vlan *p; -- -- while ((p = LIST_FIRST(&profile->macvid_head))) { -- LIST_REMOVE(p, entry); -- free(p); -- } --} -- --void vdp_delete_profile(struct vsi_profile *prof) --{ -- vdp_remove_macvlan(prof); -- free(prof); --} -- --/* vdp_profile_equal - checks for equality of 2 profiles -- * @p1: profile 1 -- * @p2: profile 2 -- * -- * returns true if equal, false if not -- * -- * compares mgrid, id, version, instance 2 vsi profiles to find -- * out if they are equal. -- */ --static bool vdp_profile_equal(struct vsi_profile *p1, struct vsi_profile *p2) --{ -- if (p1->mgrid != p2->mgrid) -- return false; -- -- if (p1->id != p2->id) -- return false; -- -- if (p1->version != p2->version) -- return false; -- -- if (memcmp(p1->instance, p2->instance, 16)) -- return false; -- -- return true; --} -- --/* -- * vdp_find_profile - Find a profile in the list of profiles already allocated -- * -- * Returns pointer to already allocated profile in list, 0 if not. -- */ -- --struct vsi_profile *vdp_find_profile(struct vdp_data *vd, -- struct vsi_profile *thisone) --{ -- struct vsi_profile *p; -- -- LIST_FOREACH(p, &vd->profile_head, profile) { -- if (vdp_profile_equal(p, thisone)) -- return p; -- } -- return 0; --} -- --/* vdp_data - searches vdp_data in the list of modules for this port -- * @ifname: interface name to search for -- * -- * returns vdp_data on success, NULL on error -- * -- * searches the list of user_data for the VDP module user_data. -- */ --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); -- if (ud) { -- LIST_FOREACH(vd, &ud->head, entry) { -- if (!strncmp(ifname, vd->ifname, IFNAMSIZ)) -- return vd; -- } -- } -- return NULL; --} -- --/* vdp_free_tlv - free tlv in vdp_data -- * @vd: vdp_data -- * -- * no return value -- * -- * frees up tlv in vdp_data. used in vdp_free_data. -- */ --static void vdp_free_tlv(struct vdp_data *vd) --{ -- if (vd) { -- FREE_UNPKD_TLV(vd, vdp); -- } --} -- --/* vdp_free_data - frees up vdp data -- * @ud: user data structure -- * -- * no return value -- * -- * removes vd_structure from the user_data list. frees up tlv in vdp_data. -- * used in vdp_unregister. -- */ --static void vdp_free_data(struct vdp_user_data *ud) --{ -- struct vdp_data *vd; -- if (ud) { -- while (!LIST_EMPTY(&ud->head)) { -- vd = LIST_FIRST(&ud->head); -- LIST_REMOVE(vd, entry); -- vdp_free_tlv(vd); -- free(vd); -- } -- } --} -- --/* vdp_response2str - map response to string -- * @response: response received -- * -- * no return value -- * -- * maps VDP response received for a profile to human readable string for -- * printing. -- */ --const char *vdp_response2str(int response) --{ -- if ((response >= VDP_RESPONSE_SUCCESS) && -- (response <= VDP_RESPONSE_OUT_OF_SYNC)) -- return vsi_responses[response]; -- -- if (response == VDP_RESPONSE_NO_RESPONSE) -- return vsi_responses[VDP_RESPONSE_NO_RESPONSE]; -- -- return vsi_responses[VDP_RESPONSE_UNKNOWN]; --} -- --/* vdp_ack_profiles - clear ackReceived for all profiles with seqnr -- * @vd: vd for the interface -- * @seqnr: seqnr the ack has been received with -- * -- * no return value -- * -- * clear the ackReceived for all profiles which have been sent out with -- * the seqnr that we now have received the ecp ack for. -- */ --void vdp_ack_profiles(struct vdp_data *vd, int seqnr) --{ -- struct vsi_profile *p; -- -- LIST_FOREACH(p, &vd->profile_head, profile) { -- if (p->seqnr == seqnr) { -- p->ackReceived = false; -- p->txmit = true; -- } -- } -- --} -- --/* vdp_vsis - find out number of VSIs for this interface -- * @ifname: interfac name -- * -- * returns the number of VSIs -- * -- * walk through the list of VSIs and return the count. -- */ --int vdp_vsis(char *ifname) --{ -- struct vdp_data *vd; -- struct vsi_profile *p; -- int count = 0; -- -- vd = vdp_data(ifname); -- -- if (!vd) -- return 0; -- -- LIST_FOREACH(p, &vd->profile_head, profile) { -- count++; -- } -- -- return count; --} -- --/* vdp_vsis_pending - check for pending VSIs -- * @vd: vdp data for the interface -- * -- * returns the number of VSIs found -- * -- * walk through the list of VSIs and return the count. -- */ --int vdp_vsis_pending(struct vdp_data *vd) --{ -- struct vsi_profile *p; -- int count = 0; -- -- LIST_FOREACH(p, &vd->profile_head, profile) { -- if (p->localChange && (p->txmit == false)) -- count++; -- } -- -- return count; --} -- --/* vdp_somethingChangedLocal - set flag if profile has changed -- * @profile: profile to set the flag for -- * @flag: set the flag to true or false -- * -- * no return value -- * -- * set the localChange flag with a mode to indicate a profile has changed. -- * used next time when a ecpdu with profiles is sent out. -- */ --void vdp_somethingChangedLocal(struct vsi_profile *profile, bool flag) --{ -- LLDPAD_DBG("%s: setting profile->localChange to %s\n", -- __func__, (flag == true) ? "true" : "false"); -- -- profile->localChange = flag; -- -- if (flag == true) -- vdp_start_localchange_timer(profile); --} -- --/* vdp_keepaliveTimer_expired - checks for expired ack timer -- * @profile: profile to be checked -- * -- * returns true or false -- * -- * returns value of profile->keepaliveTimerExpired, true if ack timer has -- * expired, * false otherwise. -- */ --static bool vdp_keepaliveTimer_expired(struct vsi_profile *profile) --{ -- return (profile->keepaliveTimer == 0); --} -- --/* vdp_ackTimer_expired - checks for expired ack timer -- * @profile: profile to be checked -- * -- * returns true or false -- * -- * returns value of profile->ackTimerExpired, true if ack timer has expired, -- * false otherwise. -- */ --static bool vdp_ackTimer_expired(struct vsi_profile *profile) --{ -- return (profile->ackTimer == 0); --} -- --/* vdp_localchange_handler - triggers in case of vdp_ack or on vdp -- * localchange -- * @eloop_data: data structure of event loop -- * @user_ctx: user context, vdp_data here -- * -- * no return value -- * -- * called from vdp_somethingchangedlocal or vdp_ack_profiles when a change is -- * pending. Calls the VDP station state machine. This detour is taken -- * to not having to call the vdp code from the ecp state machine. Instead, we -- * return to the event loop, giving other code a chance to do work. -- */ --void vdp_localchange_handler(UNUSED void *eloop_data, void *user_ctx) --{ -- struct vsi_profile *p; -- -- p = (struct vsi_profile *) user_ctx; -- -- if ((p->ackReceived) || (p->localChange)) { -- LLDPAD_DBG("%s: p->localChange %i p->ackReceived %i\n", -- __func__, p->localChange, p->ackReceived); -- vdp_vsi_sm_station(p); -- } --} -- --/* -- * vdp_stop - cancel the VDP localchange timer -- * -- * returns 0 on success, -1 on error -- * -- * cancels the VPP localchange timer when a profile has been deleted. -- */ --int vdp_stop_localchange_timer(struct vsi_profile *p) --{ -- return eloop_cancel_timeout(vdp_localchange_handler, NULL, (void *) p); --} -- --/* vdp_start_localchange_timer - starts the VDP localchange timer -- * @vd: vdp_data for the interface -- * -- * returns 0 on success, -1 on error -- * -- * starts the VPP localchange timer when a localchange has been signaled from -- * the VDP state machine. -- */ --int vdp_start_localchange_timer(struct vsi_profile *p) --{ -- unsigned int usecs; -- -- usecs = VDP_LOCALCHANGE_TIMEOUT; -- -- return eloop_register_timeout(0, usecs, vdp_localchange_handler, NULL, -- (void *) p); --} -- --/* vdp_ack_timeout_handler - handles the ack timer expiry -- * @eloop_data: data structure of event loop -- * @user_ctx: user context, vdp_data here -- * -- * no return value -- * -- * called when the VDP ack timer for a profile has expired. -- * Calls the VDP station state machine for the profile. -- */ --void vdp_ack_timeout_handler(UNUSED void *eloop_data, void *user_ctx) --{ -- struct vsi_profile *p = (struct vsi_profile *) user_ctx; -- -- if (p->ackTimer > 0) -- p->ackTimer -= VDP_ACK_TIMER_DEFAULT; -- -- if (vdp_ackTimer_expired(p)) { -- LLDPAD_DBG("%s: profile %#02x vdp_ackTimer_expired %i" -- " p->ackReceived %i\n", __func__, p->instance[15], -- vdp_ackTimer_expired(p), p->ackReceived); -- vdp_vsi_sm_station(p); -- } --} -- --/* vdp_start_ack_timer - starts the VDP profile ack timer -- * @profile: vsi_profile -- * -- * returns 0 on success, -1 on error -- * -- * starts the VDP profile ack timer when a profile has been handed to ecp for -- * transmission. -- */ --static int vdp_start_ackTimer(struct vsi_profile *profile) --{ -- unsigned int usecs; -- -- usecs = VDP_ACK_TIMER_DEFAULT; -- -- profile->ackTimer = VDP_ACK_TIMER_DEFAULT; -- -- LLDPAD_DBG("%s: %s starting ack timer for %#02x (%i)\n", -- __func__, profile->port->ifname, -- profile->instance[15], profile->ackTimer); -- -- return eloop_register_timeout(0, usecs, vdp_ack_timeout_handler, NULL, -- (void *)profile); --} -- --/* vdp_stop_ackTimer - stops the VDP profile ack timer -- * @vd: vdp_data for the interface -- * -- * returns the number of removed handlers -- * -- * stops the VDP tck imer. Used e.g. when the host interface goes down. -- */ --static int vdp_stop_ackTimer(struct vsi_profile *profile) --{ -- LLDPAD_DBG("%s: %s stopping ack timer for %#02x (%i)\n", __func__, -- profile->port->ifname, profile->instance[15], -- profile->ackTimer); -- -- return eloop_cancel_timeout(vdp_ack_timeout_handler, NULL, -- (void *)profile); --} -- --/* vdp_keepalive_timeout_handler - handles the keepalive timer expiry -- * @eloop_data: data structure of event loop -- * @user_ctx: user context, vdp_data here -- * -- * no return value -- * -- * called when the VDP keepalive timer for a profile has expired. -- * Calls the VDP station state machine for the profile. -- */ --void vdp_keepalive_timeout_handler(UNUSED void *eloop_data, void *user_ctx) --{ -- struct vsi_profile *p = (struct vsi_profile *) user_ctx; -- -- if (p->keepaliveTimer > 0) -- p->keepaliveTimer -= VDP_KEEPALIVE_TIMER_DEFAULT; -- -- if (vdp_keepaliveTimer_expired(p)) { -- LLDPAD_DBG("%s: profile %#02x vdp_keepaliveTimer_expired %i" -- " p->ackReceived %i p->ackReceived %i\n", __func__, -- p->instance[15], vdp_keepaliveTimer_expired(p), -- p->ackReceived, p->ackReceived); -- vdp_vsi_sm_station(p); -- } --} -- --/* vdp_start_keepalive_timer - starts the VDP profile keepalive timer -- * @vd: vdp_data for the interface -- * -- * returns 0 on success, -1 on error -- * -- * starts the VDP profile keepalive timer when a profile has been handed to -- * ecp for transmission. -- */ --static int vdp_start_keepaliveTimer(struct vsi_profile *profile) --{ -- unsigned int usecs; -- -- usecs = VDP_KEEPALIVE_TIMER_DEFAULT; -- -- profile->keepaliveTimer = VDP_KEEPALIVE_TIMER_DEFAULT; -- -- LLDPAD_DBG("%s: %s starting keepalive timer for %#02x (%i)\n", -- __func__, profile->port->ifname, profile->instance[15], -- profile->keepaliveTimer); -- -- return eloop_register_timeout(0, usecs, vdp_keepalive_timeout_handler, -- NULL, (void *) profile); --} -- --/* vdp_stop_keepalive_timer - stops the VDP profile keepalive timer -- * @vd: vdp_data for the interface -- * -- * returns the number of removed handlers -- * -- * stops the VDP tck imer. Used e.g. when the host interface goes down. -- */ --static int vdp_stop_keepaliveTimer(struct vsi_profile *profile) --{ -- profile->keepaliveTimer = VDP_KEEPALIVE_TIMER_STOPPED; -- -- LLDPAD_DBG("%s: %s stopping keepalive timer for %#02x (%i)\n", -- __func__, profile->port->ifname, -- profile->instance[15], profile->keepaliveTimer); -- -- return eloop_cancel_timeout(vdp_keepalive_timeout_handler, NULL, -- (void *) profile); --} -- --static bool vdp_vsi_negative_response(struct vsi_profile *profile) --{ -- if ((profile->response > 0) && (profile->response < 255)) -- return true; -- else -- return false; --} -- --/* vdp_vsi_change_station_state - changes the VDP station sm state -- * @profile: profile to process -- * @newstate: new state for the sm -- * -- * no return value -- * -- * actually changes the state of the profile -- */ --void vdp_vsi_change_station_state(struct vsi_profile *profile, u8 newstate) --{ -- switch(newstate) { -- case VSI_UNASSOCIATED: -- break; -- case VSI_ASSOC_PROCESSING: -- assert((profile->state == VSI_PREASSOCIATED) || -- (profile->state == VSI_ASSOCIATED) || -- (profile->state == VSI_UNASSOCIATED)); -- break; -- case VSI_ASSOCIATED: -- assert((profile->state == VSI_ASSOC_PROCESSING) || -- (profile->state == VSI_ASSOCIATED)); -- break; -- case VSI_PREASSOC_PROCESSING: -- assert((profile->state == VSI_PREASSOCIATED) || -- (profile->state == VSI_ASSOCIATED) || -- (profile->state == VSI_UNASSOCIATED)); -- break; -- case VSI_PREASSOCIATED: -- assert((profile->state == VSI_PREASSOC_PROCESSING) || -- (profile->state == VSI_PREASSOCIATED)); -- break; -- case VSI_DEASSOC_PROCESSING: -- assert((profile->state == VSI_PREASSOCIATED) || -- (profile->state == VSI_UNASSOCIATED) || -- (profile->state == VSI_ASSOCIATED)); -- break; -- case VSI_EXIT: -- assert((profile->state == VSI_ASSOC_PROCESSING) || -- (profile->state == VSI_PREASSOC_PROCESSING) || -- (profile->state == VSI_DEASSOC_PROCESSING) || -- (profile->state == VSI_PREASSOCIATED) || -- (profile->state == VSI_ASSOCIATED)); -- break; -- default: -- LLDPAD_ERR("ERROR: The VDP station State Machine is broken\n"); -- break; -- } -- -- LLDPAD_DBG("%s: %s state change %s -> %s\n", __func__, -- profile->port->ifname, vsi_states[profile->state], -- vsi_states[newstate]); -- -- profile->state = newstate; --} -- --/* vdp_vsi_set_station_state - sets the vdp sm station state -- * @profile: profile to process -- * -- * returns true or false -- * -- * switches the state machine to the next state depending on the input -- * variables. returns true or false depending on wether the state machine -- * can be run again with the new state or can stop at the current state. -- */ --static bool vdp_vsi_set_station_state(struct vsi_profile *profile) --{ -- switch(profile->state) { -- case VSI_UNASSOCIATED: -- if ((profile->mode == VDP_MODE_PREASSOCIATE) || -- (profile->mode == VDP_MODE_PREASSOCIATE_WITH_RR)) { -- vdp_vsi_change_station_state(profile, VSI_PREASSOC_PROCESSING); -- vdp_somethingChangedLocal(profile, true); -- return true; -- } else if (profile->mode == VDP_MODE_ASSOCIATE) { -- vdp_vsi_change_station_state(profile, VSI_ASSOC_PROCESSING); -- vdp_somethingChangedLocal(profile, true); -- return true; -- } else if (profile->mode == VDP_MODE_DEASSOCIATE) { -- vdp_vsi_change_station_state(profile, VSI_DEASSOC_PROCESSING); -- vdp_somethingChangedLocal(profile, true); -- return true; -- } -- return false; -- case VSI_ASSOC_PROCESSING: -- if (profile->ackReceived) { -- if (profile->response == 0) -- vdp_vsi_change_station_state(profile, VSI_ASSOCIATED); -- else -- vdp_vsi_change_station_state(profile, VSI_EXIT); -- return true; -- } else if (!profile->ackReceived && vdp_ackTimer_expired(profile)) { -- vdp_vsi_change_station_state(profile, VSI_EXIT); -- return true; -- } -- return false; -- case VSI_ASSOCIATED: -- if (profile->mode == VDP_MODE_PREASSOCIATE) { -- vdp_vsi_change_station_state(profile, VSI_PREASSOC_PROCESSING); -- return true; -- } else if (profile->mode == VDP_MODE_DEASSOCIATE) { -- vdp_vsi_change_station_state(profile, VSI_DEASSOC_PROCESSING); -- return true; -- } else if (vdp_vsi_negative_response(profile)) { -- vdp_vsi_change_station_state(profile, VSI_EXIT); -- return true; -- } else if (vdp_keepaliveTimer_expired(profile)) { -- vdp_stop_keepaliveTimer(profile); -- vdp_somethingChangedLocal(profile, true); -- vdp_vsi_change_station_state(profile, VSI_ASSOC_PROCESSING); -- return true; -- } -- return false; -- case VSI_PREASSOC_PROCESSING: -- LLDPAD_DBG("%s: profile->ackReceived %i, vdp_ackTimer %i\n", -- __func__, profile->ackReceived, profile->ackTimer); -- if (profile->ackReceived) { -- if (profile->response == 0) -- vdp_vsi_change_station_state(profile, VSI_PREASSOCIATED); -- else -- vdp_vsi_change_station_state(profile, VSI_EXIT); -- return true; -- } else if (!profile->ackReceived && vdp_ackTimer_expired(profile)) { -- vdp_vsi_change_station_state(profile, VSI_EXIT); -- return true; -- } -- return false; -- case VSI_PREASSOCIATED: -- if (profile->mode == VDP_MODE_ASSOCIATE) { -- vdp_vsi_change_station_state(profile, VSI_ASSOC_PROCESSING); -- return true; -- } else if (profile->mode == VDP_MODE_DEASSOCIATE) { -- vdp_vsi_change_station_state(profile, VSI_DEASSOC_PROCESSING); -- return true; -- } else if (vdp_keepaliveTimer_expired(profile)) { -- vdp_stop_keepaliveTimer(profile); -- vdp_somethingChangedLocal(profile, true); -- vdp_vsi_change_station_state(profile, VSI_PREASSOC_PROCESSING); -- return true; -- } -- return false; -- case VSI_DEASSOC_PROCESSING: -- if ((profile->ackReceived) || vdp_ackTimer_expired(profile) || -- profile->remoteChange) { -- vdp_vsi_change_station_state(profile, VSI_EXIT); -- return true; -- } -- return false; -- case VSI_EXIT: -- return false; -- default: -- LLDPAD_ERR("%s: VSI state machine in invalid state %d\n", -- profile->port->ifname, profile->state); -- return false; -- } --} -- --/* vdp_vsi_sm_station - state machine for vdp station role -- * @profile: profile for which the state is processed -- * -- * no return value -- * -- * runs the state machine for the station role of VDP. -- */ --void vdp_vsi_sm_station(struct vsi_profile *profile) --{ -- struct vdp_data *vd = vdp_data(profile->port->ifname); -- int bye = 0; -- -- vdp_vsi_set_station_state(profile); -- do { -- LLDPAD_DBG("%s: %s station for %#02x - %s\n", -- __func__, profile->port->ifname, -- profile->instance[15], vsi_states[profile->state]); -- -- switch(profile->state) { -- case VSI_UNASSOCIATED: -- break; -- case VSI_ASSOC_PROCESSING: -- vdp_stop_keepaliveTimer(profile); -- profile->response = VDP_RESPONSE_NO_RESPONSE; -- if (profile->localChange) { -- ecp_somethingChangedLocal(vd, true); -- profile->ackReceived = false; -- vdp_start_ackTimer(profile); -- } -- break; -- case VSI_ASSOCIATED: -- profile->ackReceived = false; -- vdp_somethingChangedLocal(profile, false); -- vdp_stop_ackTimer(profile); -- vdp_start_keepaliveTimer(profile); -- break; -- case VSI_PREASSOC_PROCESSING: -- vdp_stop_keepaliveTimer(profile); -- profile->response = VDP_RESPONSE_NO_RESPONSE; -- if (profile->localChange) { -- profile->ackReceived = false; -- ecp_somethingChangedLocal(vd, true); -- vdp_start_ackTimer(profile); -- } -- break; -- case VSI_PREASSOCIATED: -- profile->ackReceived = false; -- vdp_somethingChangedLocal(profile, false); -- vdp_stop_ackTimer(profile); -- vdp_start_keepaliveTimer(profile); -- break; -- case VSI_DEASSOC_PROCESSING: -- profile->ackReceived = false; -- vdp_stop_keepaliveTimer(profile); -- profile->response = VDP_RESPONSE_NO_RESPONSE; -- if (profile->localChange) { -- profile->ackReceived = false; -- ecp_somethingChangedLocal(vd, true); -- vdp_start_ackTimer(profile); -- } -- break; -- case VSI_EXIT: -- if (profile->no_nlmsg && !profile->ackReceived && -- vdp_ackTimer_expired(profile)) -- bye = 1; -- vdp_stop_ackTimer(profile); -- vdp_stop_keepaliveTimer(profile); -- vdp_stop_localchange_timer(profile); -- if (bye) -- vdp_remove_profile(profile); -- else -- vdp_trigger(profile); -- break; -- default: -- LLDPAD_ERR("%s: ERROR VSI state machine in invalid state %d\n", -- vd->ifname, profile->state); -- } -- } while (vdp_vsi_set_station_state(profile) == true); -- --} -- --/* vdp_advance_sm - advance state machine after update from switch -- * -- * no return value -- */ --void vdp_advance_sm(struct vdp_data *vd) --{ -- struct vsi_profile *p; -- -- LIST_FOREACH(p, &vd->profile_head, profile) { -- LLDPAD_DBG("%s: %s station for %#02x - %s ackReceived %i\n", -- __func__, p->port->ifname, -- p->instance[15], vsi_states[p->state], -- p->ackReceived); -- if (p->ackReceived) { -- vdp_vsi_sm_station(p); -- p->ackReceived = false; -- } -- } --} -- --/* vdp_vsi_change_bridge_state - changes the VDP bridge sm state -- * @profile: profile to process -- * @newstate: new state for the sm -- * -- * no return value -- * -- * actually changes the state of the profile -- */ --static void vdp_vsi_change_bridge_state(struct vsi_profile *profile, -- u8 newstate) --{ -- switch(newstate) { -- case VSI_UNASSOCIATED: -- break; -- case VSI_ASSOC_PROCESSING: -- assert((profile->state == VSI_UNASSOCIATED) || -- (profile->state == VSI_PREASSOCIATED) || -- (profile->state == VSI_ASSOCIATED)); -- break; -- case VSI_ASSOCIATED: -- assert(profile->state == VSI_ASSOC_PROCESSING); -- break; -- case VSI_PREASSOC_PROCESSING: -- assert((profile->state == VSI_UNASSOCIATED) || -- (profile->state == VSI_PREASSOCIATED) || -- (profile->state == VSI_ASSOCIATED)); -- break; -- case VSI_PREASSOCIATED: -- assert(profile->state == VSI_PREASSOC_PROCESSING); -- break; -- case VSI_DEASSOC_PROCESSING: -- assert((profile->state == VSI_UNASSOCIATED) || -- (profile->state == VSI_PREASSOCIATED) || -- (profile->state == VSI_ASSOCIATED)); -- break; -- case VSI_EXIT: -- assert((profile->state == VSI_DEASSOC_PROCESSING) || -- (profile->state == VSI_PREASSOC_PROCESSING) || -- (profile->state == VSI_ASSOC_PROCESSING)); -- break; -- default: -- LLDPAD_ERR("ERROR: The VDP bridge State Machine is broken\n"); -- break; -- } -- profile->state = newstate; --} -- --/* vdp_vsi_set_bridge_state - sets the vdp sm bridge state -- * @profile: profile to process -- * -- * returns true or false -- * -- * switches the state machine to the next state depending on the input -- * variables. returns true or false depending on wether the state machine -- * can be run again with the new state or can stop at the current state. -- */ --static bool vdp_vsi_set_bridge_state(struct vsi_profile *profile) --{ -- switch(profile->state) { -- case VSI_UNASSOCIATED: -- if ((profile->mode == VDP_MODE_DEASSOCIATE)) /* || (INACTIVE)) */ { -- vdp_vsi_change_bridge_state(profile, VSI_DEASSOC_PROCESSING); -- return true; -- } else if (profile->mode == VDP_MODE_ASSOCIATE) { -- vdp_vsi_change_bridge_state(profile, VSI_ASSOC_PROCESSING); -- return true; -- } else if (profile->mode == VDP_MODE_PREASSOCIATE) { -- vdp_vsi_change_bridge_state(profile, VSI_PREASSOC_PROCESSING); -- return true; -- } -- return false; -- case VSI_ASSOC_PROCESSING: -- /* TODO: handle error case -- if (!vsiError) || -- (vsiError && vsiState == Assoc) { -- */ -- if (profile->mode == VDP_MODE_ASSOCIATE) { -- vdp_vsi_change_bridge_state(profile, VSI_ASSOCIATED); -- return true; -- } -- return false; -- case VSI_ASSOCIATED: -- if (profile->mode == VDP_MODE_ASSOCIATE) /* || ( INACTIVE )*/ { -- vdp_vsi_change_bridge_state(profile, VSI_DEASSOC_PROCESSING); -- return true; -- } else if (profile->mode == VDP_MODE_PREASSOCIATE) { -- vdp_vsi_change_bridge_state(profile, VSI_PREASSOC_PROCESSING); -- return true; -- } else if (profile->mode == VDP_MODE_ASSOCIATE) { -- vdp_vsi_change_bridge_state(profile, VSI_ASSOC_PROCESSING); -- return true; -- } -- return false; -- case VSI_PREASSOC_PROCESSING: -- if (profile->response != VDP_RESPONSE_SUCCESS) { -- vdp_vsi_change_bridge_state(profile, VSI_EXIT); -- return true; -- } -- vdp_vsi_change_bridge_state(profile, VSI_PREASSOCIATED); -- return false; -- case VSI_PREASSOCIATED: -- if (profile->mode == VDP_MODE_ASSOCIATE) { -- vdp_vsi_change_bridge_state(profile, VSI_ASSOC_PROCESSING); -- return true; -- } else if (profile->mode == VDP_MODE_DEASSOCIATE ) { -- vdp_vsi_change_bridge_state(profile, VSI_DEASSOC_PROCESSING); -- return true; -- } else if (profile->mode == VDP_MODE_PREASSOCIATE ) { -- vdp_vsi_change_bridge_state(profile, VSI_PREASSOC_PROCESSING); -- return true; -- } -- return false; -- case VSI_DEASSOC_PROCESSING: -- vdp_vsi_change_bridge_state(profile, VSI_EXIT); -- return false; -- case VSI_EXIT: -- return false; -- default: -- LLDPAD_ERR("%s: ERROR VSI state machine (bridge) in invalid state %d\n", -- profile->port->ifname, profile->state); -- return false; -- } --} -- --/* vdp_vsi_sm_bridge - state machine for vdp bridge role -- * @profile: profile for which the state is processed -- * -- * no return value -- * -- * runs the state machine for the bridge role of VDP. -- */ --static void vdp_vsi_sm_bridge(struct vsi_profile *profile) --{ -- struct vdp_data *vd = vdp_data(profile->port->ifname); -- -- vdp_vsi_set_bridge_state(profile); -- do { -- LLDPAD_DBG("%s: %s bridge - %s\n", __func__, -- profile->port->ifname, vsi_states[profile->state]); -- switch(profile->state) { -- case VSI_UNASSOCIATED: -- break; -- case VSI_ASSOC_PROCESSING: -- /* TODO: vsiError = ProcRxandSetCfg(remoteTLV, localtlv, vsistate); -- * if (vsiError) -- * txTLV(Assoc NACK) -- * else -- * txTLV(Assoc ACK) -- */ -- break; -- case VSI_ASSOCIATED: -- break; -- case VSI_PREASSOC_PROCESSING: -- /* TODO: vsiError = ProcRxandSetCfg(remoteTLV, localtlv, vsistate); -- * if (vsiError) -- * txTLV(PreAssoc NACK) -- * else -- * txTLV(PreAssoc ACK) -- */ -- /* for now, we always succeed */ -- profile->response = VDP_RESPONSE_SUCCESS; -- ecp_rx_send_ack_frame(vd); -- break; -- case VSI_PREASSOCIATED: -- LLDPAD_DBG("%s: %s\n", __func__, profile->port->ifname); -- break; -- case VSI_DEASSOC_PROCESSING: -- /* TODO: txTLV(DeAssoc ACK) */ -- break; -- case VSI_EXIT: -- vdp_remove_profile(profile); -- break; -- default: -- LLDPAD_ERR("%s: ERROR VSI state machine in invalid state %d\n", -- vd->ifname, profile->state); -- } -- } while (vdp_vsi_set_bridge_state(profile) == true); -- --} -- --/* -- * vdp_validate_tlv - validates vsi tlvs -- * @vdp: decoded vsi tlv -- * -- * Returns 0 on success, 1 on error -- * -- * checks the contents of an already decoded vsi tlv for inconsistencies -- */ --static int vdp_validate_tlv(struct tlv_info_vdp *vdp, struct unpacked_tlv *tlv) --{ -- int pairs = (tlv->length - sizeof *vdp) / sizeof(struct mac_vlan_p); -- -- if (ntoh24(vdp->oui) != OUI_IEEE_8021Qbg) { -- LLDPAD_DBG("vdp->oui %#06x\n", ntoh24(vdp->oui)); -- goto out_err; -- } -- -- if (vdp->sub != LLDP_VDP_SUBTYPE) { -- LLDPAD_DBG("vdp->sub %#02x\n", vdp->sub); -- goto out_err; -- } -- -- if (vdp->mode > VDP_MODE_DEASSOCIATE) { -- LLDPAD_DBG("unknown mode %#02x in vsi tlv\n", vdp->mode); -- goto out_err; -- } -- -- if (vdp->response > VDP_RESPONSE_OUT_OF_SYNC) { -- LLDPAD_DBG("unknown response %#02x\n", vdp->response); -- goto out_err; -- } -- -- if (vdp->format != VDP_FILTER_INFO_FORMAT_MACVID) { -- LLDPAD_DBG("unknown format %#02x in vsi tlv\n", vdp->format); -- goto out_err; -- } -- -- if (ntohs(vdp->entries) < 1) { -- LLDPAD_DBG("invalid # of entries %#02x in vsi tlv\n", -- ntohs(vdp->entries)); -- goto out_err; -- } -- -- /* Check for number of entries of MAC,VLAN pairs */ -- if (ntohs(vdp->entries) != pairs) { -- LLDPAD_DBG("mismatching # of entries %#x/%#x in vsi tlv\n", -- ntohs(vdp->entries), pairs); -- goto out_err; -- } -- return 0; -- --out_err: -- return 1; --} -- --/* -- * Create a VSI profile structure from switch response. -- */ --static void make_profile(struct vsi_profile *new, struct tlv_info_vdp *vdp, -- struct unpacked_tlv *tlv) --{ -- int i; -- u8 *pos = tlv->info + sizeof *vdp; -- -- new->mode = vdp->mode; -- new->response = vdp->response; -- new->mgrid = vdp->mgrid; -- new->id = ntoh24(vdp->id); -- new->version = vdp->version; -- memcpy(&new->instance, &vdp->instance, sizeof new->instance); -- new->format = vdp->format; -- new->entries = ntohs(vdp->entries); -- LLDPAD_DBG("%s: MAC/VLAN filter info format %u, # of entries %u\n", -- __func__, new->format, new->entries); -- -- /* Add MAC,VLAN to list */ -- for (i = 0; i < new->entries; ++i) { -- struct mac_vlan *mac_vlan = calloc(1, sizeof(struct mac_vlan)); -- u16 vlan; -- char macbuf[MAC_ADDR_STRLEN + 1]; -- -- if (!mac_vlan) { -- new->entries = i; -- return; -- } -- memcpy(&mac_vlan->mac, pos, ETH_ALEN); -- pos += ETH_ALEN; -- mac2str(mac_vlan->mac, macbuf, MAC_ADDR_STRLEN); -- memcpy(&vlan, pos, 2); -- pos += 2; -- mac_vlan->vlan = ntohs(vlan); -- LLDPAD_DBG("%s: mac %s vlan %d\n", __func__, macbuf, -- mac_vlan->vlan); -- LIST_INSERT_HEAD(&new->macvid_head, mac_vlan, entry); -- } --} -- --/* -- * vdp_indicate - receive VSI TLVs from ECP -- * @port: the port on which the tlv was received -- * @tlv: the unpacked tlv to receive -- * -- * Returns 0 on success -- * -- * receives a vsi tlv and creates a profile. Take appropriate action -- * depending on the role of the (receive) port -- */ --int vdp_indicate(struct vdp_data *vd, struct unpacked_tlv *tlv) --{ -- struct tlv_info_vdp vdp; -- struct vsi_profile *p, *profile; -- struct port *port = port_find_by_name(vd->ifname); -- -- LLDPAD_DBG("%s: indicating vdp of length %u (%zu) for %s\n", -- __func__, tlv->length, sizeof(struct tlv_info_vdp), -- vd->ifname); -- -- if (!port) { -- LLDPAD_ERR("%s: port not found for %s\n", __func__, -- vd->ifname); -- goto out_err; -- } -- -- memset(&vdp, 0, sizeof vdp); -- /* copy only vdp header w/o list of mac/vlan/groupid pairs */ -- memcpy(&vdp, tlv->info, sizeof vdp); -- -- if (vdp_validate_tlv(&vdp, tlv)) { -- LLDPAD_ERR("%s: invalid TLV received\n", __func__); -- goto out_err; -- } -- -- profile = vdp_alloc_profile(); -- -- if (!profile) { -- LLDPAD_ERR("%s: unable to allocate profile\n", __func__); -- goto out_err; -- } -- make_profile(profile, &vdp, tlv); -- -- profile->port = port; -- -- if (vd->role == VDP_ROLE_STATION) { -- /* do we have the profile already ? */ -- p = vdp_find_profile(vd, profile); -- -- if (p) { -- LLDPAD_DBG("%s: station profile found localChange %i " -- "ackReceived %i no_nlmsg:%d\n", -- __func__, p->localChange, p->ackReceived, -- p->no_nlmsg); -- -- if (profile->mode == VDP_MODE_DEASSOCIATE && -- (p->response == VDP_RESPONSE_NO_RESPONSE || -- p->response == VDP_RESPONSE_SUCCESS) && -- p->mode == VDP_MODE_PREASSOCIATE) { -- LLDPAD_DBG("%s: ignore dis-associate request " -- "in pre-association\n", __func__); -- vdp_delete_profile(profile); -- return 0; -- } -- -- p->ackReceived = true; -- p->keepaliveTimer = VDP_KEEPALIVE_TIMER_DEFAULT; -- if (profile->mode != p->mode) { -- p->mode = profile->mode; -- p->remoteChange = true; -- if (profile->mode == VDP_MODE_DEASSOCIATE) -- p->no_nlmsg = 0; -- } else -- p->remoteChange = false; -- p->response = profile->response; -- LLDPAD_DBG("%s: remoteChange %i no_nlmsg %d mode %d\n", -- __func__, p->remoteChange, p->no_nlmsg, -- p->mode); -- if (vdp_vsi_negative_response(p)) -- p->mode = VDP_MODE_DEASSOCIATE; -- -- LLDPAD_DBG("%s: profile response: %s (%i) " -- "for profile %#02x at state %s\n", -- __func__, -- vdp_response2str(p->response), -- p->response, p->instance[15], -- vsi_states[p->state]); -- } else { -- LLDPAD_DBG("%s: station profile not found\n", __func__); -- } -- vdp_delete_profile(profile); -- } -- -- if (vd->role == VDP_ROLE_BRIDGE) { -- /* do we have the profile already ? */ -- p = vdp_find_profile(vd, profile); -- -- if (p) { -- LLDPAD_DBG("%s: bridge profile found\n", __func__); -- vdp_delete_profile(profile); -- } else { -- LLDPAD_DBG("%s: bridge profile not found\n", __func__); -- /* put it in the list */ -- profile->state = VSI_UNASSOCIATED; -- LIST_INSERT_HEAD(&vd->profile_head, profile, profile); -- } -- -- vdp_vsi_sm_bridge(profile); -- } -- -- return 0; -- --out_err: -- return 1; -- --} -- --/* -- * vdp_bld_vsi_tlv - build the VDP VSI TLV -- * @vd: vdp_data structure for this port -- * @profile: profile the vsi tlv is created from -- * -- * Returns 0 on success, ENOMEM otherwise -- * -- * creates a vdp structure from an existing profile -- */ --static int vdp_bld_vsi_tlv(struct vdp_data *vd, struct vsi_profile *profile) --{ -- struct mac_vlan *mv; -- struct mac_vlan_p *mv_p; -- struct tlv_info_vdp *vdp; -- int rc = 0; -- struct unpacked_tlv *tlv = NULL; -- int size = sizeof(struct tlv_info_vdp) + -- profile->entries * sizeof(struct mac_vlan_p); -- -- vdp = malloc(size); -- -- if (!vdp) { -- LLDPAD_DBG("%s: unable to allocate memory for VDP TLV\n", -- __func__); -- rc = ENOMEM; -- goto out_err; -- } -- -- memset(vdp, 0, size); -- -- hton24(vdp->oui, OUI_IEEE_8021Qbg); -- vdp->sub = LLDP_VDP_SUBTYPE; -- vdp->mode = profile->mode; -- vdp->response = 0; -- vdp->mgrid = profile->mgrid; -- hton24(vdp->id, profile->id); -- vdp->version = profile->version; -- memcpy(&vdp->instance, &profile->instance, 16); -- vdp->format = VDP_FILTER_INFO_FORMAT_MACVID; -- vdp->entries = htons(profile->entries); -- -- mv_p = (struct mac_vlan_p *)(vdp + 1); -- -- LIST_FOREACH(mv, &profile->macvid_head, entry) { -- memcpy(mv_p->mac, mv->mac, MAC_ADDR_LEN); -- mv_p->vlan = htons(mv->vlan); -- mv_p++; -- } -- -- tlv = create_tlv(); -- if (!tlv) { -- rc = ENOMEM; -- goto out_free; -- } -- -- tlv->type = ORG_SPECIFIC_TLV; -- tlv->length = size; -- tlv->info = (u8 *)malloc(tlv->length); -- if(!tlv->info) { -- free(tlv); -- tlv = NULL; -- rc = ENOMEM; -- goto out_free; -- } -- -- FREE_UNPKD_TLV(vd, vdp); -- -- memcpy(tlv->info, vdp, tlv->length); -- -- vd->vdp = tlv; -- --out_free: -- free(vdp); -- --out_err: -- return rc; -- --} -- --/* vdp_bld_tlv - builds a tlv from a profile -- * @vd: vdp_data structure for this port -- * @profile: profile the vsi tlv is created from -- * -- * returns 0 on success, != 0 on error -- * -- * wrapper function around vdp_bld_vsi_tlv. adds some checks and calls -- * vdp_bld_vsi_tlv. --*/ -- --static int vdp_bld_tlv(struct vdp_data *vd, struct vsi_profile *profile) --{ -- int rc = 0; -- -- if (!port_find_by_name(vd->ifname)) { -- rc = EEXIST; -- goto out_err; -- } -- -- if (vdp_bld_vsi_tlv(vd, profile)) { -- LLDPAD_ERR("%s: %s vdp_bld_vsi_tlv() failed\n", -- __func__, vd->ifname); -- rc = EINVAL; -- goto out_err; -- } -- --out_err: -- return rc; --} -- --/* vdp_gettlv - get the tlv for a profile -- * @port: the port on which the tlv was received -- * @profile: profile the vsi tlv is created from -- * -- * returns 0 on success -- * -- * this is the interface function called from ecp_build_ECPDU. It returns the -- * packed tlv for a profile. -- */ --struct packed_tlv *vdp_gettlv(struct vdp_data *vd, struct vsi_profile *profile) --{ -- int size; -- struct packed_tlv *ptlv = NULL; -- -- /* frees the unpacked_tlv in vdp_data -- * also done in vdp_bld_vsi_tlv */ -- vdp_free_tlv(vd); -- -- if (vdp_bld_tlv(vd, profile)) { -- LLDPAD_ERR("%s: %s vdp_bld_tlv failed\n", -- __func__, vd->ifname); -- goto out_err; -- } -- -- size = TLVSIZE(vd->vdp); -- -- if (!size) { -- LLDPAD_ERR("%s: size %i of unpacked_tlv not correct\n", -- __func__, size); -- goto out_err; -- } -- -- ptlv = create_ptlv(); -- if (!ptlv) -- goto out_err; -- -- ptlv->tlv = malloc(size); -- if (!ptlv->tlv) -- goto out_free; -- -- ptlv->size = 0; -- PACK_TLV_AFTER(vd->vdp, ptlv, size, out_free); -- -- return ptlv; -- --out_free: -- ptlv = free_pkd_tlv(ptlv); --out_err: -- LLDPAD_ERR("%s: %s failed\n", __func__, vd->ifname); -- return NULL; --} -- --/* vdp_macvlan_equal - checks for equality of 2 mac/vlan pairs -- * @mv1: mac/vlan pair 1 -- * @mv2: mac/vlan pair 2 -- * -- * returns true if equal, false if not -- * -- * compares mac address and vlan if they are equal. -- */ --bool vdp_macvlan_equal(struct mac_vlan *mv1, struct mac_vlan *mv2) --{ -- if (memcmp(mv1->mac, mv2->mac, MAC_ADDR_LEN)) -- return false; -- -- if (mv1->vlan != mv2->vlan) -- return false; -- -- return true; --} -- --/* -- * Check if the current profile already has this entry. If so take over -- * PID and other fields. If not add this MAC,VLAN to our list. -- * -- * Returns 1 it the entry already exist, 0 if not. -- */ --static int have_macvlan(struct vsi_profile *p1, struct mac_vlan *new) --{ -- struct mac_vlan *mv1; -- -- LIST_FOREACH(mv1, &p1->macvid_head, entry) -- if (vdp_macvlan_equal(mv1, new) == true) { -- mv1->req_pid = new->req_pid; -- mv1->req_seq = new->req_seq; -- mv1->qos = new->qos; -- return 1; -- } -- LIST_INSERT_HEAD(&p1->macvid_head, new, entry); -- p1->entries++; -- return 0; --} -- --/* vdp_takeover_macvlans - take over macvlan pairs from p2 into p1 -- * @p1: profile 1 -- * @p2: profile 2 -- * -- * returns number of mac/vlan pairs taken over -- * -- * loops over all mac/vlan pairs in profile 2 and looks for them in profile 1. -- * If the mac/vlan pair does not yet exist in profile 1, it adds the new pair to -- * the list in profile 1. -- */ --void vdp_takeover_macvlans(struct vsi_profile *p1, struct vsi_profile *p2) --{ -- struct mac_vlan *mv2; -- int count = 0; -- -- LLDPAD_DBG("%s: taking over mac/vlan pairs\n", __func__); -- -- while ((mv2 = LIST_FIRST(&p2->macvid_head))) { -- LIST_REMOVE(mv2, entry); -- p2->entries--; -- if (have_macvlan(p1, mv2)) -- free(mv2); -- else -- count++; -- } -- -- LLDPAD_DBG("%s: %u mac/vlan pairs taken over\n", __func__, count); --} -- --/* vdp_add_profile - adds a profile to a per port list -- * @profile: profile to add -- * -- * returns the profile that has been found or added, NULL otherwise. -- * -- * main interface function which adds a profile to a list kept on a per-port -- * basis. Checks if the profile is already in the list, adds it if necessary. -- */ --struct vsi_profile *vdp_add_profile(struct vdp_data *vd, -- struct vsi_profile *profile) --{ -- struct vsi_profile *p; -- -- LLDPAD_DBG("%s: adding vdp profile for %s\n", __func__, -- profile->port->ifname); -- vdp_trace_profile(profile); -- -- /* -- * Search this profile. If found check, -- * if the MAC/VLAN pair already exists. If not, add it. -- */ -- p = vdp_find_profile(vd, profile); -- if (p) { -- LLDPAD_DBG("%s: profile already exists\n", __func__); -- -- vdp_takeover_macvlans(p, profile); -- -- if (p->mode != profile->mode) { -- LLDPAD_DBG("%s: new mode %i\n", -- __func__, profile->mode); -- p->mode = profile->mode; -- p->response = VDP_RESPONSE_NO_RESPONSE; -- } -- profile = p; -- } else { -- -- profile->response = VDP_RESPONSE_NO_RESPONSE; -- -- LIST_INSERT_HEAD(&vd->profile_head, profile, profile); -- } -- -- vdp_somethingChangedLocal(profile, true); -- -- return profile; --} -- --/* vdp_remove_profile - remove a profile from a per port list -- * @profile: profile to remove -- * -- * returns 0 if removal was successful, -1 if removal failed -- * -- * function used in the state machines to remove a profile from a list kept on -- * a per-port basis. Checks if the profile is in the list, removes it if there. -- */ --int vdp_remove_profile(struct vsi_profile *profile) --{ -- struct vsi_profile *p; -- struct vdp_data *vd; -- -- LLDPAD_DBG("%s: removing vdp profile on %s\n", __func__, -- profile->port->ifname); -- vdp_trace_profile(profile); -- -- vd = vdp_data(profile->port->ifname); -- if (!vd) { -- LLDPAD_ERR("%s: could not find vdp_data for %s\n", __func__, -- profile->port->ifname); -- return -1; -- } -- /* Check if profile exists. If yes, remove it. */ -- p = vdp_find_profile(vd, profile); -- if (p) { -- LIST_REMOVE(p, profile); -- vdp_delete_profile(p); -- return 0; -- } -- return -1; /* Not found */ --} -- --/* vdp_ifdown - tear down vdp structures for a interface -- * @ifname: name of the interface -- * -- * no return value -- * -- * interface function to lldpad. tears down vdp specific structures if -- * interface "ifname" goes down. -- */ --void vdp_ifdown(char *ifname, UNUSED struct lldp_agent *agent) --{ -- struct vdp_data *vd; -- struct vsi_profile *p; -- -- LLDPAD_DBG("%s: called on interface %s\n", __func__, ifname); -- -- vd = vdp_data(ifname); -- if (!vd) -- goto out_err; -- -- if (ecp_deinit(ifname)) -- goto out_err; -- -- LIST_FOREACH(p, &vd->profile_head, profile) { -- if (p->ackTimer > 0) -- vdp_stop_ackTimer(p); -- if (p->keepaliveTimer > 0) -- vdp_stop_keepaliveTimer(p); -- } -- -- LLDPAD_INFO("%s: %s vdp data removed\n", __func__, ifname); -- return; --out_err: -- LLDPAD_INFO("%s: %s vdp data remove failed\n", __func__, ifname); -- -- return; --} -- --/* vdp_ifup - build up vdp structures for a interface -- * @ifname: name of the interface -- * -- * no return value -- * -- * interface function to lldpad. builds up vdp specific structures if -- * interface "ifname" goes up. -- */ --void vdp_ifup(char *ifname, struct lldp_agent *agent) --{ -- char *role; -- char config_path[16]; -- struct vdp_data *vd; -- struct vdp_user_data *ud; -- struct vsi_profile *p; -- int enabletx = false; -- -- LLDPAD_DBG("%s: %s agent:%d start VDP\n", -- __func__, ifname, agent->type); -- -- snprintf(config_path, sizeof(config_path), "%s.%s", -- VDP_PREFIX, ARG_TLVTXENABLE); -- -- if (get_config_setting(ifname, agent->type, config_path, -- (void *)&enabletx, CONFIG_TYPE_BOOL)) -- enabletx = false; -- -- if (enabletx == false) { -- LLDPAD_DBG("%s: %s not enabled for VDP\n", __func__, ifname); -- return; -- } -- -- vd = vdp_data(ifname); -- if (vd) { -- vd->enabletx = enabletx; -- -- LLDPAD_WARN("%s: %s vdp data already exists\n", -- __func__, ifname); -- goto out_start_again; -- } -- -- /* not found, alloc/init per-port module data */ -- vd = (struct vdp_data *) calloc(1, sizeof(struct vdp_data)); -- if (!vd) { -- LLDPAD_ERR("%s: %s malloc %zu failed\n", -- __func__, ifname, sizeof(*vd)); -- goto out_err; -- } -- strncpy(vd->ifname, ifname, IFNAMSIZ); -- -- vd->role = VDP_ROLE_STATION; -- vd->enabletx = enabletx; -- -- if (!get_cfg(ifname, NEAREST_BRIDGE, "vdp.role", (void *)&role, -- CONFIG_TYPE_STRING)) { -- if (!strcasecmp(role, VAL_BRIDGE)) { -- vd->role = VDP_ROLE_BRIDGE; -- } -- } -- -- LLDPAD_DBG("%s: configured for %s mode\n", ifname, -- (vd->role ==VDP_ROLE_BRIDGE) ? "bridge" : "station"); -- -- LIST_INIT(&vd->profile_head); -- -- ud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_VDP02); -- LIST_INSERT_HEAD(&ud->head, vd, entry); -- --out_start_again: -- if (ecp_init(ifname)) { -- LLDPAD_ERR("%s: %s unable to init ecp\n", __func__, ifname); -- vdp_ifdown(ifname, agent); -- goto out_err; -- } -- -- vd->keepaliveTimer = VDP_KEEPALIVE_TIMER_DEFAULT; -- vd->ackTimer = VDP_ACK_TIMER_DEFAULT; -- -- LLDPAD_DBG("%s: %s starting vdp timer (%i)\n", __func__, -- vd->ifname, vd->nroftimers); -- -- LIST_FOREACH(p, &vd->profile_head, profile) { -- if (p->ackTimer > 0) { -- vdp_somethingChangedLocal(p, true); -- vdp_start_ackTimer(p); -- } -- if (p->keepaliveTimer > 0) -- vdp_start_keepaliveTimer(p); -- } -- -- LLDPAD_DBG("%s: %s agent:%d vdp added\n", __func__, ifname, -- agent->type); -- return; -- --out_err: -- LLDPAD_ERR("%s: %s agent:%d vdp adding failed\n", -- __func__, ifname, agent->type); --} -- --static int vdp_client_cmd(UNUSED void *data, UNUSED struct sockaddr_un *from, -- UNUSED socklen_t fromlen, char *ibuf, int ilen, -- char *rbuf, int rlen) --{ -- return vdp_clif_cmd(ibuf, ilen, rbuf, rlen); --} -- --static const struct lldp_mod_ops vdp_ops = { -- .lldp_mod_register = vdp_register, -- .lldp_mod_unregister = vdp_unregister, -- .get_arg_handler = vdp_get_arg_handlers, -- .client_cmd = vdp_client_cmd --}; -- --/* vdp_register - register vdp module to lldpad -- * @none -- * -- * returns lldp_module struct on success, NULL on error -- * -- * allocates a module structure with vdp module information and returns it -- * to lldpad. -- */ --struct lldp_module *vdp_register(void) --{ -- struct lldp_module *mod; -- struct vdp_user_data *ud; -- -- mod = malloc(sizeof(*mod)); -- if (!mod) { -- LLDPAD_ERR("%s: failed to start - vdp data\n", __func__); -- return NULL; -- } -- ud = malloc(sizeof(struct vdp_user_data)); -- if (!ud) { -- free(mod); -- LLDPAD_ERR("%s: failed to start - vdp user data\n", __func__); -- return NULL; -- } -- LIST_INIT(&ud->head); -- mod->id = LLDP_MOD_VDP02; -- mod->ops = &vdp_ops; -- mod->data = ud; -- LLDPAD_DBG("%s: done\n", __func__); -- return mod; --} -- --/* vdp_unregister - unregister vdp module from lldpad -- * @none -- * -- * no return value -- * -- * frees vdp module structure. -- */ --void vdp_unregister(struct lldp_module *mod) --{ -- if (mod->data) { -- vdp_free_data((struct vdp_user_data *) mod->data); -- free(mod->data); -- } -- free(mod); -- LLDPAD_DBG("%s: done\n", __func__); --} -- --void vdp_update(char *ifname, u8 ccap) --{ -- struct vdp_data *vdp = vdp_data(ifname); -- -- if (vdp) { -- vdp->vdpbit_on = ccap & LLDP_EVB_CAPABILITY_PROTOCOL_VDP; -- LLDPAD_DBG("%s:%s vdpbit_on %d\n", __func__, ifname, -- vdp->vdpbit_on); -- } --} -- --/* -- * Handle a VSI request from buddy. -- */ --int vdp_request(struct vdpnl_vsi *vsi) --{ -- struct vdp_data *vd; -- struct vsi_profile *profile, *p; -- struct port *port = port_find_by_name(vsi->ifname); -- struct mac_vlan *mac_vlan; -- int ret = 0; -- -- vd = vdp_data(vsi->ifname); -- if (!vd) { -- LLDPAD_ERR("%s: %s has not yet been configured\n", __func__, -- vsi->ifname); -- return -ENXIO; -- } -- if (!vd->vdpbit_on) { -- LLDPAD_ERR("%s: %s has VDP disabled\n", __func__, vsi->ifname); -- return -ENXIO; -- } -- -- if (!port) { -- LLDPAD_ERR("%s: %s can not find port\n", __func__, vsi->ifname); -- return -ENODEV; -- } -- /* If the link is down, reject request */ -- if (!port->portEnabled && vsi->request != VDP_MODE_DEASSOCIATE) { -- LLDPAD_WARN("%s: %s not enabled, unable to associate\n", -- __func__, vsi->ifname); -- return -ENXIO; -- } -- -- profile = vdp_alloc_profile(); -- if (!profile) -- return -ENOMEM; -- mac_vlan = calloc(1, sizeof(struct mac_vlan)); -- if (!mac_vlan) { -- ret = -ENOMEM; -- goto out_err; -- } -- -- profile->port = port; -- memcpy(&mac_vlan->mac, vsi->maclist->mac, sizeof mac_vlan->mac); -- mac_vlan->vlan = vsi->maclist->vlan; -- mac_vlan->qos = vsi->maclist->qos; -- mac_vlan->req_pid = vsi->req_pid; -- mac_vlan->req_seq = vsi->req_seq; -- LIST_INSERT_HEAD(&profile->macvid_head, mac_vlan, entry); -- profile->entries = 1; -- -- profile->mgrid = vsi->vsi_mgrid; -- profile->id = vsi->vsi_typeid; -- profile->version = vsi->vsi_typeversion; -- profile->mode = vsi->request; -- profile->response = vsi->response; -- memcpy(profile->instance, vsi->vsi_uuid, sizeof vsi->vsi_uuid); -- p = vdp_add_profile(vd, profile); -- p->no_nlmsg = 1; -- p->txmit = false; -- vdp_trace_profile(p); -- if (p != profile) -- goto out_err; -- return ret; -- --out_err: -- vdp_delete_profile(profile); -- return ret; --} -- --/* -- * Query a VSI request from buddy and report its progress. Use the interface -- * name to determine the VSI profile list. Return one entry in parameter 'vsi' -- * use the structure members response and vsi_uuid. -- * Returns -- * 1 valid VSI data returned -- * 0 end of queue (no VSI data returned) -- * <0 errno -- */ --int vdp_status(int number, struct vdpnl_vsi *vsi) --{ -- struct vdp_data *vd; -- struct vsi_profile *p; -- int i = 0, ret = 0; -- -- vd = vdp_data(vsi->ifname); -- if (!vd) { -- LLDPAD_ERR("%s: %s has not yet been configured\n", __func__, -- vsi->ifname); -- return -ENODEV; -- } -- /* Interate to queue element number */ -- LIST_FOREACH(p, &vd->profile_head, profile) { -- if (++i == number) { -- ret = 1; -- break; -- } -- } -- if (ret) { -- vdp_trace_profile(p); -- vsi->response = p->response; -- memcpy(vsi->vsi_uuid, p->instance, sizeof vsi->vsi_uuid); -- if (p->response != VDP_RESPONSE_NO_RESPONSE -- && p->state == VSI_EXIT) -- vdp_remove_profile(p); -- } -- LLDPAD_DBG("%s: entry:%d more:%d\n", __func__, number, ret); -- return ret; --} -- --/* -- * Copy MAC-VLAN list from profile to vdpnl structure. -- */ --static void copy_maclist(struct vsi_profile *p, struct vdpnl_mac *macp) --{ -- struct mac_vlan *mv1; -- -- LIST_FOREACH(mv1, &p->macvid_head, entry) { -- macp->vlan = mv1->vlan; -- macp->qos = mv1->qos; -- memcpy(macp->mac, mv1->mac, sizeof macp->mac); -- ++macp; -- } --} -- --/* -- * Prepare data for a netlink message to originator of VSI. -- * Forward a notification from switch. -- */ --int vdp_trigger(struct vsi_profile *profile) --{ -- struct vdpnl_vsi vsi; -- struct vdp_data *vd; -- struct mac_vlan *macp = 0; -- int rc = -EINVAL; -- struct vdpnl_mac maclist[profile->entries]; -- -- vsi.macsz = profile->entries; -- vsi.maclist = maclist; -- LLDPAD_DBG("%s: no_nlmsg:%d\n", __func__, profile->no_nlmsg); -- vdp_trace_profile(profile); -- if (profile->no_nlmsg) -- return 0; -- if (LIST_EMPTY(&profile->macvid_head)) -- return 0; -- macp = LIST_FIRST(&profile->macvid_head); -- if (!macp->req_pid) -- return 0; -- sleep(1); /* Delay message notification */ -- if (!profile->port || !profile->port->ifname) { -- LLDPAD_ERR("%s: no ifname found for profile %p:\n", __func__, -- profile); -- goto error_exit; -- } -- memcpy(vsi.ifname, profile->port->ifname, sizeof vsi.ifname); -- vd = vdp_data(vsi.ifname); -- if (!vd) { -- LLDPAD_ERR("%s: %s could not find vdp_data\n", __func__, -- vsi.ifname); -- goto error_exit; -- } -- vsi.ifindex = if_nametoindex(vsi.ifname); -- if (vsi.ifindex == 0) { -- LLDPAD_ERR("%s: %s could not find index for ifname\n", -- __func__, vsi.ifname); -- goto error_exit; -- } -- vsi.macsz = profile->entries; -- copy_maclist(profile, vsi.maclist); -- vsi.req_pid = macp->req_pid; -- vsi.req_seq = macp->req_seq; -- vsi.vsi_mgrid = profile->mgrid; -- vsi.vsi_typeid = profile->id; -- vsi.vsi_typeversion = profile->version; -- memcpy(vsi.vsi_uuid, profile->instance, sizeof vsi.vsi_uuid); -- vsi.request = VDP_MODE_DEASSOCIATE; -- rc = vdpnl_send(&vsi); --error_exit: -- vdp_remove_profile(profile); -- return rc; --} -diff --git a/lldp_vdp_clif.c b/lldp_vdp_clif.c -deleted file mode 100644 -index 6fd1e8e..0000000 ---- a/lldp_vdp_clif.c -+++ /dev/null -@@ -1,193 +0,0 @@ --/******************************************************************************* -- -- Implementation of VDP according to IEEE 802.1Qbg -- (c) Copyright IBM Corp. 2010, 2012 -- -- Author(s): Jens Osterkamp -- Author(s): Thomas Richter -- -- This program is free software; you can redistribute it and/or modify it -- under the terms and conditions of the GNU General Public License, -- version 2, as published by the Free Software Foundation. -- -- This program is distributed in the hope it will be useful, but WITHOUT -- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -- more details. -- -- You should have received a copy of the GNU General Public License along with -- this program; if not, write to the Free Software Foundation, Inc., -- 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. -- -- The full GNU General Public License is included in this distribution in -- the file called "COPYING". -- --*******************************************************************************/ -- --#include --#include --#include --#include --#include --#include "lldp_mod.h" --#include "clif_msgs.h" --#include "lldp.h" --#include "lldp_vdp.h" --#include "lldp_vdp_cmds.h" --#include "lldp_vdp_clif.h" --#include "lldp_mand_clif.h" -- --static const char *mode_state(int mode) --{ -- switch (mode) { -- case VDP_MODE_PREASSOCIATE_WITH_RR: -- return "Preassociated with RR"; -- case VDP_MODE_DEASSOCIATE: -- return "Disassociated"; -- case VDP_MODE_ASSOCIATE: -- return "Associated"; -- case VDP_MODE_PREASSOCIATE: -- return "Preassociated"; -- default: return "unknown"; -- } --} -- --/* -- * Print a complete VDP TLV. Data string constructed in function -- * vdp_clif_profile(). -- */ --static void vdp_show_tlv(UNUSED u16 len, char *info) --{ -- int rc, role, enabletx, vdpbit, mode, response, mgrid, id, idver; -- unsigned int x[16]; -- -- rc = sscanf(info, "%02x%02x%02x%02x%02x%02x%06x%02x", -- &role, &enabletx, &vdpbit, &mode, &response, &mgrid, -- &id, &idver); -- if (rc != 3 && rc != 8) -- return; -- printf("Role:%s\n", role ? VAL_BRIDGE : VAL_STATION); -- printf("\tEnabled:%s\n", enabletx ? VAL_YES : VAL_NO); -- printf("\tVDP Bit:%s\n", vdpbit ? VAL_YES : VAL_NO); -- if (rc == 3) /* No active VSI profile */ -- return; -- printf("\tMode:%d (%s)\n", mode, mode_state(mode)); -- printf("\tMgrid:%d\n", mgrid); -- printf("\tTypeid:%d\n", id); -- printf("\tTypeidversion:%d\n", idver); -- rc = sscanf(info + 20, "%02x%02x%02x%02x%02x%02x%02x%02x" -- "%02x%02x%02x%02x%02x%02x%02x%02x", -- &x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &x[6], &x[7], -- &x[8], &x[9], &x[10], &x[11], &x[12], &x[13], &x[14], -- &x[15]); -- if (rc != 16) -- return; -- printf("\tUUID:%02x%02x%02x%02x-%02x%02x-%02x%02x" -- "-%02x%02x-%02x%02x%02x%02x%02x%02x\n", x[0], x[1], x[2], x[3], -- x[4], x[5], x[6], x[7], x[8], x[9], x[10], x[11], x[12], x[13], -- x[14], x[15]); -- mode = 52; -- rc = sscanf(info + mode, "%02x%04x", &role, &vdpbit); -- if (rc != 2) -- return; -- printf("\tFilter Format:%d\n", role); -- printf("\tEntries:%d\n", vdpbit); -- mode += 6; -- while (--vdpbit >= 0) { -- rc = sscanf(info + mode, "%02x%02x%02x%02x%02x%02x%04x", -- &x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &x[6]); -- if (rc != 7) -- return; -- printf("\t\tMAC:%02x:%02x:%02x:%02x:%02x:%02x\tVlanid:%d\n", -- x[0], x[1], x[2], x[3], x[4], x[5], x[6]); -- mode += 16; -- } --} -- --static struct type_name_info vdp_tlv_names[] = { -- { -- .type = ((LLDP_MOD_VDP) << 8) | LLDP_VDP_SUBTYPE, -- .name = "VDP draft 0.2 protocol configuration", -- .key = "vdp", -- .print_info = vdp_show_tlv -- }, -- { -- .type = INVALID_TLVID -- } --}; -- --static int vdp_print_help() --{ -- struct type_name_info *tn = &vdp_tlv_names[0]; -- -- while (tn->type != INVALID_TLVID) { -- if (tn->key && strlen(tn->key) && tn->name) { -- printf(" %s", tn->key); -- if (strlen(tn->key)+3 < 8) -- printf("\t"); -- printf("\t: %s\n", tn->name); -- } -- tn++; -- } -- return 0; --} -- --static u32 vdp_lookup_tlv_name(char *tlvid_str) --{ -- struct type_name_info *tn = &vdp_tlv_names[0]; -- -- while (tn->type != INVALID_TLVID) { -- if (!strcasecmp(tn->key, tlvid_str)) -- return tn->type; -- tn++; -- } -- return INVALID_TLVID; --} -- --static void vdp_cli_unregister(struct lldp_module *mod) --{ -- free(mod); --} -- --/* return 1: if it printed the TLV -- * 0: if it did not -- */ --static int vdp_print_tlv(u32 tlvid, u16 len, char *info) --{ -- struct type_name_info *tn = &vdp_tlv_names[0]; -- -- while (tn->type != INVALID_TLVID) { -- if (tlvid == tn->type) { -- printf("%s\n", tn->name); -- if (tn->print_info) { -- printf("\t"); -- tn->print_info(len-4, info); -- } -- return 1; -- } -- tn++; -- } -- return 0; --} -- --static const struct lldp_mod_ops vdp_ops_clif = { -- .lldp_mod_register = vdp_cli_register, -- .lldp_mod_unregister = vdp_cli_unregister, -- .print_tlv = vdp_print_tlv, -- .lookup_tlv_name = vdp_lookup_tlv_name, -- .print_help = vdp_print_help, --}; -- --struct lldp_module *vdp_cli_register(void) --{ -- struct lldp_module *mod; -- -- mod = malloc(sizeof(*mod)); -- if (!mod) { -- fprintf(stderr, "failed to malloc module data\n"); -- return NULL; -- } -- mod->id = (LLDP_MOD_VDP << 8) | LLDP_VDP_SUBTYPE; -- mod->ops = &vdp_ops_clif; -- return mod; --} -diff --git a/lldp_vdp_cmds.c b/lldp_vdp_cmds.c -deleted file mode 100644 -index ec9c49c..0000000 ---- a/lldp_vdp_cmds.c -+++ /dev/null -@@ -1,668 +0,0 @@ --/****************************************************************************** -- -- Implementation of VDP according to IEEE 802.1Qbg -- (c) Copyright IBM Corp. 2010, 2012 -- -- Author(s): Jens Osterkamp -- Author(s): Thomas Richter -- -- This program is free software; you can redistribute it and/or modify it -- under the terms and conditions of the GNU General Public License, -- version 2, as published by the Free Software Foundation. -- -- This program is distributed in the hope it will be useful, but WITHOUT -- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -- more details. -- -- You should have received a copy of the GNU General Public License along with -- this program; if not, write to the Free Software Foundation, Inc., -- 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. -- -- The full GNU General Public License is included in this distribution in -- the file called "COPYING". -- --******************************************************************************/ -- --#include --#include --#include --#include --#include --#include --#include "lldpad.h" --#include "ctrl_iface.h" --#include "lldp.h" --#include "lldp_vdp.h" --#include "lldp_mand_clif.h" --#include "lldp_vdp_cmds.h" --#include "lldp_qbg_utils.h" --#include "lldp/ports.h" --#include "lldp_tlv.h" --#include "messages.h" --#include "libconfig.h" --#include "config.h" --#include "clif_msgs.h" --#include "lldpad_status.h" --#include "lldp/states.h" -- --static char *check_and_update(size_t *total, size_t *length, char *s, int c) --{ -- if (c < 0) -- return NULL; -- *total += c; -- if ((unsigned)c >= *length) -- return NULL; -- *length -= c; -- return s + c; --} -- --static char *print_mode(char *s, size_t length, struct vsi_profile *p) --{ -- int c; -- size_t total = 0; -- char *r = s; -- struct mac_vlan *mac_vlan; -- char instance[VDP_UUID_STRLEN + 2]; -- -- vdp_uuid2str(p->instance, instance, sizeof(instance)); -- c = snprintf(s, length, "%d,%d,%d,%d,%s,%d", -- p->state, p->mgrid, p->id, p->version, instance, -- p->format); -- s = check_and_update(&total, &length, s, c); -- if (!s) -- return r; -- -- LIST_FOREACH(mac_vlan, &p->macvid_head, entry) { -- char macbuf[MAC_ADDR_STRLEN + 1]; -- -- mac2str(mac_vlan->mac, macbuf, MAC_ADDR_STRLEN); -- c = snprintf(s, length, ",%s,%d", macbuf, mac_vlan->vlan); -- s = check_and_update(&total, &length, s, c); -- if (!s) -- return r; -- } -- return s; --} -- --static int --get_arg_tlvtxenable(struct cmd *cmd, char *arg, UNUSED char *argvalue, -- char *obuf, int obuf_len) --{ -- int value; -- char *s; -- char arg_path[VDP_BUF_SIZE]; -- -- if (cmd->cmd != cmd_gettlv) -- return cmd_invalid; -- -- switch (cmd->tlvid) { -- case ((LLDP_MOD_VDP) << 8) | LLDP_VDP_SUBTYPE: -- snprintf(arg_path, sizeof(arg_path), "%s.%s", VDP_PREFIX, arg); -- -- if (get_cfg(cmd->ifname, cmd->type, arg_path, &value, -- CONFIG_TYPE_BOOL)) -- value = false; -- break; -- case INVALID_TLVID: -- return cmd_invalid; -- default: -- return cmd_not_applicable; -- } -- -- if (value) -- s = VAL_YES; -- else -- s = VAL_NO; -- -- snprintf(obuf, obuf_len, "%02zx%s%04zx%s", -- strlen(arg), arg, strlen(s), s); -- -- return cmd_success; --} -- --static int _set_arg_tlvtxenable(struct cmd *cmd, char *arg, char *argvalue, -- bool test) --{ -- int value, err; -- char arg_path[VDP_BUF_SIZE]; -- -- if (cmd->cmd != cmd_settlv) -- return cmd_invalid; -- -- switch (cmd->tlvid) { -- case ((LLDP_MOD_VDP) << 8) | LLDP_VDP_SUBTYPE: -- break; -- case INVALID_TLVID: -- return cmd_invalid; -- default: -- return cmd_not_applicable; -- } -- -- if (!strcasecmp(argvalue, VAL_YES)) -- value = 1; -- else if (!strcasecmp(argvalue, VAL_NO)) -- value = 0; -- else -- return cmd_invalid; -- -- if (test) -- return cmd_success; -- -- snprintf(arg_path, sizeof(arg_path), "%s.%s", VDP_PREFIX, arg); -- -- err = set_cfg(cmd->ifname, cmd->type, arg_path, -- &value, CONFIG_TYPE_BOOL); -- if (err) -- return cmd_failed; -- -- return cmd_success; -- --} -- --static int set_arg_tlvtxenable(struct cmd *cmd, char *arg, char *argvalue, -- UNUSED char *obuf, UNUSED int obuf_len) --{ -- return _set_arg_tlvtxenable(cmd, arg, argvalue, false); --} -- --static int test_arg_tlvtxenable(struct cmd *cmd, char *arg, char *argvalue, -- UNUSED char *obuf, UNUSED int obuf_len) --{ -- return _set_arg_tlvtxenable(cmd, arg, argvalue, true); --} -- --static int get_arg_mode(struct cmd *cmd, char *arg, UNUSED char *argvalue, -- char *obuf, int obuf_len) --{ -- struct vsi_profile *np; -- struct vdp_data *vd; -- char mode_str[VDP_BUF_SIZE], *t = mode_str; -- int filled = 0; -- -- if (cmd->cmd != cmd_gettlv) -- return cmd_invalid; -- -- switch (cmd->tlvid) { -- case ((LLDP_MOD_VDP) << 8) | LLDP_VDP_SUBTYPE: -- break; -- case INVALID_TLVID: -- return cmd_invalid; -- default: -- return cmd_not_applicable; -- } -- -- vd = vdp_data(cmd->ifname); -- if (!vd) { -- LLDPAD_ERR("%s: vdp_data for %s not found !\n", -- __func__, cmd->ifname); -- return cmd_device_not_found; -- } -- -- memset(mode_str, 0, sizeof mode_str); -- LIST_FOREACH(np, &vd->profile_head, profile) { -- t = print_mode(t, sizeof(mode_str) - filled, np); -- filled = t - mode_str; -- } -- -- snprintf(obuf, obuf_len, "%02x%s%04x%s", -- (unsigned int)strlen(arg), arg, (unsigned int)strlen(mode_str), -- mode_str); -- return cmd_success; --} -- --static void str2instance(struct vsi_profile *profile, char *buffer) --{ -- unsigned int i, j = 0; -- -- for (i = 0; i <= strlen(buffer); i++) { -- if (buffer[i] == '-') -- continue; -- -- if (sscanf(&buffer[i], "%02hhx", &profile->instance[j]) == 1) { -- i++; -- j++; -- } -- } --} -- --static void vdp_fill_profile(struct vsi_profile *profile, char *buffer, -- int field) --{ -- LLDPAD_DBG("%s: parsed %s\n", __func__, buffer); -- -- switch(field) { -- case MODE: -- profile->mode = atoi(buffer); -- break; -- case MGRID: -- profile->mgrid = atoi(buffer); -- break; -- case TYPEID: -- profile->id = atoi(buffer); -- break; -- case TYPEIDVERSION: -- profile->version = atoi(buffer); -- break; -- case INSTANCEID: -- str2instance(profile, buffer); -- break; -- case FORMAT: -- profile->format = atoi(buffer); -- break; -- default: -- LLDPAD_ERR("Unknown field in buffer !\n"); -- break; -- } --} -- --static struct vsi_profile *vdp_parse_mode_line(char *argvalue) --{ -- int field; -- char *cmdstring, *parsed; -- struct vsi_profile *profile; -- -- profile = vdp_alloc_profile(); -- if (!profile) -- return NULL; -- -- cmdstring = strdup(argvalue); -- if (!cmdstring) -- goto out_free; -- -- field = 0; -- -- parsed = strtok(cmdstring, ","); -- -- while (parsed != NULL) { -- vdp_fill_profile(profile, parsed, field); -- field++; -- if (field > FORMAT) -- break; -- parsed = strtok(NULL, ","); -- } -- -- if ((field <= FORMAT) || (parsed == NULL)) -- goto out_free; -- -- parsed = strtok(NULL, ","); -- -- while (parsed != NULL) { -- struct mac_vlan *mac_vlan; -- -- mac_vlan = calloc(1, sizeof(struct mac_vlan)); -- if (mac_vlan == NULL) -- goto out_free; -- -- if (str2mac(parsed, &mac_vlan->mac[0], MAC_ADDR_LEN)) { -- free(mac_vlan); -- goto out_free; -- } -- -- parsed = strtok(NULL, ","); -- if (parsed == NULL) { -- free(mac_vlan); -- goto out_free; -- } -- -- mac_vlan->vlan = atoi(parsed); -- LIST_INSERT_HEAD(&profile->macvid_head, mac_vlan, entry); -- profile->entries++; -- parsed = strtok(NULL, ","); -- } -- -- free(cmdstring); -- return profile; -- --out_free: -- free(cmdstring); -- vdp_delete_profile(profile); -- return NULL; --} -- --static int _set_arg_mode(struct cmd *cmd, char *argvalue, bool test) --{ -- struct vsi_profile *profile, *p; -- struct vdp_data *vd; -- -- if (cmd->cmd != cmd_settlv) -- return cmd_invalid; -- -- switch (cmd->tlvid) { -- case ((LLDP_MOD_VDP) << 8) | LLDP_VDP_SUBTYPE: -- break; -- case INVALID_TLVID: -- return cmd_invalid; -- default: -- return cmd_not_applicable; -- } -- -- profile = vdp_parse_mode_line(argvalue); -- if (profile == NULL) -- return cmd_failed; -- -- profile->port = port_find_by_name(cmd->ifname); -- -- if (!profile->port) { -- vdp_delete_profile(profile); -- return cmd_device_not_found; -- } -- -- vd = vdp_data(cmd->ifname); -- if (!vd) { -- vdp_delete_profile(profile); -- return cmd_device_not_found; -- } -- -- if (test) { -- vdp_delete_profile(profile); -- return cmd_success; -- } -- -- p = vdp_add_profile(vd, profile); -- if (profile != p) -- vdp_delete_profile(profile); -- -- return cmd_success; --} -- --static int set_arg_mode(struct cmd *cmd, UNUSED char *arg, char *argvalue, -- UNUSED char *obuf, UNUSED int obuf_len) --{ -- return _set_arg_mode(cmd, argvalue, false); --} -- --static int test_arg_mode(struct cmd *cmd, UNUSED char *arg, char *argvalue, -- UNUSED char *obuf, UNUSED int obuf_len) --{ -- return _set_arg_mode(cmd, argvalue, true); --} -- --static int get_arg_role(struct cmd *cmd, char *arg, UNUSED char *argvalue, -- char *obuf, int obuf_len) --{ -- struct vdp_data *vd; -- -- if (cmd->cmd != cmd_gettlv) -- return cmd_invalid; -- -- switch (cmd->tlvid) { -- case ((LLDP_MOD_VDP) << 8) | LLDP_VDP_SUBTYPE: -- vd = vdp_data(cmd->ifname); -- -- if (!vd) { -- LLDPAD_ERR("%s: could not find vdp_data for %s\n", -- __FILE__, cmd->ifname); -- return cmd_device_not_found; -- } -- -- if (vd->role == VDP_ROLE_STATION) -- snprintf(obuf, obuf_len, "%02x%s%04x%s", -- (unsigned int) strlen(arg), arg, -- (unsigned int) strlen(VAL_STATION), -- VAL_STATION); -- else if (vd->role == VDP_ROLE_BRIDGE) -- snprintf(obuf, obuf_len, "%02x%s%04x%s", -- (unsigned int) strlen(arg), arg, -- (unsigned int) strlen(VAL_BRIDGE), VAL_BRIDGE); -- else -- return cmd_failed; -- break; -- case INVALID_TLVID: -- return cmd_invalid; -- default: -- return cmd_not_applicable; -- } -- -- return cmd_success; --} -- --static int _set_arg_role(struct cmd *cmd, char *arg, char *argvalue, bool test) --{ -- struct vdp_data *vd; -- char arg_path[VDP_BUF_SIZE]; -- -- if (cmd->cmd != cmd_settlv) -- return cmd_invalid; -- -- switch (cmd->tlvid) { -- case ((LLDP_MOD_VDP) << 8) | LLDP_VDP_SUBTYPE: -- break; -- case INVALID_TLVID: -- return cmd_invalid; -- default: -- return cmd_not_applicable; -- } -- -- vd = vdp_data(cmd->ifname); -- -- if (!vd) { -- LLDPAD_ERR("%s: could not find vdp_data for %s\n", -- __FILE__, cmd->ifname); -- return cmd_device_not_found; -- } -- -- if (!strcasecmp(argvalue, VAL_BRIDGE)) { -- if (!test) -- vd->role = VDP_ROLE_BRIDGE; -- } else if (!strcasecmp(argvalue, VAL_STATION)) { -- if (!test) -- vd->role = VDP_ROLE_STATION; -- } else { -- return cmd_invalid; -- } -- -- if (test) -- return cmd_success; -- -- snprintf(arg_path, sizeof(arg_path), "%s.%s", VDP_PREFIX, arg); -- -- const char *p = &argvalue[0]; -- if (set_cfg(cmd->ifname, cmd->type, arg_path, &p, CONFIG_TYPE_STRING)) -- return cmd_failed; -- -- return cmd_success; --} -- --static int set_arg_role(struct cmd *cmd, char *arg, char *argvalue, -- UNUSED char *obuf, UNUSED int obuf_len) --{ -- return _set_arg_role(cmd, arg, argvalue, false); --} -- --static int test_arg_role(struct cmd *cmd, char *arg, char *argvalue, -- UNUSED char *obuf, UNUSED int obuf_len) --{ -- return _set_arg_role(cmd, arg, argvalue, true); --} -- --static struct arg_handlers arg_handlers[] = { -- { -- .arg = ARG_VDP_MODE, -- .arg_class = TLV_ARG, -- .handle_get = get_arg_mode, -- .handle_set = set_arg_mode, -- .handle_test = test_arg_mode -- }, -- { -- .arg = ARG_VDP_ROLE, -- .arg_class = TLV_ARG, -- .handle_get = get_arg_role, -- .handle_set = set_arg_role, -- .handle_test = test_arg_role -- }, -- { -- .arg = ARG_TLVTXENABLE, -- .arg_class = TLV_ARG, -- .handle_get = get_arg_tlvtxenable, -- .handle_set = set_arg_tlvtxenable, -- .handle_test = test_arg_tlvtxenable -- }, -- { -- .arg = 0 -- } --}; -- --struct arg_handlers *vdp_get_arg_handlers() --{ -- return &arg_handlers[0]; --} -- --/* -- * Interface to build information for lldptool -V vdp -- */ --struct tlv_info_vdp_nopp { /* VSI information without profile data */ -- u8 oui[3]; /* OUI */ -- u8 sub; /* Subtype */ -- u8 role; /* Role: station or bridge */ -- u8 enabletx; -- u8 vdpbit_on; --} __attribute__ ((__packed__)); -- --/* -- * Flatten a profile stored as TLV and append it. Skip the first 4 bytes. -- * They contain the OUI already stored. -- * Returns the number of bytes added to the buffer. -- */ --static int add_profile(unsigned char *pdu, size_t pdusz, struct vdp_data *vdp) --{ -- size_t size = 0; -- -- if (!vdp->vdp) -- return size; -- size = (unsigned)TLVSIZE(vdp->vdp) - 4; -- if (pdusz >= size) -- memcpy(pdu, vdp->vdp->info + 4, size); -- else { -- LLDPAD_ERR("%s: %s buffer size too small (need %d bytes)\n", -- __func__, vdp->ifname, TLVSIZE(vdp->vdp)); -- return -1; -- } -- return size; --} -- --/* -- * Create unpacked VDP tlv for VSI profile when active. -- */ --static int make_vdp_tlv(unsigned char *pdu, size_t pdusz, struct vdp_data *vdp) --{ -- struct unpacked_tlv *tlv = (struct unpacked_tlv *)pdu; -- struct tlv_info_vdp_nopp *vdpno; -- size_t pduoff; -- int rc; -- -- tlv->info = (unsigned char *)(tlv + 1); -- vdpno = (struct tlv_info_vdp_nopp *)tlv->info; -- tlv->type = ORG_SPECIFIC_TLV; -- tlv->length = sizeof(struct tlv_info_vdp_nopp); -- hton24(vdpno->oui, LLDP_MOD_VDP); -- vdpno->sub = LLDP_VDP_SUBTYPE; -- vdpno->role = vdp->role; -- vdpno->enabletx = vdp->enabletx; -- vdpno->vdpbit_on = vdp->vdpbit_on; -- pduoff = sizeof(*tlv) + tlv->length; -- pdusz -= pduoff; -- rc = add_profile(pdu + pduoff, pdusz - pduoff, vdp); -- if (rc > 0) { -- tlv->length += rc; -- rc = 0; -- } -- return rc; --} -- --/* -- * Flatten a VDP TLV into a byte stream. -- */ --static int vdp_clif_profile(char *ifname, char *rbuf, size_t rlen) --{ -- unsigned char pdu[VDP_BUF_SIZE]; /* Buffer for unpacked TLV */ -- int i, c, rstatus = cmd_success; -- size_t sum = 0; -- struct vdp_data *vd; -- struct unpacked_tlv *tlv = (struct unpacked_tlv *)pdu; -- struct packed_tlv *ptlv; -- -- LLDPAD_DBG("%s: %s rlen:%zu\n", __func__, ifname, rlen); -- vd = vdp_data(ifname); -- if (!vd) -- return cmd_device_not_found; -- -- if (make_vdp_tlv(pdu, sizeof pdu, vd)) -- return cmd_failed; -- -- /* Convert to packed TLV */ -- ptlv = pack_tlv(tlv); -- if (!ptlv) -- return cmd_failed; -- for (i = 0; i < TLVSIZE(tlv); ++i) { -- c = snprintf(rbuf, rlen, "%02x", ptlv->tlv[i]); -- rbuf = check_and_update(&sum, &rlen, rbuf, c); -- if (!rbuf) { -- rstatus = cmd_failed; -- break; -- } -- } -- free_pkd_tlv(ptlv); -- return rstatus; --} -- --/* -- * Module function to extract all VSI profile data on a given interface. It -- * is invoked via 'lldptool -t -i ethx -g ncb -V vdp' without any configuration -- * options. -- * This function does not support arguments and its values. They are handled -- * using the lldp_mand_cmds.c interfaces. -- */ --int vdp_clif_cmd(char *ibuf, UNUSED int ilen, char *rbuf, int rlen) --{ -- struct cmd cmd; -- u8 len, version; -- int c, ioff; -- size_t roff = 0, outlen = rlen; -- char *here; -- int rstatus = cmd_invalid; -- -- /* Pull out the command elements of the command message */ -- hexstr2bin(ibuf + MSG_VER, (u8 *)&version, sizeof(u8)); -- version >>= 4; -- hexstr2bin(ibuf + CMD_CODE, (u8 *)&cmd.cmd, sizeof(cmd.cmd)); -- hexstr2bin(ibuf + CMD_OPS, (u8 *)&cmd.ops, sizeof(cmd.ops)); -- cmd.ops = ntohl(cmd.ops); -- hexstr2bin(ibuf + CMD_IF_LEN, &len, sizeof(len)); -- ioff = CMD_IF; -- if (len < sizeof(cmd.ifname)) -- memcpy(cmd.ifname, ibuf + CMD_IF, len); -- else -- return cmd_failed; -- cmd.ifname[len] = '\0'; -- ioff += len; -- -- memset(rbuf, 0, rlen); -- c = snprintf(rbuf, rlen, "%c%1x%02x%08x%02x%s", -- CMD_REQUEST, CLIF_MSG_VERSION, cmd.cmd, cmd.ops, -- (unsigned int)strlen(cmd.ifname), cmd.ifname); -- here = check_and_update(&roff, &outlen, rbuf, c); -- if (!here) -- return cmd_failed; -- -- if (version == CLIF_MSG_VERSION) { -- hexstr2bin(ibuf+ioff, &cmd.type, sizeof(cmd.type)); -- ioff += 2 * sizeof(cmd.type); -- } else /* Command valid only for nearest customer bridge */ -- goto out; -- -- if (cmd.cmd == cmd_gettlv) { -- hexstr2bin(ibuf+ioff, (u8 *)&cmd.tlvid, sizeof(cmd.tlvid)); -- cmd.tlvid = ntohl(cmd.tlvid); -- ioff += 2 * sizeof(cmd.tlvid); -- } else -- goto out; -- -- c = snprintf(here, outlen, "%08x", cmd.tlvid); -- here = check_and_update(&roff, &outlen, here, c); -- if (!here) -- return cmd_failed; -- rstatus = vdp_clif_profile(cmd.ifname, here, outlen); --out: -- return rstatus; --} -diff --git a/lldpad.c b/lldpad.c -index d29a53d..406dcd5 100644 ---- a/lldpad.c -+++ b/lldpad.c -@@ -52,9 +52,9 @@ - #include "lldp_8023.h" - #include "lldp_evb.h" - #include "lldp_evb22.h" --#include "lldp_ecp22.h" --#include "lldp_vdp.h" --#include "lldp_vdp22.h" -+#include "qbg_ecp22.h" -+#include "qbg_vdp.h" -+#include "qbg_vdp22.h" - #include "lldp_8021qaz.h" - #include "config.h" - #include "lldpad_shm.h" -@@ -83,6 +83,7 @@ struct lldp_module *(*register_tlv_table[])(void) = { - char *cfg_file_name = NULL; - bool daemonize = 0; - int loglvl = LOG_WARNING; -+int omit_tstamp; - - static const char *lldpad_version = - "lldpad v" VERSION_STR "\n" -@@ -124,16 +125,17 @@ static void usage(void) - { - fprintf(stderr, - "\n" -- "usage: lldpad [-hdkspv] [-f configfile]" -+ "usage: lldpad [-hdksptv] [-f configfile] [-V level]" - "\n" - "options:\n" - " -h show this usage\n" -- " -f use configfile instead of default\n" - " -d run daemon in the background\n" - " -k terminate current running lldpad\n" - " -s remove lldpad state records\n" - " -p Do not create PID file\n" -+ " -t omit timestamps in log messages\n" - " -v show version\n" -+ " -f use configfile instead of default\n" - " -V set syslog level\n"); - - exit(1); -@@ -153,15 +155,13 @@ void send_event(int level, u32 moduleid, char *msg) - ctrl_iface_send(cd, level, moduleid, msg, strlen(msg)); - } - --static void remove_all_adapters() -+static void remove_all_adapters(void) - { -- struct port *port, *p; -+ struct port *port, *next; - -- port = porthead; -- while (port != NULL) { -- p = port; -- port = port->next; -- remove_port(p->ifname); -+ for (port = porthead; port; port = next) { -+ next = port->next; -+ remove_port(port->ifname); - } - - return; -@@ -231,9 +231,10 @@ int main(int argc, char *argv[]) - int pid_file = 1; - pid_t pid; - int cnt; -+ int rc = 1; - - for (;;) { -- c = getopt(argc, argv, "dhkvspf:V:"); -+ c = getopt(argc, argv, "hdksptvf:V:"); - if (c < 0) - break; - switch (c) { -@@ -256,6 +257,9 @@ int main(int argc, char *argv[]) - case 'p': - pid_file = 0; - break; -+ case 't': -+ omit_tstamp = 1; -+ break; - case 'v': - print_v = 1; - break; -@@ -330,29 +334,6 @@ int main(int argc, char *argv[]) - exit (0); - } - -- if (pid_file) { -- fd = open(PID_FILE, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); -- if (fd < 0) { -- LLDPAD_ERR("error opening lldpad lock file"); -- exit(1); -- } -- -- if (flock(fd, LOCK_EX | LOCK_NB) < 0) { -- if (errno == EWOULDBLOCK) { -- fprintf(stderr, "lldpad is already running\n"); -- if (read(fd, buf, sizeof(buf)) > 0) { -- fprintf(stderr, "pid of existing" -- "lldpad is %s\n", buf); -- } -- LLDPAD_ERR("lldpad already running"); -- } else { -- perror("error locking lldpad lock file"); -- LLDPAD_ERR("error locking lldpad lock file"); -- } -- exit(1); -- } -- } -- - lldpad_oom_adjust(); - - /* initialize lldpad user data */ -@@ -379,23 +360,30 @@ int main(int argc, char *argv[]) - exit(1); - } - -+ /* From this point on we know we're the only instance */ - if (daemonize && daemon(1, 0)) { - LLDPAD_ERR("error daemonizing lldpad"); -- goto out; -+ exit(1); - } - - if (pid_file) { -- if (lseek(fd, 0, SEEK_SET) < 0) { -- LLDPAD_ERR("error seeking lldpad lock file\n"); -+ fd = open(PID_FILE, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); -+ if (fd < 0) { -+ LLDPAD_ERR("error opening lldpad pid file"); - exit(1); - } - -+ if (lseek(fd, 0, SEEK_SET) < 0) { -+ LLDPAD_ERR("error seeking lldpad pid file\n"); -+ goto out_fail; -+ } -+ - memset(buf, 0, sizeof(buf)); - sprintf(buf, "%u\n", getpid()); - if (write(fd, buf, sizeof(buf)) < 0) -- perror("error writing to lldpad lock file"); -+ perror("error writing to lldpad pid file"); - if (fsync(fd) < 0) -- perror("error syncing lldpad lock file"); -+ perror("error syncing lldpad pid file"); - - close(fd); - } -@@ -403,23 +391,17 @@ int main(int argc, char *argv[]) - pid = lldpad_shm_getpid(); - if (pid < 0) { - LLDPAD_ERR("error getting shm pid"); -- if (pid_file) -- unlink(PID_FILE); -- exit(1); -+ goto out_fail; - } else if (pid == PID_NOT_SET) { - if (!lldpad_shm_setpid(getpid())) { - perror("lldpad_shm_setpid failed"); - LLDPAD_ERR("lldpad_shm_setpid failed\n"); -- if (pid_file) -- unlink(PID_FILE); -- exit (1); -+ goto out_fail; - } - } else if (pid != DONT_KILL_PID) { - if (!kill(pid, 0)) { - LLDPAD_ERR("lldpad already running"); -- if (pid_file) -- unlink(PID_FILE); -- exit(1); -+ goto out_fail; - } - /* pid in shm no longer has a process, go ahead - * and let this lldpad instance execute. -@@ -427,55 +409,51 @@ int main(int argc, char *argv[]) - if (!lldpad_shm_setpid(getpid())) { - perror("lldpad_shm_setpid failed"); - LLDPAD_ERR("error overwriting shm pid"); -- if (pid_file) -- unlink(PID_FILE); -- exit (1); -+ goto out_fail; - } - } - - openlog("lldpad", LOG_CONS | LOG_PID, LOG_DAEMON); - setlogmask(LOG_UPTO(loglvl)); - -- if (check_cfg_file()) -- exit(1); -- - /* setup event netlink interface for user space processes. - * This needs to be setup first to ensure it gets lldpads - * pid as netlink address. - */ - if (event_iface_init_user_space() < 0) { -- LLDPAD_ERR("lldpad failed to start - failed to register user space event interface\n"); -- exit(1); -+ LLDPAD_ERR("lldpad failed to start - " -+ "failed to register user space event interface\n"); -+ closelog(); -+ goto out_fail; - } - - init_modules(); - - eloop_register_signal_terminate(eloop_terminate, NULL); -- eloop_register_signal_reconfig(lldpad_reconfig, NULL); -+ eloop_register_signal_reconfig(lldpad_reconfig, NULL); - - /* setup LLDP agent */ - if (!start_lldp_agents()) { - LLDPAD_ERR("failed to initialize LLDP agent\n"); -- exit(1); -+ goto out; - } - - /* setup event RT netlink interface */ - if (event_iface_init() < 0) { - LLDPAD_ERR("failed to register event interface\n"); -- exit(1); -+ goto out; - } - - /* Find available interfaces and add adapters */ - init_ports(); - - if (ctrl_iface_register(clifd) < 0) { -- if (!daemonize) -- fprintf(stderr, "failed to register control interface\n"); - LLDPAD_ERR("lldpad failed to start - " - "failed to register control interface\n"); - goto out; - } - -+ rc = 0; - eloop_run(); - - clean_lldp_agents(); -@@ -485,12 +463,13 @@ int main(int argc, char *argv[]) - event_iface_deinit(); - stop_lldp_agents(); - out: -+ eloop_destroy(); -+ if (!eloop_terminated()) -+ rc = 1; - destroy_cfg(); - closelog(); -+out_fail: - if (pid_file) - unlink(PID_FILE); -- eloop_destroy(); -- if (eloop_terminated()) -- exit(0); -- exit(1); -+ exit(rc); - } -diff --git a/lldpad.service b/lldpad.service -index 8cc4aed..2cee1de 100644 ---- a/lldpad.service -+++ b/lldpad.service -@@ -4,7 +4,9 @@ After=syslog.target network.target - - [Service] - Type=simple --ExecStart=/usr/sbin/lldpad -+ExecStart=/usr/sbin/lldpad -t -+ExecReload=/bin/kill -HUP $MAINPID - - [Install] - WantedBy=multi-user.target -+Also=lldpad.socket -diff --git a/lldpad.socket b/lldpad.socket -new file mode 100644 -index 0000000..24f3eb6 ---- /dev/null -+++ b/lldpad.socket -@@ -0,0 +1,6 @@ -+[Socket] -+ListenDatagram=@/com/intel/lldpad -+PassCredentials=true -+ -+[Install] -+WantedBy=sockets.target -diff --git a/lldptool.c b/lldptool.c -index e1ff11f..1b229c1 100644 ---- a/lldptool.c -+++ b/lldptool.c -@@ -48,7 +48,7 @@ - #include "lldp_dcbx_clif.h" - #include "lldp_evb22_clif.h" - #include "lldp_evb_clif.h" --#include "lldp_vdp_clif.h" -+#include "qbg_vdp_clif.h" - #include "lldp_8021qaz_clif.h" - #include "lldp_orgspec_clif.h" - #include "lldp_cisco_clif.h" -@@ -497,12 +497,15 @@ static int request(struct clif *clif, int argc, char *argv[]) - break; - case 'g': - if (!strcasecmp(optarg, "nearestbridge") || -+ !strcasecmp(optarg, "nearest_bridge") || - !strcasecmp(optarg, "nb")) - command.type = NEAREST_BRIDGE; - else if (!strcasecmp(optarg, "nearestcustomerbridge") || -+ !strcasecmp(optarg, "nearest_customer_bridge") || - !strcasecmp(optarg, "ncb")) - command.type = NEAREST_CUSTOMER_BRIDGE; -- else if (!strcasecmp(optarg, "nearestnontmprbridge") || -+ else if (!strcasecmp(optarg, "nearestnontpmrbridge") || -+ !strcasecmp(optarg, "nearest_nontpmr_bridge") || - !strcasecmp(optarg, "nntpmrb")) - command.type = NEAREST_NONTPMR_BRIDGE; - else { -diff --git a/lldptool_cmds.c b/lldptool_cmds.c -index 17b4d8b..daef8c8 100644 ---- a/lldptool_cmds.c -+++ b/lldptool_cmds.c -@@ -349,6 +349,9 @@ static char *print_status(cmd_status status) - case cmd_no_access: - str = "Access denied"; - break; -+ case cmd_agent_not_supported: -+ str = "TLV does not support agent type"; -+ break; - default: - str = "Unknown status"; - break; -@@ -462,12 +465,10 @@ static void print_tlvs(struct cmd *cmd, char *ibuf) - - printed = 0; - LIST_FOREACH(np, &lldp_head, lldp) { -- if (np->ops->print_tlv) -- if (np->ops->print_tlv(tlvid, tlv_len, -- ibuf+offset)) { -+ if (np->ops->print_tlv(tlvid, tlv_len, ibuf+offset)) { - printed = 1; - break; -- } -+ } - } - - if (!printed) { -diff --git a/log.c b/log.c -index e66e9c2..63b942b 100644 ---- a/log.c -+++ b/log.c -@@ -59,7 +59,7 @@ void log_message(int level, const char *format, ...) - if (daemonize) - vsyslog(level, format, vb); - else if (loglvl >= level) { -- if (!bypass_time) -+ if (!omit_tstamp && !bypass_time) - showtime(); - vprintf(format, vb); - bypass_time = strchr(format, '\n') == 0; -diff --git a/qbg/ecp.c b/qbg/ecp.c -new file mode 100644 -index 0000000..c81eb19 ---- /dev/null -+++ b/qbg/ecp.c -@@ -0,0 +1,1093 @@ -+/****************************************************************************** -+ -+ Implementation of ECP according to 802.1Qbg -+ (c) Copyright IBM Corp. 2010, 2012 -+ -+ Author(s): Jens Osterkamp -+ Author(s): Thomas Richter -+ -+ This program is free software; you can redistribute it and/or modify it -+ under the terms and conditions of the GNU General Public License, -+ version 2, as published by the Free Software Foundation. -+ -+ This program is distributed in the hope it will be useful, but WITHOUT -+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ more details. -+ -+ You should have received a copy of the GNU General Public License along with -+ this program; if not, write to the Free Software Foundation, Inc., -+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. -+ -+ The full GNU General Public License is included in this distribution in -+ the file called "COPYING". -+ -+******************************************************************************/ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "eloop.h" -+#include "lldp.h" -+#include "lldp_evb.h" -+#include "qbg_utils.h" -+#include "qbg_vdp.h" -+#include "messages.h" -+#include "config.h" -+#include "lldp/l2_packet.h" -+ -+#include "lldp_tlv.h" -+ -+static void ecp_tx_run_sm(struct vdp_data *); -+static void ecp_rx_run_sm(struct vdp_data *); -+ -+/* ecp_localchange_handler - triggers the processing of a local change -+ * @eloop_data: data structure of event loop -+ * @user_ctx: user context, vdp_data here -+ * -+ * no return value -+ * -+ * called from ecp_somethingchangedlocal when a change is pending. Calls -+ * the ECP tx station state machine. A oneshot handler. This detour is taken -+ * to not having to call the ecp code from the vdp state machine. Instead, we -+ * return to the event loop, giving other code a chance to do work. -+ */ -+static void ecp_localchange_handler(UNUSED void *eloop_data, void *user_ctx) -+{ -+ struct vdp_data *vd; -+ -+ vd = (struct vdp_data *) user_ctx; -+ if (vd->ecp.tx.localChange) { -+ LLDPAD_DBG("%s:%s ecp.tx.localChange %i\n", -+ __func__, vd->ecp.ifname, vd->ecp.tx.localChange); -+ ecp_tx_run_sm(vd); -+ } -+} -+ -+/* ecp_start_localchange_timer - starts the ECP localchange timer -+ * @vd: vdp_data for the interface -+ * -+ * returns 0 on success, -1 on error -+ * -+ * starts the ECP localchange timer when a localchange has been signaled from -+ * the VDP state machine. -+ */ -+static int ecp_start_localchange_timer(struct vdp_data *vd) -+{ -+ return eloop_register_timeout(0, ECP_LOCALCHANGE_TIMEOUT, -+ ecp_localchange_handler, -+ NULL, (void *) vd); -+} -+ -+/* ecp_stop_localchange_timer - stop the ECP localchange timer -+ * @vd: vdp_data for the interface -+ * -+ * returns the number of removed handlers -+ * -+ * stops the ECP localchange timer. Used e.g. when the host interface goes down. -+ */ -+static int ecp_stop_localchange_timer(struct vdp_data *vd) -+{ -+ LLDPAD_DBG("%s:%s stopping ecp localchange timer\n", __func__, -+ vd->ecp.ifname); -+ return eloop_cancel_timeout(ecp_localchange_handler, NULL, (void *) vd); -+} -+ -+/* ecp_ackTimer_expired - checks for expired ack timer -+ * @vd: vdp_data for interface -+ * -+ * returns true or false -+ * -+ * returns true if ack timer has expired, false otherwise. -+ */ -+static bool ecp_ackTimer_expired(struct vdp_data *vd) -+{ -+ return (vd->ecp.ackTimer == 0); -+} -+ -+/* ecp_ack_timeout_handler - handles the ack timer expiry -+ * @eloop_data: data structure of event loop -+ * @user_ctx: user context, vdp_data here -+ * -+ * no return value -+ * -+ * called when the ECP timer has expired. Calls the ECP station state machine. -+ */ -+static void ecp_ack_timeout_handler(UNUSED void *eloop_data, void *user_ctx) -+{ -+ struct vdp_data *vd; -+ -+ vd = (struct vdp_data *) user_ctx; -+ if (vd->ecp.ackTimer > 0) -+ vd->ecp.ackTimer -= ECP_ACK_TIMER_DEFAULT; -+ -+ if (ecp_ackTimer_expired(vd) == true) { -+ LLDPAD_DBG("%s:%s ecp_ackTimer_expired (%i)\n", -+ __func__, vd->ecp.ifname, vd->ecp.ackTimer); -+ ecp_tx_run_sm(vd); -+ } else { -+ LLDPAD_DBG("%s:%s BUG! handler called but" -+ "vdp->ecp.ackTimer not expired (%i)\n", -+ __func__, vd->ecp.ifname, vd->ecp.ackTimer); -+ } -+} -+ -+/* ecp_start_ack_timer - starts the ECP ack timer -+ * @vd: vdp_data for the interface -+ * -+ * returns 0 on success, -1 on error -+ * -+ * starts the ECP ack timer when a frame has been sent out. -+ */ -+static int ecp_start_ack_timer(struct vdp_data *vd) -+{ -+ return eloop_register_timeout(0, ECP_ACK_TIMER_DEFAULT, -+ ecp_ack_timeout_handler, -+ NULL, (void *) vd); -+} -+ -+/* ecp_stop_ack_timer - stop the ECP ack timer -+ * @vd: vdp_data for the interface -+ * -+ * returns the number of removed handlers -+ * -+ * stops the ECP ack timer. Used e.g. when the host interface goes down. -+ */ -+static int ecp_stop_ack_timer(struct vdp_data *vd) -+{ -+ LLDPAD_DBG("%s:%s stopping ecp ack timer\n", __func__, vd->ecp.ifname); -+ return eloop_cancel_timeout(ecp_ack_timeout_handler, NULL, (void *) vd); -+} -+ -+/* ecp_tx_stop_ackTimer - stop the ECP ack timer -+ * @vd: currently used port -+ * -+ * returns the number of removed handlers -+ * -+ * stops the ECP ack timer. used when a ack frame for the port has been -+ * received. -+ */ -+static void ecp_tx_stop_ackTimer(struct vdp_data *vd) -+{ -+ vd->ecp.ackTimer = ECP_ACK_TIMER_STOPPED; -+ LLDPAD_DBG("%s:%s stopped ecp ack timer\n", __func__, vd->ecp.ifname); -+ ecp_stop_ack_timer(vd); -+} -+ -+int ecp_deinit(char *ifname) -+{ -+ struct vdp_data *vd; -+ -+ LLDPAD_DBG("%s:%s stopping ECP\n", __func__, ifname); -+ vd = vdp_data(ifname); -+ if (!vd) { -+ LLDPAD_ERR("%s:%s unable to find vd\n", __func__, ifname); -+ return -1; -+ } -+ -+ ecp_stop_ack_timer(vd); -+ ecp_stop_localchange_timer(vd); -+ ecp_tx_stop_ackTimer(vd); -+ return 0; -+} -+ -+static const char *ecp_tx_states[] = { -+ "ECP_TX_INIT_TRANSMIT", -+ "ECP_TX_TRANSMIT_ECPDU", -+ "ECP_TX_WAIT_FOR_ACK", -+ "ECP_TX_REQUEST_PDU" -+}; -+ -+/* ecp_somethingChangedLocal - set flag if port has changed -+ * @vd: port to set the flag for -+ * @mode: mode to set the flag to -+ * -+ * no return value -+ * -+ * set the localChange flag with a mode to indicate a port has changed. -+ * used to signal an ecpdu needs to be sent out. -+ */ -+ -+void ecp_somethingChangedLocal(struct vdp_data *vd, bool flag) -+{ -+ if (!vd) -+ return; -+ -+ LLDPAD_DBG("%s:%s vd->ecp.tx.localChange to %s\n", __func__, -+ vd->ecp.ifname, (flag == true) ? "true" : "false"); -+ vd->ecp.tx.localChange = flag; -+ ecp_start_localchange_timer(vd); -+} -+ -+/* -+ * Append some data at the end of the transmit data buffer. Make sure the -+ * End TLV always fits into the buffer. -+ */ -+static u8 end_tlv[2] = { 0x0, 0x0 }; /* END TLV */ -+ -+static int ecp_append(u8 *buffer, u32 *pos, void *data, u32 len) -+{ -+ if (*pos + len > ETH_FRAME_LEN - sizeof end_tlv) -+ return 0; -+ memcpy(buffer + *pos, data, len); -+ *pos += len; -+ return 1; -+} -+ -+/* ecp_build_ECPDU - create an ecp protocol data unit -+ * @vd: currently used port -+ * -+ * returns true on success, false on failure -+ * -+ * creates the frame header with the ports mac address, the ecp header with REQ -+ * plus a list of packed TLVs created from the profiles on this -+ * port. -+ */ -+static bool ecp_build_ECPDU(struct vdp_data *vd) -+{ -+ struct l2_ethhdr eth; -+ struct ecp_hdr ecp_hdr; -+ u8 own_addr[ETH_ALEN]; -+ u32 fb_offset = 0; -+ struct packed_tlv *ptlv = NULL; -+ struct vsi_profile *p; -+ int rc; -+ -+ /* TODO: use LLDP group MAC addresses to support -+ * S-channels/multichannel -+ */ -+ memcpy(eth.h_dest, nearest_bridge, ETH_ALEN); -+ l2_packet_get_own_src_addr(vd->ecp.l2,(u8 *)&own_addr); -+ memcpy(eth.h_source, &own_addr, ETH_ALEN); -+ eth.h_proto = htons(ETH_P_ECP); -+ memset(vd->ecp.tx.frame, 0, sizeof vd->ecp.tx.frame); -+ ecp_append(vd->ecp.tx.frame, &fb_offset, (void *)ð, sizeof eth); -+ -+ ecp_hdr.oui[0] = 0x0; -+ ecp_hdr.oui[1] = 0x1b; -+ ecp_hdr.oui[2] = 0x3f; -+ ecp_hdr.pad1 = 0x0; -+ ecp_hdr.subtype = ECP_SUBTYPE; -+ ecp_hdr.mode = ECP_REQUEST; -+ -+ vd->ecp.lastSequence++; -+ ecp_hdr.seqnr = htons(vd->ecp.lastSequence); -+ ecp_append(vd->ecp.tx.frame, &fb_offset, (void *)&ecp_hdr, -+ sizeof ecp_hdr); -+ -+ /* create packed_tlvs for all profiles on this interface */ -+ LIST_FOREACH(p, &vd->profile_head, profile) { -+ -+ if (!p->localChange) { -+ LLDPAD_DBG("%s:%s skipping unchanged profile\n", -+ __func__, vd->ecp.ifname); -+ continue; -+ } -+ -+ ptlv = vdp_gettlv(vd, p); -+ -+ if (!ptlv) { -+ LLDPAD_DBG("%s:%s ptlv not created\n", __func__, -+ vd->ecp.ifname); -+ continue; -+ } -+ -+ rc = ecp_append(vd->ecp.tx.frame, &fb_offset, ptlv->tlv, -+ ptlv->size); -+ ptlv = free_pkd_tlv(ptlv); -+ if (rc) -+ p->seqnr = vd->ecp.lastSequence; -+ else -+ break; -+ } -+ ecp_append(vd->ecp.tx.frame, &fb_offset, end_tlv, sizeof end_tlv); -+ vd->ecp.tx.frame_len = MAX(fb_offset, (unsigned)ETH_ZLEN); -+ return true; -+} -+ -+/* ecp_tx_Initialize - initializes the ecp tx state machine -+ * @vd: currently used port -+ * -+ * no return value -+ * -+ * initializes some variables for the ecp tx state machine. -+ */ -+static void ecp_tx_Initialize(struct vdp_data *vd) -+{ -+ memset(vd->ecp.tx.frame, 0, sizeof vd->ecp.tx.frame); -+ ecp_somethingChangedLocal(vd, true); -+ vd->ecp.lastSequence = ECP_SEQUENCE_NR_START; -+ vd->ecp.stats.statsFramesOutTotal = 0; -+ vd->ecp.ackTimer = ECP_ACK_TIMER_STOPPED; -+ vd->ecp.retries = 0; -+} -+ -+/* ecp_txFrame - transmit ecp frame -+ * @vd: currently used port -+ * -+ * returns the number of characters sent on success, -1 on failure -+ * -+ * sends out the frame stored in the frame structure using l2_packet_send. -+ */ -+static u8 ecp_txFrame(struct vdp_data *vd) -+{ -+ int status = 0; -+ -+ status = l2_packet_send(vd->ecp.l2, (u8 *)&nearest_bridge, -+ htons(ETH_P_ECP), vd->ecp.tx.frame, vd->ecp.tx.frame_len); -+ vd->ecp.stats.statsFramesOutTotal++; -+ vd->ecp.tx.frame_len = 0; -+ return status; -+} -+ -+/* ecp_tx_create_frame - create ecp frame -+ * @vd: currently used port -+ * -+ * no return value -+ */ -+static void ecp_tx_create_frame(struct vdp_data *vd) -+{ -+ /* send REQs */ -+ if (vd->ecp.tx.localChange) { -+ int ret; -+ -+ LLDPAD_DBG("%s:%s sending REQs\n", __func__, vd->ecp.ifname); -+ ret = ecp_build_ECPDU(vd); -+ -+ /* ECPDU construction succesful, send out frame */ -+ if (ret == true) { -+ hexdump_frame(vd->ecp.ifname, "frame-out", -+ vd->ecp.tx.frame, vd->ecp.tx.frame_len); -+ ecp_txFrame(vd); -+ } -+ } -+ -+ ecp_somethingChangedLocal(vd, false); -+} -+ -+/* ecp_tx_start_ackTimer - starts the ECP ack timer -+ * @vd: vdp_data to process -+ * -+ * returns 0 on success, -1 on error -+ * -+ * starts the ack timer when a frame has been sent out. -+ */ -+static void ecp_tx_start_ackTimer(struct vdp_data *vd) -+{ -+ vd->ecp.ackTimer = ECP_ACK_TIMER_DEFAULT; -+ LLDPAD_DBG("%s-%s: starting ecp ack timer\n", __func__, vd->ifname); -+ ecp_start_ack_timer(vd); -+} -+ -+/* ecp_tx_change_state - changes the ecp tx sm state -+ * @vd: currently used port -+ * @newstate: new state for the sm -+ * -+ * no return value -+ * -+ * checks state transistion for consistency and finally changes the state of -+ * the profile. -+ */ -+static void ecp_tx_change_state(struct vdp_data *vd, u8 newstate) -+{ -+ switch(newstate) { -+ case ECP_TX_INIT_TRANSMIT: -+ break; -+ case ECP_TX_TRANSMIT_ECPDU: -+ assert((vd->ecp.tx.state == ECP_TX_INIT_TRANSMIT) || -+ (vd->ecp.tx.state == ECP_TX_WAIT_FOR_ACK) || -+ (vd->ecp.tx.state == ECP_TX_REQUEST_PDU)); -+ break; -+ case ECP_TX_WAIT_FOR_ACK: -+ assert(vd->ecp.tx.state == ECP_TX_TRANSMIT_ECPDU); -+ break; -+ case ECP_TX_REQUEST_PDU: -+ assert(vd->ecp.tx.state == ECP_TX_WAIT_FOR_ACK); -+ break; -+ default: -+ LLDPAD_ERR("%s: LLDP TX state machine invalid state %d\n", -+ vd->ifname, newstate); -+ } -+ LLDPAD_DBG("%s-%s: state change %s -> %s\n", __func__, -+ vd->ifname, ecp_tx_states[vd->ecp.tx.state], -+ ecp_tx_states[newstate]); -+ vd->ecp.tx.state = newstate; -+ return; -+} -+ -+/* ecp_set_tx_state - sets the ecp tx sm state -+ * @vd: currently used port -+ * -+ * returns true or false -+ * -+ * switches the state machine to the next state depending on the input -+ * variables. returns true or false depending on wether the state machine -+ * can be run again with the new state or can stop at the current state. -+ */ -+static bool ecp_set_tx_state(struct vdp_data *vd) -+{ -+ struct port *port = port_find_by_ifindex(get_ifidx(vd->ifname)); -+ -+ if (!port) { -+ LLDPAD_ERR("%s: port not found\n", __func__); -+ return 0; -+ } -+ -+ if (!port->portEnabled && port->prevPortEnabled) { -+ LLDPAD_ERR("set_tx_state: port was disabled\n"); -+ ecp_tx_change_state(vd, ECP_TX_INIT_TRANSMIT); -+ } -+ port->prevPortEnabled = port->portEnabled; -+ -+ switch (vd->ecp.tx.state) { -+ case ECP_TX_INIT_TRANSMIT: -+ if (port->portEnabled && vd->enabletx && -+ vd->ecp.tx.localChange) { -+ ecp_tx_change_state(vd, ECP_TX_TRANSMIT_ECPDU); -+ return true; -+ } -+ return false; -+ case ECP_TX_TRANSMIT_ECPDU: -+ if (!vd->enabletx) { -+ ecp_tx_change_state(vd, ECP_TX_INIT_TRANSMIT); -+ return true; -+ } -+ ecp_tx_change_state(vd, ECP_TX_WAIT_FOR_ACK); -+ return false; -+ case ECP_TX_WAIT_FOR_ACK: -+ if (ecp_ackTimer_expired(vd)) { -+ vd->ecp.retries++; -+ if (vd->ecp.retries < ECP_MAX_RETRIES) { -+ ecp_somethingChangedLocal(vd, true); -+ ecp_tx_change_state(vd, ECP_TX_TRANSMIT_ECPDU); -+ return true; -+ } -+ if (vd->ecp.retries == ECP_MAX_RETRIES) { -+ LLDPAD_DBG("%s-%s: retries expired\n", -+ __func__, vd->ifname); -+ ecp_tx_stop_ackTimer(vd); -+ ecp_tx_change_state(vd, ECP_TX_REQUEST_PDU); -+ return true; -+ } -+ } -+ if (vd->ecp.ackReceived && -+ vd->ecp.seqECPDU == vd->ecp.lastSequence) { -+ vd->ecp.ackReceived = false; -+ if (vdp_vsis_pending(vd)) { -+ LLDPAD_DBG("%s-%s: still work pending\n", -+ __func__, vd->ifname); -+ ecp_somethingChangedLocal(vd, true); -+ } -+ ecp_tx_change_state(vd, ECP_TX_REQUEST_PDU); -+ return true; -+ } -+ return false; -+ case ECP_TX_REQUEST_PDU: -+ if (vd->ecp.tx.localChange) { -+ ecp_tx_change_state(vd, ECP_TX_TRANSMIT_ECPDU); -+ return true; -+ } -+ return false; -+ default: -+ LLDPAD_ERR("%s: LLDP TX state machine in invalid state %d\n", -+ vd->ifname, vd->ecp.tx.state); -+ return false; -+ } -+} -+ -+/* ecp_tx_run_sm - state machine for ecp tx -+ * @vd: currently used vdp_data -+ * -+ * no return value -+ * -+ * runs the state machine for ecp tx. -+ */ -+void ecp_tx_run_sm(struct vdp_data *vd) -+{ -+ do { -+ LLDPAD_DBG("%s-%s: ecp_tx - %s\n", __func__, -+ vd->ifname, ecp_tx_states[vd->ecp.tx.state]); -+ -+ switch(vd->ecp.tx.state) { -+ case ECP_TX_INIT_TRANSMIT: -+ ecp_tx_Initialize(vd); -+ break; -+ case ECP_TX_TRANSMIT_ECPDU: -+ ecp_tx_create_frame(vd); -+ ecp_tx_start_ackTimer(vd); -+ ecp_somethingChangedLocal(vd, false); -+ break; -+ case ECP_TX_WAIT_FOR_ACK: -+ if (vd->ecp.ackReceived) { -+ LLDPAD_DBG("%s-%s: ECP_TX_WAIT_FOR_ACK " -+ "ackReceived seqECPDU %#x " -+ "lastSequence %#x\n", __func__, -+ vd->ifname, vd->ecp.seqECPDU, -+ vd->ecp.lastSequence); -+ ecp_somethingChangedLocal(vd, false); -+ ecp_tx_stop_ackTimer(vd); -+ } -+ break; -+ case ECP_TX_REQUEST_PDU: -+ vd->ecp.retries = 0; -+ LLDPAD_DBG("%s-%s: ECP_TX_REQUEST_PDU lastSeq %#x\n", -+ __func__, vd->ifname, vd->ecp.lastSequence); -+ break; -+ default: -+ LLDPAD_ERR("%s: LLDP TX state machine in invalid state %d\n", -+ vd->ifname, vd->ecp.tx.state); -+ } -+ } while (ecp_set_tx_state(vd) == true); -+} -+ -+static const char *ecp_rx_states[] = { -+ "ECP_RX_IDLE", -+ "ECP_RX_INIT_RECEIVE", -+ "ECP_RX_RECEIVE_WAIT", -+ "ECP_RX_RECEIVE_ECPDU", -+ "ECP_RX_SEND_ACK", -+ "ECP_RX_RESEND_ACK", -+}; -+ -+/* ecp_rx_Initialize - initializes the ecp rx state machine -+ * @vd: vd for the state machine -+ * -+ * no return value -+ * -+ * initialize some variables, get rid of old frame if necessary -+ */ -+static void ecp_rx_Initialize(struct vdp_data *vd) -+{ -+ vd->ecp.rx.rcvFrame = false; -+ vd->ecp.ackReceived = false; -+ vd->ecp.rx.frame_len = 0; -+} -+ -+/* ecp_rx_SendAckFrame - send ack frame -+ * @vd: port used by ecp -+ * -+ * currently always returns 0 -+ * -+ * copies current received frame over to frame out, fills in address of this -+ * port and set mode field to ACK. used by ecp_rx_send_ack_frame. -+ */ -+static int ecp_rx_SendAckFrame(struct vdp_data *vd) -+{ -+ u16 tlv_offset = 0; -+ struct ecp_hdr *ecp_hdr; -+ struct l2_ethhdr *hdr; -+ u8 own_addr[ETH_ALEN]; -+ -+ LLDPAD_DBG("%s:%s acking frame\n", __func__, vd->ecp.ifname); -+ /* copy over to transmit buffer */ -+ memcpy(vd->ecp.tx.frame, vd->ecp.rx.frame, vd->ecp.rx.frame_len); -+ vd->ecp.tx.frame_len = vd->ecp.rx.frame_len; -+ -+ /* use my own addr to send ACK */ -+ hdr = (struct l2_ethhdr *)vd->ecp.tx.frame; -+ l2_packet_get_own_src_addr(vd->ecp.l2,(u8 *)&own_addr); -+ memcpy(hdr->h_source, &own_addr, ETH_ALEN); -+ -+ tlv_offset = sizeof(struct l2_ethhdr); -+ ecp_hdr = (struct ecp_hdr *)&vd->ecp.tx.frame[tlv_offset]; -+ ecp_hdr->mode = ECP_ACK; -+ -+ tlv_offset = sizeof(struct l2_ethhdr) + sizeof(struct ecp_hdr); -+ LLDPAD_DBG("%s:%s zeroing out rest of ack frame from %i to %i\n", -+ __func__, vd->ecp.ifname, tlv_offset, vd->ecp.rx.frame_len); -+ memset(&vd->ecp.tx.frame[tlv_offset], 0, -+ vd->ecp.rx.frame_len - tlv_offset); -+ return 0; -+} -+ -+/* ecp_rx_send_ack_frame - send out ack frame for received frame -+ * @vd: vd for the state machine -+ * -+ * no return value -+ * -+ * creates an ack frame for a just received frame, prints the about to be -+ * sent frame and finally transmits it. -+ */ -+void ecp_rx_send_ack_frame(struct vdp_data *vd) -+{ -+ ecp_rx_SendAckFrame(vd); -+ hexdump_frame(vd->ecp.ifname, "frame-ack", vd->ecp.tx.frame, -+ vd->ecp.tx.frame_len); -+ ecp_txFrame(vd); -+} -+ -+/* ecp_rx_ReceiveFrame - receive ecp frame -+ * @ctx: rx callback context, struct vd * in this case -+ * @ifindex: index of interface -+ * @buf: buffer which contains the frame just received -+ * @len: size of buffer (frame) -+ * -+ * no return value -+ * -+ * creates a local copy of the buffer and checks the header. keeps some -+ * statistics about ecp frames. Checks if it is a request or an ack frame -+ * and branches to ecp rx or ecp tx state machine. -+ */ -+static void ecp_rx_ReceiveFrame(void *ctx, UNUSED int ifindex, const u8 *buf, -+ size_t len) -+{ -+ struct vdp_data *vd; -+ struct port *port; -+ u8 frame_error = 0; -+ u16 tlv_offset; -+ struct l2_ethhdr *hdr; -+ struct l2_ethhdr example_hdr,*ex; -+ struct ecp_hdr *ecp_hdr; -+ -+ if (!ctx) { -+ LLDPAD_WARN("%s: no ctx - can't process frame\n", __func__); -+ return; -+ } -+ -+ vd = (struct vdp_data *)ctx; -+ port = port_find_by_ifindex(get_ifidx(vd->ifname)); -+ if (!port) -+ return; -+ -+ LLDPAD_DBG("%s:%s received packet with size %i\n", __func__, -+ vd->ecp.ifname, (int)len); -+ if (vd->enabletx == false) -+ return; -+ -+ if (vd->ecp.rx.frame_len == len && -+ (memcmp(buf, vd->ecp.rx.frame, len) == 0)) { -+ vd->ecp.stats.statsFramesInTotal++; -+ return; -+ } -+ -+ memset(vd->ecp.rx.frame, 0, len); -+ memcpy(vd->ecp.rx.frame, buf, len); -+ -+ vd->ecp.rx.frame_len = (u16)len; -+ ex = &example_hdr; -+ memcpy(ex->h_dest, nearest_bridge, ETH_ALEN); -+ ex->h_proto = htons(ETH_P_ECP); -+ hdr = (struct l2_ethhdr *)vd->ecp.rx.frame; -+ -+ if ((memcmp(hdr->h_dest, ex->h_dest, ETH_ALEN) != 0)) { -+ LLDPAD_ERR("%s:%s ERROR multicast address error in incoming frame." -+ " Dropping frame.\n", __func__, vd->ecp.ifname); -+ frame_error++; -+ return; -+ } -+ -+ if (hdr->h_proto != example_hdr.h_proto) { -+ LLDPAD_ERR("%s:%s ERROR ethertype %#x not ECP ethertype", -+ __func__, vd->ecp.ifname, htons(hdr->h_proto)); -+ frame_error++; -+ return; -+ } -+ -+ if (!frame_error) { -+ vd->ecp.stats.statsFramesInTotal++; -+ vd->ecp.rx.rcvFrame = true; -+ } -+ -+ tlv_offset = sizeof(struct l2_ethhdr); -+ ecp_hdr = (struct ecp_hdr *)&vd->ecp.rx.frame[tlv_offset]; -+ vd->ecp.seqECPDU = ntohs(ecp_hdr->seqnr); -+ hexdump_frame(vd->ecp.ifname, "frame-in", vd->ecp.rx.frame, -+ vd->ecp.rx.frame_len); -+ -+ switch(ecp_hdr->mode) { -+ case ECP_REQUEST: -+ LLDPAD_DBG("%s:%s received REQ frame\n", __func__, -+ vd->ecp.ifname); -+ vd->ecp.ackReceived = false; -+ ecp_rx_run_sm(vd); -+ break; -+ case ECP_ACK: -+ LLDPAD_DBG("%s:%s received ACK frame\n", __func__, -+ vd->ecp.ifname); -+ vd->ecp.ackReceived = true; -+ vdp_ack_profiles(vd, vd->ecp.seqECPDU); -+ ecp_tx_run_sm(vd); -+ vd->ecp.ackReceived = false; -+ break; -+ default: -+ LLDPAD_ERR("%s:%s ERROR: unknown mode %i\n", __func__, -+ vd->ecp.ifname, ecp_hdr->mode); -+ return; -+ } -+ -+} -+ -+/* ecp_rx_change_state - changes the ecp rx sm state -+ * @vd: currently used port -+ * @newstate: new state for the sm -+ * -+ * no return value -+ * -+ * checks state transistion for consistency and finally changes the state of -+ * the profile. -+ */ -+static void ecp_rx_change_state(struct vdp_data *vd, u8 newstate) -+{ -+ switch(newstate) { -+ case ECP_RX_IDLE: -+ break; -+ case ECP_RX_INIT_RECEIVE: -+ break; -+ case ECP_RX_RECEIVE_WAIT: -+ assert((vd->ecp.rx.state == ECP_RX_INIT_RECEIVE) || -+ (vd->ecp.rx.state == ECP_RX_IDLE) || -+ (vd->ecp.rx.state == ECP_RX_SEND_ACK) || -+ (vd->ecp.rx.state == ECP_RX_RESEND_ACK)); -+ break; -+ case ECP_RX_RECEIVE_ECPDU: -+ assert(vd->ecp.rx.state == ECP_RX_RECEIVE_WAIT); -+ break; -+ case ECP_RX_SEND_ACK: -+ assert(vd->ecp.rx.state == ECP_RX_RECEIVE_ECPDU); -+ break; -+ case ECP_RX_RESEND_ACK: -+ assert(vd->ecp.rx.state == ECP_RX_RECEIVE_ECPDU); -+ break; -+ default: -+ LLDPAD_ERR("%s:%s LLDP RX state machine invalid state %d\n", -+ __func__, vd->ecp.ifname, newstate); -+ } -+ -+ LLDPAD_DBG("%s:%s state change %s -> %s\n", __func__, -+ vd->ecp.ifname, ecp_rx_states[vd->ecp.rx.state], -+ ecp_rx_states[newstate]); -+ -+ vd->ecp.rx.state = newstate; -+} -+ -+/* ecp_init - initialize ecp module -+ * @ifname: interface for which the module is initialized -+ * -+ * returns 0 on success, -1 on error -+ * -+ * finds the port to the interface name, sets up the receive handle for -+ * incoming ecp frames and initializes the ecp rx and tx state machines. -+ * should usually be called when a successful exchange of EVB TLVs has been -+ * made and ECP and VDP protocols are supported by both sides. -+ */ -+int ecp_init(char *ifname) -+{ -+ struct vdp_data *vd; -+ -+ LLDPAD_DBG("%s:%s starting ECP\n", __func__, ifname); -+ vd = vdp_data(ifname); -+ if (!vd) { -+ LLDPAD_ERR("%s:%s unable to find vd\n", __func__, ifname); -+ return -1; -+ } -+ -+ if (!vd->ecp.l2) -+ vd->ecp.l2 = l2_packet_init(vd->ifname, NULL, ETH_P_ECP, -+ ecp_rx_ReceiveFrame, vd, 1); -+ -+ if (!vd->ecp.l2) { -+ LLDPAD_ERR("%s:%s failed to access layer 2 access ETH_P_ECP\n", -+ __func__, ifname); -+ return -1; -+ } -+ strncpy(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); -+ return 0; -+} -+ -+/* ecp_rx_validate_frame - validates received frame -+ * @vd: vdp_data used by ecp -+ * -+ * no return value -+ * -+ * checks wether received frame has correct subtype and mode -+ */ -+ -+static void ecp_rx_validate_frame(struct vdp_data *vd) -+{ -+ u16 tlv_offset = 0; -+ struct ecp_hdr *ecp_hdr; -+ -+ LLDPAD_DBG("%s:%s validating frame\n", __func__, vd->ecp.ifname); -+ tlv_offset = sizeof(struct l2_ethhdr); -+ ecp_hdr = (struct ecp_hdr *)&vd->ecp.rx.frame[tlv_offset]; -+ LLDPAD_DBG("%s:%s ecp packet with subtype %#x mode %#x seq %#04x\n", -+ __func__, vd->ecp.ifname, ecp_hdr->subtype, ecp_hdr->mode, -+ ntohs(ecp_hdr->seqnr)); -+ -+ if (ecp_hdr->subtype != ECP_SUBTYPE) { -+ LLDPAD_ERR("%s:%s ERROR: unknown subtype\n", __func__, -+ vd->ecp.ifname); -+ return; -+ } -+ -+ if ((ecp_hdr->oui[0] != 0x0) || (ecp_hdr->oui[1] != 0x1b) || -+ (ecp_hdr->oui[2] != 0x3f)) { -+ LLDPAD_ERR("%s:%s ERROR: incorrect OUI 0x%02x%02x%02x\n", -+ __func__, vd->ecp.ifname, ecp_hdr->oui[0], -+ ecp_hdr->oui[1], ecp_hdr->oui[2]); -+ return; -+ } -+ -+ switch(ecp_hdr->mode) { -+ case ECP_REQUEST: -+ break; -+ case ECP_ACK: -+ break; -+ default: -+ LLDPAD_ERR("%s:%s ERROR: unknown mode %i\n", __func__, -+ vd->ecp.ifname, ecp_hdr->mode); -+ return; -+ } -+ -+ /* FIXME: also done in ecp_rx_ReceiveFrame, -+ * are both necessary ? */ -+ vd->ecp.seqECPDU = ntohs(ecp_hdr->seqnr); -+} -+ -+/* ecp_rx_ProcessFrame - process received ecp frames -+ * @vd: currently used port -+ * -+ * no return value -+ * -+ * walks through the packed vsi tlvs in an ecp frame, extracts them -+ * and passes them to the VDP ULP with vdp_indicate. -+ */ -+static void ecp_rx_ProcessFrame(struct vdp_data *vd) -+{ -+ u16 tlv_cnt = 0; -+ u8 tlv_type = 0; -+ u16 tlv_length = 0; -+ u16 tlv_offset = 0; -+ u16 *tlv_head_ptr = NULL; -+ u8 frame_error = 0; -+ bool tlv_stored = false; -+ struct ecp_hdr *ecp_hdr; -+ int vdp_called; -+ -+ LLDPAD_DBG("%s:%s processing frame\n", __func__, vd->ecp.ifname); -+ tlv_offset = sizeof(struct l2_ethhdr); -+ -+ ecp_hdr = (struct ecp_hdr *)&vd->ecp.rx.frame[tlv_offset]; -+ LLDPAD_DBG("%s:%s ecp packet with subtype %#x mode %#x seq %#04x\n", -+ __func__, vd->ifname, ecp_hdr->subtype, -+ ecp_hdr->mode, ntohs(ecp_hdr->seqnr)); -+ if (ecp_hdr->mode == ECP_ACK) -+ return; -+ -+ /* processing of VSI_TLVs starts here */ -+ tlv_offset += sizeof(struct ecp_hdr); -+ vdp_called = 0; -+ do { -+ tlv_cnt++; -+ -+ if (tlv_offset > vd->ecp.rx.frame_len) { -+ LLDPAD_ERR("%s:%s ERROR: Frame overrun! tlv_offset %i" -+ " frame_len %i cnt %i\n", __func__, -+ vd->ecp.ifname, tlv_offset, -+ vd->ecp.rx.frame_len, tlv_cnt); -+ frame_error++; -+ goto out; -+ } -+ -+ if (tlv_offset + 2 > vd->ecp.rx.frame_len) { -+ LLDPAD_DBG("%s:%s tlv EOF problem size=%d offset=%d\n", -+ __func__, vd->ecp.ifname, -+ vd->ecp.rx.frame_len, tlv_offset); -+ frame_error++; -+ goto out; -+ } -+ -+ tlv_head_ptr = (u16 *)&vd->ecp.rx.frame[tlv_offset]; -+ tlv_length = htons(*tlv_head_ptr) & 0x01FF; -+ tlv_type = (u8)(htons(*tlv_head_ptr) >> 9); -+ -+ u16 tmp_offset = tlv_offset + tlv_length; -+ if (tmp_offset > vd->ecp.rx.frame_len) { -+ LLDPAD_ERR("%s:%s ERROR: Frame overflow: offset=%d " -+ "rx.size=%d\n", __func__, vd->ecp.ifname, -+ tmp_offset, vd->ecp.rx.frame_len); -+ frame_error++; -+ goto out; -+ } -+ -+ u8 *info = (u8 *)&vd->ecp.rx.frame[tlv_offset + -+ sizeof(*tlv_head_ptr)]; -+ -+ struct unpacked_tlv *tlv = create_tlv(); -+ -+ if (!tlv) { -+ LLDPAD_DBG("%s:%s failed malloc for incoming TLV\n", -+ __func__, vd->ecp.ifname); -+ goto out; -+ } -+ -+ if ((tlv_length == 0) && (tlv->type != TYPE_0)) { -+ LLDPAD_DBG("%s:%s tlv_length == 0\n", __func__, -+ vd->ecp.ifname); -+ free_unpkd_tlv(tlv); -+ goto out; -+ } -+ -+ tlv->type = tlv_type; -+ tlv->length = tlv_length; -+ tlv->info = (u8 *)malloc(tlv_length); -+ if (tlv->info) { -+ memset(tlv->info,0, tlv_length); -+ memcpy(tlv->info, info, tlv_length); -+ } else { -+ LLDPAD_DBG("%s:%s failed malloc for incoming TLV info\n", -+ __func__, vd->ecp.ifname); -+ free_unpkd_tlv(tlv); -+ goto out; -+ } -+ -+ /* Validate the TLV */ -+ tlv_offset += sizeof(*tlv_head_ptr) + tlv_length; -+ -+ if (tlv->type == TYPE_127) { /* private TLV */ -+ /* give VSI TLV to VDP */ -+ if (!vdp_indicate(vd, tlv)) { -+ tlv_stored = true; -+ ++vdp_called; -+ } else { -+ /* TODO -+ * put it in a list and try again later until -+ * timer and retries have expired -+ */ -+ tlv_stored = false; -+ } -+ } -+ -+ 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); -+ vd->ecp.stats.statsTLVsUnrecognizedTotal++; -+ } -+ tlv = NULL; -+ tlv_stored = false; -+ } while (tlv_offset < vd->ecp.rx.frame_len); -+out: -+ if (frame_error) { -+ vd->ecp.stats.statsFramesDiscardedTotal++; -+ vd->ecp.stats.statsFramesInErrorsTotal++; -+ } -+ if (vdp_called) -+ vdp_advance_sm(vd); -+} -+ -+/* ecp_set_rx_state - sets the ecp rx sm state -+ * @vd: currently used port -+ * -+ * returns true or false -+ * -+ * switches the state machine to the next state depending on the input -+ * variables. returns true or false depending on wether the state machine -+ * can be run again with the new state or can stop at the current state. -+ */ -+static bool ecp_set_rx_state(struct vdp_data *vd) -+{ -+ struct port *port = port_find_by_ifindex(get_ifidx(vd->ifname)); -+ -+ if (!port) -+ return false; -+ -+ if (port->portEnabled == false) -+ ecp_rx_change_state(vd, ECP_RX_IDLE); -+ -+ switch(vd->ecp.rx.state) { -+ case ECP_RX_IDLE: -+ if (port->portEnabled == true) { -+ ecp_rx_change_state(vd, ECP_RX_INIT_RECEIVE); -+ return true; -+ } -+ return false; -+ case ECP_RX_INIT_RECEIVE: -+ if (vd->enabletx == true) { -+ ecp_rx_change_state(vd, ECP_RX_RECEIVE_WAIT); -+ return true; -+ } -+ return false; -+ case ECP_RX_RECEIVE_WAIT: -+ if (vd->enabletx == false) { -+ ecp_rx_change_state(vd, ECP_RX_IDLE); -+ return true; -+ } -+ if (vd->ecp.rx.rcvFrame == true) { -+ ecp_rx_change_state(vd, ECP_RX_RECEIVE_ECPDU); -+ return true; -+ } -+ return false; -+ case ECP_RX_RECEIVE_ECPDU: -+ if (vd->ecp.seqECPDU == vd->ecp.lastSequence) { -+ LLDPAD_DBG("%s:%s seqECPDU %x, lastSequence %x\n", -+ __func__, vd->ecp.ifname, vd->ecp.seqECPDU, -+ vd->ecp.lastSequence); -+ ecp_rx_change_state(vd, ECP_RX_RESEND_ACK); -+ return true; -+ } -+ if (vd->ecp.seqECPDU != vd->ecp.lastSequence) { -+ ecp_rx_change_state(vd, ECP_RX_RESEND_ACK); -+ return true; -+ } -+ return false; -+ case ECP_RX_SEND_ACK: -+ case ECP_RX_RESEND_ACK: -+ ecp_rx_change_state(vd, ECP_RX_RECEIVE_WAIT); -+ return false; -+ default: -+ LLDPAD_DBG("%s:%s ECP RX state machine in invalid state %d\n", -+ __func__, vd->ecp.ifname, vd->ecp.rx.state); -+ return false; -+ } -+} -+ -+/* ecp_rx_run_sm - state machine for ecp rx -+ * @vd: currently used port -+ * -+ * no return value -+ * -+ * runs the state machine for ecp rx. -+ */ -+static void ecp_rx_run_sm(struct vdp_data *vd) -+{ -+ ecp_set_rx_state(vd); -+ do { -+ LLDPAD_DBG("%s:%s ecp_rx - %s\n", __func__, vd->ecp.ifname, -+ ecp_rx_states[vd->ecp.tx.state]); -+ -+ switch(vd->ecp.rx.state) { -+ case ECP_RX_IDLE: -+ break; -+ case ECP_RX_INIT_RECEIVE: -+ ecp_rx_Initialize(vd); -+ break; -+ case ECP_RX_RECEIVE_WAIT: -+ break; -+ case ECP_RX_RECEIVE_ECPDU: -+ vd->ecp.rx.rcvFrame = false; -+ ecp_rx_validate_frame(vd); -+ break; -+ case ECP_RX_SEND_ACK: -+ ecp_rx_ProcessFrame(vd); -+ break; -+ case ECP_RX_RESEND_ACK: -+ ecp_rx_ProcessFrame(vd); -+ if (!vd->ecp.ackReceived) { -+ ecp_rx_send_ack_frame(vd); -+ } -+ break; -+ default: -+ LLDPAD_DBG("%s:%s ECP RX state machine in invalid state %d\n", -+ __func__, vd->ecp.ifname, vd->ecp.rx.state); -+ } -+ } while (ecp_set_rx_state(vd) == true); -+} -diff --git a/qbg/ecp22.c b/qbg/ecp22.c -new file mode 100644 -index 0000000..604f4cc ---- /dev/null -+++ b/qbg/ecp22.c -@@ -0,0 +1,1062 @@ -+/****************************************************************************** -+ -+ Implementation of ECP according to 802.1Qbg -+ (c) Copyright IBM Corp. 2010, 2012 -+ -+ Author(s): Jens Osterkamp -+ Author(s): Thomas Richter -+ -+ This program is free software; you can redistribute it and/or modify it -+ under the terms and conditions of the GNU General Public License, -+ version 2, as published by the Free Software Foundation. -+ -+ This program is distributed in the hope it will be useful, but WITHOUT -+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ more details. -+ -+ You should have received a copy of the GNU General Public License along with -+ this program; if not, write to the Free Software Foundation, Inc., -+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. -+ -+ The full GNU General Public License is included in this distribution in -+ the file called "COPYING". -+ -+******************************************************************************/ -+ -+#include -+#include -+#include -+#include -+ -+#include "eloop.h" -+#include "qbg_ecp22.h" -+#include "messages.h" -+#include "qbg_utils.h" -+#include "lldp/l2_packet.h" -+#include "lldp_tlv.h" -+ -+#define ECP22_MAX_RETRIES_DEFAULT (3) /* Default # of max retries */ -+#define ECP22_ACK_TIMER_STOPPED (-1) -+/* -+ * Defaults to 2ms wait time for acknowledgement packet reception. -+ */ -+#define ECP22_ACK_TIMER_DEFAULT (8) -+ -+static void ecp22_tx_run_sm(struct ecp22 *); -+ -+static const char *const ecp22_rx_states[] = { /* Receive states verbatim */ -+ "ECP22_RX_BEGIN", -+ "ECP22_RX_WAIT", -+ "ECP22_RX_WAIT2", -+ "ECP22_RX_FIRST", -+ "ECP22_RX_REC_ECPDU", -+ "ECP22_RX_NEW_ECPDU", -+ "ECP22_RX_SEND_ACK" -+}; -+ -+static const char *const ecp22_tx_states[] = { /* Transmit states verbatim */ -+ "ECP22_TX_BEGIN", -+ "ECP22_TX_INIT", -+ "ECP22_TX_TXMIT_ECPDU", -+ "ECP22_TX_WAIT_FORREQ", -+ "ECP22_TX_WAIT_ONDATA", -+ "ECP22_TX_ERROR" -+}; -+ -+/* -+ * Increment sequence number. Do not return zero as sequence number. -+ */ -+static unsigned short inc_seqno(unsigned short x) -+{ -+ ++x; -+ if (!x) /* Wrapped */ -+ ++x; -+ return x; -+} -+ -+/* -+ * Find the ecp data associated with an interface. -+ * Return pointer or NULL if not found. -+ */ -+static struct ecp22 *find_ecpdata(char *ifname, struct ecp22_user_data *eud) -+{ -+ struct ecp22 *ecp = 0; -+ -+ if (eud) { -+ LIST_FOREACH(ecp, &eud->head, node) -+ if (!strncmp(ifname, ecp->ifname, IFNAMSIZ)) -+ break; -+ } -+ return ecp; -+} -+ -+/* -+ * ecp22_txframe - transmit ecp frame -+ * @ecp: pointer to currently used ecp data structure -+ * -+ * returns the number of characters sent on success, -1 on failure -+ * -+ * sends out the frame stored in the frame structure using l2_packet_send. -+ */ -+static int ecp22_txframe(struct ecp22 *ecp, char *txt, unsigned char *dst, -+ unsigned char *ack, size_t len) -+{ -+ hexdump_frame(ecp->ifname, txt, ack, len); -+ return l2_packet_send(ecp->l2, dst, htons(ETH_P_ECP22), ack, len); -+} -+ -+/* -+ * Append some data at the end of the transmit data buffer. Make sure the -+ * End TLV always fits into the buffer. -+ */ -+static unsigned char end_tlv[2] = { 0x0, 0x0 }; /* END TLV */ -+ -+static void ecp22_append(u8 *buffer, u32 *pos, void *data, u32 len) -+{ -+ if (*pos + len > ETH_FRAME_LEN - sizeof end_tlv) -+ return; -+ memcpy(buffer + *pos, data, len); -+ *pos += len; -+} -+ -+/* -+ * Return a payload node to the freelist. -+ */ -+void ecp22_putnode(struct ecp22_freelist *list, struct ecp22_payload_node *elm) -+{ -+ elm->ptlv = free_pkd_tlv(elm->ptlv); -+ if (list->freecnt > ecp22_maxpayload) -+ free(elm); -+ else { -+ ++list->freecnt; -+ LIST_INSERT_HEAD(&list->head, elm, node); -+ } -+} -+ -+/* -+ * ecp22_build_ecpdu - create an ecp protocol data unit -+ * @ecp: pointer to currently used ecp data structure -+ * -+ * returns true on success, false on failure -+ * -+ * creates the frame header with the ports mac address, the ecp header with REQ -+ * plus a packed TLVs created taken from the send queue. -+ */ -+static bool ecp22_build_ecpdu(struct ecp22 *ecp) -+{ -+ struct l2_ethhdr eth; -+ struct ecp22_hdr ecph; -+ u32 fb_offset = 0; -+ struct packed_tlv *ptlv; -+ struct ecp22_payload_node *p = LIST_FIRST(&ecp->inuse.head); -+ -+ if (!p) -+ return false; -+ ecp->tx.ecpdu_received = true; /* Txmit buffer in use */ -+ memcpy(eth.h_dest, p->mac, ETH_ALEN); -+ l2_packet_get_own_src_addr(ecp->l2, eth.h_source); -+ eth.h_proto = htons(ETH_P_ECP22); -+ memset(ecp->tx.frame, 0, sizeof ecp->tx.frame); -+ ecp22_append(ecp->tx.frame, &fb_offset, (void *)ð, sizeof eth); -+ -+ ecp22_hdr_set_version(&ecph, 1); -+ ecp22_hdr_set_op(&ecph, ECP22_REQUEST); -+ ecp22_hdr_set_subtype(&ecph, ECP22_VDP); -+ ecph.ver_op_sub = htons(ecph.ver_op_sub); -+ ecph.seqno = htons(ecp->tx.seqno); -+ ecp22_append(ecp->tx.frame, &fb_offset, (void *)&ecph, sizeof ecph); -+ -+ ptlv = p->ptlv; -+ ecp22_append(ecp->tx.frame, &fb_offset, ptlv->tlv, ptlv->size); -+ ecp22_append(ecp->tx.frame, &fb_offset, end_tlv, sizeof end_tlv); -+ ecp->tx.frame_len = MAX(fb_offset, (unsigned)ETH_ZLEN); -+ LIST_REMOVE(p, node); -+ ecp22_putnode(&ecp->isfree, p); -+ LLDPAD_DBG("%s:%s seqno %#hx frame_len %#hx\n", __func__, -+ ecp->ifname, ecp->tx.seqno, ecp->tx.frame_len); -+ return true; -+} -+ -+/* -+ * Execute transmit state transmitECPDU. -+ */ -+static void ecp22_es_waitforreq(struct ecp22 *ecp) -+{ -+ ecp->tx.retries = 0; -+ ecp->tx.ack_received = false; -+ ecp->tx.ecpdu_received = false; -+ ecp->tx.seqno = inc_seqno(ecp->tx.seqno); -+ LLDPAD_DBG("%s:%s seqno %#hx\n", __func__, ecp->ifname, ecp->tx.seqno); -+} -+ -+/* -+ * Execute transmit state countErrors. -+ */ -+static void ecp22_es_counterror(struct ecp22 *ecp) -+{ -+ ++ecp->tx.errors; -+ LLDPAD_DBG("%s:%s errors %lu\n", __func__, ecp->ifname, -+ ecp->tx.errors); -+} -+ -+/* -+ * Execute transmit state initTransmit. -+ */ -+static void ecp22_es_inittransmit(struct ecp22 *ecp) -+{ -+ ecp->tx.errors = 0; -+ ecp->tx.seqno = 0; -+} -+ -+/* -+ * Return RTE value in milliseconds. -+ */ -+static int rtevalue(unsigned char rte) -+{ -+ return (1 << rte) * 10; -+} -+ -+/* -+ * ecp22_ack_timeout_handler - handles the ack timer expiry -+ * @eloop_data: data structure of event loop -+ * @user_ctx: user context, vdp_data here -+ * -+ * no return value -+ * -+ * called when the ECP timer has expired. Calls the ECP station state machine. -+ */ -+static void ecp22_ack_timeout_handler(UNUSED void *eloop_data, void *user_ctx) -+{ -+ struct ecp22 *ecp = (struct ecp22 *)user_ctx; -+ -+ LLDPAD_DBG("%s:%s retries:%d\n", __func__, -+ ecp->ifname, ecp->tx.retries); -+ ecp22_tx_run_sm(ecp); -+} -+ -+/* -+ * ecp22_tx_start_acktimer - starts the ECP ack timer -+ * @ecp: pointer to currently used ecp data structure -+ * -+ * returns 0 on success, -1 on error -+ * -+ * starts the ack timer when a frame has been sent out. -+ */ -+static void ecp22_tx_start_acktimer(struct ecp22 *ecp) -+{ -+ unsigned long ack_sec = rtevalue(ecp->max_rte) / 1000000; -+ unsigned long ack_usec = rtevalue(ecp->max_rte) % 1000000; -+ -+ LLDPAD_DBG("%s:%s [%ld.%06ld]\n", __func__, ecp->ifname, ack_sec, -+ ack_usec); -+ eloop_register_timeout(ack_sec, ack_usec, ecp22_ack_timeout_handler, -+ 0, (void *)ecp); -+} -+ -+/* -+ * ecp22_tx_change_state - changes the ecp tx sm state -+ * @ecp: pointer to currently used ecp data structure -+ * @newstate: new state for the sm -+ * -+ * no return value -+ * -+ * checks state transistion for consistency and finally changes the state of -+ * the profile. -+ */ -+static void ecp22_tx_change_state(struct ecp22 *ecp, unsigned char newstate) -+{ -+ switch (newstate) { -+ case ECP22_TX_BEGIN: -+ break; -+ case ECP22_TX_INIT: -+ assert(ecp->tx.state == ECP22_TX_BEGIN); -+ break; -+ case ECP22_TX_WAIT_FORREQ: -+ assert(ecp->tx.state == ECP22_TX_INIT || -+ ecp->tx.state == ECP22_TX_ERROR || -+ ecp->tx.state == ECP22_TX_TXMIT_ECPDU); -+ break; -+ case ECP22_TX_WAIT_ONDATA: -+ assert(ecp->tx.state == ECP22_TX_WAIT_FORREQ); -+ break; -+ case ECP22_TX_TXMIT_ECPDU: -+ assert(ecp->tx.state == ECP22_TX_WAIT_ONDATA); -+ break; -+ case ECP22_TX_ERROR: -+ assert(ecp->tx.state == ECP22_TX_TXMIT_ECPDU); -+ break; -+ default: -+ LLDPAD_ERR("%s: ECP TX state machine invalid state %d\n", -+ ecp->ifname, newstate); -+ } -+ LLDPAD_DBG("%s:%s state change %s -> %s\n", __func__, -+ ecp->ifname, ecp22_tx_states[ecp->tx.state], -+ ecp22_tx_states[newstate]); -+ ecp->tx.state = newstate; -+} -+ -+/* -+ * Send the payload data. -+ */ -+static int ecp22_es_txmit(struct ecp22 *ecp) -+{ -+ int rc = 0; -+ -+ ++ecp->tx.retries; -+ ecp22_txframe(ecp, "ecp-out", ecp->tx.frame, ecp->tx.frame, -+ ecp->tx.frame_len); -+ ecp22_tx_start_acktimer(ecp); -+ return rc; -+} -+ -+/* -+ * ecp22_set_tx_state - sets the ecp tx state machine state -+ * @ecp: pointer to currently used ecp data structure -+ * -+ * returns true or false -+ * -+ * switches the state machine to the next state depending on the input -+ * variables. returns true or false depending on wether the state machine -+ * can be run again with the new state or can stop at the current state. -+ */ -+static bool ecp22_set_tx_state(struct ecp22 *ecp) -+{ -+ struct port *port = port_find_by_ifindex(get_ifidx(ecp->ifname)); -+ -+ if (!port) { -+ LLDPAD_ERR("%s:%s port not found\n", __func__, ecp->ifname); -+ return false; -+ } -+ if (!port->portEnabled && port->prevPortEnabled) { -+ LLDPAD_ERR("%s:%s port was disabled\n", __func__, ecp->ifname); -+ ecp22_tx_change_state(ecp, ECP22_TX_BEGIN); -+ } -+ port->prevPortEnabled = port->portEnabled; -+ -+ switch (ecp->tx.state) { -+ case ECP22_TX_BEGIN: -+ ecp22_tx_change_state(ecp, ECP22_TX_INIT); -+ return true; -+ case ECP22_TX_INIT: -+ ecp22_tx_change_state(ecp, ECP22_TX_WAIT_FORREQ); -+ return true; -+ case ECP22_TX_WAIT_FORREQ: -+ ecp22_tx_change_state(ecp, ECP22_TX_WAIT_ONDATA); -+ return true; -+ case ECP22_TX_WAIT_ONDATA: -+ if (LIST_FIRST(&ecp->inuse.head)) { /* Data to send */ -+ ecp22_build_ecpdu(ecp); -+ ecp22_tx_change_state(ecp, ECP22_TX_TXMIT_ECPDU); -+ return true; -+ } -+ return false; -+ case ECP22_TX_TXMIT_ECPDU: -+ if (ecp->tx.ack_received) { -+ ecp22_tx_change_state(ecp, ECP22_TX_WAIT_FORREQ); -+ return true; -+ } -+ if (ecp->tx.retries > ecp->max_retries) { -+ ecp22_tx_change_state(ecp, ECP22_TX_ERROR); -+ return true; -+ } -+ return false; -+ case ECP22_TX_ERROR: -+ ecp22_tx_change_state(ecp, ECP22_TX_WAIT_FORREQ); -+ return true; -+ default: -+ LLDPAD_ERR("%s: ECP TX state machine in invalid state %d\n", -+ ecp->ifname, ecp->tx.state); -+ return false; -+ } -+} -+ -+/* -+ * ecp22_tx_run_sm - state machine for ecp transmit -+ * @ecp: pointer to currently used ecp data structure -+ * -+ * no return value -+ */ -+static void ecp22_tx_run_sm(struct ecp22 *ecp) -+{ -+ ecp22_set_tx_state(ecp); -+ do { -+ LLDPAD_DBG("%s:%s state %s\n", __func__, -+ ecp->ifname, ecp22_tx_states[ecp->tx.state]); -+ -+ switch (ecp->tx.state) { -+ case ECP22_TX_BEGIN: -+ break; -+ case ECP22_TX_INIT: -+ ecp22_es_inittransmit(ecp); -+ break; -+ case ECP22_TX_WAIT_FORREQ: -+ ecp22_es_waitforreq(ecp); -+ break; -+ case ECP22_TX_WAIT_ONDATA: -+ break; -+ case ECP22_TX_TXMIT_ECPDU: -+ ecp22_es_txmit(ecp); -+ break; -+ case ECP22_TX_ERROR: -+ ecp22_es_counterror(ecp); -+ break; -+ } -+ } while (ecp22_set_tx_state(ecp) == true); -+} -+ -+/* -+ * ecp22_rx_change_state - changes the ecp rx sm state -+ * @ecp: pointer to currently used ecp data structure -+ * @newstate: new state for the sm -+ * -+ * no return value -+ * -+ * checks state transistion for consistency and finally changes the state of -+ * the ecp receive buffer. -+ */ -+static void ecp22_rx_change_state(struct ecp22 *ecp, u8 newstate) -+{ -+ switch (newstate) { -+ case ECP22_RX_BEGIN: -+ break; -+ case ECP22_RX_WAIT: -+ assert(ecp->rx.state == ECP22_RX_BEGIN); -+ break; -+ case ECP22_RX_FIRST: -+ assert(ecp->rx.state == ECP22_RX_WAIT); -+ break; -+ case ECP22_RX_REC_ECPDU: -+ assert((ecp->rx.state == ECP22_RX_FIRST) || -+ (ecp->rx.state == ECP22_RX_WAIT2)); -+ break; -+ case ECP22_RX_NEW_ECPDU: -+ assert(ecp->rx.state == ECP22_RX_REC_ECPDU); -+ break; -+ case ECP22_RX_SEND_ACK: -+ assert((ecp->rx.state == ECP22_RX_REC_ECPDU) || -+ (ecp->rx.state == ECP22_RX_NEW_ECPDU)); -+ break; -+ case ECP22_RX_WAIT2: -+ assert(ecp->rx.state == ECP22_RX_SEND_ACK); -+ break; -+ default: -+ LLDPAD_ERR("%s:%s LLDP RX state machine invalid state %d\n", -+ __func__, ecp->ifname, newstate); -+ } -+ LLDPAD_DBG("%s:%s state change %s -> %s\n", __func__, -+ ecp->ifname, ecp22_rx_states[ecp->rx.state], -+ ecp22_rx_states[newstate]); -+ ecp->rx.state = newstate; -+} -+ -+/* -+ * Execute action in state sendack. Construct and send an acknowledgement -+ * for the received ECP packet. -+ */ -+static void ecp22_es_send_ack(struct ecp22 *ecp) -+{ -+ unsigned char ack_frame[ETH_HLEN + sizeof(struct ecp22_hdr)]; -+ struct ethhdr *ethdst = (struct ethhdr *)ack_frame; -+ struct ecp22_hdr *ecpdst = (struct ecp22_hdr *)&ack_frame[ETH_HLEN]; -+ struct ethhdr *ethsrc = (struct ethhdr *)ecp->rx.frame; -+ struct ecp22_hdr *ecpsrc = (struct ecp22_hdr *)&ecp->rx.frame[ETH_HLEN]; -+ struct ecp22_hdr ack; -+ -+ LLDPAD_DBG("%s:%s state %s seqno %#hx\n", __func__, ecp->ifname, -+ ecp22_rx_states[ecp->rx.state], ecp->rx.seqno); -+ memcpy(ethdst->h_dest, nearest_customer_bridge, ETH_ALEN); -+ l2_packet_get_own_src_addr(ecp->l2, (u8 *)ðdst->h_source); -+ ethdst->h_proto = ethsrc->h_proto; -+ /* Set ECP header */ -+ ack.ver_op_sub = ntohs(ecpsrc->ver_op_sub); -+ ecp22_hdr_set_op(&ack, ECP22_ACK); -+ ecpdst->ver_op_sub = htons(ack.ver_op_sub); -+ ecpdst->seqno = htons(ecp->rx.seqno); -+ ecp22_txframe(ecp, "ecp-ack", ethsrc->h_source, ack_frame, -+ sizeof ack_frame); -+} -+ -+ -+/* -+ * Notify upper layer protocol function of ECP payload data just received. -+ */ -+static void ecp22_to_ulp(unsigned short ulp, struct ecp22 *ecp) -+{ -+ size_t offset = ETH_HLEN + sizeof(struct ecp22_hdr); -+ struct qbg22_imm to_ulp; -+ -+ to_ulp.data_type = ECP22_TO_ULP; -+ to_ulp.u.c.len = ecp->rx.frame_len - offset; -+ to_ulp.u.c.data = &ecp->rx.frame[offset]; -+ if (ulp == ECP22_VDP) -+ modules_notify(LLDP_MOD_VDP22, LLDP_MOD_ECP22, ecp->ifname, -+ &to_ulp); -+ else -+ LLDPAD_INFO("%s:%s ECP subtype %d not yet implemented\n", -+ __func__, ecp->ifname, ulp); -+} -+ -+/* -+ * Execute action in state newECPDU. -+ * Notify upper layer protocol of new data. -+ */ -+static void ecp22_es_new_ecpdu(struct ecp22 *ecp) -+{ -+ struct ecp22_hdr *hdr = (struct ecp22_hdr *)&ecp->rx.frame[ETH_HLEN]; -+ struct ecp22_hdr ecphdr; -+ unsigned short ulp; -+ -+ ecphdr.ver_op_sub = ntohs(hdr->ver_op_sub); -+ ulp = ecp22_hdr_read_subtype(&ecphdr); -+ LLDPAD_DBG("%s:%s state %s notify ULP %d seqno %#hx\n", __func__, -+ ecp->ifname, ecp22_rx_states[ecp->rx.state], -+ ulp, ecp->rx.seqno); -+ ecp->rx.last_seqno = ecp->rx.seqno; -+ ecp22_to_ulp(ulp, ecp); -+} -+ -+/* -+ * Execute action in state receiveECPDU. -+ */ -+static void ecp22_es_rec_ecpdu(struct ecp22 *ecp) -+{ -+ struct ecp22_hdr *hdr = (struct ecp22_hdr *)&ecp->rx.frame[ETH_HLEN]; -+ -+ ecp->rx.seqno = ntohs(hdr->seqno); -+ LLDPAD_DBG("%s:%s state %s seqno %#hx\n", __func__, ecp->ifname, -+ ecp22_rx_states[ecp->rx.state], ecp->rx.seqno); -+} -+ -+/* -+ * Execute action in state receiveFirst. -+ */ -+static void ecp22_es_first(struct ecp22 *ecp) -+{ -+ struct ecp22_hdr *hdr = (struct ecp22_hdr *)&ecp->rx.frame[ETH_HLEN]; -+ -+ LLDPAD_DBG("%s:%s state %s\n", __func__, ecp->ifname, -+ ecp22_rx_states[ecp->rx.state]); -+ ecp->rx.last_seqno = ntohs(hdr->seqno) - 1; -+} -+ -+/* -+ * Execute action in state receiveWait. -+ */ -+static void ecp22_es_wait(struct ecp22 *ecp) -+{ -+ LLDPAD_DBG("%s:%s state %s\n", __func__, ecp->ifname, -+ ecp22_rx_states[ecp->rx.state]); -+ ecp->rx.ecpdu_received = false; -+} -+ -+/* -+ * ecp22_set_rx_state - sets the ecp receive state machine state -+ * @ecp: pointer to currently used ecp data structure -+ * -+ * returns true or false -+ * -+ * switches the state machine to the next state depending on the input -+ * variables. Returns true or false depending on wether the state machine -+ * can be run again with the new state or can stop at the current state. -+ */ -+static bool ecp22_set_rx_state(struct ecp22 *ecp) -+{ -+ struct port *port = port_find_by_ifindex(get_ifidx(ecp->ifname)); -+ -+ if (!port) -+ return false; -+ -+ LLDPAD_DBG("%s:%s state %s\n", __func__, ecp->ifname, -+ ecp22_rx_states[ecp->rx.state]); -+ if (!port->portEnabled) -+ ecp22_rx_change_state(ecp, ECP22_RX_BEGIN); -+ switch (ecp->rx.state) { -+ case ECP22_RX_BEGIN: -+ ecp22_rx_change_state(ecp, ECP22_RX_WAIT); -+ return false; -+ case ECP22_RX_WAIT: -+ if (ecp->rx.ecpdu_received) { -+ ecp22_rx_change_state(ecp, ECP22_RX_FIRST); -+ return true; -+ } -+ return false; -+ case ECP22_RX_WAIT2: -+ if (ecp->rx.ecpdu_received) { -+ ecp22_rx_change_state(ecp, ECP22_RX_REC_ECPDU); -+ return true; -+ } -+ return false; -+ case ECP22_RX_FIRST: -+ ecp22_rx_change_state(ecp, ECP22_RX_REC_ECPDU); -+ return true; -+ case ECP22_RX_REC_ECPDU: -+ if (ecp->rx.seqno == ecp->rx.last_seqno) -+ ecp22_rx_change_state(ecp, ECP22_RX_SEND_ACK); -+ else -+ ecp22_rx_change_state(ecp, ECP22_RX_NEW_ECPDU); -+ return true; -+ case ECP22_RX_NEW_ECPDU: -+ ecp22_rx_change_state(ecp, ECP22_RX_SEND_ACK); -+ return true; -+ case ECP22_RX_SEND_ACK: -+ ecp22_rx_change_state(ecp, ECP22_RX_WAIT2); -+ return true; -+ default: -+ LLDPAD_DBG("%s:%s ECP RX state machine in invalid state %d\n", -+ __func__, ecp->ifname, ecp->rx.state); -+ return false; -+ } -+} -+ -+/* -+ * ecp22_rx_run_sm - state machine for ecp receive protocol -+ * @ecp: pointer to currently used ecp data structure -+ * -+ * no return value -+ * -+ * runs the state machine for ecp22 receive function. -+ */ -+static void ecp22_rx_run_sm(struct ecp22 *ecp) -+{ -+ ecp22_set_rx_state(ecp); -+ do { -+ switch (ecp->rx.state) { -+ case ECP22_RX_WAIT: -+ case ECP22_RX_WAIT2: -+ ecp22_es_wait(ecp); -+ break; -+ case ECP22_RX_FIRST: -+ ecp22_es_first(ecp); -+ break; -+ case ECP22_RX_REC_ECPDU: -+ ecp22_es_rec_ecpdu(ecp); -+ break; -+ case ECP22_RX_NEW_ECPDU: -+ ecp22_es_new_ecpdu(ecp); -+ break; -+ case ECP22_RX_SEND_ACK: -+ ecp22_es_send_ack(ecp); -+ break; -+ default: -+ LLDPAD_DBG("%s:%s ECP RX state machine in invalid " -+ "state %d\n", __func__, ecp->ifname, -+ ecp->rx.state); -+ } -+ } while (ecp22_set_rx_state(ecp) == true); -+} -+ -+/* -+ * Received an aknowledgement frame. -+ * Check if we have a transmit pending and the ack'ed packet number matches -+ * the send packet. -+ */ -+static void ecp22_recack_frame(struct ecp22 *ecp, unsigned short seqno) -+{ -+ LLDPAD_DBG("%s:%s txmit:%d seqno %#hx ack-seqno %#hx\n", __func__, -+ ecp->ifname, ecp->tx.ecpdu_received, ecp->tx.seqno, seqno); -+ if (ecp->tx.ecpdu_received) { -+ if (ecp->tx.seqno == seqno) -+ ecp->tx.ack_received = true; -+ } -+} -+ -+/* -+ * ecp22_rx_receiveframe - receive am ecp frame -+ * @ctx: rx callback context, struct ecp * in this case -+ * @ifindex: index of interface -+ * @buf: buffer which contains the frame just received -+ * @len: size of buffer (frame) -+ * -+ * no return value -+ * -+ * creates a local copy of the buffer and checks the header. keeps some -+ * statistics about ecp frames. Checks if it is a request or an ack frame and -+ * branches to ecp rx or ecp tx state machine. -+ */ -+static void ecp22_rx_receiveframe(void *ctx, int ifindex, const u8 *buf, -+ size_t len) -+{ -+ struct ecp22 *ecp = (struct ecp22 *)ctx; -+ struct port *port; -+ struct ecp22_hdr *ecp_hdr, ecphdr; -+ -+ LLDPAD_DBG("%s:%s ifindex:%d len:%zd state:%s ecpdu_received:%d\n", -+ __func__, ecp->ifname, ifindex, len, -+ ecp22_rx_states[ecp->rx.state], ecp->rx.ecpdu_received); -+ hexdump_frame(ecp->ifname, "frame-in", buf, len); -+ port = port_find_by_ifindex(get_ifidx(ecp->ifname)); -+ if (!port || ecp->rx.ecpdu_received) -+ /* Port not found or buffer not free */ -+ return; -+ -+ memcpy(ecp->rx.frame, buf, len); -+ ecp->rx.frame_len = len; -+ ecp->stats.statsFramesInTotal++; -+ -+ ecp_hdr = (struct ecp22_hdr *)&ecp->rx.frame[ETH_HLEN]; -+ ecphdr.ver_op_sub = ntohs(ecp_hdr->ver_op_sub); -+ -+ /* Check for correct subtype and version number */ -+ if (ecp22_hdr_read_version(&ecphdr) != 1) { -+ LLDPAD_ERR("%s:%s ERROR unknown version %#02hx seqno %#hx\n", -+ __func__, ecp->ifname, ecphdr.ver_op_sub, -+ ntohs(ecp_hdr->seqno)); -+ return; -+ } -+ switch (ecp22_hdr_read_subtype(&ecphdr)) { -+ default: -+ LLDPAD_ERR("%s:%s ERROR unknown subtype %#02hx seqno %#hx\n", -+ __func__, ecp->ifname, ecphdr.ver_op_sub, -+ ntohs(ecp_hdr->seqno)); -+ return; -+ case ECP22_PECSP: -+ case ECP22_VDP: -+ /* Subtype ok, fall through intended */ -+ break; -+ } -+ -+ switch (ecp22_hdr_read_op(&ecphdr)) { -+ case ECP22_REQUEST: -+ LLDPAD_DBG("%s:%s received REQ frame seqno %#hx\n", __func__, -+ ecp->ifname, ntohs(ecp_hdr->seqno)); -+ ecp->rx.ecpdu_received = true; -+ ecp22_rx_run_sm(ecp); -+ break; -+ case ECP22_ACK: -+ LLDPAD_DBG("%s:%s received ACK frame seqno %#hx\n", __func__, -+ ecp->ifname, ntohs(ecp_hdr->seqno)); -+ ecp22_recack_frame(ecp, ntohs(ecp_hdr->seqno)); -+ break; -+ default: -+ LLDPAD_ERR("%s:%s ERROR unknown mode %#02hx seqno %#hx\n", -+ __func__, ecp->ifname, ecphdr.ver_op_sub, -+ ntohs(ecp_hdr->seqno)); -+ } -+} -+ -+/* -+ * ecp22_create - create data structure and initialize ecp protocol -+ * @ifname: interface for which the ecp protocol is initialized -+ * -+ * returns NULL on error and an pointer to the ecp22 structure on success. -+ * -+ * finds the port to the interface name, sets up the receive handle for -+ * incoming ecp frames and initializes the ecp rx and tx state machines. -+ * To be called when a successful exchange of EVB TLVs has been -+ * made and ECP protocols are supported by both sides. -+ */ -+static struct ecp22 *ecp22_create(char *ifname, struct ecp22_user_data *eud) -+{ -+ struct ecp22 *ecp; -+ -+ ecp = calloc(1, sizeof *ecp); -+ if (!ecp) { -+ LLDPAD_ERR("%s:%s unable to allocate ecp protocol\n", __func__, -+ ifname); -+ return NULL; -+ } -+ strncpy(ecp->ifname, ifname, sizeof ecp->ifname); -+ ecp->l2 = l2_packet_init(ecp->ifname, 0, ETH_P_ECP22, -+ ecp22_rx_receiveframe, ecp, 1); -+ -+ if (!ecp->l2) { -+ LLDPAD_ERR("%s:%s error open layer 2 ETH_P_ECP\n", __func__, -+ ifname); -+ free(ecp); -+ return NULL; -+ } -+ LIST_INSERT_HEAD(&eud->head, ecp, node); -+ LLDPAD_DBG("%s:%s create ecp data\n", __func__, ifname); -+ return ecp; -+} -+ -+/* -+ * ecp22_start - build up ecp structures for an interface -+ * @ifname: name of the interface -+ */ -+void ecp22_start(char *ifname) -+{ -+ struct ecp22_user_data *eud; -+ struct ecp22 *ecp; -+ -+ LLDPAD_DBG("%s:%s start ecp\n", __func__, ifname); -+ eud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_ECP22); -+ if (!eud) { -+ LLDPAD_DBG("%s:%s no ECP module\n", __func__, ifname); -+ return; -+ } -+ ecp = find_ecpdata(ifname, eud); -+ if (!ecp) -+ ecp = ecp22_create(ifname, eud); -+ ecp->max_retries = ECP22_MAX_RETRIES_DEFAULT; -+ ecp->max_rte = ECP22_ACK_TIMER_DEFAULT; -+ LIST_INIT(&ecp->inuse.head); -+ ecp->inuse.last = 0; -+ LIST_INIT(&ecp->isfree.head); -+ ecp->isfree.freecnt = 0; -+ ecp->rx.state = ECP22_RX_BEGIN; -+ ecp22_rx_run_sm(ecp); -+ ecp->tx.state = ECP22_TX_BEGIN; -+ ecp22_tx_run_sm(ecp); -+} -+ -+/* -+ * Remove the ecp_payload nodes -+ */ -+static void ecp22_removelist(ecp22_list *ptr) -+{ -+ struct ecp22_payload_node *np; -+ -+ while ((np = LIST_FIRST(ptr))) { -+ LIST_REMOVE(np, node); -+ np->ptlv = free_pkd_tlv(np->ptlv); -+ free(np); -+ } -+} -+ -+static void ecp22_remove(struct ecp22 *ecp) -+{ -+ LLDPAD_DBG("%s:%s remove ecp\n", __func__, ecp->ifname); -+ ecp22_removelist(&ecp->inuse.head); -+ ecp->inuse.last = 0; -+ ecp22_removelist(&ecp->isfree.head); -+ ecp->isfree.freecnt = 0; -+ LIST_REMOVE(ecp, node); -+ free(ecp); -+} -+ -+/* -+ * ecp22_stop - tear down ecp structures for a interface -+ * @ifname: name of the interface -+ * -+ * no return value -+ * -+ */ -+void ecp22_stop(char *ifname) -+{ -+ struct ecp22_user_data *eud; -+ struct ecp22 *ecp; -+ -+ LLDPAD_DBG("%s:%s stop ecp\n", __func__, ifname); -+ eud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_ECP22); -+ ecp = find_ecpdata(ifname, eud); -+ if (ecp) -+ ecp22_remove(ecp); -+} -+ -+/* -+ * Update data exchanged via EVB protocol. -+ * Returns true when data update succeeded. -+ */ -+static int ecp22_data_from_evb(char *ifname, struct evb22_to_ecp22 *ptr) -+{ -+ struct ecp22_user_data *eud; -+ struct ecp22 *ecp; -+ -+ eud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_ECP22); -+ ecp = find_ecpdata(ifname, eud); -+ if (ecp) { -+ ecp->max_rte = ptr->max_rte; -+ ecp->max_retries = ptr->max_retry; -+ LLDPAD_DBG("%s:%s max_rte:%d max_retries:%d\n", __func__, -+ ifname, ecp->max_rte, ecp->max_retries); -+ return 0; -+ } -+ return -ENOENT; -+} -+ -+/* -+ * Add ecp payload data at the end of the queue. -+ */ -+static void ecp22_add_payload(struct ecp22 *ecp, -+ struct ecp22_payload_node *elem) -+{ -+ if (LIST_EMPTY(&ecp->inuse.head)) -+ LIST_INSERT_HEAD(&ecp->inuse.head, elem, node); -+ else -+ LIST_INSERT_AFTER(ecp->inuse.last, elem, node); -+ ecp->inuse.last = elem; -+ if (!ecp->tx.ecpdu_received) /* Transmit buffer free */ -+ ecp22_tx_run_sm(ecp); -+} -+ -+/* -+ * Copy the payload data. -+ */ -+static struct packed_tlv *copy_ptlv(struct packed_tlv *from) -+{ -+ struct packed_tlv *ptlv = create_ptlv(); -+ -+ if (!ptlv) -+ return NULL; -+ ptlv->size = from->size; -+ ptlv->tlv = calloc(ptlv->size, sizeof(unsigned char)); -+ if (!ptlv->tlv) { -+ free_pkd_tlv(ptlv); -+ return NULL; -+ } -+ memcpy(ptlv->tlv, from->tlv, from->size); -+ return ptlv; -+} -+ -+/* -+ * Create a node for the ecp payload data. Get it from the free list if not -+ * empty. Otherwise allocate from heap. -+ */ -+static struct ecp22_payload_node *ecp22_getnode(struct ecp22_freelist *list) -+{ -+ struct ecp22_payload_node *elem = LIST_FIRST(&list->head); -+ -+ if (!elem) -+ elem = calloc(1, sizeof *elem); -+ else { -+ LIST_REMOVE(elem, node); -+ --list->freecnt; -+ } -+ return elem; -+} -+ -+/* -+ * Receive upper layer protocol data unit for transmit. -+ * Returns error if the request could not be queued for transmision. -+ */ -+static int ecp22_req2send(char *ifname, unsigned short subtype, -+ unsigned const char *mac, struct packed_tlv *du) -+{ -+ struct ecp22_user_data *eud; -+ struct ecp22 *ecp; -+ struct ecp22_payload_node *payda; -+ struct packed_tlv *ptlv = copy_ptlv(du); -+ int rc = 0; -+ -+ LLDPAD_DBG("%s:%s subtype:%d\n", __func__, ifname, subtype); -+ -+ eud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_ECP22); -+ ecp = find_ecpdata(ifname, eud); -+ if (!ecp) { -+ rc = -ENODEV; -+ goto out; -+ } -+ if (!ptlv) { -+ rc = -ENOMEM; -+ goto out; -+ } -+ if (ptlv->size >= ECP22_MAXPAYLOAD_LEN) { -+ rc = -E2BIG; -+ goto out; -+ } -+ payda = ecp22_getnode(&ecp->isfree); -+ if (!payda) { -+ free_pkd_tlv(ptlv); -+ rc = -ENOMEM; -+ goto out; -+ } -+ payda->ptlv = ptlv; -+ payda->subtype = subtype; -+ memcpy(payda->mac, mac, sizeof payda->mac); -+ ecp22_add_payload(ecp, payda); -+out: -+ LLDPAD_DBG("%s:%s rc:%d\n", __func__, ifname, rc); -+ return rc; -+} -+ -+/* -+ * Payload data from VDP module. -+ * Returns true when data update succeeded. -+ */ -+static int data_from_vdp(char *ifname, struct ecp22_to_ulp *ptr) -+{ -+ struct packed_tlv d; -+ -+ d.size = ptr->len; -+ d.tlv = ptr->data; -+ return ecp22_req2send(ifname, ECP22_VDP, nearest_customer_bridge, &d); -+} -+ -+/* -+ * Handle notifications from other modules. Check if sender-id and data type -+ * indicator match. Return false when data could not be delivered. -+ */ -+static int ecp22_notify(int sender_id, char *ifname, void *data) -+{ -+ struct qbg22_imm *qbg = (struct qbg22_imm *)data; -+ -+ LLDPAD_DBG("%s:%s sender-id:%#x data_type:%d\n", __func__, ifname, -+ sender_id, qbg->data_type); -+ if (sender_id == LLDP_MOD_EVB22 && qbg->data_type == EVB22_TO_ECP22) -+ return ecp22_data_from_evb(ifname, &qbg->u.a); -+ if (sender_id == LLDP_MOD_VDP22 && qbg->data_type == VDP22_TO_ECP22) -+ return data_from_vdp(ifname, &qbg->u.c); -+ return 0; -+} -+ -+static const struct lldp_mod_ops ecp22_ops = { -+ .lldp_mod_register = ecp22_register, -+ .lldp_mod_unregister = ecp22_unregister, -+ .lldp_mod_notify = ecp22_notify -+}; -+ -+/* -+ * ecp22_register - register ecp module to lldpad -+ * -+ * returns lldp_module struct on success, NULL on error -+ * -+ * allocates a module structure with ecp module information and returns it -+ * to lldpad. -+ */ -+struct lldp_module *ecp22_register(void) -+{ -+ struct lldp_module *mod; -+ struct ecp22_user_data *eud; -+ -+ mod = calloc(1, sizeof *mod); -+ if (!mod) { -+ LLDPAD_ERR("%s:can not allocate ecp module data\n", __func__); -+ return NULL; -+ } -+ eud = calloc(1, sizeof(struct ecp22_user_data)); -+ if (!eud) { -+ free(mod); -+ LLDPAD_ERR("%s:can not allocate ecp user data\n", __func__); -+ return NULL; -+ } -+ LIST_INIT(&eud->head); -+ mod->id = LLDP_MOD_ECP22; -+ mod->ops = &ecp22_ops; -+ mod->data = eud; -+ LLDPAD_DBG("%s: done\n", __func__); -+ return mod; -+} -+ -+/* -+ * ecp22_free_data - frees up ecp data chain -+ */ -+static void ecp22_free_data(struct ecp22_user_data *ud) -+{ -+ struct ecp22 *ecp; -+ -+ if (ud) { -+ while (!LIST_EMPTY(&ud->head)) { -+ ecp = LIST_FIRST(&ud->head); -+ ecp22_remove(ecp); -+ } -+ } -+} -+ -+/* -+ * ecp22_unregister - unregister ecp module from lldpad -+ * -+ * no return value -+ * -+ * frees ecp module structure and user data. -+ */ -+void ecp22_unregister(struct lldp_module *mod) -+{ -+ if (mod->data) { -+ ecp22_free_data((struct ecp22_user_data *)mod->data); -+ free(mod->data); -+ } -+ free(mod); -+ LLDPAD_DBG("%s: done\n", __func__); -+} -diff --git a/qbg/lldp_ecp22.c b/qbg/lldp_ecp22.c -deleted file mode 100644 -index 3341cc6..0000000 ---- a/qbg/lldp_ecp22.c -+++ /dev/null -@@ -1,1060 +0,0 @@ --/****************************************************************************** -- -- Implementation of ECP according to 802.1Qbg -- (c) Copyright IBM Corp. 2010, 2012 -- -- Author(s): Jens Osterkamp -- Author(s): Thomas Richter -- -- This program is free software; you can redistribute it and/or modify it -- under the terms and conditions of the GNU General Public License, -- version 2, as published by the Free Software Foundation. -- -- This program is distributed in the hope it will be useful, but WITHOUT -- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -- more details. -- -- You should have received a copy of the GNU General Public License along with -- this program; if not, write to the Free Software Foundation, Inc., -- 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. -- -- The full GNU General Public License is included in this distribution in -- the file called "COPYING". -- --******************************************************************************/ -- --#include --#include --#include --#include -- --#include "eloop.h" --#include "lldp_ecp22.h" --#include "messages.h" --#include "lldp_qbg_utils.h" --#include "lldp/l2_packet.h" --#include "lldp_tlv.h" -- --#define ECP22_MAX_RETRIES_DEFAULT (3) /* Default # of max retries */ --#define ECP22_ACK_TIMER_STOPPED (-1) --/* -- * Defaults to 2ms wait time for acknowledgement packet reception. -- */ --#define ECP22_ACK_TIMER_DEFAULT (8) -- --static void ecp22_tx_run_sm(struct ecp22 *); -- --static const char *const ecp22_rx_states[] = { /* Receive states verbatim */ -- "ECP22_RX_BEGIN", -- "ECP22_RX_WAIT", -- "ECP22_RX_WAIT2", -- "ECP22_RX_FIRST", -- "ECP22_RX_REC_ECPDU", -- "ECP22_RX_NEW_ECPDU", -- "ECP22_RX_SEND_ACK" --}; -- --static const char *const ecp22_tx_states[] = { /* Transmit states verbatim */ -- "ECP22_TX_BEGIN", -- "ECP22_TX_INIT", -- "ECP22_TX_TXMIT_ECPDU", -- "ECP22_TX_WAIT_FORREQ", -- "ECP22_TX_WAIT_ONDATA", -- "ECP22_TX_ERROR" --}; -- --/* -- * Increment sequence number. Do not return zero as sequence number. -- */ --static unsigned short inc_seqno(unsigned short x) --{ -- ++x; -- if (!x) /* Wrapped */ -- ++x; -- return x; --} -- --/* -- * Find the ecp data associated with an interface. -- * Return pointer or NULL if not found. -- */ --static struct ecp22 *find_ecpdata(char *ifname, struct ecp22_user_data *eud) --{ -- struct ecp22 *ecp = 0; -- -- if (eud) { -- LIST_FOREACH(ecp, &eud->head, node) -- if (!strncmp(ifname, ecp->ifname, IFNAMSIZ)) -- break; -- } -- return ecp; --} -- --/* -- * ecp22_txframe - transmit ecp frame -- * @ecp: pointer to currently used ecp data structure -- * -- * returns the number of characters sent on success, -1 on failure -- * -- * sends out the frame stored in the frame structure using l2_packet_send. -- */ --static int ecp22_txframe(struct ecp22 *ecp, char *txt, unsigned char *dst, -- unsigned char *ack, size_t len) --{ -- hexdump_frame(ecp->ifname, txt, ack, len); -- return l2_packet_send(ecp->l2, dst, htons(ETH_P_ECP22), ack, len); --} -- --/* -- * Append some data at the end of the transmit data buffer. Make sure the -- * End TLV always fits into the buffer. -- */ --static unsigned char end_tlv[2] = { 0x0, 0x0 }; /* END TLV */ -- --static void ecp22_append(u8 *buffer, u32 *pos, void *data, u32 len) --{ -- if (*pos + len > ETH_FRAME_LEN - sizeof end_tlv) -- return; -- memcpy(buffer + *pos, data, len); -- *pos += len; --} -- --/* -- * Return a payload node to the freelist. -- */ --void ecp22_putnode(struct ecp22_freelist *list, struct ecp22_payload_node *elm) --{ -- elm->ptlv = free_pkd_tlv(elm->ptlv); -- if (list->freecnt > ecp22_maxpayload) -- free(elm); -- else { -- ++list->freecnt; -- LIST_INSERT_HEAD(&list->head, elm, node); -- } --} -- --/* -- * ecp22_build_ecpdu - create an ecp protocol data unit -- * @ecp: pointer to currently used ecp data structure -- * -- * returns true on success, false on failure -- * -- * creates the frame header with the ports mac address, the ecp header with REQ -- * plus a packed TLVs created taken from the send queue. -- */ --static bool ecp22_build_ecpdu(struct ecp22 *ecp) --{ -- struct l2_ethhdr eth; -- struct ecp22_hdr ecph; -- u32 fb_offset = 0; -- struct packed_tlv *ptlv; -- struct ecp22_payload_node *p = LIST_FIRST(&ecp->inuse.head); -- -- if (!p) -- return false; -- ecp->tx.ecpdu_received = true; /* Txmit buffer in use */ -- memcpy(eth.h_dest, p->mac, ETH_ALEN); -- l2_packet_get_own_src_addr(ecp->l2, eth.h_source); -- eth.h_proto = htons(ETH_P_ECP22); -- memset(ecp->tx.frame, 0, sizeof ecp->tx.frame); -- ecp22_append(ecp->tx.frame, &fb_offset, (void *)ð, sizeof eth); -- -- ecp22_hdr_set_version(&ecph, 1); -- ecp22_hdr_set_op(&ecph, ECP22_REQUEST); -- ecp22_hdr_set_subtype(&ecph, ECP22_VDP); -- ecph.ver_op_sub = htons(ecph.ver_op_sub); -- ecph.seqno = htons(ecp->tx.seqno); -- ecp22_append(ecp->tx.frame, &fb_offset, (void *)&ecph, sizeof ecph); -- -- ptlv = p->ptlv; -- ecp22_append(ecp->tx.frame, &fb_offset, ptlv->tlv, ptlv->size); -- ecp22_append(ecp->tx.frame, &fb_offset, end_tlv, sizeof end_tlv); -- ecp->tx.frame_len = MAX(fb_offset, (unsigned)ETH_ZLEN); -- LIST_REMOVE(p, node); -- ecp22_putnode(&ecp->isfree, p); -- LLDPAD_DBG("%s:%s seqno %#hx frame_len %#hx\n", __func__, -- ecp->ifname, ecp->tx.seqno, ecp->tx.frame_len); -- return true; --} -- --/* -- * Execute transmit state transmitECPDU. -- */ --static void ecp22_es_waitforreq(struct ecp22 *ecp) --{ -- ecp->tx.retries = 0; -- ecp->tx.ack_received = false; -- ecp->tx.ecpdu_received = false; -- ecp->tx.seqno = inc_seqno(ecp->tx.seqno); -- LLDPAD_DBG("%s:%s seqno %#hx\n", __func__, ecp->ifname, ecp->tx.seqno); --} -- --/* -- * Execute transmit state countErrors. -- */ --static void ecp22_es_counterror(struct ecp22 *ecp) --{ -- ++ecp->tx.errors; -- LLDPAD_DBG("%s:%s errors %lu\n", __func__, ecp->ifname, -- ecp->tx.errors); --} -- --/* -- * Execute transmit state initTransmit. -- */ --static void ecp22_es_inittransmit(struct ecp22 *ecp) --{ -- ecp->tx.errors = 0; -- ecp->tx.seqno = 0; --} -- --/* -- * Return RTE value in milliseconds. -- */ --static int rtevalue(unsigned char rte) --{ -- return (1 << rte) * 10; --} -- --/* -- * ecp22_ack_timeout_handler - handles the ack timer expiry -- * @eloop_data: data structure of event loop -- * @user_ctx: user context, vdp_data here -- * -- * no return value -- * -- * called when the ECP timer has expired. Calls the ECP station state machine. -- */ --static void ecp22_ack_timeout_handler(UNUSED void *eloop_data, void *user_ctx) --{ -- struct ecp22 *ecp = (struct ecp22 *)user_ctx; -- -- LLDPAD_DBG("%s:%s retries:%d\n", __func__, -- ecp->ifname, ecp->tx.retries); -- ecp22_tx_run_sm(ecp); --} -- --/* -- * ecp22_tx_start_acktimer - starts the ECP ack timer -- * @ecp: pointer to currently used ecp data structure -- * -- * returns 0 on success, -1 on error -- * -- * starts the ack timer when a frame has been sent out. -- */ --static void ecp22_tx_start_acktimer(struct ecp22 *ecp) --{ -- unsigned long ack_sec = rtevalue(ecp->max_rte) / 1000000; -- unsigned long ack_usec = rtevalue(ecp->max_rte) % 1000000; -- -- LLDPAD_DBG("%s:%s [%ld.%06ld]\n", __func__, ecp->ifname, ack_sec, -- ack_usec); -- eloop_register_timeout(ack_sec, ack_usec, ecp22_ack_timeout_handler, -- 0, (void *)ecp); --} -- --/* -- * ecp22_tx_change_state - changes the ecp tx sm state -- * @ecp: pointer to currently used ecp data structure -- * @newstate: new state for the sm -- * -- * no return value -- * -- * checks state transistion for consistency and finally changes the state of -- * the profile. -- */ --static void ecp22_tx_change_state(struct ecp22 *ecp, unsigned char newstate) --{ -- switch (newstate) { -- case ECP22_TX_BEGIN: -- break; -- case ECP22_TX_INIT: -- assert(ecp->tx.state == ECP22_TX_BEGIN); -- break; -- case ECP22_TX_WAIT_FORREQ: -- assert(ecp->tx.state == ECP22_TX_INIT || -- ecp->tx.state == ECP22_TX_ERROR || -- ecp->tx.state == ECP22_TX_TXMIT_ECPDU); -- break; -- case ECP22_TX_WAIT_ONDATA: -- assert(ecp->tx.state == ECP22_TX_WAIT_FORREQ); -- break; -- case ECP22_TX_TXMIT_ECPDU: -- assert(ecp->tx.state == ECP22_TX_WAIT_ONDATA); -- break; -- case ECP22_TX_ERROR: -- assert(ecp->tx.state == ECP22_TX_TXMIT_ECPDU); -- break; -- default: -- LLDPAD_ERR("%s: ECP TX state machine invalid state %d\n", -- ecp->ifname, newstate); -- } -- LLDPAD_DBG("%s:%s state change %s -> %s\n", __func__, -- ecp->ifname, ecp22_tx_states[ecp->tx.state], -- ecp22_tx_states[newstate]); -- ecp->tx.state = newstate; --} -- --/* -- * Send the payload data. -- */ --static int ecp22_es_txmit(struct ecp22 *ecp) --{ -- int rc = 0; -- -- ++ecp->tx.retries; -- ecp22_txframe(ecp, "ecp-out", ecp->tx.frame, ecp->tx.frame, -- ecp->tx.frame_len); -- ecp22_tx_start_acktimer(ecp); -- return rc; --} -- --/* -- * ecp22_set_tx_state - sets the ecp tx state machine state -- * @ecp: pointer to currently used ecp data structure -- * -- * returns true or false -- * -- * switches the state machine to the next state depending on the input -- * variables. returns true or false depending on wether the state machine -- * can be run again with the new state or can stop at the current state. -- */ --static bool ecp22_set_tx_state(struct ecp22 *ecp) --{ -- struct port *port = port_find_by_name(ecp->ifname); -- -- if (!port) { -- LLDPAD_ERR("%s:%s port not found\n", __func__, ecp->ifname); -- return 0; -- } -- if ((port->portEnabled == false) && (port->prevPortEnabled == true)) { -- LLDPAD_ERR("%s:%s port was disabled\n", __func__, ecp->ifname); -- ecp22_tx_change_state(ecp, ECP22_TX_BEGIN); -- } -- port->prevPortEnabled = port->portEnabled; -- -- switch (ecp->tx.state) { -- case ECP22_TX_BEGIN: -- ecp22_tx_change_state(ecp, ECP22_TX_INIT); -- return true; -- case ECP22_TX_INIT: -- ecp22_tx_change_state(ecp, ECP22_TX_WAIT_FORREQ); -- return true; -- case ECP22_TX_WAIT_FORREQ: -- ecp22_tx_change_state(ecp, ECP22_TX_WAIT_ONDATA); -- return true; -- case ECP22_TX_WAIT_ONDATA: -- if (LIST_FIRST(&ecp->inuse.head)) { /* Data to send */ -- ecp22_build_ecpdu(ecp); -- ecp22_tx_change_state(ecp, ECP22_TX_TXMIT_ECPDU); -- return true; -- } -- return false; -- case ECP22_TX_TXMIT_ECPDU: -- if (ecp->tx.ack_received) { -- ecp22_tx_change_state(ecp, ECP22_TX_WAIT_FORREQ); -- return true; -- } -- if (ecp->tx.retries > ecp->max_retries) { -- ecp22_tx_change_state(ecp, ECP22_TX_ERROR); -- return true; -- } -- return false; -- case ECP22_TX_ERROR: -- ecp22_tx_change_state(ecp, ECP22_TX_WAIT_FORREQ); -- return true; -- default: -- LLDPAD_ERR("%s: ECP TX state machine in invalid state %d\n", -- ecp->ifname, ecp->tx.state); -- return false; -- } --} -- --/* -- * ecp22_tx_run_sm - state machine for ecp transmit -- * @ecp: pointer to currently used ecp data structure -- * -- * no return value -- */ --static void ecp22_tx_run_sm(struct ecp22 *ecp) --{ -- ecp22_set_tx_state(ecp); -- do { -- LLDPAD_DBG("%s:%s state %s\n", __func__, -- ecp->ifname, ecp22_tx_states[ecp->tx.state]); -- -- switch (ecp->tx.state) { -- case ECP22_TX_BEGIN: -- break; -- case ECP22_TX_INIT: -- ecp22_es_inittransmit(ecp); -- break; -- case ECP22_TX_WAIT_FORREQ: -- ecp22_es_waitforreq(ecp); -- break; -- case ECP22_TX_WAIT_ONDATA: -- break; -- case ECP22_TX_TXMIT_ECPDU: -- ecp22_es_txmit(ecp); -- break; -- case ECP22_TX_ERROR: -- ecp22_es_counterror(ecp); -- break; -- } -- } while (ecp22_set_tx_state(ecp) == true); --} -- --/* -- * ecp22_rx_change_state - changes the ecp rx sm state -- * @ecp: pointer to currently used ecp data structure -- * @newstate: new state for the sm -- * -- * no return value -- * -- * checks state transistion for consistency and finally changes the state of -- * the ecp receive buffer. -- */ --static void ecp22_rx_change_state(struct ecp22 *ecp, u8 newstate) --{ -- switch (newstate) { -- case ECP22_RX_BEGIN: -- break; -- case ECP22_RX_WAIT: -- assert(ecp->rx.state == ECP22_RX_BEGIN); -- break; -- case ECP22_RX_FIRST: -- assert(ecp->rx.state == ECP22_RX_WAIT); -- break; -- case ECP22_RX_REC_ECPDU: -- assert((ecp->rx.state == ECP22_RX_FIRST) || -- (ecp->rx.state == ECP22_RX_WAIT2)); -- break; -- case ECP22_RX_NEW_ECPDU: -- assert(ecp->rx.state == ECP22_RX_REC_ECPDU); -- break; -- case ECP22_RX_SEND_ACK: -- assert((ecp->rx.state == ECP22_RX_REC_ECPDU) || -- (ecp->rx.state == ECP22_RX_NEW_ECPDU)); -- break; -- case ECP22_RX_WAIT2: -- assert(ecp->rx.state == ECP22_RX_SEND_ACK); -- break; -- default: -- LLDPAD_ERR("%s:%s LLDP RX state machine invalid state %d\n", -- __func__, ecp->ifname, newstate); -- } -- LLDPAD_DBG("%s:%s state change %s -> %s\n", __func__, -- ecp->ifname, ecp22_rx_states[ecp->rx.state], -- ecp22_rx_states[newstate]); -- ecp->rx.state = newstate; --} -- --/* -- * Execute action in state sendack. Construct and send an acknowledgement -- * for the received ECP packet. -- */ --static void ecp22_es_send_ack(struct ecp22 *ecp) --{ -- unsigned char ack_frame[ETH_HLEN + sizeof(struct ecp22_hdr)]; -- struct ethhdr *ethdst = (struct ethhdr *)ack_frame; -- struct ecp22_hdr *ecpdst = (struct ecp22_hdr *)&ack_frame[ETH_HLEN]; -- struct ethhdr *ethsrc = (struct ethhdr *)ecp->rx.frame; -- struct ecp22_hdr *ecpsrc = (struct ecp22_hdr *)&ecp->rx.frame[ETH_HLEN]; -- struct ecp22_hdr ack; -- -- LLDPAD_DBG("%s:%s state %s seqno %#hx\n", __func__, ecp->ifname, -- ecp22_rx_states[ecp->rx.state], ecp->rx.seqno); -- memcpy(ethdst->h_dest, nearest_customer_bridge, ETH_ALEN); -- l2_packet_get_own_src_addr(ecp->l2, (u8 *)ðdst->h_source); -- ethdst->h_proto = ethsrc->h_proto; -- /* Set ECP header */ -- ack.ver_op_sub = ntohs(ecpsrc->ver_op_sub); -- ecp22_hdr_set_op(&ack, ECP22_ACK); -- ecpdst->ver_op_sub = htons(ack.ver_op_sub); -- ecpdst->seqno = htons(ecp->rx.seqno); -- ecp22_txframe(ecp, "ecp-ack", ethsrc->h_source, ack_frame, -- sizeof ack_frame); --} -- -- --/* -- * Notify upper layer protocol function of ECP payload data just received. -- */ --static void ecp22_to_ulp(unsigned short ulp, struct ecp22 *ecp) --{ -- size_t offset = ETH_HLEN + sizeof(struct ecp22_hdr); -- struct qbg22_imm to_ulp; -- -- to_ulp.data_type = ECP22_TO_ULP; -- to_ulp.u.c.len = ecp->rx.frame_len - offset; -- to_ulp.u.c.data = &ecp->rx.frame[offset]; -- if (ulp == ECP22_VDP) -- modules_notify(LLDP_MOD_VDP22, LLDP_MOD_ECP22, ecp->ifname, -- &to_ulp); -- else -- LLDPAD_INFO("%s:%s ECP subtype %d not yet implemented\n", -- __func__, ecp->ifname, ulp); --} -- --/* -- * Execute action in state newECPDU. -- * Notify upper layer protocol of new data. -- */ --static void ecp22_es_new_ecpdu(struct ecp22 *ecp) --{ -- struct ecp22_hdr *hdr = (struct ecp22_hdr *)&ecp->rx.frame[ETH_HLEN]; -- struct ecp22_hdr ecphdr; -- unsigned short ulp; -- -- ecphdr.ver_op_sub = ntohs(hdr->ver_op_sub); -- ulp = ecp22_hdr_read_subtype(&ecphdr); -- LLDPAD_DBG("%s:%s state %s notify ULP %d seqno %#hx\n", __func__, -- ecp->ifname, ecp22_rx_states[ecp->rx.state], -- ulp, ecp->rx.seqno); -- ecp->rx.last_seqno = ecp->rx.seqno; -- ecp22_to_ulp(ulp, ecp); --} -- --/* -- * Execute action in state receiveECPDU. -- */ --static void ecp22_es_rec_ecpdu(struct ecp22 *ecp) --{ -- struct ecp22_hdr *hdr = (struct ecp22_hdr *)&ecp->rx.frame[ETH_HLEN]; -- -- ecp->rx.seqno = ntohs(hdr->seqno); -- LLDPAD_DBG("%s:%s state %s seqno %#hx\n", __func__, ecp->ifname, -- ecp22_rx_states[ecp->rx.state], ecp->rx.seqno); --} -- --/* -- * Execute action in state receiveFirst. -- */ --static void ecp22_es_first(struct ecp22 *ecp) --{ -- struct ecp22_hdr *hdr = (struct ecp22_hdr *)&ecp->rx.frame[ETH_HLEN]; -- -- LLDPAD_DBG("%s:%s state %s\n", __func__, ecp->ifname, -- ecp22_rx_states[ecp->rx.state]); -- ecp->rx.last_seqno = ntohs(hdr->seqno) - 1; --} -- --/* -- * Execute action in state receiveWait. -- */ --static void ecp22_es_wait(struct ecp22 *ecp) --{ -- LLDPAD_DBG("%s:%s state %s\n", __func__, ecp->ifname, -- ecp22_rx_states[ecp->rx.state]); -- ecp->rx.ecpdu_received = false; --} -- --/* -- * ecp22_set_rx_state - sets the ecp receive state machine state -- * @ecp: pointer to currently used ecp data structure -- * -- * returns true or false -- * -- * switches the state machine to the next state depending on the input -- * variables. Returns true or false depending on wether the state machine -- * can be run again with the new state or can stop at the current state. -- */ --static bool ecp22_set_rx_state(struct ecp22 *ecp) --{ -- struct port *port = port_find_by_name(ecp->ifname); -- -- if (!port) -- return false; -- -- LLDPAD_DBG("%s:%s state %s\n", __func__, ecp->ifname, -- ecp22_rx_states[ecp->rx.state]); -- if (port->portEnabled == false) -- ecp22_rx_change_state(ecp, ECP22_RX_BEGIN); -- switch (ecp->rx.state) { -- case ECP22_RX_BEGIN: -- ecp22_rx_change_state(ecp, ECP22_RX_WAIT); -- return false; -- case ECP22_RX_WAIT: -- if (ecp->rx.ecpdu_received) { -- ecp22_rx_change_state(ecp, ECP22_RX_FIRST); -- return true; -- } -- return false; -- case ECP22_RX_WAIT2: -- if (ecp->rx.ecpdu_received) { -- ecp22_rx_change_state(ecp, ECP22_RX_REC_ECPDU); -- return true; -- } -- return false; -- case ECP22_RX_FIRST: -- ecp22_rx_change_state(ecp, ECP22_RX_REC_ECPDU); -- return true; -- case ECP22_RX_REC_ECPDU: -- if (ecp->rx.seqno == ecp->rx.last_seqno) -- ecp22_rx_change_state(ecp, ECP22_RX_SEND_ACK); -- else -- ecp22_rx_change_state(ecp, ECP22_RX_NEW_ECPDU); -- return true; -- case ECP22_RX_NEW_ECPDU: -- ecp22_rx_change_state(ecp, ECP22_RX_SEND_ACK); -- return true; -- case ECP22_RX_SEND_ACK: -- ecp22_rx_change_state(ecp, ECP22_RX_WAIT2); -- return true; -- default: -- LLDPAD_DBG("%s:%s ECP RX state machine in invalid state %d\n", -- __func__, ecp->ifname, ecp->rx.state); -- return false; -- } --} -- --/* -- * ecp22_rx_run_sm - state machine for ecp receive protocol -- * @ecp: pointer to currently used ecp data structure -- * -- * no return value -- * -- * runs the state machine for ecp22 receive function. -- */ --static void ecp22_rx_run_sm(struct ecp22 *ecp) --{ -- ecp22_set_rx_state(ecp); -- do { -- switch (ecp->rx.state) { -- case ECP22_RX_WAIT: -- case ECP22_RX_WAIT2: -- ecp22_es_wait(ecp); -- break; -- case ECP22_RX_FIRST: -- ecp22_es_first(ecp); -- break; -- case ECP22_RX_REC_ECPDU: -- ecp22_es_rec_ecpdu(ecp); -- break; -- case ECP22_RX_NEW_ECPDU: -- ecp22_es_new_ecpdu(ecp); -- break; -- case ECP22_RX_SEND_ACK: -- ecp22_es_send_ack(ecp); -- break; -- default: -- LLDPAD_DBG("%s:%s ECP RX state machine in invalid " -- "state %d\n", __func__, ecp->ifname, -- ecp->rx.state); -- } -- } while (ecp22_set_rx_state(ecp) == true); --} -- --/* -- * Received an aknowledgement frame. -- * Check if we have a transmit pending and the ack'ed packet number matches -- * the send packet. -- */ --static void ecp22_recack_frame(struct ecp22 *ecp, unsigned short seqno) --{ -- LLDPAD_DBG("%s:%s txmit:%d seqno %#hx ack-seqno %#hx\n", __func__, -- ecp->ifname, ecp->tx.ecpdu_received, ecp->tx.seqno, seqno); -- if (ecp->tx.ecpdu_received) { -- if (ecp->tx.seqno == seqno) -- ecp->tx.ack_received = true; -- } --} -- --/* -- * ecp22_rx_receiveframe - receive am ecp frame -- * @ctx: rx callback context, struct ecp * in this case -- * @ifindex: index of interface -- * @buf: buffer which contains the frame just received -- * @len: size of buffer (frame) -- * -- * no return value -- * -- * creates a local copy of the buffer and checks the header. keeps some -- * statistics about ecp frames. Checks if it is a request or an ack frame and -- * branches to ecp rx or ecp tx state machine. -- */ --static void ecp22_rx_receiveframe(void *ctx, int ifindex, const u8 *buf, -- size_t len) --{ -- struct ecp22 *ecp = (struct ecp22 *)ctx; -- struct port *port; -- struct ecp22_hdr *ecp_hdr, ecphdr; -- -- LLDPAD_DBG("%s:%s ifindex:%d len:%zd state:%s ecpdu_received:%d\n", -- __func__, ecp->ifname, ifindex, len, -- ecp22_rx_states[ecp->rx.state], ecp->rx.ecpdu_received); -- hexdump_frame(ecp->ifname, "frame-in", buf, len); -- port = port_find_by_name(ecp->ifname); -- if (!port || ecp->rx.ecpdu_received) -- /* Port not found or buffer not free */ -- return; -- -- memcpy(ecp->rx.frame, buf, len); -- ecp->rx.frame_len = len; -- ecp->stats.statsFramesInTotal++; -- -- ecp_hdr = (struct ecp22_hdr *)&ecp->rx.frame[ETH_HLEN]; -- ecphdr.ver_op_sub = ntohs(ecp_hdr->ver_op_sub); -- -- /* Check for correct subtype and version number */ -- if (ecp22_hdr_read_version(&ecphdr) != 1) { -- LLDPAD_ERR("%s:%s ERROR unknown version %#02hx seqno %#hx\n", -- __func__, ecp->ifname, ecphdr.ver_op_sub, -- ntohs(ecp_hdr->seqno)); -- return; -- } -- switch (ecp22_hdr_read_subtype(&ecphdr)) { -- default: -- LLDPAD_ERR("%s:%s ERROR unknown subtype %#02hx seqno %#hx\n", -- __func__, ecp->ifname, ecphdr.ver_op_sub, -- ntohs(ecp_hdr->seqno)); -- return; -- case ECP22_PECSP: -- case ECP22_VDP: -- /* Subtype ok, fall through intended */ -- break; -- } -- -- switch (ecp22_hdr_read_op(&ecphdr)) { -- case ECP22_REQUEST: -- LLDPAD_DBG("%s:%s received REQ frame seqno %#hx\n", __func__, -- ecp->ifname, ntohs(ecp_hdr->seqno)); -- ecp->rx.ecpdu_received = true; -- ecp22_rx_run_sm(ecp); -- break; -- case ECP22_ACK: -- LLDPAD_DBG("%s:%s received ACK frame seqno %#hx\n", __func__, -- ecp->ifname, ntohs(ecp_hdr->seqno)); -- ecp22_recack_frame(ecp, ntohs(ecp_hdr->seqno)); -- break; -- default: -- LLDPAD_ERR("%s:%s ERROR unknown mode %#02hx seqno %#hx\n", -- __func__, ecp->ifname, ecphdr.ver_op_sub, -- ntohs(ecp_hdr->seqno)); -- } --} -- --/* -- * ecp22_create - create data structure and initialize ecp protocol -- * @ifname: interface for which the ecp protocol is initialized -- * -- * returns NULL on error and an pointer to the ecp22 structure on success. -- * -- * finds the port to the interface name, sets up the receive handle for -- * incoming ecp frames and initializes the ecp rx and tx state machines. -- * To be called when a successful exchange of EVB TLVs has been -- * made and ECP protocols are supported by both sides. -- */ --static struct ecp22 *ecp22_create(char *ifname, struct ecp22_user_data *eud) --{ -- struct ecp22 *ecp; -- -- ecp = calloc(1, sizeof *ecp); -- if (!ecp) { -- LLDPAD_ERR("%s:%s unable to allocate ecp protocol\n", __func__, -- ifname); -- return NULL; -- } -- strncpy(ecp->ifname, ifname, sizeof ecp->ifname); -- ecp->l2 = l2_packet_init(ecp->ifname, 0, ETH_P_ECP22, -- ecp22_rx_receiveframe, ecp, 1); -- -- if (!ecp->l2) { -- LLDPAD_ERR("%s:%s error open layer 2 ETH_P_ECP\n", __func__, -- ifname); -- free(ecp); -- return NULL; -- } -- LIST_INSERT_HEAD(&eud->head, ecp, node); -- LLDPAD_DBG("%s:%s create ecp data\n", __func__, ifname); -- return ecp; --} -- --/* -- * ecp22_start - build up ecp structures for an interface -- * @ifname: name of the interface -- */ --void ecp22_start(char *ifname) --{ -- struct ecp22_user_data *eud; -- struct ecp22 *ecp; -- -- LLDPAD_DBG("%s:%s start ecp\n", __func__, ifname); -- eud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_ECP22); -- if (!eud) { -- LLDPAD_DBG("%s:%s no ECP module\n", __func__, ifname); -- return; -- } -- ecp = find_ecpdata(ifname, eud); -- if (!ecp) -- ecp = ecp22_create(ifname, eud); -- ecp->max_retries = ECP22_MAX_RETRIES_DEFAULT; -- ecp->max_rte = ECP22_ACK_TIMER_DEFAULT; -- LIST_INIT(&ecp->inuse.head); -- ecp->inuse.last = 0; -- LIST_INIT(&ecp->isfree.head); -- ecp->isfree.freecnt = 0; -- ecp->rx.state = ECP22_RX_BEGIN; -- ecp22_rx_run_sm(ecp); -- ecp->tx.state = ECP22_TX_BEGIN; -- ecp22_tx_run_sm(ecp); --} -- --/* -- * Remove the ecp_payload nodes -- */ --static void ecp22_removelist(ecp22_list *ptr) --{ -- struct ecp22_payload_node *np; -- -- while ((np = LIST_FIRST(ptr))) { -- LIST_REMOVE(np, node); -- np->ptlv = free_pkd_tlv(np->ptlv); -- free(np); -- } --} -- --static void ecp22_remove(struct ecp22 *ecp) --{ -- LLDPAD_DBG("%s:%s remove ecp\n", __func__, ecp->ifname); -- ecp22_removelist(&ecp->inuse.head); -- ecp->inuse.last = 0; -- ecp22_removelist(&ecp->isfree.head); -- ecp->isfree.freecnt = 0; -- LIST_REMOVE(ecp, node); -- free(ecp); --} -- --/* -- * ecp22_stop - tear down ecp structures for a interface -- * @ifname: name of the interface -- * -- * no return value -- * -- */ --void ecp22_stop(char *ifname) --{ -- struct ecp22_user_data *eud; -- struct ecp22 *ecp; -- -- LLDPAD_DBG("%s:%s stop ecp\n", __func__, ifname); -- eud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_ECP22); -- ecp = find_ecpdata(ifname, eud); -- if (ecp) -- ecp22_remove(ecp); --} -- --/* -- * Update data exchanged via EVB protocol. -- * Returns true when data update succeeded. -- */ --static int data_from_evb(char *ifname, struct evb22_to_ecp22 *ptr) --{ -- struct ecp22_user_data *eud; -- struct ecp22 *ecp; -- -- eud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_ECP22); -- ecp = find_ecpdata(ifname, eud); -- if (ecp) { -- ecp->max_rte = ptr->max_rte; -- ecp->max_retries = ptr->max_retry; -- return 0; -- } -- return -ENOENT; --} -- --/* -- * Add ecp payload data at the end of the queue. -- */ --static void ecp22_add_payload(struct ecp22 *ecp, -- struct ecp22_payload_node *elem) --{ -- if (LIST_EMPTY(&ecp->inuse.head)) -- LIST_INSERT_HEAD(&ecp->inuse.head, elem, node); -- else -- LIST_INSERT_AFTER(ecp->inuse.last, elem, node); -- ecp->inuse.last = elem; -- if (!ecp->tx.ecpdu_received) /* Transmit buffer free */ -- ecp22_tx_run_sm(ecp); --} -- --/* -- * Copy the payload data. -- */ --static struct packed_tlv *copy_ptlv(struct packed_tlv *from) --{ -- struct packed_tlv *ptlv = create_ptlv(); -- -- if (!ptlv) -- return NULL; -- ptlv->size = from->size; -- ptlv->tlv = calloc(ptlv->size, sizeof(unsigned char)); -- if (!ptlv->tlv) { -- free_pkd_tlv(ptlv); -- return NULL; -- } -- memcpy(ptlv->tlv, from->tlv, from->size); -- return ptlv; --} -- --/* -- * Create a node for the ecp payload data. Get it from the free list if not -- * empty. Otherwise allocate from heap. -- */ --static struct ecp22_payload_node *ecp22_getnode(struct ecp22_freelist *list) --{ -- struct ecp22_payload_node *elem = LIST_FIRST(&list->head); -- -- if (!elem) -- elem = calloc(1, sizeof *elem); -- else { -- LIST_REMOVE(elem, node); -- --list->freecnt; -- } -- return elem; --} -- --/* -- * Receive upper layer protocol data unit for transmit. -- * Returns error if the request could not be queued for transmision. -- */ --static int ecp22_req2send(char *ifname, unsigned short subtype, -- unsigned const char *mac, struct packed_tlv *du) --{ -- struct ecp22_user_data *eud; -- struct ecp22 *ecp; -- struct ecp22_payload_node *payda; -- struct packed_tlv *ptlv = copy_ptlv(du); -- int rc = 0; -- -- LLDPAD_DBG("%s:%s subtype:%d\n", __func__, ifname, subtype); -- -- eud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_ECP22); -- ecp = find_ecpdata(ifname, eud); -- if (!ecp) { -- rc = -ENODEV; -- goto out; -- } -- if (!ptlv) { -- rc = -ENOMEM; -- goto out; -- } -- if (ptlv->size >= ECP22_MAXPAYLOAD_LEN) { -- rc = -E2BIG; -- goto out; -- } -- payda = ecp22_getnode(&ecp->isfree); -- if (!payda) { -- free_pkd_tlv(ptlv); -- rc = -ENOMEM; -- goto out; -- } -- payda->ptlv = ptlv; -- payda->subtype = subtype; -- memcpy(payda->mac, mac, sizeof payda->mac); -- ecp22_add_payload(ecp, payda); --out: -- LLDPAD_DBG("%s:%s rc:%d\n", __func__, ifname, rc); -- return rc; --} -- --/* -- * Payload data from VDP module. -- * Returns true when data update succeeded. -- */ --static int data_from_vdp(char *ifname, struct ecp22_to_ulp *ptr) --{ -- struct packed_tlv d; -- -- d.size = ptr->len; -- d.tlv = ptr->data; -- return ecp22_req2send(ifname, ECP22_VDP, nearest_customer_bridge, &d); --} -- --/* -- * Handle notifications from other modules. Check if sender-id and data type -- * indicator match. Return false when data could not be delivered. -- */ --static int ecp22_notify(int sender_id, char *ifname, void *data) --{ -- struct qbg22_imm *qbg = (struct qbg22_imm *)data; -- -- LLDPAD_DBG("%s:%s sender-id:%#x data_type:%d\n", __func__, ifname, -- sender_id, qbg->data_type); -- if (sender_id == LLDP_MOD_EVB22 && qbg->data_type == EVB22_TO_ECP22) -- return data_from_evb(ifname, &qbg->u.a); -- if (sender_id == LLDP_MOD_VDP22 && qbg->data_type == VDP22_TO_ECP22) -- return data_from_vdp(ifname, &qbg->u.c); -- return 0; --} -- --static const struct lldp_mod_ops ecp22_ops = { -- .lldp_mod_register = ecp22_register, -- .lldp_mod_unregister = ecp22_unregister, -- .lldp_mod_notify = ecp22_notify --}; -- --/* -- * ecp22_register - register ecp module to lldpad -- * -- * returns lldp_module struct on success, NULL on error -- * -- * allocates a module structure with ecp module information and returns it -- * to lldpad. -- */ --struct lldp_module *ecp22_register(void) --{ -- struct lldp_module *mod; -- struct ecp22_user_data *eud; -- -- mod = calloc(1, sizeof *mod); -- if (!mod) { -- LLDPAD_ERR("%s:can not allocate ecp module data\n", __func__); -- return NULL; -- } -- eud = calloc(1, sizeof(struct ecp22_user_data)); -- if (!eud) { -- free(mod); -- LLDPAD_ERR("%s:can not allocate ecp user data\n", __func__); -- return NULL; -- } -- LIST_INIT(&eud->head); -- mod->id = LLDP_MOD_ECP22; -- mod->ops = &ecp22_ops; -- mod->data = eud; -- LLDPAD_DBG("%s: done\n", __func__); -- return mod; --} -- --/* -- * ecp22_free_data - frees up ecp data chain -- */ --static void ecp22_free_data(struct ecp22_user_data *ud) --{ -- struct ecp22 *ecp; -- -- if (ud) { -- while (!LIST_EMPTY(&ud->head)) { -- ecp = LIST_FIRST(&ud->head); -- ecp22_remove(ecp); -- } -- } --} -- --/* -- * ecp22_unregister - unregister ecp module from lldpad -- * -- * no return value -- * -- * frees ecp module structure and user data. -- */ --void ecp22_unregister(struct lldp_module *mod) --{ -- if (mod->data) { -- ecp22_free_data((struct ecp22_user_data *)mod->data); -- free(mod->data); -- } -- free(mod); -- LLDPAD_DBG("%s: done\n", __func__); --} -diff --git a/qbg/lldp_evb22.c b/qbg/lldp_evb22.c -deleted file mode 100644 -index f9eeace..0000000 ---- a/qbg/lldp_evb22.c -+++ /dev/null -@@ -1,556 +0,0 @@ --/****************************************************************************** -- -- Implementation of EVB TLVs for LLDP -- (c) Copyright IBM Corp. 2012 -- -- Author(s): Thomas Richter -- -- This program is free software; you can redistribute it and/or modify it -- under the terms and conditions of the GNU General Public License, -- version 2, as published by the Free Software Foundation. -- -- This program is distributed in the hope it will be useful, but WITHOUT -- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -- more details. -- -- You should have received a copy of the GNU General Public License along with -- this program; if not, write to the Free Software Foundation, Inc., -- 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. -- -- The full GNU General Public License is included in this distribution in -- the file called "COPYING". -- --******************************************************************************/ -- --#define _GNU_SOURCE --#include --#include -- --#include "lldp.h" --#include "lldp_tlv.h" --#include "lldp_evb22.h" --#include "lldp_ecp22.h" --#include "lldp_vdp22.h" --#include "lldp_qbg_utils.h" --#include "lldp_evb_cmds.h" --#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); -- if (ud) { -- LIST_FOREACH(ed, &ud->head, entry) { -- if (!strncmp(ifname, ed->ifname, IFNAMSIZ) && -- (type == ed->agenttype)) -- break; -- } -- } -- return ed; --} -- --static void evb22_format_tlv(char *buf, size_t len, struct evb22_tlv *tlv) --{ -- int comma = 0; -- char bridge_txt[32], station_txt[32]; -- -- memset(bridge_txt, 0, sizeof bridge_txt); -- if (evb_ex_bgid(tlv->bridge_s)) { -- strcat(bridge_txt, "bgid"); -- comma = 1; -- } -- if (evb_ex_rrcap(tlv->bridge_s)) { -- if (comma) -- strcat(bridge_txt, ","); -- strcat(bridge_txt, "rrcap"); -- comma = 1; -- } -- if (evb_ex_rrctr(tlv->bridge_s)) { -- if (comma) -- strcat(bridge_txt, ","); -- strcat(bridge_txt, "rrctr"); -- } -- -- comma = 0; -- memset(station_txt, 0, sizeof station_txt); -- if (evb_ex_sgid(tlv->station_s)) { -- strcat(station_txt, "sgid"); -- comma = 1; -- } -- if (evb_ex_rrreq(tlv->station_s)) { -- if (comma) -- strcat(station_txt, ","); -- strcat(station_txt, "rrreq"); -- comma = 1; -- } -- if (evb_ex_rrstat(tlv->station_s)) { -- if (comma) -- strcat(station_txt, ","); -- strcat(station_txt, "rrstat"); -- } -- snprintf(buf, len, "bridge:%s(%#02x) station:%s(%#02x) " -- "retries:%d rte:%d mode:%d r/l:%d rwd:%d " -- "r/l:%d rka:%d", bridge_txt, tlv->bridge_s, -- station_txt, tlv->station_s, -- evb_ex_retries(tlv->r_rte), evb_ex_rte(tlv->r_rte), -- evb_ex_evbmode(tlv->evb_mode), evb_ex_rol(tlv->evb_mode), -- evb_ex_rwd(tlv->evb_mode), -- evb_ex_rol(tlv->rl_rka), evb_ex_rka(tlv->rl_rka)); --} -- --static void evb22_print_tlvinfo(char *ifname, struct evb22_tlv *tlv) --{ -- char buf[256]; -- -- evb22_format_tlv(buf, sizeof buf, tlv); -- LLDPAD_DBG("%s evb %s\n", ifname, buf); --} -- --static void evb22_dump_tlv(char *ifname, struct unpacked_tlv *tlv) --{ -- int i, left = 0; -- char buffer[256]; -- -- for (i = 0; i < tlv->length; i++) { -- int c; -- -- c = snprintf(buffer + left, -- sizeof buffer - left, -- "%02x ", tlv->info[i]); -- -- if (c < 0 || (c >= (int)sizeof buffer - left)) -- break; -- else -- left += c; -- } -- -- LLDPAD_DBG("%s:%s type %i length %i info %s\n", -- __func__, ifname, tlv->type, tlv->length, buffer); --} -- --static void common_tlv(struct evb22_data *ed) --{ -- struct evb22_tlv *recv = &ed->last; -- struct evb22_tlv *mine = &ed->policy; -- u8 val; -- -- /* Set retries and rte value */ -- val = evb_ex_retries(recv->r_rte); -- if (evb_ex_retries(mine->r_rte) > val) -- val = evb_ex_retries(mine->r_rte); -- ed->out.r_rte = evb_set_retries(val); -- val = evb_ex_rte(recv->r_rte); -- if (evb_ex_rte(mine->r_rte) > val) -- val = evb_ex_rte(mine->r_rte); -- ed->out.r_rte |= evb_set_rte(val); -- -- /* Set evbmode */ -- ed->out.evb_mode = evb_set_evbmode(evb_ex_evbmode(mine->evb_mode)); -- val = evb_ex_rwd(recv->evb_mode); -- if (evb_ex_rwd(mine->evb_mode) > val) -- val = evb_ex_rwd(mine->evb_mode); -- else -- ed->out.evb_mode |= evb_set_rol(1); -- ed->out.evb_mode |= evb_set_rwd(val); -- -- /* Set rka */ -- ed->out.rl_rka = 0; -- val = evb_ex_rka(recv->rl_rka); -- if (evb_ex_rka(mine->rl_rka) > val) -- val = evb_ex_rka(mine->rl_rka); -- else -- ed->out.rl_rka = evb_set_rol(1); -- ed->out.rl_rka |= evb_set_rka(val); --} -- --/* -- * Fill the EVB DU for LLDP transmition. Sender is bridge. -- */ --static void bridge_tlv(struct evb22_data *ed) --{ -- struct evb22_tlv *recv = &ed->last; -- struct evb22_tlv *mine = &ed->policy; -- -- /* Copy my last station status */ -- ed->out.station_s = recv->station_s; -- -- /* Set bridge status */ -- ed->out.bridge_s = mine->bridge_s; -- if (evb_ex_rrreq(recv->station_s) && evb_ex_rrcap(mine->bridge_s)) -- ed->out.bridge_s |= evb_set_rrctr(1); -- common_tlv(ed); --} -- --/* -- * Fill the EVB DU for LLDP transmition. Sender is station. -- */ --static void station_tlv(struct evb22_data *ed) --{ -- struct evb22_tlv *recv = &ed->last; -- struct evb22_tlv *mine = &ed->policy; -- u8 val; -- -- /* Copy my last bridge status */ -- ed->out.bridge_s = recv->bridge_s; -- -- /* -- * Set station status, 2nd byte of OUI is 0x80. If 0x00 -- * nothing received from bridge. -- */ -- if (recv->oui[1] == 0) -- val = EVB_RRSTAT_DONT; -- else if (evb_ex_rrctr(recv->bridge_s)) -- val = EVB_RRSTAT_YES; -- else -- val = EVB_RRSTAT_NO; -- ed->out.station_s = evb_maskoff_rrstat(mine->station_s) -- | evb_set_rrstat(val); -- common_tlv(ed); --} -- --/* -- * Checks values received in TLV and takes over some values. -- * Sets the new suggestion in member tie to be send out to switch. -- * -- * Also notify depending modules about the new values. -- */ --static void evb22_update_tlv(struct evb22_data *ed) --{ -- struct qbg22_imm qbg; -- -- if (evb_ex_evbmode(ed->policy.evb_mode) == EVB_STATION) -- station_tlv(ed); -- else -- bridge_tlv(ed); -- -- qbg.data_type = EVB22_TO_ECP22; -- qbg.u.a.max_rte = evb_ex_rte(ed->out.r_rte); -- qbg.u.a.max_retry = evb_ex_retries(ed->out.r_rte); -- modules_notify(LLDP_MOD_ECP22, LLDP_MOD_EVB22, ed->ifname, &qbg); -- -- qbg.data_type = EVB22_TO_VDP22; -- qbg.u.b.max_rka = evb_ex_rka(ed->out.rl_rka); -- qbg.u.b.max_rwd = evb_ex_rwd(ed->out.evb_mode); -- /* Support group identifiers when advertised by both sides */ -- qbg.u.b.gpid = evb_ex_bgid(ed->out.bridge_s) -- && evb_ex_sgid(ed->out.station_s); -- modules_notify(LLDP_MOD_VDP22, LLDP_MOD_EVB22, ed->ifname, &qbg); --} -- --/* -- * Build the packed EVB TLV. -- * Returns a pointer to the packed tlv or 0 on failure. -- */ --static struct packed_tlv *evb22_build_tlv(struct evb22_data *ed) --{ -- struct packed_tlv *ptlv = 0; -- u8 infobuf[sizeof(struct evb22_tlv)]; -- struct unpacked_tlv tlv = { -- .type = ORG_SPECIFIC_TLV, -- .length = sizeof(struct evb22_tlv), -- .info = infobuf -- }; -- -- evb22_update_tlv(ed); -- memcpy(tlv.info, &ed->out, tlv.length); -- ptlv = pack_tlv(&tlv); -- if (ptlv) { -- LLDPAD_DBG("%s:%s TLV about to be sent out:\n", __func__, -- ed->ifname); -- evb22_dump_tlv(ed->ifname, &tlv); -- } else -- LLDPAD_DBG("%s:%s failed to pack EVB TLV\n", __func__, -- ed->ifname); -- return ptlv; --} -- --/* -- * Function call to build and return module specific packed EVB TLV. -- * Returned packed_tlv is free'ed by caller of this function. -- */ --static struct packed_tlv *evb22_gettlv(struct port *port, -- struct lldp_agent *agent) --{ -- struct evb22_data *ed; -- -- if (agent->type != NEAREST_CUSTOMER_BRIDGE) -- return 0; -- ed = evb22_data(port->ifname, agent->type); -- if (!ed) { -- LLDPAD_ERR("%s:%s agent %d failed\n", __func__, port->ifname, -- agent->type); -- return 0; -- } -- return (ed->txmit) ? evb22_build_tlv(ed) : 0; --} -- --/* -- * evb_rchange: process received EVB TLV LLDPDU -- * -- * TLV not consumed on error -- */ --static int evb22_rchange(struct port *port, struct lldp_agent *agent, -- struct unpacked_tlv *tlv) --{ -- struct evb22_data *ed; -- u8 oui_subtype[OUI_SUB_SIZE] = LLDP_MOD_EVB22_OUI; -- -- if (agent->type != NEAREST_CUSTOMER_BRIDGE) -- return 0; -- ed = evb22_data(port->ifname, agent->type); -- -- if (!ed) -- return SUBTYPE_INVALID; -- -- if (tlv->type == TYPE_127) { -- /* check for length */ -- if (tlv->length < OUI_SUB_SIZE) -- return TLV_ERR; -- -- /* check for oui */ -- if (memcmp(tlv->info, &oui_subtype, OUI_SUB_SIZE)) -- return SUBTYPE_INVALID; -- -- /* disable rx if tx has been disabled by administrator */ -- if (!ed->txmit) { -- LLDPAD_WARN("%s:%s agent %d EVB Config disabled\n", -- __func__, ed->ifname, agent->type); -- return TLV_OK; -- } -- -- LLDPAD_DBG("%s:%s agent %d received tlv:\n", __func__, -- port->ifname, agent->type); -- evb22_dump_tlv(ed->ifname, tlv); -- memcpy(&ed->last, tlv->info, tlv->length); -- evb22_print_tlvinfo(ed->ifname, &ed->last); -- -- evb22_update_tlv(ed); -- somethingChangedLocal(ed->ifname, agent->type); -- -- LLDPAD_DBG("%s:%s agent %d new tlv:\n", __func__, port->ifname, -- agent->type); -- evb22_print_tlvinfo(ed->ifname, &ed->out); -- /* TODO vdp_update(port->ifname, ed->tie.ccap); */ -- } -- return TLV_OK; --} -- --/* -- * Stop all modules which depend on EVB capabilities. -- */ --static void evb22_stop_modules(char *ifname) --{ -- LLDPAD_DBG("%s:%s STOP\n", __func__, ifname); -- ecp22_stop(ifname); -- vdp22_stop(ifname); --} -- --static void evb22_ifdown(char *ifname, struct lldp_agent *agent) --{ -- struct evb22_data *ed; -- -- if (agent->type != NEAREST_CUSTOMER_BRIDGE) -- return; -- LLDPAD_DBG("%s:%s agent %d called\n", __func__, ifname, agent->type); -- -- ed = evb22_data(ifname, agent->type); -- if (!ed) { -- LLDPAD_DBG("%s:%s agent %d does not exist.\n", __func__, -- ifname, agent->type); -- return; -- } -- if (ed->vdp_start) -- evb22_stop_modules(ifname); -- LIST_REMOVE(ed, entry); -- free(ed); -- LLDPAD_INFO("%s:%s agent %d removed\n", __func__, ifname, agent->type); --} -- --/* -- * Fill up evb structure with reasonable info from the configuration file. -- */ --static void evb22_init_tlv(struct evb22_data *ed, struct lldp_agent *agent) --{ -- u8 mode; -- -- memset(&ed->last, 0, sizeof ed->last); -- memset(&ed->out, 0, sizeof ed->out); -- memset(&ed->policy, 0, sizeof ed->policy); -- -- ed->txmit = evb22_conf_enabletx(ed->ifname, agent->type); -- if (!ed->txmit) -- LLDPAD_DBG("%s:%s agent %d EVB tx is currently disabled\n", -- __func__, ed->ifname, agent->type); -- -- hton24(ed->policy.oui, LLDP_MOD_EVB22); -- ed->policy.sub = LLDP_MOD_EVB22_SUBTYPE; -- hton24(ed->out.oui, LLDP_MOD_EVB22); -- ed->out.sub = LLDP_MOD_EVB22_SUBTYPE; -- -- mode = evb22_conf_evbmode(ed->ifname, agent->type); -- ed->policy.evb_mode = evb_set_rol(0) -- | evb_set_rwd(evb22_conf_rwd(ed->ifname, agent->type)) -- | evb_set_evbmode(mode); -- if (mode == EVB_STATION) { -- mode = evb22_conf_rrreq(ed->ifname, agent->type); -- ed->policy.station_s = evb_set_rrstat(EVB_RRSTAT_DONT) -- | evb_set_sgid(evb22_conf_gid(ed->ifname, agent->type)) -- | evb_set_rrreq(mode); -- ed->policy.bridge_s = 0; -- } else { -- mode = evb22_conf_rrcap(ed->ifname, agent->type); -- ed->policy.bridge_s = evb_set_rrcap(mode) -- | evb_set_bgid(evb22_conf_gid(ed->ifname, agent->type)); -- ed->policy.station_s = 0; -- } -- ed->policy.r_rte = -- evb_set_retries(evb22_conf_retries(ed->ifname, agent->type)) -- | evb_set_rte(evb22_conf_rte(ed->ifname, agent->type)); -- ed->policy.rl_rka = evb_set_rol(0) -- | evb_set_rka(evb22_conf_rka(ed->ifname, agent->type)); --} -- --static void evb22_ifup(char *ifname, struct lldp_agent *agent) --{ -- struct evb22_data *ed; -- struct evb22_user_data *ud; -- -- if (agent->type != NEAREST_CUSTOMER_BRIDGE) -- return; -- LLDPAD_DBG("%s:%s agent %d called\n", __func__, ifname, agent->type); -- -- ed = evb22_data(ifname, agent->type); -- if (ed) { -- LLDPAD_DBG("%s:%s agent %d already exists\n", __func__, ifname, -- agent->type); -- return; -- } -- -- /* not found, alloc/init per-port tlv data */ -- ed = (struct evb22_data *) calloc(1, sizeof *ed); -- if (!ed) { -- LLDPAD_ERR("%s:%s agent %d malloc %zu failed\n", -- __func__, ifname, agent->type, sizeof *ed); -- return; -- } -- strncpy(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); -- LIST_INSERT_HEAD(&ud->head, ed, entry); -- LLDPAD_DBG("%s:%s agent %d added\n", __func__, ifname, agent->type); --} -- --/* -- * Start all modules which depend on EVB capabilities: ECP, VDP, CDCP. -- */ --static void evb22_start_modules(char *ifname) --{ -- LLDPAD_DBG("%s:%s START\n", __func__, ifname); -- ecp22_start(ifname); -- vdp22_start(ifname); --} -- --/* -- * Check for stable interfaces. When an interface goes up the carrier might -- * come and go during a start up time. Define a window during which the port -- * is considered unstable for EVB/VDP protocols. -- * -- * Use the dormantDelay counter of the port to determine a stable interface. -- */ --static int evb22_timer(struct port *port, struct lldp_agent *agent) --{ -- struct evb22_data *ed; -- -- if (agent->type != NEAREST_CUSTOMER_BRIDGE) -- return 0; -- ed = evb22_data(port->ifname, agent->type); -- if (!ed) -- return 0; -- if (!ed->vdp_start -- && evb_ex_rrstat(ed->out.station_s) == EVB_RRSTAT_YES) { -- ed->vdp_start = true; -- evb22_start_modules(port->ifname); -- } -- return 0; --} -- --static u8 evb22_mibdelete(struct port *port, struct lldp_agent *agent) --{ -- struct evb22_data *ed; -- -- ed = evb22_data(port->ifname, agent->type); -- if (ed && (agent->type == ed->agenttype)) { -- memset(&ed->last, 0, sizeof ed->last); -- /* TODO vdp_update(port->ifname, 0); */ -- } -- return 0; --} -- --/* -- * Remove all interface/agent specific evb data. -- */ --static void evb22_free_data(struct evb22_user_data *ud) --{ -- struct evb22_data *ed; -- -- if (ud) { -- while (!LIST_EMPTY(&ud->head)) { -- ed = LIST_FIRST(&ud->head); -- LIST_REMOVE(ed, entry); -- free(ed); -- } -- } --} -- --void evb22_unregister(struct lldp_module *mod) --{ -- if (mod->data) { -- evb22_free_data((struct evb22_user_data *) mod->data); -- free(mod->data); -- } -- free(mod); -- LLDPAD_DBG("%s:done\n", __func__); --} -- --static const struct lldp_mod_ops evb22_ops = { -- .lldp_mod_gettlv = evb22_gettlv, -- .lldp_mod_rchange = evb22_rchange, -- .lldp_mod_mibdelete = evb22_mibdelete, -- .timer = evb22_timer, -- .lldp_mod_ifdown = evb22_ifdown, -- .lldp_mod_ifup = evb22_ifup, -- .lldp_mod_register = evb22_register, -- .lldp_mod_unregister = evb22_unregister, -- .get_arg_handler = evb22_get_arg_handlers --}; -- --struct lldp_module *evb22_register(void) --{ -- struct lldp_module *mod; -- struct evb22_user_data *ud; -- -- mod = calloc(1, sizeof *mod); -- if (!mod) { -- LLDPAD_ERR("%s: failed to malloc module data\n", __func__); -- return NULL; -- } -- ud = calloc(1, sizeof *ud); -- if (!ud) { -- free(mod); -- LLDPAD_ERR("%s failed to malloc module user data\n", __func__); -- return NULL; -- } -- LIST_INIT(&ud->head); -- mod->id = LLDP_MOD_EVB22; -- mod->ops = &evb22_ops; -- mod->data = ud; -- LLDPAD_DBG("%s:done\n", __func__); -- return mod; --} -diff --git a/qbg/lldp_evb22_clif.c b/qbg/lldp_evb22_clif.c -deleted file mode 100644 -index 336273f..0000000 ---- a/qbg/lldp_evb22_clif.c -+++ /dev/null -@@ -1,201 +0,0 @@ --/****************************************************************************** -- -- Implementation of EVB TLVs for LLDP -- (c) Copyright IBM Corp. 2010, 2012 -- -- Author(s): Thomas Richter -- -- This program is free software; you can redistribute it and/or modify it -- under the terms and conditions of the GNU General Public License, -- version 2, as published by the Free Software Foundation. -- -- This program is distributed in the hope it will be useful, but WITHOUT -- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -- more details. -- -- You should have received a copy of the GNU General Public License along with -- this program; if not, write to the Free Software Foundation, Inc., -- 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. -- -- The full GNU General Public License is included in this distribution in -- the file called "COPYING". -- --******************************************************************************/ -- --#include --#include -- --#include "lldp_tlv.h" --#include "clif_msgs.h" --#include "lldp_mod.h" --#include "lldptool.h" --#include "lldp.h" --#include "lldp_evb22.h" --#include "lldp_evb22_clif.h" -- --static void show_tlv(char *buf, size_t len, struct evb22_tlv *tlv) --{ -- int comma = 0; -- char bridge_txt[32], station_txt[32]; -- -- memset(bridge_txt, 0, sizeof bridge_txt); -- if (evb_ex_bgid(tlv->bridge_s)) { -- strcat(bridge_txt, "bgid"); -- comma = 1; -- } -- if (evb_ex_rrcap(tlv->bridge_s)) { -- if (comma) -- strcat(bridge_txt, ","); -- strcat(bridge_txt, "rrcap"); -- comma = 1; -- } -- if (evb_ex_rrctr(tlv->bridge_s)) { -- if (comma) -- strcat(bridge_txt, ","); -- strcat(bridge_txt, "rrctr"); -- } -- -- comma = 0; -- memset(station_txt, 0, sizeof station_txt); -- if (evb_ex_sgid(tlv->station_s)) { -- strcat(station_txt, "sgid"); -- comma = 1; -- } -- if (evb_ex_rrreq(tlv->station_s)) { -- if (comma) -- strcat(station_txt, ","); -- strcat(station_txt, "rrreq"); -- comma = 1; -- } -- if (evb_ex_rrstat(tlv->station_s)) { -- if (comma) -- strcat(station_txt, ","); -- strcat(station_txt, "rrstat"); -- } -- -- snprintf(buf, len, "bridge:%s(%#02x)\n" -- "\tstation:%s(%#02x)\n" -- "\tretries:%d rte:%d\n" -- "\tmode:%s r/l:%d rwd:%d\n" -- "\tr/l:%d rka:%d\n", -- bridge_txt, tlv->bridge_s, -- station_txt, tlv->station_s, -- evb_ex_retries(tlv->r_rte), evb_ex_rte(tlv->r_rte), -- evb_ex_evbmode(tlv->evb_mode) == EVB_STATION ? -- "station" : "bridge", -- evb_ex_rol(tlv->evb_mode), -- evb_ex_rwd(tlv->evb_mode), -- evb_ex_rol(tlv->rl_rka), evb_ex_rka(tlv->rl_rka)); --} -- --static void evb22_print_cfg_tlv(u16 len, char *info) --{ -- struct evb22_tlv tlv; -- char buf[256]; -- -- if (len != 5) { -- printf("Bad evbcfg TLV: %s\n", info); -- return; -- } -- memset(&tlv, 0, sizeof tlv); -- memset(buf, 0, sizeof buf); -- hexstr2bin(&info[0], &tlv.bridge_s, sizeof tlv.bridge_s); -- hexstr2bin(&info[2], &tlv.station_s, sizeof tlv.station_s); -- hexstr2bin(&info[4], &tlv.r_rte, sizeof tlv.r_rte); -- hexstr2bin(&info[6], &tlv.evb_mode, sizeof tlv.evb_mode); -- hexstr2bin(&info[8], &tlv.rl_rka, sizeof tlv.rl_rka); -- show_tlv(buf, sizeof buf, &tlv); -- printf("%s", buf); --} -- --static struct type_name_info evb22_tlv_names[] = { -- { -- .type = TLVID(OUI_IEEE_8021Qbg22, LLDP_EVB22_SUBTYPE), -- .name = "EVB Configuration TLV", -- .key = "evb", -- .print_info = evb22_print_cfg_tlv -- }, -- { -- .type = INVALID_TLVID -- } --}; -- --static int evb22_print_help() --{ -- struct type_name_info *tn = &evb22_tlv_names[0]; -- -- while (tn->type != INVALID_TLVID) { -- if (tn->key && strlen(tn->key) && tn->name) { -- printf(" %s", tn->key); -- if (strlen(tn->key)+3 < 8) -- printf("\t"); -- printf("\t: %s\n", tn->name); -- } -- tn++; -- } -- -- return 0; --} -- --static void evb22_cli_unregister(struct lldp_module *mod) --{ -- free(mod); --} -- --/* return 1: if it printed the TLV -- * 0: if it did not -- */ --static int evb22_print_tlv(u32 tlvid, u16 len, char *info) --{ -- struct type_name_info *tn = &evb22_tlv_names[0]; -- -- while (tn->type != INVALID_TLVID) { -- if (tlvid == tn->type) { -- printf("%s\n", tn->name); -- if (tn->print_info) { -- printf("\t"); -- tn->print_info(len-4, info); -- } -- return 1; -- } -- tn++; -- } -- -- return 0; --} -- --static u32 evb22_lookup_tlv_name(char *tlvid_str) --{ -- struct type_name_info *tn = &evb22_tlv_names[0]; -- -- while (tn->type != INVALID_TLVID) { -- if (!strcasecmp(tn->key, tlvid_str)) -- return tn->type; -- tn++; -- } -- return INVALID_TLVID; --} -- --static const struct lldp_mod_ops evb22_ops_clif = { -- .lldp_mod_register = evb22_cli_register, -- .lldp_mod_unregister = evb22_cli_unregister, -- .print_tlv = evb22_print_tlv, -- .lookup_tlv_name = evb22_lookup_tlv_name, -- .print_help = evb22_print_help --}; -- --struct lldp_module *evb22_cli_register(void) --{ -- struct lldp_module *mod; -- -- mod = calloc(1, sizeof(*mod)); -- if (!mod) { -- fprintf(stderr, "%s failed to malloc module data\n", __func__); -- return NULL; -- } -- mod->id = LLDP_MOD_EVB22; -- mod->ops = &evb22_ops_clif; -- -- return mod; --} -diff --git a/qbg/lldp_evb22_cmds.c b/qbg/lldp_evb22_cmds.c -deleted file mode 100644 -index 51b7ba1..0000000 ---- a/qbg/lldp_evb22_cmds.c -+++ /dev/null -@@ -1,738 +0,0 @@ --/****************************************************************************** -- -- Implementation of EVB TLVs for LLDP -- (c) Copyright IBM Corp. 2012 -- -- Author(s): Thomas Richter -- -- This program is free software; you can redistribute it and/or modify it -- under the terms and conditions of the GNU General Public License, -- version 2, as published by the Free Software Foundation. -- -- This program is distributed in the hope it will be useful, but WITHOUT -- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -- more details. -- -- You should have received a copy of the GNU General Public License along with -- this program; if not, write to the Free Software Foundation, Inc., -- 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. -- -- The full GNU General Public License is included in this distribution in -- the file called "COPYING". -- --******************************************************************************/ -- --#define _GNU_SOURCE -- --#include --#include --#include -- --#include "lldp.h" --#include "lldp_evb22.h" --#include "lldp_tlv.h" --#include "lldp_mand_clif.h" --#include "config.h" --#include "clif_msgs.h" --#include "messages.h" -- --/* -- * Defines for configuration file name tags. -- */ --#define EVB_BUF_SIZE 256 --#define EVB_CONF_MODE "evbmode" --#define EVB_CONF_RRREQ "evbrrreq" --#define EVB_CONF_RRCAP "evbrrcap" --#define EVB_CONF_GPID "evbgpid" --#define EVB_CONF_RETRIES "ecpretries" --#define EVB_CONF_RTE "ecprte" --#define EVB_CONF_RWD "vdprwd" --#define EVB_CONF_RKA "vdprka" --#define EVB_CONF_BRIDGE "bridge" --#define EVB_CONF_STATION "station" -- --/* -- * Read EVB specific data from the configuration file. -- */ --static const char *evb22_conf_string(char *ifname, enum agent_type type, -- char *ext, int def) --{ -- char arg_path[EVB_BUF_SIZE]; -- const char *param = NULL; -- -- snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", -- TLVID_PREFIX, TLVID(OUI_IEEE_8021Qbg22, LLDP_EVB22_SUBTYPE), -- ext); -- if (get_cfg(ifname, type, arg_path, ¶m, CONFIG_TYPE_STRING)) -- LLDPAD_INFO("%s:%s agent %d loading EVB policy for %s" -- " failed, using default (%d)\n", __func__, -- ifname, type, ext, def); -- return param; --} -- --static int evb22_conf_int(char *ifname, enum agent_type type, -- char *ext, int def, int cfgtype) --{ -- char arg_path[EVB_BUF_SIZE]; -- int param; -- -- snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", -- TLVID_PREFIX, TLVID(OUI_IEEE_8021Qbg22, LLDP_EVB22_SUBTYPE), -- ext); -- if (get_cfg(ifname, type, arg_path, ¶m, cfgtype)) { -- LLDPAD_INFO("%s:%s agent %d loading EVB policy for %s" -- " failed, using default (%d)\n", __func__, -- ifname, type, ext, def); -- return def; -- } -- return param; --} -- --/* -- * Read EXP parameter. Defaults to 8 --> 10 * 2 ^ 8 = 2560us > 2ms. -- */ --static int exponent(char *ifname, enum agent_type type, char *txt, int def) --{ -- int value; -- -- value = evb22_conf_int(ifname, type, txt, def, CONFIG_TYPE_INT); -- if (value > 31) { -- LLDPAD_DBG("%s:%s agent %d invalid %s %d\n", __func__, -- ifname, type, txt, value); -- value = def; -- } -- LLDPAD_DBG("%s:%s agent %d policy %s %d\n", __func__, -- ifname, type, txt, value); -- return value; --} -- --/* -- * Read retransmission exponent parameter. -- */ --int evb22_conf_rte(char *ifname, enum agent_type type) --{ -- return exponent(ifname, type, EVB_CONF_RTE, 8); --} -- --/* -- * Read reinit keep alive parameter. Same as RTE. -- */ --int evb22_conf_rka(char *ifname, enum agent_type type) --{ -- return exponent(ifname, type, EVB_CONF_RKA, 20); --} -- --/* -- * Read resource wait delay parameter. Same as RTE. -- */ --int evb22_conf_rwd(char *ifname, enum agent_type type) --{ -- return exponent(ifname, type, EVB_CONF_RWD, 20); --} -- --/* -- * Read max retries parameter. Defaults to 3. -- */ --int evb22_conf_retries(char *ifname, enum agent_type type) --{ -- int value; -- -- value = evb22_conf_int(ifname, type, EVB_CONF_RETRIES, 3, -- CONFIG_TYPE_INT); -- if (value > 7) { -- LLDPAD_DBG("%s:%s agent %d invalid %s %d\n", __func__, -- ifname, type, EVB_CONF_RETRIES, value); -- value = 3; -- } -- LLDPAD_DBG("%s:%s agent %d policy %s %d\n", __func__, -- ifname, type, EVB_CONF_RETRIES, value); -- return value; --} -- --/* -- * Read station group id parameter. Defaults to false. -- */ --int evb22_conf_gid(char *ifname, enum agent_type type) --{ -- int value; -- -- value = evb22_conf_int(ifname, type, EVB_CONF_GPID, false, -- CONFIG_TYPE_BOOL); -- LLDPAD_DBG("%s:%s agent %d policy %s %s\n", __func__, -- ifname, type, EVB_CONF_GPID, value ? "true" : "false"); -- return value; --} -- --/* -- * Read reflective-relay bridge capability parameter. Defaults to false. -- */ --int evb22_conf_rrcap(char *ifname, enum agent_type type) --{ -- int value; -- -- value = evb22_conf_int(ifname, type, EVB_CONF_RRCAP, false, -- CONFIG_TYPE_BOOL); -- LLDPAD_DBG("%s:%s agent %d policy %s %s\n", __func__, -- ifname, type, EVB_CONF_RRCAP, value ? "true" : "false"); -- return value; --} -- --/* -- * Read reflective-relay station request parameter. Defaults to false. -- */ --int evb22_conf_rrreq(char *ifname, enum agent_type type) --{ -- int value; -- -- value = evb22_conf_int(ifname, type, EVB_CONF_RRREQ, false, -- CONFIG_TYPE_BOOL); -- LLDPAD_DBG("%s:%s agent %d policy %s %s\n", __func__, -- ifname, type, EVB_CONF_RRREQ, value ? "true" : "false"); -- return value; --} -- --/* -- * Read station/bridge role from configuration file. Defaults to station -- */ --int evb22_conf_evbmode(char *ifname, enum agent_type type) --{ -- int mode = EVB_STATION; -- const char *value; -- -- value = evb22_conf_string(ifname, type, EVB_CONF_MODE, mode); -- if (value) { -- if (!strcasecmp(value, EVB_CONF_BRIDGE)) -- mode = EVB_BRIDGE; -- else if (strcasecmp(value, EVB_CONF_STATION)) { -- LLDPAD_ERR("%s:%s agent %d invalid evbmode %s\n", -- __func__, ifname, type, value); -- value = EVB_CONF_STATION; -- } -- } else -- value = EVB_CONF_STATION; -- LLDPAD_DBG("%s:%s agent %d policy %s %s(%#x)\n", __func__, -- ifname, type, EVB_CONF_MODE, value, mode); -- return mode; --} -- --/* -- * Read transmit status from configuration file. -- */ --int evb22_conf_enabletx(char *ifname, enum agent_type type) --{ -- return is_tlv_txenabled(ifname, type, -- TLVID(OUI_IEEE_8021Qbg22, LLDP_EVB22_SUBTYPE)); --} -- --static int evb22_cmdok(struct cmd *cmd, cmd_status expected) --{ -- if (cmd->cmd != expected) -- return cmd_invalid; -- switch (cmd->tlvid) { -- case TLVID(OUI_IEEE_8021Qbg22, LLDP_EVB22_SUBTYPE): -- return cmd_success; -- case INVALID_TLVID: -- return cmd_invalid; -- default: -- return cmd_not_applicable; -- } --} -- --static int get_arg_evbmode(struct cmd *cmd, char *arg, UNUSED char *argvalue, -- char *obuf, int obuf_len) --{ -- struct evb22_data *ed; -- char *s; -- cmd_status good_cmd = evb22_cmdok(cmd, cmd_gettlv); -- -- if (good_cmd != cmd_success) -- return good_cmd; -- ed = evb22_data((char *) &cmd->ifname, cmd->type); -- if (!ed) -- return cmd_invalid; -- if (evb_ex_evbmode(ed->policy.evb_mode) == EVB_STATION) -- s = EVB_CONF_STATION; -- else -- s = EVB_CONF_BRIDGE; -- snprintf(obuf, obuf_len, "%02x%s%04x%s", -- (unsigned int)strlen(arg), arg, (unsigned int)strlen(s), s); -- return cmd_success; --} -- --static int set2_arg_evbmode(struct cmd *cmd, char *arg, const char *argvalue, -- bool test) --{ -- char arg_path[EVB_BUF_SIZE]; -- struct evb22_data *ed; -- cmd_status good_cmd = evb22_cmdok(cmd, cmd_settlv); -- u8 mode; -- -- if (good_cmd != cmd_success) -- return good_cmd; -- if (strcasecmp(argvalue, EVB_CONF_BRIDGE) -- && strcasecmp(argvalue, EVB_CONF_STATION)) -- return cmd_bad_params; -- ed = evb22_data((char *) &cmd->ifname, cmd->type); -- if (!ed) -- return cmd_invalid; -- if (test) -- return cmd_success; -- snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", -- TLVID_PREFIX, cmd->tlvid, arg); -- -- if (set_cfg(cmd->ifname, cmd->type, arg_path, &argvalue, -- CONFIG_TYPE_STRING)) { -- LLDPAD_ERR("%s: error saving EVB mode (%s)\n", ed->ifname, -- argvalue); -- return cmd_failed; -- } -- mode = strcasecmp(argvalue, EVB_CONF_BRIDGE) ? EVB_STATION : EVB_BRIDGE; -- ed->policy.evb_mode = evb_maskoff_evbmode(ed->policy.evb_mode) | -- evb_set_evbmode(mode); -- LLDPAD_INFO("%s: changed EVB mode (%s)\n", ed->ifname, argvalue); -- return cmd_success; --} -- --static int set_arg_evbmode(struct cmd *cmd, char *arg, char *argvalue, -- UNUSED char *obuf, UNUSED int obuf_len) --{ -- return set2_arg_evbmode(cmd, arg, argvalue, false); --} -- --static int test_arg_evbmode(struct cmd *cmd, char *arg, char *argvalue, -- UNUSED char *obuf, UNUSED int obuf_len) --{ -- return set2_arg_evbmode(cmd, arg, argvalue, true); --} -- --static int get_txmit(struct evb22_data *ed) --{ -- return ed->txmit; --} -- --static void set_txmit(struct evb22_data *ed, int value) --{ -- ed->txmit = value; --} -- --static int get_gpid(struct evb22_data *ed) --{ -- int mode = evb_ex_evbmode(ed->policy.evb_mode); -- -- if (mode == EVB_STATION && evb_ex_sgid(ed->policy.station_s)) -- return 1; -- if (mode == EVB_BRIDGE && evb_ex_bgid(ed->policy.bridge_s)) -- return 1; -- return 0; --} -- --static void set_gpid(struct evb22_data *ed, int value) --{ -- if (evb_ex_evbmode(ed->policy.evb_mode) == EVB_STATION) -- ed->policy.station_s = evb_maskoff_sgid(ed->policy.station_s) -- | evb_set_sgid(value); -- else -- ed->policy.bridge_s = evb_maskoff_bgid(ed->policy.bridge_s) -- | evb_set_bgid(value); --} -- --static void set_rrcap(struct evb22_data *ed, int value) --{ -- ed->policy.bridge_s = evb_maskoff_rrcap(ed->policy.bridge_s) -- | evb_set_rrcap(value); --} -- --static int get_rrcap(struct evb22_data *ed) --{ -- return evb_ex_rrcap(ed->policy.bridge_s); --} -- --static void set_rrreq(struct evb22_data *ed, int value) --{ -- ed->policy.station_s = evb_maskoff_rrreq(ed->policy.station_s) -- | evb_set_rrreq(value); --} -- --static int get_rrreq(struct evb22_data *ed) --{ -- return evb_ex_rrreq(ed->policy.station_s); --} -- --/* -- * Read a boolean value from the command line argument and apply the new -- * value to parameter. -- */ --static int scan_bool(struct cmd *cmd, char *arg, char *argvalue, bool test, -- void (*fct)(struct evb22_data *, int)) --{ -- int value; -- char arg_path[EVB_BUF_SIZE]; -- struct evb22_data *ed; -- cmd_status good_cmd = evb22_cmdok(cmd, cmd_settlv); -- -- if (good_cmd != cmd_success) -- return good_cmd; -- if (!strcasecmp(argvalue, VAL_YES)) -- value = 1; -- else if (!strcasecmp(argvalue, VAL_NO)) -- value = 0; -- else -- return cmd_bad_params; -- ed = evb22_data((char *) &cmd->ifname, cmd->type); -- if (!ed) -- return cmd_invalid; -- if (test) -- return cmd_success; -- snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", -- TLVID_PREFIX, cmd->tlvid, arg); -- if (set_cfg(cmd->ifname, cmd->type, arg_path, &value, -- CONFIG_TYPE_BOOL)){ -- LLDPAD_ERR("%s: error saving EVB enabletx (%s)\n", ed->ifname, -- argvalue); -- return cmd_failed; -- } -- LLDPAD_INFO("%s: changed EVB %s (%s)\n", ed->ifname, arg, argvalue); -- (*fct)(ed, value); -- somethingChangedLocal(cmd->ifname, cmd->type); -- return cmd_success; --} -- --static int show_bool(struct cmd *cmd, char *arg, UNUSED char *argvalue, -- char *obuf, int obuf_len, -- int (*fct)(struct evb22_data *)) --{ -- struct evb22_data *ed; -- char *s; -- cmd_status good_cmd = evb22_cmdok(cmd, cmd_gettlv); -- -- if (good_cmd != cmd_success) -- return good_cmd; -- ed = evb22_data((char *) &cmd->ifname, cmd->type); -- if (!ed) -- return cmd_invalid; -- if ((*fct)(ed)) -- s = VAL_YES; -- else -- s = VAL_NO; -- snprintf(obuf, obuf_len, "%02x%s%04x%s", -- (unsigned int)strlen(arg), arg, (unsigned int)strlen(s), s); -- return cmd_success; --} -- --static int get_arg_tlvtxenable(struct cmd *cmd, char *arg, -- UNUSED char *argvalue, char *obuf, int obuf_len) --{ -- return show_bool(cmd, arg, argvalue, obuf, obuf_len, get_txmit); --} -- --static int set_arg_tlvtxenable(struct cmd *cmd, char *arg, char *argvalue, -- UNUSED char *obuf, UNUSED int obuf_len) --{ -- return scan_bool(cmd, arg, argvalue, false, set_txmit); --} -- --static int test_arg_tlvtxenable(struct cmd *cmd, char *arg, char *argvalue, -- UNUSED char *obuf, UNUSED int obuf_len) --{ -- return scan_bool(cmd, arg, argvalue, true, 0); --} -- --static int get_arg_gpid(struct cmd *cmd, char *arg, UNUSED char *argvalue, -- char *obuf, int obuf_len) --{ -- return show_bool(cmd, arg, argvalue, obuf, obuf_len, get_gpid); --} -- --static int set_arg_gpid(struct cmd *cmd, char *arg, char *argvalue, -- UNUSED char *obuf, UNUSED int obuf_len) --{ -- return scan_bool(cmd, arg, argvalue, false, set_gpid); --} -- --static int test_arg_gpid(struct cmd *cmd, char *arg, char *argvalue, -- UNUSED char *obuf, UNUSED int obuf_len) --{ -- return scan_bool(cmd, arg, argvalue, true, 0); --} -- --static int get_arg_rrcap(struct cmd *cmd, char *arg, UNUSED char *argvalue, -- char *obuf, int obuf_len) --{ -- return show_bool(cmd, arg, argvalue, obuf, obuf_len, get_rrcap); --} -- --static int set_arg_rrcap(struct cmd *cmd, char *arg, char *argvalue, -- UNUSED char *obuf, UNUSED int obuf_len) --{ -- return scan_bool(cmd, arg, argvalue, false, set_rrcap); --} -- --static int test_arg_rrcap(struct cmd *cmd, char *arg, char *argvalue, -- UNUSED char *obuf, UNUSED int obuf_len) --{ -- return scan_bool(cmd, arg, argvalue, true, 0); --} -- --static int get_arg_rrreq(struct cmd *cmd, char *arg, UNUSED char *argvalue, -- char *obuf, int obuf_len) --{ -- return show_bool(cmd, arg, argvalue, obuf, obuf_len, get_rrreq); --} -- --static int set_arg_rrreq(struct cmd *cmd, char *arg, char *argvalue, -- UNUSED char *obuf, UNUSED int obuf_len) --{ -- return scan_bool(cmd, arg, argvalue, false, set_rrreq); --} -- --static int test_arg_rrreq(struct cmd *cmd, char *arg, char *argvalue, -- UNUSED char *obuf, UNUSED int obuf_len) --{ -- return scan_bool(cmd, arg, argvalue, true, 0); --} -- -- --static void set_retries(struct evb22_data *ed, int value) --{ -- ed->policy.r_rte = evb_maskoff_retries(ed->policy.r_rte) -- | evb_set_retries(value); --} -- --static int get_retries(struct evb22_data *ed) --{ -- return evb_ex_retries(ed->policy.r_rte); --} -- --static void set_rte(struct evb22_data *ed, int value) --{ -- ed->policy.r_rte = evb_maskoff_rte(ed->policy.r_rte) -- | evb_set_rte(value); --} -- --static int get_rte(struct evb22_data *ed) --{ -- return evb_ex_rte(ed->policy.r_rte); --} -- --static void set_rwd(struct evb22_data *ed, int value) --{ -- ed->policy.evb_mode = evb_maskoff_rwd(ed->policy.evb_mode) -- | evb_set_rwd(value); --} -- --static int get_rwd(struct evb22_data *ed) --{ -- return evb_ex_rwd(ed->policy.evb_mode); --} -- --static void set_rka(struct evb22_data *ed, int value) --{ -- ed->policy.rl_rka = evb_maskoff_rka(ed->policy.rl_rka) -- | evb_set_rka(value); --} -- --static int get_rka(struct evb22_data *ed) --{ -- return evb_ex_rka(ed->policy.rl_rka); --} -- --static int scan_31bit(struct cmd *cmd, char *arg, const char *argvalue, -- bool test, void (*fct)(struct evb22_data *, int), -- int limit) --{ -- char arg_path[EVB_BUF_SIZE]; -- struct evb22_data *ed; -- int value; -- char *endp; -- cmd_status good_cmd = evb22_cmdok(cmd, cmd_settlv); -- -- if (good_cmd != cmd_success) -- return good_cmd; -- value = strtoul(argvalue, &endp, 0); -- if (*endp != '\0' || value > limit) -- return cmd_bad_params; -- ed = evb22_data((char *) &cmd->ifname, cmd->type); -- if (!ed) -- return cmd_invalid; -- if (test) -- return cmd_success; -- snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", -- TLVID_PREFIX, cmd->tlvid, arg); -- if (set_cfg(ed->ifname, cmd->type, arg_path, &value, -- CONFIG_TYPE_INT)){ -- LLDPAD_ERR("%s: error saving EVB %s (%d)\n", ed->ifname, arg, -- value); -- return cmd_failed; -- } -- LLDPAD_INFO("%s: changed EVB %s (%s)\n", ed->ifname, arg, argvalue); -- (*fct)(ed, value); -- somethingChangedLocal(cmd->ifname, cmd->type); -- return cmd_success; --} -- --static int show_31bit(struct cmd *cmd, char *arg, UNUSED char *argvalue, -- char *obuf, int obuf_len, -- int (*fct)(struct evb22_data *)) --{ -- struct evb22_data *ed; -- char s[EVB_BUF_SIZE]; -- cmd_status good_cmd = evb22_cmdok(cmd, cmd_gettlv); -- -- if (good_cmd != cmd_success) -- return good_cmd; -- ed = evb22_data((char *) &cmd->ifname, cmd->type); -- if (!ed) -- return cmd_invalid; -- if (sprintf(s, "%i", (*fct)(ed)) <= 0) -- return cmd_invalid; -- snprintf(obuf, obuf_len, "%02x%s%04x%s", -- (unsigned int)strlen(arg), arg, (unsigned int)strlen(s), s); -- return cmd_success; --} -- --static int get_arg_retries(struct cmd *cmd, char *arg, UNUSED char *argvalue, -- char *obuf, int obuf_len) --{ -- return show_31bit(cmd, arg, argvalue, obuf, obuf_len, get_retries); --} -- --static int set_arg_retries(struct cmd *cmd, char *arg, char *argvalue, -- UNUSED char *obuf, UNUSED int obuf_len) --{ -- return scan_31bit(cmd, arg, argvalue, false, set_retries, 7); --} -- --static int test_arg_retries(struct cmd *cmd, char *arg, char *argvalue, -- UNUSED char *obuf, UNUSED int obuf_len) --{ -- return scan_31bit(cmd, arg, argvalue, true, 0, 7); --} -- --static int get_arg_rte(struct cmd *cmd, char *arg, UNUSED char *argvalue, -- char *obuf, int obuf_len) --{ -- return show_31bit(cmd, arg, argvalue, obuf, obuf_len, get_rte); --} -- --static int set_arg_rte(struct cmd *cmd, char *arg, char *argvalue, -- UNUSED char *obuf, UNUSED int obuf_len) --{ -- return scan_31bit(cmd, arg, argvalue, false, set_rte, 31); --} -- --static int test_arg_rte(struct cmd *cmd, char *arg, char *argvalue, -- UNUSED char *obuf, UNUSED int obuf_len) --{ -- return scan_31bit(cmd, arg, argvalue, true, 0, 31); --} -- --static int get_arg_rwd(struct cmd *cmd, char *arg, UNUSED char *argvalue, -- char *obuf, int obuf_len) --{ -- return show_31bit(cmd, arg, argvalue, obuf, obuf_len, get_rwd); --} -- --static int set_arg_rwd(struct cmd *cmd, char *arg, char *argvalue, -- UNUSED char *obuf, UNUSED int obuf_len) --{ -- return scan_31bit(cmd, arg, argvalue, false, set_rwd, 31); --} -- --static int test_arg_rwd(struct cmd *cmd, char *arg, char *argvalue, -- UNUSED char *obuf, UNUSED int obuf_len) --{ -- return scan_31bit(cmd, arg, argvalue, true, 0, 31); --} -- --static int get_arg_rka(struct cmd *cmd, char *arg, UNUSED char *argvalue, -- char *obuf, int obuf_len) --{ -- return show_31bit(cmd, arg, argvalue, obuf, obuf_len, get_rka); --} -- --static int set_arg_rka(struct cmd *cmd, char *arg, char *argvalue, -- UNUSED char *obuf, UNUSED int obuf_len) --{ -- return scan_31bit(cmd, arg, argvalue, false, set_rka, 31); --} -- --static int test_arg_rka(struct cmd *cmd, char *arg, char *argvalue, -- UNUSED char *obuf, UNUSED int obuf_len) --{ -- return scan_31bit(cmd, arg, argvalue, true, 0, 31); --} -- --static struct arg_handlers arg_handlers[] = { -- { -- .arg = EVB_CONF_RKA, -- .arg_class = TLV_ARG, -- .handle_get = get_arg_rka, -- .handle_set = set_arg_rka, -- .handle_test = test_arg_rka -- }, -- { -- .arg = EVB_CONF_RWD, -- .arg_class = TLV_ARG, -- .handle_get = get_arg_rwd, -- .handle_set = set_arg_rwd, -- .handle_test = test_arg_rwd -- }, -- { -- .arg = EVB_CONF_RTE, -- .arg_class = TLV_ARG, -- .handle_get = get_arg_rte, -- .handle_set = set_arg_rte, -- .handle_test = test_arg_rte -- }, -- { -- .arg = EVB_CONF_RETRIES, -- .arg_class = TLV_ARG, -- .handle_get = get_arg_retries, -- .handle_set = set_arg_retries, -- .handle_test = test_arg_retries -- }, -- { -- .arg = EVB_CONF_RRREQ, -- .arg_class = TLV_ARG, -- .handle_get = get_arg_rrreq, -- .handle_set = set_arg_rrreq, -- .handle_test = test_arg_rrreq -- }, -- { -- .arg = EVB_CONF_RRCAP, -- .arg_class = TLV_ARG, -- .handle_get = get_arg_rrcap, -- .handle_set = set_arg_rrcap, -- .handle_test = test_arg_rrcap -- }, -- { -- .arg = EVB_CONF_GPID, -- .arg_class = TLV_ARG, -- .handle_get = get_arg_gpid, -- .handle_set = set_arg_gpid, -- .handle_test = test_arg_gpid -- }, -- { -- .arg = EVB_CONF_MODE, -- .arg_class = TLV_ARG, -- .handle_get = get_arg_evbmode, -- .handle_set = set_arg_evbmode, -- .handle_test = test_arg_evbmode -- }, -- { -- .arg = ARG_TLVTXENABLE, -- .arg_class = TLV_ARG, -- .handle_get = get_arg_tlvtxenable, -- .handle_set = set_arg_tlvtxenable, -- .handle_test = test_arg_tlvtxenable -- }, -- { -- .arg = 0 -- } --}; -- --struct arg_handlers *evb22_get_arg_handlers() --{ -- return &arg_handlers[0]; --} -diff --git a/qbg/lldp_vdp22.c b/qbg/lldp_vdp22.c -deleted file mode 100644 -index 1d151ea..0000000 ---- a/qbg/lldp_vdp22.c -+++ /dev/null -@@ -1,287 +0,0 @@ --/****************************************************************************** -- -- Implementation of EVB TLVs for LLDP -- (c) Copyright IBM Corp. 2013 -- -- Author(s): Thomas Richter -- -- This program is free software; you can redistribute it and/or modify it -- under the terms and conditions of the GNU General Public License, -- version 2, as published by the Free Software Foundation. -- -- This program is distributed in the hope it will be useful, but WITHOUT -- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -- more details. -- -- You should have received a copy of the GNU General Public License along with -- this program; if not, write to the Free Software Foundation, Inc., -- 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. -- -- The full GNU General Public License is included in this distribution in -- the file called "COPYING". -- --******************************************************************************/ -- --#define _GNU_SOURCE --#include --#include --#include -- --#include -- --#include "messages.h" --#include "config.h" -- --#include "lldp_vdpnl.h" --#include "lldp_qbg22.h" --#include "lldp_vdp22.h" -- --/* -- * VDP22 helper functions -- */ --/* -- * Find the vdp data associated with an interface. -- * Return pointer or NULL if not found. -- */ --static struct vdp22 *vdp22_findif(const char *ifname, -- struct vdp22_user_data *ud) --{ -- struct vdp22 *vdp = 0; -- -- if (ud) { -- LIST_FOREACH(vdp, &ud->head, entry) -- if (!strncmp(ifname, vdp->ifname, IFNAMSIZ)) -- break; -- } -- return vdp; --} -- --/* -- * Update data exchanged via ECP protocol. -- * Returns true when data update succeeded. -- */ --static int data_from_ecp(char *ifname, struct ecp22_to_ulp *ptr) --{ -- struct vdp22_user_data *vud; -- struct vdp22 *vdp; -- -- vud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_VDP22); -- vdp = vdp22_findif(ifname, vud); -- if (vdp) { -- memcpy(vdp->input, ptr->data, ptr->len); -- vdp->input_len = ptr->len; -- return 0; -- } -- return -ENOENT; --} -- --/* -- * Update data exchanged via EVB protocol. -- * Returns true when data update succeeded. -- */ --static int data_from_evb(char *ifname, struct evb22_to_vdp22 *ptr) --{ -- struct vdp22_user_data *vud; -- struct vdp22 *vdp; -- -- vud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_VDP22); -- vdp = vdp22_findif(ifname, vud); -- if (vdp) { -- vdp->max_rwd = ptr->max_rwd; -- vdp->max_rka = ptr->max_rka; -- vdp->gpid = ptr->gpid; -- return 0; -- } -- return -ENOENT; --} -- --/* -- * Handle notifications from other modules. Check if sender-id and data type -- * indicator match. Return false when data could not be delivered. -- */ --static int vdp22_notify(int sender_id, char *ifname, void *data) --{ -- struct qbg22_imm *qbg = (struct qbg22_imm *)data; -- -- LLDPAD_DBG("%s:%s sender-id:%#x data_type:%d\n", __func__, ifname, -- sender_id, qbg->data_type); -- if (sender_id == LLDP_MOD_EVB22 && qbg->data_type == EVB22_TO_VDP22) -- return data_from_evb(ifname, &qbg->u.b); -- if (sender_id == LLDP_MOD_ECP22 && qbg->data_type == ECP22_TO_ULP) -- return data_from_ecp(ifname, &qbg->u.c); -- return 0; --} -- --/* -- * Remove a vdp22 element and delete the chain of active profiles. -- */ --static void vdp22_free_elem(struct vdp22 *vdp) --{ -- while (!LIST_EMPTY(&vdp->prof22_head)) { -- struct vsi22_profile *prof = LIST_FIRST(&vdp->prof22_head); -- -- free(prof); -- } -- LIST_REMOVE(vdp, entry); -- free(vdp); --} -- --/* -- * Disable the interface for VDP protocol support. -- */ --void vdp22_stop(char *ifname) --{ -- struct vdp22_user_data *vud; -- struct vdp22 *vdp; -- -- LLDPAD_DBG("%s:%s stop vdp\n", __func__, ifname); -- vud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_VDP22); -- if (!vud) { -- LLDPAD_ERR("%s:%s no VDP22 module\n", __func__, ifname); -- return; -- } -- vdp = vdp22_findif(ifname, vud); -- if (!vdp) { -- LLDPAD_ERR("%s:%s no VDP22 data\n", __func__, ifname); -- return; -- } -- vdp22_free_elem(vdp); --} -- --/* -- * vdp22_create - create data structure and initialize vdp protocol -- * @ifname: interface for which the vdp protocol is initialized -- * -- * returns NULL on error and an pointer to the vdp22 structure on success. -- * -- * finds the port to the interface name, sets up the receive handle for -- * incoming vdp frames and initializes the vdp rx and tx state machines. -- * To be called when a successful exchange of EVB TLVs has been -- * made and ECP protocols are supported by both sides. -- */ --static struct vdp22 *vdp22_create(const char *ifname, -- struct vdp22_user_data *eud) --{ -- struct vdp22 *vdp; -- -- vdp = calloc(1, sizeof *vdp); -- if (!vdp) { -- LLDPAD_ERR("%s:%s unable to allocate vdp protocol\n", __func__, -- ifname); -- return NULL; -- } -- strncpy(vdp->ifname, ifname, sizeof vdp->ifname); -- LIST_INIT(&vdp->prof22_head); -- LIST_INSERT_HEAD(&eud->head, vdp, entry); -- LLDPAD_DBG("%s:%s create vdp data\n", __func__, ifname); -- return vdp; --} -- --/* -- * Query the supported VDP protocol on an interface. -- */ --static struct vdp22 *vdp22_getvdp(const char *ifname) --{ -- struct vdp22_user_data *vud; -- struct vdp22 *vdp = NULL; -- -- vud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_VDP22); -- if (vud) -- vdp = vdp22_findif(ifname, vud); -- LLDPAD_DBG("%s:%s vdp %p\n", __func__, ifname, vdp); -- return vdp; --} -- --int vdp22_query(const char *ifname) --{ -- int rc = 0; -- -- if (vdp22_getvdp(ifname)) -- rc = 1; -- LLDPAD_DBG("%s:%s rc:%d\n", __func__, ifname, rc); -- return rc; --} -- --/* -- * Enable the interface for VDP protocol support. -- */ --void vdp22_start(const char *ifname) --{ -- struct vdp22_user_data *vud; -- struct vdp22 *vdp; -- -- LLDPAD_DBG("%s:%s start vdp\n", __func__, ifname); -- vud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_VDP22); -- if (!vud) { -- LLDPAD_ERR("%s:%s no VDP22 module\n", __func__, ifname); -- return; -- } -- vdp = vdp22_findif(ifname, vud); -- if (!vdp) -- vdp = vdp22_create(ifname, vud); --} -- --/* -- * Handle a VSI request from buddy. -- */ --int vdp22_request(struct vdpnl_vsi *vsi) --{ -- int rc = -ENODEV; -- LLDPAD_DBG("%s:%s rc:%d\n", __func__, vsi->ifname, rc); -- return rc; --} -- --/* -- * Remove all interface/agent specific vdp data. -- */ --static void vdp22_free_data(struct vdp22_user_data *ud) --{ -- if (ud) { -- while (!LIST_EMPTY(&ud->head)) { -- struct vdp22 *vd = LIST_FIRST(&ud->head); -- -- vdp22_free_elem(vd); -- } -- } --} -- --void vdp22_unregister(struct lldp_module *mod) --{ -- if (mod->data) { -- vdp22_free_data((struct vdp22_user_data *)mod->data); -- free(mod->data); -- } -- free(mod); -- LLDPAD_DBG("%s:done\n", __func__); --} -- --static const struct lldp_mod_ops vdp22_ops = { -- .lldp_mod_register = vdp22_register, -- .lldp_mod_unregister = vdp22_unregister, -- .lldp_mod_notify = vdp22_notify --}; -- --struct lldp_module *vdp22_register(void) --{ -- struct lldp_module *mod; -- struct vdp22_user_data *ud; -- -- mod = calloc(1, sizeof *mod); -- if (!mod) { -- LLDPAD_ERR("%s: failed to malloc module data\n", __func__); -- return NULL; -- } -- ud = calloc(1, sizeof *ud); -- if (!ud) { -- free(mod); -- LLDPAD_ERR("%s failed to malloc module user data\n", __func__); -- return NULL; -- } -- LIST_INIT(&ud->head); -- mod->id = LLDP_MOD_VDP22; -- mod->ops = &vdp22_ops; -- mod->data = ud; -- LLDPAD_DBG("%s:done\n", __func__); -- return mod; --} -diff --git a/qbg/lldp_vdpnl.c b/qbg/lldp_vdpnl.c -deleted file mode 100644 -index 4a117d6..0000000 ---- a/qbg/lldp_vdpnl.c -+++ /dev/null -@@ -1,502 +0,0 @@ --/****************************************************************************** -- -- Implementation of VDP according to IEEE 802.1Qbg -- (c) Copyright IBM Corp. 2013 -- -- Author(s): Thomas Richter -- -- This program is free software; you can redistribute it and/or modify it -- under the terms and conditions of the GNU General Public License, -- version 2, as published by the Free Software Foundation. -- -- This program is distributed in the hope it will be useful, but WITHOUT -- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -- more details. -- -- You should have received a copy of the GNU General Public License along with -- this program; if not, write to the Free Software Foundation, Inc., -- 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. -- -- The full GNU General Public License is included in this distribution in -- the file called "COPYING". -- --******************************************************************************/ -- --/* -- * Contains netlink message parsing for VDP protocol from libvirtd or other -- * buddies. -- */ -- --#include --#include --#include -- --#include -- --#include --#include --#include -- --#include "messages.h" --#include "lldp_vdp.h" --#include "lldp_vdp22.h" --#include "lldp_vdpnl.h" --#include "lldp_qbg_utils.h" --#include "lldp_rtnl.h" -- --static struct nla_policy ifla_vf_policy[IFLA_VF_MAX + 1] = { -- [IFLA_VF_MAC] = { .minlen = sizeof(struct ifla_vf_mac), -- .maxlen = sizeof(struct ifla_vf_mac)}, -- [IFLA_VF_VLAN] = { .minlen = sizeof(struct ifla_vf_vlan), -- .maxlen = sizeof(struct ifla_vf_vlan)}, --}; -- --static struct nla_policy ifla_port_policy[IFLA_PORT_MAX + 1] = { -- [IFLA_PORT_VF] = { .type = NLA_U32 }, -- [IFLA_PORT_PROFILE] = { .type = NLA_STRING }, -- [IFLA_PORT_VSI_TYPE] = { .minlen = sizeof(struct ifla_port_vsi) }, -- [IFLA_PORT_INSTANCE_UUID] = { .minlen = PORT_UUID_MAX, -- .maxlen = PORT_UUID_MAX, }, -- [IFLA_PORT_HOST_UUID] = { .minlen = PORT_UUID_MAX, -- .maxlen = PORT_UUID_MAX, }, -- [IFLA_PORT_REQUEST] = { .type = NLA_U8 }, -- [IFLA_PORT_RESPONSE] = { .type = NLA_U16 }, --}; -- --/* -- * Retrieve name of interface and its index value from the netlink messaage -- * and store it in the data structure. -- * The GETLINK message may or may not contain the IFLA_IFNAME attribute. -- * Return 0 on success and errno on error. -- */ --static int vdpnl_get(struct nlmsghdr *nlh, struct vdpnl_vsi *p) --{ -- struct nlattr *tb[IFLA_MAX + 1]; -- struct ifinfomsg *ifinfo; -- -- if (nlmsg_parse(nlh, sizeof(struct ifinfomsg), -- (struct nlattr **)&tb, IFLA_MAX, NULL)) { -- LLDPAD_ERR("%s: error parsing GETLINK request\n", __func__); -- return -EINVAL; -- } -- -- ifinfo = (struct ifinfomsg *)NLMSG_DATA(nlh); -- p->ifindex = ifinfo->ifi_index; -- if (tb[IFLA_IFNAME]) { -- memcpy(p->ifname, (char *)RTA_DATA(tb[IFLA_IFNAME]), -- sizeof p->ifname); -- } else if (!if_indextoname(p->ifindex, p->ifname)) { -- LLDPAD_ERR("%s: ifindex %d without interface name\n", __func__, -- p->ifindex); -- return -EINVAL; -- } -- LLDPAD_DBG("%s: IFLA_IFNAME:%s ifindex:%d\n", __func__, p->ifname, -- p->ifindex); -- return 0; --} -- --static void vdpnl_show(struct vdpnl_vsi *vsi) --{ -- char instance[VDP_UUID_STRLEN + 2]; -- struct vdpnl_mac *mac; -- int i; -- -- LLDPAD_DBG("%s: IFLA_IFNAME=%s index:%d\n", __func__, vsi->ifname, -- vsi->ifindex); -- for (i = 0, mac = vsi->maclist; i < vsi->macsz; ++i, ++mac) { -- LLDPAD_DBG("%s: IFLA_VF_MAC=%2x:%2x:%2x:%2x:%2x:%2x\n", -- __func__, mac->mac[0], mac->mac[1], mac->mac[2], -- mac->mac[3], mac->mac[4], mac->mac[5]); -- LLDPAD_DBG("%s: IFLA_VF_VLAN=%d\n", __func__, mac->vlan); -- } -- LLDPAD_DBG("%s: IFLA_PORT_VSI_TYPE=mgr_id:%d type_id:%ld " -- "typeid_version:%d\n", -- __func__, vsi->vsi_mgrid, vsi->vsi_typeid, -- vsi->vsi_typeversion); -- vdp_uuid2str(vsi->vsi_uuid, instance, sizeof(instance)); -- LLDPAD_DBG("%s: IFLA_PORT_INSTANCE_UUID=%s\n", __func__, instance); -- LLDPAD_DBG("%s: IFLA_PORT_REQUEST=%d\n", __func__, vsi->request); -- LLDPAD_DBG("%s: IFLA_PORT_RESPONSE=%d\n", __func__, vsi->response); --} -- --/* -- * Parse the IFLA_IFLA_VF_PORTIFLA_VF_PORTS block of the netlink message. -- * Return zero on success and errno else. -- */ --static int vdpnl_vfports(struct nlattr *vfports, struct vdpnl_vsi *vsi) --{ -- char instance[VDP_UUID_STRLEN + 2]; -- struct nlattr *tb_vf_ports, *tb3[IFLA_PORT_MAX + 1]; -- int rem; -- -- if (!vfports) { -- LLDPAD_DBG("%s: FOUND NO IFLA_VF_PORTS\n", __func__); -- return -EINVAL; -- } -- -- nla_for_each_nested(tb_vf_ports, vfports, rem) { -- if (nla_type(tb_vf_ports) != IFLA_VF_PORT) { -- LLDPAD_DBG("%s: not a IFLA_VF_PORT skipping\n", -- __func__); -- continue; -- } -- if (nla_parse_nested(tb3, IFLA_PORT_MAX, tb_vf_ports, -- ifla_port_policy)) { -- LLDPAD_ERR("%s: IFLA_PORT_MAX parsing failed\n", -- __func__); -- return -EINVAL; -- } -- if (tb3[IFLA_PORT_VF]) -- LLDPAD_DBG("%s: IFLA_PORT_VF=%d\n", __func__, -- *(uint32_t *) RTA_DATA(tb3[IFLA_PORT_VF])); -- if (tb3[IFLA_PORT_PROFILE]) -- LLDPAD_DBG("%s: IFLA_PORT_PROFILE=%s\n", __func__, -- (char *)RTA_DATA(tb3[IFLA_PORT_PROFILE])); -- if (tb3[IFLA_PORT_HOST_UUID]) { -- unsigned char *uuid; -- -- uuid = (unsigned char *) -- RTA_DATA(tb3[IFLA_PORT_HOST_UUID]); -- vdp_uuid2str(uuid, instance, sizeof(instance)); -- LLDPAD_DBG("%s: IFLA_PORT_HOST_UUID=%s\n", __func__, -- instance); -- } -- if (tb3[IFLA_PORT_VSI_TYPE]) { -- struct ifla_port_vsi *pvsi; -- int tid = 0; -- -- pvsi = (struct ifla_port_vsi *) -- RTA_DATA(tb3[IFLA_PORT_VSI_TYPE]); -- tid = pvsi->vsi_type_id[2] << 16 | -- pvsi->vsi_type_id[1] << 8 | -- pvsi->vsi_type_id[0]; -- vsi->vsi_mgrid = pvsi->vsi_mgr_id; -- vsi->vsi_typeversion = pvsi->vsi_type_version; -- vsi->vsi_typeid = tid; -- } -- if (tb3[IFLA_PORT_INSTANCE_UUID]) { -- unsigned char *uuid = (unsigned char *) -- RTA_DATA(tb3[IFLA_PORT_INSTANCE_UUID]); -- memcpy(vsi->vsi_uuid, uuid, sizeof vsi->vsi_uuid); -- } -- if (tb3[IFLA_PORT_REQUEST]) -- vsi->request = -- *(uint8_t *) RTA_DATA(tb3[IFLA_PORT_REQUEST]); -- if (tb3[IFLA_PORT_RESPONSE]) -- vsi->response = -- *(uint16_t *) RTA_DATA(tb3[IFLA_PORT_RESPONSE]); -- } -- return 0; --} -- --/* -- * Parse the IFLA_VFINFO_LIST block of the netlink message. -- * Return zero on success and errno else. -- */ --static int vdpnl_vfinfolist(struct nlattr *vfinfolist, struct vdpnl_vsi *vsi) --{ -- struct nlattr *le1, *vf[IFLA_VF_MAX + 1]; -- int rem; -- -- if (!vfinfolist) { -- LLDPAD_ERR("%s: IFLA_VFINFO_LIST missing\n", __func__); -- return -EINVAL; -- } -- nla_for_each_nested(le1, vfinfolist, rem) { -- if (nla_type(le1) != IFLA_VF_INFO) { -- LLDPAD_ERR("%s: parsing of IFLA_VFINFO_LIST failed\n", -- __func__); -- return -EINVAL; -- } -- if (nla_parse_nested(vf, IFLA_VF_MAX, le1, ifla_vf_policy)) { -- LLDPAD_ERR("%s: parsing of IFLA_VF_INFO failed\n", -- __func__); -- return -EINVAL; -- } -- -- if (vf[IFLA_VF_MAC]) { -- struct ifla_vf_mac *mac = RTA_DATA(vf[IFLA_VF_MAC]); -- -- memcpy(vsi->maclist->mac, mac->mac, ETH_ALEN); -- } -- -- if (vf[IFLA_VF_VLAN]) { -- struct ifla_vf_vlan *vlan = RTA_DATA(vf[IFLA_VF_VLAN]); -- -- vsi->maclist->vlan = vlan->vlan; -- } -- } -- return 0; --} -- --/* -- * Convert the SETLINK message into internal data structure. -- */ --static int vdpnl_set(struct nlmsghdr *nlh, struct vdpnl_vsi *vsi) --{ -- struct nlattr *tb[IFLA_MAX + 1]; -- struct ifinfomsg *ifinfo = (struct ifinfomsg *)NLMSG_DATA(nlh); -- int rc; -- -- if (nlmsg_parse(nlh, sizeof(struct ifinfomsg), -- (struct nlattr **)&tb, IFLA_MAX, NULL)) { -- LLDPAD_ERR("%s: error parsing SETLINK request\n", __func__); -- return -EINVAL; -- } -- -- vsi->ifindex = ifinfo->ifi_index; -- if (tb[IFLA_IFNAME]) -- strncpy(vsi->ifname, (char *)RTA_DATA(tb[IFLA_IFNAME]), -- sizeof vsi->ifname); -- else { -- if (!if_indextoname(ifinfo->ifi_index, vsi->ifname)) { -- LLDPAD_ERR("%s: can not find name for interface %i\n", -- __func__, ifinfo->ifi_index); -- return -ENXIO; -- } -- } -- vsi->req_pid = nlh->nlmsg_pid; -- vsi->req_seq = nlh->nlmsg_seq; -- rc = vdpnl_vfinfolist(tb[IFLA_VFINFO_LIST], vsi); -- if (!rc) { -- rc = vdpnl_vfports(tb[IFLA_VF_PORTS], vsi); -- if (!rc) -- vdpnl_show(vsi); -- } -- return rc; --} -- --/* -- * Return the error code (can be zero) to the sender. Assume buffer is -- * large enough to hold the information. -- * Construct the netlink response on the input buffer. -- */ --static int vdpnl_error(int err, struct nlmsghdr *from, size_t len) --{ -- struct nlmsgerr nlmsgerr; -- -- LLDPAD_DBG("%s: error %d\n", __func__, err); -- nlmsgerr.error = err; -- nlmsgerr.msg = *from; -- memset(from, 0, len); -- from->nlmsg_type = NLMSG_ERROR; -- from->nlmsg_seq = nlmsgerr.msg.nlmsg_seq; -- from->nlmsg_pid = nlmsgerr.msg.nlmsg_pid; -- from->nlmsg_flags = 0; -- from->nlmsg_len = NLMSG_SPACE(sizeof nlmsgerr); -- memcpy(NLMSG_DATA(from), &nlmsgerr, sizeof nlmsgerr); -- return from->nlmsg_len; --} -- --/* -- * Build the first part of the netlink reply message for status inquiry. -- * It contains the header and the ifinfo data structure. -- */ --static void vdpnl_reply1(struct vdpnl_vsi *p, struct nlmsghdr *nlh, size_t len) --{ -- struct nlmsghdr to; -- struct ifinfomsg ifinfo; -- -- to.nlmsg_type = NLMSG_DONE; -- to.nlmsg_seq = nlh->nlmsg_seq; -- to.nlmsg_pid = nlh->nlmsg_pid; -- to.nlmsg_flags = 0; -- to.nlmsg_len = NLMSG_SPACE(sizeof ifinfo); -- -- memset(&ifinfo, 0, sizeof ifinfo); -- ifinfo.ifi_index = p->ifindex; -- memset(nlh, 0, len); -- memcpy(nlh, &to, sizeof to); -- memcpy(NLMSG_DATA(nlh), &ifinfo, sizeof ifinfo); --} -- --/* -- * Build the variable part of the netlink reply message for status inquiry. -- * It contains the UUID and the response field for the VSI profile. -- */ --static void vdpnl_reply2(struct vdpnl_vsi *p, struct nlmsghdr *nlh) --{ -- char instance[VDP_UUID_STRLEN + 2]; -- -- mynla_put(nlh, IFLA_PORT_INSTANCE_UUID, sizeof p->vsi_uuid, -- p->vsi_uuid); -- vdp_uuid2str(p->vsi_uuid, instance, sizeof instance); -- LLDPAD_DBG("%s: IFLA_PORT_INSTANCE_UUID=%s\n", __func__, instance); -- mynla_put_u32(nlh, IFLA_PORT_VF, PORT_SELF_VF); -- LLDPAD_DBG("%s: IFLA_PORT_VF=%d\n", __func__, PORT_SELF_VF); -- if (p->response != VDP_RESPONSE_NO_RESPONSE) { -- mynla_put_u16(nlh, IFLA_PORT_RESPONSE, p->response); -- LLDPAD_DBG("%s: IFLA_PORT_RESPONSE=%d\n", __func__, -- p->response); -- } --} -- --/* -- * Extract the interface name and loop over all VSI profile entries. -- * Find UUID and response field for each active profile and construct a -- * netlink response message. -- * -- * Return message size. -- */ --static int vdpnl_getlink(struct nlmsghdr *nlh, size_t len) --{ -- struct vdpnl_vsi p; -- int i = 0, rc; -- struct nlattr *vf_ports, *vf_port; -- -- memset(&p, 0, sizeof p); -- rc = vdpnl_get(nlh, &p); -- if (rc) -- return vdpnl_error(rc, nlh, len); -- vdpnl_reply1(&p, nlh, len); -- vf_ports = mynla_nest_start(nlh, IFLA_VF_PORTS); -- vf_port = mynla_nest_start(nlh, IFLA_VF_PORT); -- /* Iterate over all profiles */ -- do { -- rc = vdp_status(++i, &p); -- if (rc == 1) -- vdpnl_reply2(&p, nlh); -- if (rc == 0) { -- mynla_nest_end(nlh, vf_port); -- mynla_nest_end(nlh, vf_ports); -- } -- } while (rc == 1); -- if (rc < 0) -- return vdpnl_error(rc, nlh, len); -- LLDPAD_DBG("%s: message-size:%d\n", __func__, nlh->nlmsg_len); -- return nlh->nlmsg_len; --} -- --/* -- * Parse incoming command and create a data structure to store the VSI data. -- */ --static int vdpnl_setlink(struct nlmsghdr *nlh, size_t len) --{ -- int rc = -ENOMEM; -- struct vdpnl_mac mac; -- struct vdpnl_vsi p; -- -- memset(&p, 0, sizeof p); -- p.macsz = 1; -- p.maclist = &mac; -- rc = vdpnl_set(nlh, &p); -- if (!rc) -- rc = vdp22_query(p.ifname) ? vdp22_request(&p) -- : vdp_request(&p); -- return vdpnl_error(rc, nlh, len); --} -- --/* -- * Process the netlink message. Parameters are the socket, the message and -- * its length in bytes. -- * The message buffer 'buf' is used for parsing the incoming message. -- * After parsing and decoding, the outgoing message is stored in 'buf'. -- * -- * Returns: -- * < 0: Errno number when message parsing failed. -- * == 0: Message ok and no response. -- * > 0: Message ok and response returned in buf parameter. Returns bytes -- * of response. -- */ --int vdpnl_recv(unsigned char *buf, size_t buflen) --{ -- struct nlmsghdr *nlh = (struct nlmsghdr *)buf; -- -- LLDPAD_DBG("%s: buflen:%zd nlh.nl_pid:%d nlh_type:%d nlh_seq:%d " -- "nlh_len:%d\n", __func__, buflen, nlh->nlmsg_pid, -- nlh->nlmsg_type, nlh->nlmsg_seq, nlh->nlmsg_len); -- -- switch (nlh->nlmsg_type) { -- case RTM_SETLINK: -- return vdpnl_setlink(nlh, buflen); -- case RTM_GETLINK: -- return vdpnl_getlink(nlh, buflen); -- default: -- LLDPAD_ERR("%s: unknown type %d\n", __func__, nlh->nlmsg_type); -- } -- return -ENODEV; --} -- --/* -- * Add one entry in the list of MAC,VLAN pairs. -- */ --static void add_pair(struct vdpnl_mac *mac, struct nlmsghdr *nlh) --{ -- struct nlattr *vfinfo; -- struct ifla_vf_mac ifla_vf_mac = { -- .vf = PORT_SELF_VF, -- .mac = { 0, } -- }; -- struct ifla_vf_vlan ifla_vf_vlan = { -- .vf = PORT_SELF_VF, -- .vlan = mac->vlan, -- .qos = mac->qos -- }; -- -- vfinfo = mynla_nest_start(nlh, IFLA_VF_INFO); -- memcpy(ifla_vf_mac.mac, mac->mac, sizeof mac->mac); -- mynla_put(nlh, IFLA_VF_MAC, sizeof ifla_vf_mac, &ifla_vf_mac); -- mynla_put(nlh, IFLA_VF_VLAN, sizeof ifla_vf_vlan, &ifla_vf_vlan); -- mynla_nest_end(nlh, vfinfo); --} -- --/* -- * Walk along the MAC,VLAN ID list and add each entry into the message. -- */ --static void add_mac_vlan(struct vdpnl_vsi *vsi, struct nlmsghdr *nlh) --{ -- struct nlattr *vfinfolist; -- int i; -- -- vfinfolist = mynla_nest_start(nlh, IFLA_VFINFO_LIST); -- for (i = 0; i < vsi->macsz; ++i) -- add_pair(&vsi->maclist[i], nlh); -- mynla_nest_end(nlh, vfinfolist); --} -- --/* -- * Build an unsolicited netlink message to the VSI requestor. The originator -- * is the switch abondoning the VSI profile. -- * Assumes the messages fits into an 4KB buffer. -- * Returns the message size in bytes. -- */ --int vdpnl_send(struct vdpnl_vsi *vsi) --{ -- unsigned char buf[MAX_PAYLOAD]; -- struct nlmsghdr *nlh = (struct nlmsghdr *)buf; -- struct nlattr *vf_ports, *vf_port; -- struct ifinfomsg ifinfo; -- struct ifla_port_vsi portvsi; -- -- memset(buf, 0, sizeof buf); -- nlh->nlmsg_pid = getpid(); -- nlh->nlmsg_seq = vsi->req_seq; -- nlh->nlmsg_type = RTM_SETLINK; -- nlh->nlmsg_len = NLMSG_SPACE(sizeof ifinfo); -- -- memset(&ifinfo, 0, sizeof ifinfo); -- ifinfo.ifi_index = vsi->ifindex; -- memcpy(NLMSG_DATA(nlh), &ifinfo, sizeof ifinfo); -- mynla_put(nlh, IFLA_IFNAME, 1 + strlen(vsi->ifname), vsi->ifname); -- -- add_mac_vlan(vsi, nlh); -- portvsi.vsi_mgr_id = vsi->vsi_mgrid; -- portvsi.vsi_type_id[0] = vsi->vsi_typeid & 0xff; -- portvsi.vsi_type_id[1] = (vsi->vsi_typeid >> 8) & 0xff; -- portvsi.vsi_type_id[2] = (vsi->vsi_typeid >> 16) & 0xff; -- portvsi.vsi_type_version = vsi->vsi_typeversion; -- vf_ports = mynla_nest_start(nlh, IFLA_VF_PORTS); -- vf_port = mynla_nest_start(nlh, IFLA_VF_PORT); -- mynla_put(nlh, IFLA_PORT_VSI_TYPE, sizeof portvsi, &portvsi); -- mynla_put(nlh, IFLA_PORT_INSTANCE_UUID, PORT_UUID_MAX, vsi->vsi_uuid); -- mynla_put_u32(nlh, IFLA_PORT_VF, PORT_SELF_VF); -- mynla_put_u16(nlh, IFLA_PORT_REQUEST, vsi->request); -- mynla_nest_end(nlh, vf_port); -- mynla_nest_end(nlh, vf_ports); -- vdpnl_show(vsi); -- LLDPAD_DBG("%s: nlh.nl_pid:%d nlh_type:%d nlh_seq:%d nlh_len:%d\n", -- __func__, nlh->nlmsg_pid, nlh->nlmsg_type, nlh->nlmsg_seq, -- nlh->nlmsg_len); -- return event_trigger(nlh, vsi->req_pid); --} -diff --git a/qbg/vdp.c b/qbg/vdp.c -new file mode 100644 -index 0000000..f522f91 ---- /dev/null -+++ b/qbg/vdp.c -@@ -0,0 +1,1906 @@ -+/****************************************************************************** -+ -+ Implementation of VDP according to IEEE 802.1Qbg -+ (c) Copyright IBM Corp. 2010, 2012 -+ -+ Author(s): Jens Osterkamp -+ Author(s): Thomas Richter -+ -+ This program is free software; you can redistribute it and/or modify it -+ under the terms and conditions of the GNU General Public License, -+ version 2, as published by the Free Software Foundation. -+ -+ This program is distributed in the hope it will be useful, but WITHOUT -+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ more details. -+ -+ You should have received a copy of the GNU General Public License along with -+ this program; if not, write to the Free Software Foundation, Inc., -+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. -+ -+ The full GNU General Public License is included in this distribution in -+ the file called "COPYING". -+ -+******************************************************************************/ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "lldp.h" -+#include "qbg_vdp.h" -+#include "qbg_vdpnl.h" -+#include "eloop.h" -+#include "lldp_evb.h" -+#include "messages.h" -+#include "config.h" -+#include "lldp_tlv.h" -+#include "qbg_vdp_cmds.h" -+#include "qbg_utils.h" -+#include "lldp_mand_clif.h" -+ -+/* Define Module id. Must match with value in lldp_vdp_clif.c */ -+#define LLDP_MOD_VDP02 ((LLDP_MOD_VDP << 8) | LLDP_VDP_SUBTYPE) -+ -+static const char * const vsi_responses[] = { -+ [VDP_RESPONSE_SUCCESS] = "success", -+ [VDP_RESPONSE_INVALID_FORMAT] = "invalid format", -+ [VDP_RESPONSE_INSUFF_RESOURCES] = "insufficient resources", -+ [VDP_RESPONSE_UNUSED_VTID] = "unused VTID", -+ [VDP_RESPONSE_VTID_VIOLATION] = "VTID violation", -+ [VDP_RESPONSE_VTID_VER_VIOLATION] = "VTID version violation", -+ [VDP_RESPONSE_OUT_OF_SYNC] = "out of sync", -+ [VDP_RESPONSE_UNKNOWN] = "unknown response", -+ [VDP_RESPONSE_NO_RESPONSE] = "no response", -+}; -+ -+const char * const vsi_states[] = { -+ [VSI_UNASSOCIATED] = "VSI_UNASSOCIATED", -+ [VSI_ASSOC_PROCESSING] = "VSI_ASSOC_PROCESSING", -+ [VSI_ASSOCIATED] = "VSI_ASSOCIATED", -+ [VSI_PREASSOC_PROCESSING] = "VSI_PREASSOC_PROCESSING", -+ [VSI_PREASSOCIATED] = "VSI_PREASSOCIATED", -+ [VSI_DEASSOC_PROCESSING] = "VSI_DEASSOC_PROCESSING", -+ [VSI_EXIT] = "VSI_EXIT", -+}; -+ -+int vdp_start_localchange_timer(struct vsi_profile *p); -+int vdp_remove_profile(struct vsi_profile *profile); -+int vdp_trigger(struct vsi_profile *profile); -+ -+void vdp_trace_profile(struct vsi_profile *p) -+{ -+ char instance[VDP_UUID_STRLEN + 2]; -+ struct mac_vlan *mac_vlan; -+ -+ vdp_uuid2str(p->instance, instance, sizeof(instance)); -+ -+ LLDPAD_DBG("profile:%p mode:%d response:%d state:%d (%s) no_nlmsg:%d" -+ " txmit:%i" -+ " mgrid:%d id:%d(%#x) version:%d %s format:%d entries:%d\n", -+ p, p->mode, p->response, p->state, vsi_states[p->state], -+ p->no_nlmsg, p->txmit, -+ p->mgrid, p->id, p->id, p->version, instance, p->format, -+ p->entries); -+ LIST_FOREACH(mac_vlan, &p->macvid_head, entry) { -+ char macbuf[MAC_ADDR_STRLEN + 1]; -+ -+ mac2str(mac_vlan->mac, macbuf, MAC_ADDR_STRLEN); -+ LLDPAD_DBG("profile:%p mac:%s vlan:%d qos:%d pid:%d seq:%d\n", -+ p, macbuf, mac_vlan->vlan, mac_vlan->qos, -+ mac_vlan->req_pid, mac_vlan->req_seq); -+ } -+} -+ -+struct vsi_profile *vdp_alloc_profile() -+{ -+ struct vsi_profile *prof; -+ -+ prof = calloc(1, sizeof *prof); -+ if (prof) -+ LIST_INIT(&prof->macvid_head); -+ return prof; -+} -+ -+/* -+ * vdp_remove_macvlan - remove all mac/vlan pairs in the profile -+ * @profile: profile to remove -+ * -+ * Remove all allocated pairs on the profile. -+ */ -+static void vdp_remove_macvlan(struct vsi_profile *profile) -+{ -+ struct mac_vlan *p; -+ -+ while ((p = LIST_FIRST(&profile->macvid_head))) { -+ LIST_REMOVE(p, entry); -+ free(p); -+ } -+} -+ -+void vdp_delete_profile(struct vsi_profile *prof) -+{ -+ vdp_remove_macvlan(prof); -+ free(prof); -+} -+ -+/* vdp_profile_equal - checks for equality of 2 profiles -+ * @p1: profile 1 -+ * @p2: profile 2 -+ * -+ * returns true if equal, false if not -+ * -+ * compares mgrid, id, version, instance 2 vsi profiles to find -+ * out if they are equal. -+ */ -+static bool vdp_profile_equal(struct vsi_profile *p1, struct vsi_profile *p2) -+{ -+ if (p1->mgrid != p2->mgrid) -+ return false; -+ -+ if (p1->id != p2->id) -+ return false; -+ -+ if (p1->version != p2->version) -+ return false; -+ -+ if (memcmp(p1->instance, p2->instance, 16)) -+ return false; -+ -+ return true; -+} -+ -+/* -+ * vdp_find_profile - Find a profile in the list of profiles already allocated -+ * -+ * Returns pointer to already allocated profile in list, 0 if not. -+ */ -+ -+struct vsi_profile *vdp_find_profile(struct vdp_data *vd, -+ struct vsi_profile *thisone) -+{ -+ struct vsi_profile *p; -+ -+ LIST_FOREACH(p, &vd->profile_head, profile) { -+ if (vdp_profile_equal(p, thisone)) -+ return p; -+ } -+ return 0; -+} -+ -+/* vdp_data - searches vdp_data in the list of modules for this port -+ * @ifname: interface name to search for -+ * -+ * returns vdp_data on success, NULL on error -+ * -+ * searches the list of user_data for the VDP module user_data. -+ */ -+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); -+ if (ud) { -+ LIST_FOREACH(vd, &ud->head, entry) { -+ if (!strncmp(ifname, vd->ifname, IFNAMSIZ)) -+ return vd; -+ } -+ } -+ return NULL; -+} -+ -+/* vdp_free_tlv - free tlv in vdp_data -+ * @vd: vdp_data -+ * -+ * no return value -+ * -+ * frees up tlv in vdp_data. used in vdp_free_data. -+ */ -+static void vdp_free_tlv(struct vdp_data *vd) -+{ -+ if (vd) { -+ FREE_UNPKD_TLV(vd, vdp); -+ } -+} -+ -+/* vdp_free_data - frees up vdp data -+ * @ud: user data structure -+ * -+ * no return value -+ * -+ * removes vd_structure from the user_data list. frees up tlv in vdp_data. -+ * used in vdp_unregister. -+ */ -+static void vdp_free_data(struct vdp_user_data *ud) -+{ -+ struct vdp_data *vd; -+ if (ud) { -+ while (!LIST_EMPTY(&ud->head)) { -+ vd = LIST_FIRST(&ud->head); -+ LIST_REMOVE(vd, entry); -+ vdp_free_tlv(vd); -+ free(vd); -+ } -+ } -+} -+ -+/* vdp_response2str - map response to string -+ * @response: response received -+ * -+ * no return value -+ * -+ * maps VDP response received for a profile to human readable string for -+ * printing. -+ */ -+const char *vdp_response2str(int response) -+{ -+ if ((response >= VDP_RESPONSE_SUCCESS) && -+ (response <= VDP_RESPONSE_OUT_OF_SYNC)) -+ return vsi_responses[response]; -+ -+ if (response == VDP_RESPONSE_NO_RESPONSE) -+ return vsi_responses[VDP_RESPONSE_NO_RESPONSE]; -+ -+ return vsi_responses[VDP_RESPONSE_UNKNOWN]; -+} -+ -+/* vdp_ack_profiles - clear ackReceived for all profiles with seqnr -+ * @vd: vd for the interface -+ * @seqnr: seqnr the ack has been received with -+ * -+ * no return value -+ * -+ * clear the ackReceived for all profiles which have been sent out with -+ * the seqnr that we now have received the ecp ack for. -+ */ -+void vdp_ack_profiles(struct vdp_data *vd, int seqnr) -+{ -+ struct vsi_profile *p; -+ -+ LIST_FOREACH(p, &vd->profile_head, profile) { -+ if (p->seqnr == seqnr) { -+ p->ackReceived = false; -+ p->txmit = true; -+ } -+ } -+ -+} -+ -+/* vdp_vsis - find out number of VSIs for this interface -+ * @ifname: interfac name -+ * -+ * returns the number of VSIs -+ * -+ * walk through the list of VSIs and return the count. -+ */ -+int vdp_vsis(char *ifname) -+{ -+ struct vdp_data *vd; -+ struct vsi_profile *p; -+ int count = 0; -+ -+ vd = vdp_data(ifname); -+ -+ if (!vd) -+ return 0; -+ -+ LIST_FOREACH(p, &vd->profile_head, profile) { -+ count++; -+ } -+ -+ return count; -+} -+ -+/* vdp_vsis_pending - check for pending VSIs -+ * @vd: vdp data for the interface -+ * -+ * returns the number of VSIs found -+ * -+ * walk through the list of VSIs and return the count. -+ */ -+int vdp_vsis_pending(struct vdp_data *vd) -+{ -+ struct vsi_profile *p; -+ int count = 0; -+ -+ LIST_FOREACH(p, &vd->profile_head, profile) { -+ if (p->localChange && (p->txmit == false)) -+ count++; -+ } -+ -+ return count; -+} -+ -+/* vdp_somethingChangedLocal - set flag if profile has changed -+ * @profile: profile to set the flag for -+ * @flag: set the flag to true or false -+ * -+ * no return value -+ * -+ * set the localChange flag with a mode to indicate a profile has changed. -+ * used next time when a ecpdu with profiles is sent out. -+ */ -+void vdp_somethingChangedLocal(struct vsi_profile *profile, bool flag) -+{ -+ LLDPAD_DBG("%s: setting profile->localChange to %s\n", -+ __func__, (flag == true) ? "true" : "false"); -+ -+ profile->localChange = flag; -+ -+ if (flag == true) -+ vdp_start_localchange_timer(profile); -+} -+ -+/* vdp_keepaliveTimer_expired - checks for expired ack timer -+ * @profile: profile to be checked -+ * -+ * returns true or false -+ * -+ * returns value of profile->keepaliveTimerExpired, true if ack timer has -+ * expired, * false otherwise. -+ */ -+static bool vdp_keepaliveTimer_expired(struct vsi_profile *profile) -+{ -+ return (profile->keepaliveTimer == 0); -+} -+ -+/* vdp_ackTimer_expired - checks for expired ack timer -+ * @profile: profile to be checked -+ * -+ * returns true or false -+ * -+ * returns value of profile->ackTimerExpired, true if ack timer has expired, -+ * false otherwise. -+ */ -+static bool vdp_ackTimer_expired(struct vsi_profile *profile) -+{ -+ return (profile->ackTimer == 0); -+} -+ -+/* vdp_localchange_handler - triggers in case of vdp_ack or on vdp -+ * localchange -+ * @eloop_data: data structure of event loop -+ * @user_ctx: user context, vdp_data here -+ * -+ * no return value -+ * -+ * called from vdp_somethingchangedlocal or vdp_ack_profiles when a change is -+ * pending. Calls the VDP station state machine. This detour is taken -+ * to not having to call the vdp code from the ecp state machine. Instead, we -+ * return to the event loop, giving other code a chance to do work. -+ */ -+void vdp_localchange_handler(UNUSED void *eloop_data, void *user_ctx) -+{ -+ struct vsi_profile *p; -+ -+ p = (struct vsi_profile *) user_ctx; -+ -+ if ((p->ackReceived) || (p->localChange)) { -+ LLDPAD_DBG("%s: p->localChange %i p->ackReceived %i\n", -+ __func__, p->localChange, p->ackReceived); -+ vdp_vsi_sm_station(p); -+ } -+} -+ -+/* -+ * vdp_stop - cancel the VDP localchange timer -+ * -+ * returns 0 on success, -1 on error -+ * -+ * cancels the VPP localchange timer when a profile has been deleted. -+ */ -+int vdp_stop_localchange_timer(struct vsi_profile *p) -+{ -+ return eloop_cancel_timeout(vdp_localchange_handler, NULL, (void *) p); -+} -+ -+/* vdp_start_localchange_timer - starts the VDP localchange timer -+ * @vd: vdp_data for the interface -+ * -+ * returns 0 on success, -1 on error -+ * -+ * starts the VPP localchange timer when a localchange has been signaled from -+ * the VDP state machine. -+ */ -+int vdp_start_localchange_timer(struct vsi_profile *p) -+{ -+ unsigned int usecs; -+ -+ usecs = VDP_LOCALCHANGE_TIMEOUT; -+ -+ return eloop_register_timeout(0, usecs, vdp_localchange_handler, NULL, -+ (void *) p); -+} -+ -+/* vdp_ack_timeout_handler - handles the ack timer expiry -+ * @eloop_data: data structure of event loop -+ * @user_ctx: user context, vdp_data here -+ * -+ * no return value -+ * -+ * called when the VDP ack timer for a profile has expired. -+ * Calls the VDP station state machine for the profile. -+ */ -+void vdp_ack_timeout_handler(UNUSED void *eloop_data, void *user_ctx) -+{ -+ struct vsi_profile *p = (struct vsi_profile *) user_ctx; -+ -+ if (p->ackTimer > 0) -+ p->ackTimer -= VDP_ACK_TIMER_DEFAULT; -+ -+ if (vdp_ackTimer_expired(p)) { -+ LLDPAD_DBG("%s: profile %#02x vdp_ackTimer_expired %i" -+ " p->ackReceived %i\n", __func__, p->instance[15], -+ vdp_ackTimer_expired(p), p->ackReceived); -+ vdp_vsi_sm_station(p); -+ } -+} -+ -+/* vdp_start_ack_timer - starts the VDP profile ack timer -+ * @profile: vsi_profile -+ * -+ * returns 0 on success, -1 on error -+ * -+ * starts the VDP profile ack timer when a profile has been handed to ecp for -+ * transmission. -+ */ -+static int vdp_start_ackTimer(struct vsi_profile *profile) -+{ -+ unsigned int usecs; -+ -+ usecs = VDP_ACK_TIMER_DEFAULT; -+ -+ profile->ackTimer = VDP_ACK_TIMER_DEFAULT; -+ -+ LLDPAD_DBG("%s: %s starting ack timer for %#02x (%i)\n", -+ __func__, profile->port->ifname, -+ profile->instance[15], profile->ackTimer); -+ -+ return eloop_register_timeout(0, usecs, vdp_ack_timeout_handler, NULL, -+ (void *)profile); -+} -+ -+/* vdp_stop_ackTimer - stops the VDP profile ack timer -+ * @vd: vdp_data for the interface -+ * -+ * returns the number of removed handlers -+ * -+ * stops the VDP tck imer. Used e.g. when the host interface goes down. -+ */ -+static int vdp_stop_ackTimer(struct vsi_profile *profile) -+{ -+ LLDPAD_DBG("%s: %s stopping ack timer for %#02x (%i)\n", __func__, -+ profile->port->ifname, profile->instance[15], -+ profile->ackTimer); -+ -+ return eloop_cancel_timeout(vdp_ack_timeout_handler, NULL, -+ (void *)profile); -+} -+ -+/* vdp_keepalive_timeout_handler - handles the keepalive timer expiry -+ * @eloop_data: data structure of event loop -+ * @user_ctx: user context, vdp_data here -+ * -+ * no return value -+ * -+ * called when the VDP keepalive timer for a profile has expired. -+ * Calls the VDP station state machine for the profile. -+ */ -+void vdp_keepalive_timeout_handler(UNUSED void *eloop_data, void *user_ctx) -+{ -+ struct vsi_profile *p = (struct vsi_profile *) user_ctx; -+ -+ if (p->keepaliveTimer > 0) -+ p->keepaliveTimer -= VDP_KEEPALIVE_TIMER_DEFAULT; -+ -+ if (vdp_keepaliveTimer_expired(p)) { -+ LLDPAD_DBG("%s: profile %#02x vdp_keepaliveTimer_expired %i" -+ " p->ackReceived %i p->ackReceived %i\n", __func__, -+ p->instance[15], vdp_keepaliveTimer_expired(p), -+ p->ackReceived, p->ackReceived); -+ vdp_vsi_sm_station(p); -+ } -+} -+ -+/* vdp_start_keepalive_timer - starts the VDP profile keepalive timer -+ * @vd: vdp_data for the interface -+ * -+ * returns 0 on success, -1 on error -+ * -+ * starts the VDP profile keepalive timer when a profile has been handed to -+ * ecp for transmission. -+ */ -+static int vdp_start_keepaliveTimer(struct vsi_profile *profile) -+{ -+ unsigned int usecs; -+ -+ usecs = VDP_KEEPALIVE_TIMER_DEFAULT; -+ -+ profile->keepaliveTimer = VDP_KEEPALIVE_TIMER_DEFAULT; -+ -+ LLDPAD_DBG("%s: %s starting keepalive timer for %#02x (%i)\n", -+ __func__, profile->port->ifname, profile->instance[15], -+ profile->keepaliveTimer); -+ -+ return eloop_register_timeout(0, usecs, vdp_keepalive_timeout_handler, -+ NULL, (void *) profile); -+} -+ -+/* vdp_stop_keepalive_timer - stops the VDP profile keepalive timer -+ * @vd: vdp_data for the interface -+ * -+ * returns the number of removed handlers -+ * -+ * stops the VDP tck imer. Used e.g. when the host interface goes down. -+ */ -+static int vdp_stop_keepaliveTimer(struct vsi_profile *profile) -+{ -+ profile->keepaliveTimer = VDP_KEEPALIVE_TIMER_STOPPED; -+ -+ LLDPAD_DBG("%s: %s stopping keepalive timer for %#02x (%i)\n", -+ __func__, profile->port->ifname, -+ profile->instance[15], profile->keepaliveTimer); -+ -+ return eloop_cancel_timeout(vdp_keepalive_timeout_handler, NULL, -+ (void *) profile); -+} -+ -+static bool vdp_vsi_negative_response(struct vsi_profile *profile) -+{ -+ if ((profile->response > 0) && (profile->response < 255)) -+ return true; -+ else -+ return false; -+} -+ -+/* vdp_vsi_change_station_state - changes the VDP station sm state -+ * @profile: profile to process -+ * @newstate: new state for the sm -+ * -+ * no return value -+ * -+ * actually changes the state of the profile -+ */ -+void vdp_vsi_change_station_state(struct vsi_profile *profile, u8 newstate) -+{ -+ switch(newstate) { -+ case VSI_UNASSOCIATED: -+ break; -+ case VSI_ASSOC_PROCESSING: -+ assert((profile->state == VSI_PREASSOCIATED) || -+ (profile->state == VSI_ASSOCIATED) || -+ (profile->state == VSI_UNASSOCIATED)); -+ break; -+ case VSI_ASSOCIATED: -+ assert((profile->state == VSI_ASSOC_PROCESSING) || -+ (profile->state == VSI_ASSOCIATED)); -+ break; -+ case VSI_PREASSOC_PROCESSING: -+ assert((profile->state == VSI_PREASSOCIATED) || -+ (profile->state == VSI_ASSOCIATED) || -+ (profile->state == VSI_UNASSOCIATED)); -+ break; -+ case VSI_PREASSOCIATED: -+ assert((profile->state == VSI_PREASSOC_PROCESSING) || -+ (profile->state == VSI_PREASSOCIATED)); -+ break; -+ case VSI_DEASSOC_PROCESSING: -+ assert((profile->state == VSI_PREASSOCIATED) || -+ (profile->state == VSI_UNASSOCIATED) || -+ (profile->state == VSI_ASSOCIATED)); -+ break; -+ case VSI_EXIT: -+ assert((profile->state == VSI_ASSOC_PROCESSING) || -+ (profile->state == VSI_PREASSOC_PROCESSING) || -+ (profile->state == VSI_DEASSOC_PROCESSING) || -+ (profile->state == VSI_PREASSOCIATED) || -+ (profile->state == VSI_ASSOCIATED)); -+ break; -+ default: -+ LLDPAD_ERR("ERROR: The VDP station State Machine is broken\n"); -+ break; -+ } -+ -+ LLDPAD_DBG("%s: %s state change %s -> %s\n", __func__, -+ profile->port->ifname, vsi_states[profile->state], -+ vsi_states[newstate]); -+ -+ profile->state = newstate; -+} -+ -+/* vdp_vsi_set_station_state - sets the vdp sm station state -+ * @profile: profile to process -+ * -+ * returns true or false -+ * -+ * switches the state machine to the next state depending on the input -+ * variables. returns true or false depending on wether the state machine -+ * can be run again with the new state or can stop at the current state. -+ */ -+static bool vdp_vsi_set_station_state(struct vsi_profile *profile) -+{ -+ switch(profile->state) { -+ case VSI_UNASSOCIATED: -+ if ((profile->mode == VDP_MODE_PREASSOCIATE) || -+ (profile->mode == VDP_MODE_PREASSOCIATE_WITH_RR)) { -+ vdp_vsi_change_station_state(profile, VSI_PREASSOC_PROCESSING); -+ vdp_somethingChangedLocal(profile, true); -+ return true; -+ } else if (profile->mode == VDP_MODE_ASSOCIATE) { -+ vdp_vsi_change_station_state(profile, VSI_ASSOC_PROCESSING); -+ vdp_somethingChangedLocal(profile, true); -+ return true; -+ } else if (profile->mode == VDP_MODE_DEASSOCIATE) { -+ vdp_vsi_change_station_state(profile, VSI_DEASSOC_PROCESSING); -+ vdp_somethingChangedLocal(profile, true); -+ return true; -+ } -+ return false; -+ case VSI_ASSOC_PROCESSING: -+ if (profile->ackReceived) { -+ if (profile->response == 0) -+ vdp_vsi_change_station_state(profile, VSI_ASSOCIATED); -+ else -+ vdp_vsi_change_station_state(profile, VSI_EXIT); -+ return true; -+ } else if (!profile->ackReceived && vdp_ackTimer_expired(profile)) { -+ vdp_vsi_change_station_state(profile, VSI_EXIT); -+ return true; -+ } -+ return false; -+ case VSI_ASSOCIATED: -+ if (profile->mode == VDP_MODE_PREASSOCIATE) { -+ vdp_vsi_change_station_state(profile, VSI_PREASSOC_PROCESSING); -+ return true; -+ } else if (profile->mode == VDP_MODE_DEASSOCIATE) { -+ vdp_vsi_change_station_state(profile, VSI_DEASSOC_PROCESSING); -+ return true; -+ } else if (vdp_vsi_negative_response(profile)) { -+ vdp_vsi_change_station_state(profile, VSI_EXIT); -+ return true; -+ } else if (vdp_keepaliveTimer_expired(profile)) { -+ vdp_stop_keepaliveTimer(profile); -+ vdp_somethingChangedLocal(profile, true); -+ vdp_vsi_change_station_state(profile, VSI_ASSOC_PROCESSING); -+ return true; -+ } -+ return false; -+ case VSI_PREASSOC_PROCESSING: -+ LLDPAD_DBG("%s: profile->ackReceived %i, vdp_ackTimer %i\n", -+ __func__, profile->ackReceived, profile->ackTimer); -+ if (profile->ackReceived) { -+ if (profile->response == 0) -+ vdp_vsi_change_station_state(profile, VSI_PREASSOCIATED); -+ else -+ vdp_vsi_change_station_state(profile, VSI_EXIT); -+ return true; -+ } else if (!profile->ackReceived && vdp_ackTimer_expired(profile)) { -+ vdp_vsi_change_station_state(profile, VSI_EXIT); -+ return true; -+ } -+ return false; -+ case VSI_PREASSOCIATED: -+ if (profile->mode == VDP_MODE_ASSOCIATE) { -+ vdp_vsi_change_station_state(profile, VSI_ASSOC_PROCESSING); -+ return true; -+ } else if (profile->mode == VDP_MODE_DEASSOCIATE) { -+ vdp_vsi_change_station_state(profile, VSI_DEASSOC_PROCESSING); -+ return true; -+ } else if (vdp_keepaliveTimer_expired(profile)) { -+ vdp_stop_keepaliveTimer(profile); -+ vdp_somethingChangedLocal(profile, true); -+ vdp_vsi_change_station_state(profile, VSI_PREASSOC_PROCESSING); -+ return true; -+ } -+ return false; -+ case VSI_DEASSOC_PROCESSING: -+ if ((profile->ackReceived) || vdp_ackTimer_expired(profile) || -+ profile->remoteChange) { -+ vdp_vsi_change_station_state(profile, VSI_EXIT); -+ return true; -+ } -+ return false; -+ case VSI_EXIT: -+ return false; -+ default: -+ LLDPAD_ERR("%s: VSI state machine in invalid state %d\n", -+ profile->port->ifname, profile->state); -+ return false; -+ } -+} -+ -+/* vdp_vsi_sm_station - state machine for vdp station role -+ * @profile: profile for which the state is processed -+ * -+ * no return value -+ * -+ * runs the state machine for the station role of VDP. -+ */ -+void vdp_vsi_sm_station(struct vsi_profile *profile) -+{ -+ struct vdp_data *vd = vdp_data(profile->port->ifname); -+ int bye = 0; -+ -+ vdp_vsi_set_station_state(profile); -+ do { -+ LLDPAD_DBG("%s: %s station for %#02x - %s\n", -+ __func__, profile->port->ifname, -+ profile->instance[15], vsi_states[profile->state]); -+ -+ switch(profile->state) { -+ case VSI_UNASSOCIATED: -+ break; -+ case VSI_ASSOC_PROCESSING: -+ vdp_stop_keepaliveTimer(profile); -+ profile->response = VDP_RESPONSE_NO_RESPONSE; -+ if (profile->localChange) { -+ ecp_somethingChangedLocal(vd, true); -+ profile->ackReceived = false; -+ vdp_start_ackTimer(profile); -+ } -+ break; -+ case VSI_ASSOCIATED: -+ profile->ackReceived = false; -+ vdp_somethingChangedLocal(profile, false); -+ vdp_stop_ackTimer(profile); -+ vdp_start_keepaliveTimer(profile); -+ break; -+ case VSI_PREASSOC_PROCESSING: -+ vdp_stop_keepaliveTimer(profile); -+ profile->response = VDP_RESPONSE_NO_RESPONSE; -+ if (profile->localChange) { -+ profile->ackReceived = false; -+ ecp_somethingChangedLocal(vd, true); -+ vdp_start_ackTimer(profile); -+ } -+ break; -+ case VSI_PREASSOCIATED: -+ profile->ackReceived = false; -+ vdp_somethingChangedLocal(profile, false); -+ vdp_stop_ackTimer(profile); -+ vdp_start_keepaliveTimer(profile); -+ break; -+ case VSI_DEASSOC_PROCESSING: -+ profile->ackReceived = false; -+ vdp_stop_keepaliveTimer(profile); -+ profile->response = VDP_RESPONSE_NO_RESPONSE; -+ if (profile->localChange) { -+ profile->ackReceived = false; -+ ecp_somethingChangedLocal(vd, true); -+ vdp_start_ackTimer(profile); -+ } -+ break; -+ case VSI_EXIT: -+ if (profile->no_nlmsg && !profile->ackReceived && -+ vdp_ackTimer_expired(profile)) -+ bye = 1; -+ vdp_stop_ackTimer(profile); -+ vdp_stop_keepaliveTimer(profile); -+ vdp_stop_localchange_timer(profile); -+ if (bye) -+ vdp_remove_profile(profile); -+ else -+ vdp_trigger(profile); -+ break; -+ default: -+ LLDPAD_ERR("%s: ERROR VSI state machine in invalid state %d\n", -+ vd->ifname, profile->state); -+ } -+ } while (vdp_vsi_set_station_state(profile) == true); -+ -+} -+ -+/* vdp_advance_sm - advance state machine after update from switch -+ * -+ * no return value -+ */ -+void vdp_advance_sm(struct vdp_data *vd) -+{ -+ struct vsi_profile *p; -+ -+ LIST_FOREACH(p, &vd->profile_head, profile) { -+ LLDPAD_DBG("%s: %s station for %#02x - %s ackReceived %i\n", -+ __func__, p->port->ifname, -+ p->instance[15], vsi_states[p->state], -+ p->ackReceived); -+ if (p->ackReceived) { -+ vdp_vsi_sm_station(p); -+ p->ackReceived = false; -+ } -+ } -+} -+ -+/* vdp_vsi_change_bridge_state - changes the VDP bridge sm state -+ * @profile: profile to process -+ * @newstate: new state for the sm -+ * -+ * no return value -+ * -+ * actually changes the state of the profile -+ */ -+static void vdp_vsi_change_bridge_state(struct vsi_profile *profile, -+ u8 newstate) -+{ -+ switch(newstate) { -+ case VSI_UNASSOCIATED: -+ break; -+ case VSI_ASSOC_PROCESSING: -+ assert((profile->state == VSI_UNASSOCIATED) || -+ (profile->state == VSI_PREASSOCIATED) || -+ (profile->state == VSI_ASSOCIATED)); -+ break; -+ case VSI_ASSOCIATED: -+ assert(profile->state == VSI_ASSOC_PROCESSING); -+ break; -+ case VSI_PREASSOC_PROCESSING: -+ assert((profile->state == VSI_UNASSOCIATED) || -+ (profile->state == VSI_PREASSOCIATED) || -+ (profile->state == VSI_ASSOCIATED)); -+ break; -+ case VSI_PREASSOCIATED: -+ assert(profile->state == VSI_PREASSOC_PROCESSING); -+ break; -+ case VSI_DEASSOC_PROCESSING: -+ assert((profile->state == VSI_UNASSOCIATED) || -+ (profile->state == VSI_PREASSOCIATED) || -+ (profile->state == VSI_ASSOCIATED)); -+ break; -+ case VSI_EXIT: -+ assert((profile->state == VSI_DEASSOC_PROCESSING) || -+ (profile->state == VSI_PREASSOC_PROCESSING) || -+ (profile->state == VSI_ASSOC_PROCESSING)); -+ break; -+ default: -+ LLDPAD_ERR("ERROR: The VDP bridge State Machine is broken\n"); -+ break; -+ } -+ profile->state = newstate; -+} -+ -+/* vdp_vsi_set_bridge_state - sets the vdp sm bridge state -+ * @profile: profile to process -+ * -+ * returns true or false -+ * -+ * switches the state machine to the next state depending on the input -+ * variables. returns true or false depending on wether the state machine -+ * can be run again with the new state or can stop at the current state. -+ */ -+static bool vdp_vsi_set_bridge_state(struct vsi_profile *profile) -+{ -+ switch(profile->state) { -+ case VSI_UNASSOCIATED: -+ if ((profile->mode == VDP_MODE_DEASSOCIATE)) /* || (INACTIVE)) */ { -+ vdp_vsi_change_bridge_state(profile, VSI_DEASSOC_PROCESSING); -+ return true; -+ } else if (profile->mode == VDP_MODE_ASSOCIATE) { -+ vdp_vsi_change_bridge_state(profile, VSI_ASSOC_PROCESSING); -+ return true; -+ } else if (profile->mode == VDP_MODE_PREASSOCIATE) { -+ vdp_vsi_change_bridge_state(profile, VSI_PREASSOC_PROCESSING); -+ return true; -+ } -+ return false; -+ case VSI_ASSOC_PROCESSING: -+ /* TODO: handle error case -+ if (!vsiError) || -+ (vsiError && vsiState == Assoc) { -+ */ -+ if (profile->mode == VDP_MODE_ASSOCIATE) { -+ vdp_vsi_change_bridge_state(profile, VSI_ASSOCIATED); -+ return true; -+ } -+ return false; -+ case VSI_ASSOCIATED: -+ if (profile->mode == VDP_MODE_ASSOCIATE) /* || ( INACTIVE )*/ { -+ vdp_vsi_change_bridge_state(profile, VSI_DEASSOC_PROCESSING); -+ return true; -+ } else if (profile->mode == VDP_MODE_PREASSOCIATE) { -+ vdp_vsi_change_bridge_state(profile, VSI_PREASSOC_PROCESSING); -+ return true; -+ } else if (profile->mode == VDP_MODE_ASSOCIATE) { -+ vdp_vsi_change_bridge_state(profile, VSI_ASSOC_PROCESSING); -+ return true; -+ } -+ return false; -+ case VSI_PREASSOC_PROCESSING: -+ if (profile->response != VDP_RESPONSE_SUCCESS) { -+ vdp_vsi_change_bridge_state(profile, VSI_EXIT); -+ return true; -+ } -+ vdp_vsi_change_bridge_state(profile, VSI_PREASSOCIATED); -+ return false; -+ case VSI_PREASSOCIATED: -+ if (profile->mode == VDP_MODE_ASSOCIATE) { -+ vdp_vsi_change_bridge_state(profile, VSI_ASSOC_PROCESSING); -+ return true; -+ } else if (profile->mode == VDP_MODE_DEASSOCIATE ) { -+ vdp_vsi_change_bridge_state(profile, VSI_DEASSOC_PROCESSING); -+ return true; -+ } else if (profile->mode == VDP_MODE_PREASSOCIATE ) { -+ vdp_vsi_change_bridge_state(profile, VSI_PREASSOC_PROCESSING); -+ return true; -+ } -+ return false; -+ case VSI_DEASSOC_PROCESSING: -+ vdp_vsi_change_bridge_state(profile, VSI_EXIT); -+ return false; -+ case VSI_EXIT: -+ return false; -+ default: -+ LLDPAD_ERR("%s: ERROR VSI state machine (bridge) in invalid state %d\n", -+ profile->port->ifname, profile->state); -+ return false; -+ } -+} -+ -+/* vdp_vsi_sm_bridge - state machine for vdp bridge role -+ * @profile: profile for which the state is processed -+ * -+ * no return value -+ * -+ * runs the state machine for the bridge role of VDP. -+ */ -+static void vdp_vsi_sm_bridge(struct vsi_profile *profile) -+{ -+ struct vdp_data *vd = vdp_data(profile->port->ifname); -+ -+ vdp_vsi_set_bridge_state(profile); -+ do { -+ LLDPAD_DBG("%s: %s bridge - %s\n", __func__, -+ profile->port->ifname, vsi_states[profile->state]); -+ switch(profile->state) { -+ case VSI_UNASSOCIATED: -+ break; -+ case VSI_ASSOC_PROCESSING: -+ /* TODO: vsiError = ProcRxandSetCfg(remoteTLV, localtlv, vsistate); -+ * if (vsiError) -+ * txTLV(Assoc NACK) -+ * else -+ * txTLV(Assoc ACK) -+ */ -+ break; -+ case VSI_ASSOCIATED: -+ break; -+ case VSI_PREASSOC_PROCESSING: -+ /* TODO: vsiError = ProcRxandSetCfg(remoteTLV, localtlv, vsistate); -+ * if (vsiError) -+ * txTLV(PreAssoc NACK) -+ * else -+ * txTLV(PreAssoc ACK) -+ */ -+ /* for now, we always succeed */ -+ profile->response = VDP_RESPONSE_SUCCESS; -+ ecp_rx_send_ack_frame(vd); -+ break; -+ case VSI_PREASSOCIATED: -+ LLDPAD_DBG("%s: %s\n", __func__, profile->port->ifname); -+ break; -+ case VSI_DEASSOC_PROCESSING: -+ /* TODO: txTLV(DeAssoc ACK) */ -+ break; -+ case VSI_EXIT: -+ vdp_remove_profile(profile); -+ break; -+ default: -+ LLDPAD_ERR("%s: ERROR VSI state machine in invalid state %d\n", -+ vd->ifname, profile->state); -+ } -+ } while (vdp_vsi_set_bridge_state(profile) == true); -+ -+} -+ -+/* -+ * vdp_validate_tlv - validates vsi tlvs -+ * @vdp: decoded vsi tlv -+ * -+ * Returns 0 on success, 1 on error -+ * -+ * checks the contents of an already decoded vsi tlv for inconsistencies -+ */ -+static int vdp_validate_tlv(struct tlv_info_vdp *vdp, struct unpacked_tlv *tlv) -+{ -+ int pairs = (tlv->length - sizeof *vdp) / sizeof(struct mac_vlan_p); -+ -+ if (ntoh24(vdp->oui) != OUI_IEEE_8021Qbg) { -+ LLDPAD_DBG("vdp->oui %#06x\n", ntoh24(vdp->oui)); -+ goto out_err; -+ } -+ -+ if (vdp->sub != LLDP_VDP_SUBTYPE) { -+ LLDPAD_DBG("vdp->sub %#02x\n", vdp->sub); -+ goto out_err; -+ } -+ -+ if (vdp->mode > VDP_MODE_DEASSOCIATE) { -+ LLDPAD_DBG("unknown mode %#02x in vsi tlv\n", vdp->mode); -+ goto out_err; -+ } -+ -+ if (vdp->response > VDP_RESPONSE_OUT_OF_SYNC) { -+ LLDPAD_DBG("unknown response %#02x\n", vdp->response); -+ goto out_err; -+ } -+ -+ if (vdp->format != VDP_FILTER_INFO_FORMAT_MACVID) { -+ LLDPAD_DBG("unknown format %#02x in vsi tlv\n", vdp->format); -+ goto out_err; -+ } -+ -+ if (ntohs(vdp->entries) < 1) { -+ LLDPAD_DBG("invalid # of entries %#02x in vsi tlv\n", -+ ntohs(vdp->entries)); -+ goto out_err; -+ } -+ -+ /* Check for number of entries of MAC,VLAN pairs */ -+ if (ntohs(vdp->entries) != pairs) { -+ LLDPAD_DBG("mismatching # of entries %#x/%#x in vsi tlv\n", -+ ntohs(vdp->entries), pairs); -+ goto out_err; -+ } -+ return 0; -+ -+out_err: -+ return 1; -+} -+ -+/* -+ * Create a VSI profile structure from switch response. -+ */ -+static void make_profile(struct vsi_profile *new, struct tlv_info_vdp *vdp, -+ struct unpacked_tlv *tlv) -+{ -+ int i; -+ u8 *pos = tlv->info + sizeof *vdp; -+ -+ new->mode = vdp->mode; -+ new->response = vdp->response; -+ new->mgrid = vdp->mgrid; -+ new->id = ntoh24(vdp->id); -+ new->version = vdp->version; -+ memcpy(&new->instance, &vdp->instance, sizeof new->instance); -+ new->format = vdp->format; -+ new->entries = ntohs(vdp->entries); -+ LLDPAD_DBG("%s: MAC/VLAN filter info format %u, # of entries %u\n", -+ __func__, new->format, new->entries); -+ -+ /* Add MAC,VLAN to list */ -+ for (i = 0; i < new->entries; ++i) { -+ struct mac_vlan *mac_vlan = calloc(1, sizeof(struct mac_vlan)); -+ u16 vlan; -+ char macbuf[MAC_ADDR_STRLEN + 1]; -+ -+ if (!mac_vlan) { -+ new->entries = i; -+ return; -+ } -+ memcpy(&mac_vlan->mac, pos, ETH_ALEN); -+ pos += ETH_ALEN; -+ mac2str(mac_vlan->mac, macbuf, MAC_ADDR_STRLEN); -+ memcpy(&vlan, pos, 2); -+ pos += 2; -+ mac_vlan->vlan = ntohs(vlan); -+ LLDPAD_DBG("%s: mac %s vlan %d\n", __func__, macbuf, -+ mac_vlan->vlan); -+ LIST_INSERT_HEAD(&new->macvid_head, mac_vlan, entry); -+ } -+} -+ -+/* -+ * vdp_indicate - receive VSI TLVs from ECP -+ * @port: the port on which the tlv was received -+ * @tlv: the unpacked tlv to receive -+ * -+ * Returns 0 on success -+ * -+ * receives a vsi tlv and creates a profile. Take appropriate action -+ * depending on the role of the (receive) port -+ */ -+int vdp_indicate(struct vdp_data *vd, struct unpacked_tlv *tlv) -+{ -+ struct tlv_info_vdp vdp; -+ struct vsi_profile *p, *profile; -+ struct port *port = port_find_by_ifindex(get_ifidx(vd->ifname)); -+ -+ LLDPAD_DBG("%s: indicating vdp of length %u (%zu) for %s\n", -+ __func__, tlv->length, sizeof(struct tlv_info_vdp), -+ vd->ifname); -+ -+ if (!port) { -+ LLDPAD_ERR("%s: port not found for %s\n", __func__, -+ vd->ifname); -+ goto out_err; -+ } -+ -+ memset(&vdp, 0, sizeof vdp); -+ /* copy only vdp header w/o list of mac/vlan/groupid pairs */ -+ memcpy(&vdp, tlv->info, sizeof vdp); -+ -+ if (vdp_validate_tlv(&vdp, tlv)) { -+ LLDPAD_ERR("%s: invalid TLV received\n", __func__); -+ goto out_err; -+ } -+ -+ profile = vdp_alloc_profile(); -+ if (!profile) { -+ LLDPAD_ERR("%s: unable to allocate profile\n", __func__); -+ goto out_err; -+ } -+ make_profile(profile, &vdp, tlv); -+ -+ profile->port = port; -+ -+ if (vd->role == VDP_ROLE_STATION) { -+ /* do we have the profile already ? */ -+ p = vdp_find_profile(vd, profile); -+ if (p) { -+ LLDPAD_DBG("%s: station profile found localChange %i " -+ "ackReceived %i no_nlmsg:%d\n", -+ __func__, p->localChange, p->ackReceived, -+ p->no_nlmsg); -+ -+ if (profile->mode == VDP_MODE_DEASSOCIATE && -+ (p->response == VDP_RESPONSE_NO_RESPONSE || -+ p->response == VDP_RESPONSE_SUCCESS) && -+ p->mode == VDP_MODE_PREASSOCIATE) { -+ LLDPAD_DBG("%s: ignore dis-associate request " -+ "in pre-association\n", __func__); -+ vdp_delete_profile(profile); -+ return 0; -+ } -+ -+ p->ackReceived = true; -+ p->keepaliveTimer = VDP_KEEPALIVE_TIMER_DEFAULT; -+ if (profile->mode != p->mode) { -+ p->mode = profile->mode; -+ p->remoteChange = true; -+ if (profile->mode == VDP_MODE_DEASSOCIATE) -+ p->no_nlmsg = 0; -+ } else -+ p->remoteChange = false; -+ p->response = profile->response; -+ LLDPAD_DBG("%s: remoteChange %i no_nlmsg %d mode %d\n", -+ __func__, p->remoteChange, p->no_nlmsg, -+ p->mode); -+ if (vdp_vsi_negative_response(p)) -+ p->mode = VDP_MODE_DEASSOCIATE; -+ -+ LLDPAD_DBG("%s: profile response: %s (%i) " -+ "for profile %#02x at state %s\n", -+ __func__, -+ vdp_response2str(p->response), -+ p->response, p->instance[15], -+ vsi_states[p->state]); -+ } else { -+ LLDPAD_DBG("%s: station profile not found\n", __func__); -+ } -+ vdp_delete_profile(profile); -+ } -+ -+ if (vd->role == VDP_ROLE_BRIDGE) { -+ /* do we have the profile already ? */ -+ p = vdp_find_profile(vd, profile); -+ if (p) { -+ LLDPAD_DBG("%s: bridge profile found\n", __func__); -+ vdp_delete_profile(profile); -+ } else { -+ LLDPAD_DBG("%s: bridge profile not found\n", __func__); -+ /* put it in the list */ -+ profile->state = VSI_UNASSOCIATED; -+ LIST_INSERT_HEAD(&vd->profile_head, profile, profile); -+ } -+ -+ vdp_vsi_sm_bridge(profile); -+ } -+ -+ return 0; -+ -+out_err: -+ return 1; -+} -+ -+/* -+ * vdp_bld_vsi_tlv - build the VDP VSI TLV -+ * @vd: vdp_data structure for this port -+ * @profile: profile the vsi tlv is created from -+ * -+ * Returns 0 on success, ENOMEM otherwise -+ * -+ * creates a vdp structure from an existing profile -+ */ -+static int vdp_bld_vsi_tlv(struct vdp_data *vd, struct vsi_profile *profile) -+{ -+ struct mac_vlan *mv; -+ struct mac_vlan_p *mv_p; -+ struct tlv_info_vdp *vdp; -+ int rc = 0; -+ struct unpacked_tlv *tlv = NULL; -+ int size = sizeof(struct tlv_info_vdp) + -+ profile->entries * sizeof(struct mac_vlan_p); -+ -+ vdp = malloc(size); -+ -+ if (!vdp) { -+ LLDPAD_DBG("%s: unable to allocate memory for VDP TLV\n", -+ __func__); -+ rc = ENOMEM; -+ goto out_err; -+ } -+ -+ memset(vdp, 0, size); -+ -+ hton24(vdp->oui, OUI_IEEE_8021Qbg); -+ vdp->sub = LLDP_VDP_SUBTYPE; -+ vdp->mode = profile->mode; -+ vdp->response = 0; -+ vdp->mgrid = profile->mgrid; -+ hton24(vdp->id, profile->id); -+ vdp->version = profile->version; -+ memcpy(&vdp->instance, &profile->instance, 16); -+ vdp->format = VDP_FILTER_INFO_FORMAT_MACVID; -+ vdp->entries = htons(profile->entries); -+ -+ mv_p = (struct mac_vlan_p *)(vdp + 1); -+ -+ LIST_FOREACH(mv, &profile->macvid_head, entry) { -+ memcpy(mv_p->mac, mv->mac, MAC_ADDR_LEN); -+ mv_p->vlan = htons(mv->vlan); -+ mv_p++; -+ } -+ -+ tlv = create_tlv(); -+ if (!tlv) { -+ rc = ENOMEM; -+ goto out_free; -+ } -+ -+ tlv->type = ORG_SPECIFIC_TLV; -+ tlv->length = size; -+ tlv->info = (u8 *)malloc(tlv->length); -+ if(!tlv->info) { -+ free(tlv); -+ tlv = NULL; -+ rc = ENOMEM; -+ goto out_free; -+ } -+ -+ FREE_UNPKD_TLV(vd, vdp); -+ -+ memcpy(tlv->info, vdp, tlv->length); -+ -+ vd->vdp = tlv; -+ -+out_free: -+ free(vdp); -+ -+out_err: -+ return rc; -+} -+ -+/* vdp_bld_tlv - builds a tlv from a profile -+ * @vd: vdp_data structure for this port -+ * @profile: profile the vsi tlv is created from -+ * -+ * returns 0 on success, != 0 on error -+ * -+ * wrapper function around vdp_bld_vsi_tlv. adds some checks and calls -+ * vdp_bld_vsi_tlv. -+ */ -+ -+static int vdp_bld_tlv(struct vdp_data *vd, struct vsi_profile *profile) -+{ -+ if (!port_find_by_ifindex(get_ifidx(vd->ifname))) -+ return -EEXIST; -+ -+ if (vdp_bld_vsi_tlv(vd, profile)) { -+ LLDPAD_ERR("%s: %s vdp_bld_vsi_tlv() failed\n", -+ __func__, vd->ifname); -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+/* vdp_gettlv - get the tlv for a profile -+ * @port: the port on which the tlv was received -+ * @profile: profile the vsi tlv is created from -+ * -+ * returns 0 on success -+ * -+ * this is the interface function called from ecp_build_ECPDU. It returns the -+ * packed tlv for a profile. -+ */ -+struct packed_tlv *vdp_gettlv(struct vdp_data *vd, struct vsi_profile *profile) -+{ -+ int size; -+ struct packed_tlv *ptlv = NULL; -+ -+ /* frees the unpacked_tlv in vdp_data -+ * also done in vdp_bld_vsi_tlv */ -+ vdp_free_tlv(vd); -+ -+ if (vdp_bld_tlv(vd, profile)) { -+ LLDPAD_ERR("%s: %s vdp_bld_tlv failed\n", -+ __func__, vd->ifname); -+ goto out_err; -+ } -+ -+ size = TLVSIZE(vd->vdp); -+ -+ if (!size) { -+ LLDPAD_ERR("%s: size %i of unpacked_tlv not correct\n", -+ __func__, size); -+ goto out_err; -+ } -+ -+ ptlv = create_ptlv(); -+ if (!ptlv) -+ goto out_err; -+ -+ ptlv->tlv = malloc(size); -+ if (!ptlv->tlv) -+ goto out_free; -+ -+ ptlv->size = 0; -+ PACK_TLV_AFTER(vd->vdp, ptlv, size, out_free); -+ -+ return ptlv; -+ -+out_free: -+ ptlv = free_pkd_tlv(ptlv); -+out_err: -+ LLDPAD_ERR("%s: %s failed\n", __func__, vd->ifname); -+ return NULL; -+} -+ -+/* vdp_macvlan_equal - checks for equality of 2 mac/vlan pairs -+ * @mv1: mac/vlan pair 1 -+ * @mv2: mac/vlan pair 2 -+ * -+ * returns true if equal, false if not -+ * -+ * compares mac address and vlan if they are equal. -+ */ -+bool vdp_macvlan_equal(struct mac_vlan *mv1, struct mac_vlan *mv2) -+{ -+ if (memcmp(mv1->mac, mv2->mac, MAC_ADDR_LEN)) -+ return false; -+ -+ if (mv1->vlan != mv2->vlan) -+ return false; -+ -+ return true; -+} -+ -+/* -+ * Check if the current profile already has this entry. If so take over -+ * PID and other fields. If not add this MAC,VLAN to our list. -+ * -+ * Returns 1 it the entry already exist, 0 if not. -+ */ -+static int have_macvlan(struct vsi_profile *p1, struct mac_vlan *new) -+{ -+ struct mac_vlan *mv1; -+ -+ LIST_FOREACH(mv1, &p1->macvid_head, entry) -+ if (vdp_macvlan_equal(mv1, new) == true) { -+ mv1->req_pid = new->req_pid; -+ mv1->req_seq = new->req_seq; -+ mv1->qos = new->qos; -+ return 1; -+ } -+ LIST_INSERT_HEAD(&p1->macvid_head, new, entry); -+ p1->entries++; -+ return 0; -+} -+ -+/* vdp_takeover_macvlans - take over macvlan pairs from p2 into p1 -+ * @p1: profile 1 -+ * @p2: profile 2 -+ * -+ * returns number of mac/vlan pairs taken over -+ * -+ * loops over all mac/vlan pairs in profile 2 and looks for them in profile 1. -+ * If the mac/vlan pair does not yet exist in profile 1, it adds the new pair to -+ * the list in profile 1. -+ */ -+void vdp_takeover_macvlans(struct vsi_profile *p1, struct vsi_profile *p2) -+{ -+ struct mac_vlan *mv2; -+ int count = 0; -+ -+ LLDPAD_DBG("%s: taking over mac/vlan pairs\n", __func__); -+ -+ while ((mv2 = LIST_FIRST(&p2->macvid_head))) { -+ LIST_REMOVE(mv2, entry); -+ p2->entries--; -+ if (have_macvlan(p1, mv2)) -+ free(mv2); -+ else -+ count++; -+ } -+ -+ LLDPAD_DBG("%s: %u mac/vlan pairs taken over\n", __func__, count); -+} -+ -+/* vdp_add_profile - adds a profile to a per port list -+ * @profile: profile to add -+ * -+ * returns the profile that has been found or added, NULL otherwise. -+ * -+ * main interface function which adds a profile to a list kept on a per-port -+ * basis. Checks if the profile is already in the list, adds it if necessary. -+ */ -+struct vsi_profile *vdp_add_profile(struct vdp_data *vd, -+ struct vsi_profile *profile) -+{ -+ struct vsi_profile *p; -+ -+ LLDPAD_DBG("%s: adding vdp profile for %s\n", __func__, -+ profile->port->ifname); -+ vdp_trace_profile(profile); -+ -+ /* -+ * Search this profile. If found check, -+ * if the MAC/VLAN pair already exists. If not, add it. -+ */ -+ p = vdp_find_profile(vd, profile); -+ if (p) { -+ LLDPAD_DBG("%s: profile already exists\n", __func__); -+ -+ vdp_takeover_macvlans(p, profile); -+ -+ if (p->mode != profile->mode) { -+ LLDPAD_DBG("%s: new mode %i\n", -+ __func__, profile->mode); -+ p->mode = profile->mode; -+ p->response = VDP_RESPONSE_NO_RESPONSE; -+ } -+ profile = p; -+ } else { -+ -+ profile->response = VDP_RESPONSE_NO_RESPONSE; -+ -+ LIST_INSERT_HEAD(&vd->profile_head, profile, profile); -+ } -+ -+ vdp_somethingChangedLocal(profile, true); -+ -+ return profile; -+} -+ -+/* vdp_remove_profile - remove a profile from a per port list -+ * @profile: profile to remove -+ * -+ * returns 0 if removal was successful, -1 if removal failed -+ * -+ * function used in the state machines to remove a profile from a list kept on -+ * a per-port basis. Checks if the profile is in the list, removes it if there. -+ */ -+int vdp_remove_profile(struct vsi_profile *profile) -+{ -+ struct vsi_profile *p; -+ struct vdp_data *vd; -+ -+ LLDPAD_DBG("%s: removing vdp profile on %s\n", __func__, -+ profile->port->ifname); -+ vdp_trace_profile(profile); -+ -+ vd = vdp_data(profile->port->ifname); -+ if (!vd) { -+ LLDPAD_ERR("%s: could not find vdp_data for %s\n", __func__, -+ profile->port->ifname); -+ return -1; -+ } -+ /* Check if profile exists. If yes, remove it. */ -+ p = vdp_find_profile(vd, profile); -+ if (p) { -+ LIST_REMOVE(p, profile); -+ vdp_delete_profile(p); -+ return 0; -+ } -+ return -1; /* Not found */ -+} -+ -+/* vdp_ifdown - tear down vdp structures for a interface -+ * @ifname: name of the interface -+ * -+ * no return value -+ * -+ * interface function to lldpad. tears down vdp specific structures if -+ * interface "ifname" goes down. -+ */ -+void vdp_ifdown(char *ifname, UNUSED struct lldp_agent *agent) -+{ -+ struct vdp_data *vd; -+ struct vsi_profile *p; -+ -+ LLDPAD_DBG("%s: called on interface %s\n", __func__, ifname); -+ -+ vd = vdp_data(ifname); -+ if (!vd) -+ goto out_err; -+ -+ if (ecp_deinit(ifname)) -+ goto out_err; -+ -+ LIST_FOREACH(p, &vd->profile_head, profile) { -+ if (p->ackTimer > 0) -+ vdp_stop_ackTimer(p); -+ if (p->keepaliveTimer > 0) -+ vdp_stop_keepaliveTimer(p); -+ } -+ -+ LLDPAD_INFO("%s: %s vdp data removed\n", __func__, ifname); -+ return; -+out_err: -+ LLDPAD_INFO("%s: %s vdp data remove failed\n", __func__, ifname); -+ -+ return; -+} -+ -+/* vdp_ifup - build up vdp structures for a interface -+ * @ifname: name of the interface -+ * -+ * no return value -+ * -+ * interface function to lldpad. builds up vdp specific structures if -+ * interface "ifname" goes up. -+ */ -+void vdp_ifup(char *ifname, struct lldp_agent *agent) -+{ -+ char *role; -+ char config_path[16]; -+ struct vdp_data *vd; -+ struct vdp_user_data *ud; -+ struct vsi_profile *p; -+ int enabletx = false; -+ -+ LLDPAD_DBG("%s: %s agent:%d start VDP\n", -+ __func__, ifname, agent->type); -+ -+ snprintf(config_path, sizeof(config_path), "%s.%s", -+ VDP_PREFIX, ARG_TLVTXENABLE); -+ -+ if (get_config_setting(ifname, agent->type, config_path, -+ (void *)&enabletx, CONFIG_TYPE_BOOL)) -+ enabletx = false; -+ -+ if (enabletx == false) { -+ LLDPAD_DBG("%s: %s not enabled for VDP\n", __func__, ifname); -+ return; -+ } -+ -+ vd = vdp_data(ifname); -+ if (vd) { -+ vd->enabletx = enabletx; -+ -+ LLDPAD_WARN("%s: %s vdp data already exists\n", -+ __func__, ifname); -+ goto out_start_again; -+ } -+ -+ /* not found, alloc/init per-port module data */ -+ vd = (struct vdp_data *) calloc(1, sizeof(struct vdp_data)); -+ if (!vd) { -+ LLDPAD_ERR("%s: %s malloc %zu failed\n", -+ __func__, ifname, sizeof(*vd)); -+ goto out_err; -+ } -+ strncpy(vd->ifname, ifname, IFNAMSIZ); -+ -+ vd->role = VDP_ROLE_STATION; -+ vd->enabletx = enabletx; -+ -+ if (!get_cfg(ifname, NEAREST_CUSTOMER_BRIDGE, "vdp.role", (void *)&role, -+ CONFIG_TYPE_STRING)) { -+ if (!strcasecmp(role, VAL_BRIDGE)) { -+ vd->role = VDP_ROLE_BRIDGE; -+ } -+ } -+ -+ LLDPAD_DBG("%s: configured for %s mode\n", ifname, -+ (vd->role ==VDP_ROLE_BRIDGE) ? "bridge" : "station"); -+ -+ LIST_INIT(&vd->profile_head); -+ -+ ud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_VDP02); -+ LIST_INSERT_HEAD(&ud->head, vd, entry); -+ -+out_start_again: -+ if (ecp_init(ifname)) { -+ LLDPAD_ERR("%s: %s unable to init ecp\n", __func__, ifname); -+ vdp_ifdown(ifname, agent); -+ goto out_err; -+ } -+ -+ vd->keepaliveTimer = VDP_KEEPALIVE_TIMER_DEFAULT; -+ vd->ackTimer = VDP_ACK_TIMER_DEFAULT; -+ -+ LLDPAD_DBG("%s: %s starting vdp timer (%i)\n", __func__, -+ vd->ifname, vd->nroftimers); -+ -+ LIST_FOREACH(p, &vd->profile_head, profile) { -+ if (p->ackTimer > 0) { -+ vdp_somethingChangedLocal(p, true); -+ vdp_start_ackTimer(p); -+ } -+ if (p->keepaliveTimer > 0) -+ vdp_start_keepaliveTimer(p); -+ } -+ -+ LLDPAD_DBG("%s: %s agent:%d vdp added\n", __func__, ifname, -+ agent->type); -+ return; -+ -+out_err: -+ LLDPAD_ERR("%s: %s agent:%d vdp adding failed\n", -+ __func__, ifname, agent->type); -+} -+ -+static int vdp_client_cmd(UNUSED void *data, UNUSED struct sockaddr_un *from, -+ UNUSED socklen_t fromlen, char *ibuf, int ilen, -+ char *rbuf, int rlen) -+{ -+ return vdp_clif_cmd(ibuf, ilen, rbuf, rlen); -+} -+ -+static const struct lldp_mod_ops vdp_ops = { -+ .lldp_mod_register = vdp_register, -+ .lldp_mod_unregister = vdp_unregister, -+ .get_arg_handler = vdp_get_arg_handlers, -+ .client_cmd = vdp_client_cmd -+}; -+ -+/* vdp_register - register vdp module to lldpad -+ * @none -+ * -+ * returns lldp_module struct on success, NULL on error -+ * -+ * allocates a module structure with vdp module information and returns it -+ * to lldpad. -+ */ -+struct lldp_module *vdp_register(void) -+{ -+ struct lldp_module *mod; -+ struct vdp_user_data *ud; -+ -+ mod = malloc(sizeof(*mod)); -+ if (!mod) { -+ LLDPAD_ERR("%s: failed to start - vdp data\n", __func__); -+ return NULL; -+ } -+ ud = malloc(sizeof(struct vdp_user_data)); -+ if (!ud) { -+ free(mod); -+ LLDPAD_ERR("%s: failed to start - vdp user data\n", __func__); -+ return NULL; -+ } -+ LIST_INIT(&ud->head); -+ mod->id = LLDP_MOD_VDP02; -+ mod->ops = &vdp_ops; -+ mod->data = ud; -+ LLDPAD_DBG("%s: done\n", __func__); -+ return mod; -+} -+ -+/* vdp_unregister - unregister vdp module from lldpad -+ * @none -+ * -+ * no return value -+ * -+ * frees vdp module structure. -+ */ -+void vdp_unregister(struct lldp_module *mod) -+{ -+ if (mod->data) { -+ vdp_free_data((struct vdp_user_data *) mod->data); -+ free(mod->data); -+ } -+ free(mod); -+ LLDPAD_DBG("%s: done\n", __func__); -+} -+ -+void vdp_update(char *ifname, u8 ccap) -+{ -+ struct vdp_data *vdp = vdp_data(ifname); -+ -+ if (vdp) { -+ vdp->vdpbit_on = ccap & LLDP_EVB_CAPABILITY_PROTOCOL_VDP; -+ LLDPAD_DBG("%s:%s vdpbit_on %d\n", __func__, ifname, -+ vdp->vdpbit_on); -+ } -+} -+ -+/* -+ * Handle a VSI request from buddy. -+ */ -+int vdp_request(struct vdpnl_vsi *vsi) -+{ -+ struct vdp_data *vd; -+ struct vsi_profile *profile, *p; -+ struct port *port = port_find_by_ifindex(get_ifidx(vsi->ifname)); -+ struct mac_vlan *mac_vlan; -+ int ret = 0; -+ -+ vd = vdp_data(vsi->ifname); -+ if (!vd) { -+ LLDPAD_ERR("%s: %s has not yet been configured\n", __func__, -+ vsi->ifname); -+ return -ENXIO; -+ } -+ if (!vd->vdpbit_on) { -+ LLDPAD_ERR("%s: %s has VDP disabled\n", __func__, vsi->ifname); -+ return -ENXIO; -+ } -+ -+ if (!port) { -+ LLDPAD_ERR("%s: %s can not find port\n", __func__, vsi->ifname); -+ return -ENODEV; -+ } -+ /* If the link is down, reject request */ -+ if (!port->portEnabled && vsi->request != VDP_MODE_DEASSOCIATE) { -+ LLDPAD_WARN("%s: %s not enabled, unable to associate\n", -+ __func__, vsi->ifname); -+ return -ENXIO; -+ } -+ -+ profile = vdp_alloc_profile(); -+ if (!profile) -+ return -ENOMEM; -+ mac_vlan = calloc(1, sizeof(struct mac_vlan)); -+ if (!mac_vlan) { -+ ret = -ENOMEM; -+ goto out_err; -+ } -+ -+ profile->port = port; -+ memcpy(&mac_vlan->mac, vsi->maclist->mac, sizeof mac_vlan->mac); -+ mac_vlan->vlan = vsi->maclist->vlan; -+ mac_vlan->qos = vsi->maclist->qos; -+ mac_vlan->req_pid = vsi->req_pid; -+ mac_vlan->req_seq = vsi->req_seq; -+ LIST_INSERT_HEAD(&profile->macvid_head, mac_vlan, entry); -+ profile->entries = 1; -+ -+ profile->mgrid = vsi->vsi_mgrid; -+ profile->id = vsi->vsi_typeid; -+ profile->version = vsi->vsi_typeversion; -+ profile->mode = vsi->request; -+ profile->response = vsi->response; -+ memcpy(profile->instance, vsi->vsi_uuid, sizeof vsi->vsi_uuid); -+ p = vdp_add_profile(vd, profile); -+ p->no_nlmsg = 1; -+ p->txmit = false; -+ vdp_trace_profile(p); -+ if (p != profile) -+ goto out_err; -+ return ret; -+ -+out_err: -+ vdp_delete_profile(profile); -+ return ret; -+} -+ -+/* -+ * Query a VSI request from buddy and report its progress. Use the interface -+ * name to determine the VSI profile list. Return one entry in parameter 'vsi' -+ * use the structure members response and vsi_uuid. -+ * Returns -+ * 1 valid VSI data returned -+ * 0 end of queue (no VSI data returned) -+ * <0 errno -+ */ -+int vdp_status(int number, struct vdpnl_vsi *vsi) -+{ -+ struct vdp_data *vd; -+ struct vsi_profile *p; -+ int i = 0, ret = 0; -+ -+ vd = vdp_data(vsi->ifname); -+ if (!vd) { -+ LLDPAD_ERR("%s: %s has not yet been configured\n", __func__, -+ vsi->ifname); -+ return -ENODEV; -+ } -+ /* Interate to queue element number */ -+ LIST_FOREACH(p, &vd->profile_head, profile) { -+ if (++i == number) { -+ ret = 1; -+ break; -+ } -+ } -+ if (ret) { -+ vdp_trace_profile(p); -+ vsi->macsz = 0; -+ vsi->response = p->response; -+ memcpy(vsi->vsi_uuid, p->instance, sizeof vsi->vsi_uuid); -+ if (p->response != VDP_RESPONSE_NO_RESPONSE -+ && p->state == VSI_EXIT) -+ vdp_remove_profile(p); -+ } -+ LLDPAD_DBG("%s: entry:%d more:%d\n", __func__, number, ret); -+ return ret; -+} -+ -+/* -+ * Copy MAC-VLAN list from profile to vdpnl structure. -+ */ -+static void copy_maclist(struct vsi_profile *p, struct vdpnl_mac *macp) -+{ -+ struct mac_vlan *mv1; -+ -+ LIST_FOREACH(mv1, &p->macvid_head, entry) { -+ macp->vlan = mv1->vlan; -+ macp->qos = mv1->qos; -+ memcpy(macp->mac, mv1->mac, sizeof macp->mac); -+ ++macp; -+ } -+} -+ -+/* -+ * Prepare data for a netlink message to originator of VSI. -+ * Forward a notification from switch. -+ */ -+int vdp_trigger(struct vsi_profile *profile) -+{ -+ struct vdpnl_vsi vsi; -+ struct vdp_data *vd; -+ struct mac_vlan *macp = 0; -+ int rc = -EINVAL; -+ struct vdpnl_mac maclist[profile->entries]; -+ -+ vsi.macsz = profile->entries; -+ vsi.maclist = maclist; -+ LLDPAD_DBG("%s: no_nlmsg:%d\n", __func__, profile->no_nlmsg); -+ vdp_trace_profile(profile); -+ if (profile->no_nlmsg) -+ return 0; -+ if (LIST_EMPTY(&profile->macvid_head)) -+ return 0; -+ macp = LIST_FIRST(&profile->macvid_head); -+ if (!macp->req_pid) -+ return 0; -+ sleep(1); /* Delay message notification */ -+ if (!profile->port || !profile->port->ifname) { -+ LLDPAD_ERR("%s: no ifname found for profile %p:\n", __func__, -+ profile); -+ goto error_exit; -+ } -+ memcpy(vsi.ifname, profile->port->ifname, sizeof vsi.ifname); -+ vd = vdp_data(vsi.ifname); -+ if (!vd) { -+ LLDPAD_ERR("%s: %s could not find vdp_data\n", __func__, -+ vsi.ifname); -+ goto error_exit; -+ } -+ vsi.ifindex = if_nametoindex(vsi.ifname); -+ if (vsi.ifindex == 0) { -+ LLDPAD_ERR("%s: %s could not find index for ifname\n", -+ __func__, vsi.ifname); -+ goto error_exit; -+ } -+ vsi.macsz = profile->entries; -+ copy_maclist(profile, vsi.maclist); -+ vsi.req_pid = macp->req_pid; -+ vsi.req_seq = macp->req_seq; -+ vsi.vsi_mgrid = profile->mgrid; -+ vsi.vsi_typeid = profile->id; -+ vsi.vsi_typeversion = profile->version; -+ memcpy(vsi.vsi_uuid, profile->instance, sizeof vsi.vsi_uuid); -+ vsi.request = VDP_MODE_DEASSOCIATE; -+ rc = vdpnl_send(&vsi); -+error_exit: -+ vdp_remove_profile(profile); -+ return rc; -+} -diff --git a/qbg/vdp22.c b/qbg/vdp22.c -new file mode 100644 -index 0000000..6188fbc ---- /dev/null -+++ b/qbg/vdp22.c -@@ -0,0 +1,968 @@ -+/****************************************************************************** -+ -+ Implementation of VDP22 protocol for IEEE 802.1 Qbg ratified standard -+ (c) Copyright IBM Corp. 2013 -+ -+ Author(s): Thomas Richter -+ -+ This program is free software; you can redistribute it and/or modify it -+ under the terms and conditions of the GNU General Public License, -+ version 2, as published by the Free Software Foundation. -+ -+ This program is distributed in the hope it will be useful, but WITHOUT -+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ more details. -+ -+ You should have received a copy of the GNU General Public License along with -+ this program; if not, write to the Free Software Foundation, Inc., -+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. -+ -+ The full GNU General Public License is included in this distribution in -+ the file called "COPYING". -+ -+******************************************************************************/ -+ -+#define _GNU_SOURCE -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+#include "messages.h" -+#include "config.h" -+ -+#include "lldp_mod.h" -+#include "lldp_util.h" -+#include "qbg_vdpnl.h" -+#include "qbg22.h" -+#include "qbg_vdp22.h" -+#include "qbg_utils.h" -+ -+/* -+ * VDP22 helper functions -+ */ -+ -+/* -+ * Convert IPv4 address to string. -+ */ -+int vdp22_ipv42str(const u8 *p, char *dst, size_t size) -+{ -+ if (dst && size > VDP_UUID_STRLEN) { -+ snprintf(dst, size, "%02x%02x:%02x%02x:%02x%02x", -+ p[10], p[11], p[12], p[13], p[14], p[15]); -+ return 0; -+ } -+ return -1; -+} -+ -+/* -+ * Convert IPv6 address to string. -+ * TODO -+ * - compression of 16 bits zero fields -+ * - omit leading zeroes -+ */ -+int vdp22_ipv62str(const u8 *p, char *dst, size_t size) -+{ -+ if (dst && size > VDP_UUID_STRLEN) { -+ snprintf(dst, size, "%02x%02x:%02x%02x:%02x%02x:%02x%02x:" -+ "%02x%02x:%02x%02x:%02x%02x:%02x%02x", -+ p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], -+ p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); -+ return 0; -+ } -+ return -1; -+} -+ -+int vdp22_local2str(const u8 *p, char *dst, size_t size) -+{ -+ if (dst && size > VDP_UUID_STRLEN) { -+ snprintf(dst, size, "%02x%02x%02x%02x%02x%02x%02x%02x" -+ "%02x%02x%02x%02x%02x%02x%02x%02x", -+ p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], -+ p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); -+ return 0; -+ } -+ return -1; -+} -+ -+/* -+ * Print VSI filter information data. -+ */ -+static void showvsifid(char *txt, unsigned char fif, unsigned short no, -+ struct fid22 *fe) -+{ -+ char idbuf[VDP_UUID_STRLEN + 2]; -+ int i; -+ -+ for (i = 0; i < no; ++i, ++fe) { -+ switch (fif) { -+ case VDP22_FFMT_GROUPVID: -+ LLDPAD_DBG("%s:grpid:%ld vlan:%d qos:%d" -+ " pid:%d seq:%ld\n", txt, fe->grpid, -+ vdp22_get_vlanid(fe->vlan), -+ vdp22_get_qos(fe->vlan), -+ fe->requestor.req_pid, -+ fe->requestor.req_seq); -+ break; -+ case VDP22_FFMT_GROUPMACVID: -+ mac2str(fe->mac, idbuf, sizeof idbuf); -+ LLDPAD_DBG("%s:mac:%s grpid:%ld vlan:%d" -+ " qos:%d pid:%d seq:%ld\n", txt, idbuf, -+ fe->grpid, vdp22_get_vlanid(fe->vlan), -+ vdp22_get_qos(fe->vlan), -+ fe->requestor.req_pid, -+ fe->requestor.req_seq); -+ break; -+ case VDP22_FFMT_VID: -+ LLDPAD_DBG("%s:vlan:%d qos:%d pid:%d seq:%ld\n", -+ txt, vdp22_get_vlanid(fe->vlan), -+ vdp22_get_qos(fe->vlan), -+ fe->requestor.req_pid, -+ fe->requestor.req_seq); -+ break; -+ case VDP22_FFMT_MACVID: -+ mac2str(fe->mac, idbuf, sizeof idbuf); -+ LLDPAD_DBG("%s:mac:%s vlan:%d qos:%d" -+ " pid:%d seq:%ld\n", txt, idbuf, -+ vdp22_get_vlanid(fe->vlan), -+ vdp22_get_qos(fe->vlan), -+ fe->requestor.req_pid, -+ fe->requestor.req_seq); -+ break; -+ default: -+ LLDPAD_DBG("%s:unsupported filter info format\n", txt); -+ } -+ } -+} -+ -+/* -+ * Convert a mgrid to a printable string. -+ */ -+static void mgrid2str(struct vsi22 *p, char *buf, size_t len) -+{ -+ int i, nul; -+ bool print = false; -+ -+ /* Find last non nul byte */ -+ for (nul = sizeof(p->mgrid) - 1; nul >= 0; --nul) { -+ if (p->mgrid[nul] != '\0') -+ break; -+ } -+ if (nul == 0) { -+ sprintf(buf, "%d", p->mgrid[0]); -+ return; -+ } -+ for (i = 0; i <= nul; ++i) { -+ if (isprint(p->mgrid[i])) -+ print = true; -+ else -+ break; -+ } -+ if (print) -+ strncpy(buf, (char *)p->mgrid, len); -+ else -+ vdp22_local2str(p->mgrid, buf, len); -+} -+ -+/* -+ * Print VSI data -+ */ -+void vdp22_showvsi(struct vsi22 *p) -+{ -+ char idbuf[VDP_UUID_STRLEN + 2]; -+ char mgridbuf[VDP_UUID_STRLEN + 2]; -+ -+ switch (p->vsi_fmt) { -+ case VDP22_ID_UUID: -+ vdp_uuid2str(p->vsi, idbuf, sizeof(idbuf)); -+ break; -+ case VDP22_ID_MAC: -+ mac2str(p->vsi + 10, idbuf, sizeof(idbuf)); -+ break; -+ case VDP22_ID_IP4: -+ vdp22_ipv42str(p->vsi, idbuf, sizeof(idbuf)); -+ break; -+ case VDP22_ID_IP6: -+ vdp22_ipv62str(p->vsi, idbuf, sizeof(idbuf)); -+ break; -+ case VDP22_ID_LOCAL: -+ vdp22_local2str(p->vsi, idbuf, sizeof(idbuf)); -+ break; -+ default: -+ strcpy(idbuf, "unsupported format"); -+ break; -+ } -+ -+ mgrid2str(p, mgridbuf, sizeof(mgridbuf)); -+ LLDPAD_DBG("vsi:%p flags:%#lx vsi_mode:%d,%d status:%#x" -+ " mgrid:%s id:%ld(%#lx) version:%d" -+ " id_fmt:%d %s format:%d no:%d\n", -+ p, p->flags, p->vsi_mode, p->cc_vsi_mode, p->status, -+ mgridbuf, p->type_id, -+ p->type_id, p->type_ver, p->vsi_fmt, idbuf, -+ p->fif, p->no_fdata); -+ if (p->fdata) -+ showvsifid("fid", p->fif, p->no_fdata, p->fdata); -+ LLDPAD_DBG("smi:state:%d kato:%d ackreceived:%d acktimeout:%d" -+ " localchg:%d deassoc:%d txmit:%d resp_ok:%d" -+ " txmit_error:%d\n", p->smi.state, p->smi.kato, -+ p->smi.ackreceived, p->smi.acktimeout, p->smi.localchg, -+ p->smi.deassoc, p->smi.txmit, p->smi.resp_ok, -+ p->smi.txmit_error); -+} -+ -+/* -+ * Delete a complete VSI node not on queue. -+ */ -+static void vdp22_delete_vsi(struct vsi22 *p) -+{ -+ LLDPAD_DBG("%s:%s vsi:%p(%02x)\n", __func__, p->vdp->ifname, p, -+ p->vsi[0]); -+ free(p->fdata); -+ free(p); -+} -+ -+/* -+ * Remove a VSI node from list and delete it. -+ */ -+void vdp22_listdel_vsi(struct vsi22 *p) -+{ -+ LLDPAD_DBG("%s:%s vsi:%p(%02x)\n", __func__, p->vdp->ifname, p, -+ p->vsi[0]); -+ LIST_REMOVE(p, node); -+ vdp22_delete_vsi(p); -+} -+ -+/* Check for valid VSI request mode, filter info format and VSI ID */ -+/* -+ * Return true if data consists completely of zeroes. -+ */ -+static bool is_zeroes(unsigned char *cp, size_t len) -+{ -+ size_t x; -+ -+ for (x = 0; x < len; ++x) -+ if (*cp++) -+ return false; -+ return true; -+} -+ -+/* -+ * IPV4 address right aligned with leading zeros. -+ */ -+static bool is_ipv4(unsigned char *cp) -+{ -+ if (!is_zeroes(cp, 10)) -+ return false; -+ if (cp[10] != 0xff && cp[11] != 0xff) -+ return false; -+ if (is_zeroes(cp + 12, 4)) -+ return false; -+ return true; -+} -+ -+/* -+ * MAC address right aligned with leading zeros. -+ */ -+static bool is_mac(unsigned char *cp) -+{ -+ if (!is_zeroes(cp, 10)) -+ return false; -+ return is_valid_mac(cp + 10); -+} -+ -+/* -+ * IPV6 address. -+ */ -+static bool is_ipv6(unsigned char *cp) -+{ -+ if (is_zeroes(cp, 16)) -+ return false; -+ return true; -+} -+ -+/* -+ * Check if VSI request is valid. -+ */ -+static bool check_vsirequest(unsigned char request) -+{ -+ bool rc = true; -+ -+ switch (request) { -+ case VDP22_PREASSOC: -+ case VDP22_PREASSOC_WITH_RR: -+ case VDP22_ASSOC: -+ case VDP22_DEASSOC: -+ case VDP22_MGRID: -+ case VDP22_OUI: -+ break; -+ default: -+ rc = false; -+ } -+ LLDPAD_DBG("%s rc:%d\n", __func__, rc); -+ return rc; -+} -+ -+/* -+ * Check if VSI filter information format is valid. -+ */ -+static bool check_filterfmt(unsigned char filter_fmt) -+{ -+ bool rc = true; -+ -+ switch (filter_fmt) { -+ case VDP22_FFMT_VID: -+ case VDP22_FFMT_MACVID: -+ case VDP22_FFMT_GROUPVID: -+ case VDP22_FFMT_GROUPMACVID: -+ break; -+ default: -+ rc = false; -+ } -+ LLDPAD_DBG("%s rc:%d\n", __func__, rc); -+ return rc; -+} -+ -+/* -+ * Check if VSI identifier is valid. -+ */ -+static bool check_vsiid(unsigned char vsiid_fmt, unsigned char *vsi_uuid) -+{ -+ bool rc = true; -+ -+ switch (vsiid_fmt) { -+ case VDP22_ID_IP4: -+ if (!is_ipv4(vsi_uuid)) -+ rc = false; -+ break; -+ case VDP22_ID_IP6: -+ if (!is_ipv6(vsi_uuid)) -+ rc = false; -+ break; -+ case VDP22_ID_MAC: -+ if (!is_mac(vsi_uuid)) -+ rc = false; -+ break; -+ case VDP22_ID_UUID: -+ if (is_zeroes(vsi_uuid, sizeof(vsi_uuid))) -+ rc = false; -+ break; -+ case VDP22_ID_LOCAL: -+ /* Anything goes */ -+ break; -+ default: -+ rc = false; -+ } -+ LLDPAD_DBG("%s rc:%d\n", __func__, rc); -+ return rc; -+} -+ -+/* -+ * Check if VSI information received via netlink message is valid. -+ */ -+static bool check_vsinl(struct vdpnl_vsi *vsi) -+{ -+ bool rc; -+ -+ rc = check_vsiid(vsi->vsiid_fmt, vsi->vsi_uuid) -+ && check_vsirequest(vsi->request) -+ && check_filterfmt(vsi->filter_fmt); -+ LLDPAD_DBG("%s:%s request:%d filter_fmt:%d vsi_fmt:%d rc:%d\n", -+ __func__, vsi->ifname, vsi->request, vsi->filter_fmt, -+ vsi->vsiid_fmt, rc); -+ return rc; -+} -+ -+/* -+ * Check if VSI information received via TLV message is valid. -+ */ -+static bool check_vsi(struct vsi22 *vsi) -+{ -+ bool rc; -+ -+ rc = check_vsiid(vsi->vsi_fmt, vsi->vsi) -+ && check_vsirequest(vsi->vsi_mode) && check_filterfmt(vsi->fif); -+ LLDPAD_DBG("%s:%s vsi_mode:%d filter_fmt:%d vsi_fmt:%d rc:%d\n", -+ __func__, vsi->vdp->ifname, vsi->vsi_mode, vsi->fif, -+ vsi->vsi_fmt, rc); -+ return rc; -+} -+ -+/* -+ * Copy filter information data. -+ */ -+static void copy_filter(unsigned char fif, struct fid22 *fp, -+ struct vdpnl_mac *from) -+{ -+ switch (fif) { -+ case VDP22_FFMT_GROUPMACVID: -+ case VDP22_FFMT_GROUPVID: -+ fp->grpid = from->gpid; -+ if (fif == VDP22_FFMT_GROUPVID) -+ goto vid; -+ /* Fall through intended */ -+ case VDP22_FFMT_MACVID: -+ memcpy(fp->mac, from->mac, sizeof(fp->mac)); -+ /* Fall through intended */ -+ case VDP22_FFMT_VID: -+vid: -+ fp->vlan = from->vlan; -+ break; -+ } -+} -+ -+/* -+ * Check supplied filter information. -+ */ -+static bool check_mac(struct fid22 *fp) -+{ -+ if (!is_valid_mac(fp->mac)) -+ return false; -+ return true; -+} -+ -+static bool check_vid(struct fid22 *fp) -+{ -+ unsigned short num = vdp22_get_vlanid(fp->vlan); -+ -+ if (num > 0 && (num < 2 || num > 4094)) -+ return false; -+ return true; -+} -+ -+static bool check_group(struct fid22 *fp) -+{ -+ return fp->grpid ? true : false; -+} -+ -+/* -+ * Check for filter information consistency. -+ */ -+static bool filter_ok(unsigned char ffmt, struct fid22 *fp, -+ unsigned char gpid_on) -+{ -+ bool rc = false; -+ -+ switch (ffmt) { -+ case VDP22_FFMT_VID: -+ rc = check_vid(fp); -+ break; -+ case VDP22_FFMT_MACVID: -+ rc = check_vid(fp) && check_mac(fp); -+ break; -+ case VDP22_FFMT_GROUPVID: -+ if (gpid_on) -+ rc = check_vid(fp) && check_group(fp); -+ else -+ rc = false; -+ break; -+ case VDP22_FFMT_GROUPMACVID: -+ if (gpid_on) -+ rc = check_vid(fp) && check_mac(fp) && -+ check_group(fp); -+ else -+ rc = false; -+ } -+ LLDPAD_DBG("%s:rc:%d\n", __func__, rc); -+ return rc; -+} -+ -+/* -+ * Allocate a VSI node with filter information data. -+ * Check if input data is valid. -+ */ -+static struct vsi22 *vdp22_alloc_vsi(struct vdpnl_vsi *vsi, struct vdp22 *vdp, -+ int *rc) -+{ -+ struct vsi22 *p; -+ int i; -+ -+ *rc = -EINVAL; -+ if (!check_vsinl(vsi)) -+ return NULL; -+ p = calloc(1, sizeof(*p)); -+ if (!p) { -+ *rc = -ENOMEM; -+ return p; -+ } -+ -+ p->no_fdata = vsi->macsz; -+ p->fdata = calloc(vsi->macsz, sizeof(struct fid22)); -+ if (!p->fdata) { -+ free(p); -+ *rc = -ENOMEM; -+ return NULL; -+ } -+ -+ p->vdp = vdp; -+ p->vsi_mode = vsi->request; -+ p->cc_vsi_mode = VDP22_DEASSOC; -+ p->hints = vsi->hints; -+ p->status = VDP22_RESP_NONE; -+ p->flags = VDP22_BUSY | VDP22_NLCMD; -+ if (vsi->nl_version == vdpnl_nlf2) -+ memcpy(p->mgrid, vsi->vsi_mgrid2, sizeof(p->mgrid)); -+ else -+ p->mgrid[0] = vsi->vsi_mgrid; -+ p->type_ver = vsi->vsi_typeversion; -+ p->type_id = vsi->vsi_typeid; -+ p->vsi_fmt = VDP22_ID_UUID; -+ memcpy(p->vsi, vsi->vsi_uuid, sizeof(p->vsi)); -+ p->fif = vsi->filter_fmt; -+ -+ /* Copy filter info and do some sanity checks based on format */ -+ for (i = 0; i < vsi->macsz; ++i) { -+ struct vdpnl_mac *from = &vsi->maclist[i]; -+ struct fid22 *fp = &p->fdata[i]; -+ -+ copy_filter(p->fif, fp, from); -+ if (from->vlan == 0) { -+ /* Only one filter member with null vlan id */ -+ if (vsi->macsz > 1 && p->fif == VDP22_FFMT_VID) { -+ *rc = -EINVAL; -+ goto error1; -+ } -+ p->flags |= VDP22_RETURN_VID; -+ } -+ if (!filter_ok(p->fif, fp, vdp->gpid)) { -+ *rc = -EINVAL; -+ goto error1; -+ } -+ fp->requestor.req_pid = vsi->req_pid; -+ fp->requestor.req_seq = vsi->req_seq; -+ } -+ *rc = 0; -+ LLDPAD_DBG("%s:%s vsi:%p(%02x)\n", __func__, vsi->ifname, p, p->vsi[0]); -+ return p; -+error1: -+ vdp22_showvsi(p); -+ vdp22_delete_vsi(p); -+ return NULL; -+} -+ -+/* -+ * Allocate a VSI node with filter information data. -+ * Check if input data is valid. Data was received by bridge from unknown -+ * counterpart and might be invalid. -+ */ -+struct vsi22 *vdp22_copy_vsi(struct vsi22 *old) -+{ -+ struct vsi22 *p; -+ int i; -+ -+ if (!check_vsi(old)) -+ return NULL; -+ p = calloc(1, sizeof(*p)); -+ if (!p) -+ return p; -+ *p = *old; -+ p->flags = 0; -+ p->cc_vsi_mode = VDP22_DEASSOC; -+ p->fdata = calloc(p->no_fdata, sizeof(struct fid22)); -+ if (!p->fdata) -+ goto error1; -+ -+ /* Copy filter info and do some sanity checks based on format */ -+ for (i = 0; i < p->no_fdata; ++i) { -+ p->fdata[i] = old->fdata[i]; -+ /* Only one filter member with wildcard vlan id */ -+ if (p->fdata[i].vlan == 0) { -+ if (p->no_fdata > 1 && p->fif == VDP22_FFMT_VID) -+ goto error1; -+ } -+ if (!filter_ok(p->fif, &p->fdata[i], p->vdp->gpid)) -+ goto error1; -+ } -+ LLDPAD_DBG("%s:%s vsi:%p(%02x)\n", __func__, p->vdp->ifname, p, -+ p->vsi[0]); -+ return p; -+error1: -+ vdp22_delete_vsi(p); -+ return NULL; -+} -+ -+/* -+ * Find the vdp data associated with an interface. -+ * Parameter 'ud' may be zero, then search for the module first. -+ * -+ * Return pointer or NULL if not found. -+ */ -+static struct vdp22 *vdp22_findif(const char *ifname, -+ struct vdp22_user_data *ud) -+{ -+ struct vdp22 *vdp = 0; -+ -+ if (!ud) { -+ ud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_VDP22); -+ if (!ud) -+ LLDPAD_DBG("%s:%s no VDP22 module\n", __func__, -+ ifname); -+ } -+ if (ud) { -+ LIST_FOREACH(vdp, &ud->head, node) -+ if (!strncmp(ifname, vdp->ifname, IFNAMSIZ)) -+ break; -+ } -+ return vdp; -+} -+ -+/* -+ * Update data exchanged via ECP protocol. -+ * Returns true when data update succeeded. -+ */ -+static int data_from_ecp(char *ifname, struct ecp22_to_ulp *ptr) -+{ -+ int rc = -ENOENT; -+ struct vdp22 *vdp; -+ -+ vdp = vdp22_findif(ifname, NULL); -+ if (vdp) { -+ memcpy(vdp->input, ptr->data, ptr->len); -+ vdp->input_len = ptr->len; -+ rc = vdp22_from_ecp22(vdp); -+ LLDPAD_DBG("%s:%s rc:%d ", __func__, ifname, rc); -+ } -+ return rc; -+} -+ -+/* -+ * Update data exchanged via EVB protocol. -+ * Calculate the various time out values based in input parameters. -+ * See IEEE 802.1Qbg ratified standard 41.5.5.7 + 41.5.5.9 -+ * Returns true when data update succeeded. -+ */ -+static int data_from_evb(char *ifname, struct evb22_to_vdp22 *ptr) -+{ -+ int rc = -ENOENT; -+ struct vdp22 *vdp; -+ -+ vdp = vdp22_findif(ifname, NULL); -+ if (vdp) { -+ vdp->ecp_retries = ptr->max_retry; -+ vdp->ecp_rte = ptr->max_rte; -+ vdp->vdp_rka = ptr->max_rka; -+ vdp->vdp_rwd = ptr->max_rwd; -+ vdp->gpid = ptr->gpid; -+ LLDPAD_DBG("%s:%s rwd:%d rka:%d gpid:%d retry:%d rte:%d\n", -+ __func__, ifname, ptr->max_rwd, ptr->max_rka, -+ ptr->gpid, ptr->max_retry, ptr->max_rte); -+ rc = 0; -+ } -+ return rc; -+} -+ -+/* -+ * Handle notifications from other modules. Check if sender-id and data type -+ * indicator match. Return false when data could not be delivered. -+ */ -+static int vdp22_notify(int sender_id, char *ifname, void *data) -+{ -+ struct qbg22_imm *qbg = (struct qbg22_imm *)data; -+ -+ LLDPAD_DBG("%s:%s sender-id:%#x data_type:%d\n", __func__, ifname, -+ sender_id, qbg->data_type); -+ if (sender_id == LLDP_MOD_EVB22 && qbg->data_type == EVB22_TO_VDP22) -+ return data_from_evb(ifname, &qbg->u.b); -+ if (sender_id == LLDP_MOD_ECP22 && qbg->data_type == ECP22_TO_ULP) -+ return data_from_ecp(ifname, &qbg->u.c); -+ return 0; -+} -+ -+/* -+ * Remove a vdp22 element and delete the chain of active VSIs -+ */ -+static void vdp22_free_elem(struct vdp22 *vdp) -+{ -+ while (!LIST_EMPTY(&vdp->vsi22_que)) { -+ struct vsi22 *p = LIST_FIRST(&vdp->vsi22_que); -+ -+ vdp22_listdel_vsi(p); -+ } -+ LIST_REMOVE(vdp, node); -+ free(vdp); -+} -+ -+/* -+ * Disable the interface for VDP protocol support. -+ */ -+void vdp22_stop(char *ifname) -+{ -+ struct vdp22_user_data *vud; -+ struct vdp22 *vdp; -+ -+ LLDPAD_DBG("%s:%s stop vdp\n", __func__, ifname); -+ vud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_VDP22); -+ if (!vud) { -+ LLDPAD_ERR("%s:%s no VDP22 module\n", __func__, ifname); -+ return; -+ } -+ vdp = vdp22_findif(ifname, vud); -+ if (!vdp) { -+ LLDPAD_ERR("%s:%s no VDP22 data\n", __func__, ifname); -+ return; -+ } -+ vdp22_free_elem(vdp); -+} -+ -+/* -+ * vdp22_create - create data structure and initialize vdp protocol -+ * @ifname: interface for which the vdp protocol is initialized -+ * -+ * returns NULL on error and an pointer to the vdp22 structure on success. -+ * -+ * Finds the port to the interface name, sets up the receive handle for -+ * incoming vdp frames and initializes the vdp rx and tx state machines. -+ * To be called when a successful exchange of EVB TLVs has been -+ * made and ECP protocols are supported by both sides. -+ * -+ * Read the role (station vs bridge) from the configuration file. -+ */ -+static struct vdp22 *vdp22_create(const char *ifname, -+ struct vdp22_user_data *eud, int role) -+{ -+ struct vdp22 *vdp; -+ -+ vdp = calloc(1, sizeof *vdp); -+ if (!vdp) { -+ LLDPAD_ERR("%s:%s unable to allocate vdp protocol\n", __func__, -+ ifname); -+ return NULL; -+ } -+ strncpy(vdp->ifname, ifname, sizeof vdp->ifname); -+ vdp->myrole = role; -+ LIST_INIT(&vdp->vsi22_que); -+ LIST_INSERT_HEAD(&eud->head, vdp, node); -+ LLDPAD_DBG("%s:%s role:%d\n", __func__, ifname, role); -+ return vdp; -+} -+ -+/* -+ * Query the supported VDP protocol on an interface. -+ */ -+static struct vdp22 *vdp22_getvdp(const char *ifname) -+{ -+ struct vdp22 *vdp; -+ -+ vdp = vdp22_findif(ifname, NULL); -+ LLDPAD_DBG("%s:%s vdp %p\n", __func__, ifname, vdp); -+ return vdp; -+} -+ -+int vdp22_query(const char *ifname) -+{ -+ int rc = 0; -+ -+ if (vdp22_getvdp(ifname)) -+ rc = 1; -+ LLDPAD_DBG("%s:%s rc:%d\n", __func__, ifname, rc); -+ return rc; -+} -+ -+/* -+ * Enable the interface for VDP protocol support. -+ */ -+void vdp22_start(const char *ifname, int role) -+{ -+ struct vdp22_user_data *vud; -+ struct vdp22 *vdp; -+ -+ LLDPAD_DBG("%s:%s start vdp\n", __func__, ifname); -+ vud = find_module_user_data_by_id(&lldp_head, LLDP_MOD_VDP22); -+ if (!vud) { -+ LLDPAD_ERR("%s:%s no VDP22 module\n", __func__, ifname); -+ return; -+ } -+ vdp = vdp22_findif(ifname, vud); -+ if (!vdp) -+ vdp = vdp22_create(ifname, vud, role); -+} -+ -+/* -+ * Handle a VSI request from buddy. -+ */ -+int vdp22_request(struct vdpnl_vsi *vsi) -+{ -+ int rc; -+ struct vsi22 *p; -+ struct vdp22 *vdp; -+ -+ LLDPAD_DBG("%s:%s\n", __func__, vsi->ifname); -+ vdp = vdp22_findif(vsi->ifname, NULL); -+ if (vdp) { -+ if (vdp->myrole == VDP22_BRIDGE) { -+ rc = -EOPNOTSUPP; -+ goto out; -+ } -+ /* Adjust numbering for VDP22 protocol */ -+ vsi->request += 1; -+ p = vdp22_alloc_vsi(vsi, vdp, &rc); -+ if (p) { -+ rc = vdp22_addreq(p, vdp); -+ if (rc) -+ vdp22_delete_vsi(p); -+ } -+ } else -+ rc = -ENODEV; -+out: -+ LLDPAD_DBG("%s:%s rc:%d\n", __func__, vsi->ifname, rc); -+ return rc; -+} -+ -+/* -+ * Remove all interface/agent specific vdp data. -+ */ -+static void vdp22_free_data(struct vdp22_user_data *ud) -+{ -+ if (ud) { -+ while (!LIST_EMPTY(&ud->head)) { -+ struct vdp22 *vd = LIST_FIRST(&ud->head); -+ -+ vdp22_free_elem(vd); -+ } -+ } -+} -+ -+void vdp22_unregister(struct lldp_module *mod) -+{ -+ if (mod->data) { -+ vdp22_free_data((struct vdp22_user_data *)mod->data); -+ free(mod->data); -+ } -+ free(mod); -+ LLDPAD_DBG("%s:done\n", __func__); -+} -+ -+static const struct lldp_mod_ops vdp22_ops = { -+ .lldp_mod_register = vdp22_register, -+ .lldp_mod_unregister = vdp22_unregister, -+ .lldp_mod_notify = vdp22_notify -+}; -+ -+struct lldp_module *vdp22_register(void) -+{ -+ struct lldp_module *mod; -+ struct vdp22_user_data *ud; -+ -+ mod = calloc(1, sizeof *mod); -+ if (!mod) { -+ LLDPAD_ERR("%s: failed to malloc module data\n", __func__); -+ return NULL; -+ } -+ ud = calloc(1, sizeof *ud); -+ if (!ud) { -+ free(mod); -+ LLDPAD_ERR("%s failed to malloc module user data\n", __func__); -+ return NULL; -+ } -+ LIST_INIT(&ud->head); -+ mod->id = LLDP_MOD_VDP22; -+ mod->ops = &vdp22_ops; -+ mod->data = ud; -+ LLDPAD_DBG("%s:done\n", __func__); -+ return mod; -+} -+ -+static void copy_fid(struct vdpnl_vsi *vsi, struct vsi22 *p) -+{ -+ int i; -+ -+ vsi->filter_fmt = p->fif; -+ for (i = 0; i < vsi->macsz; ++i) { -+ if( i == p->no_fdata) -+ break; -+ vsi->maclist[i].gpid = p->fdata[i].grpid; -+ vsi->maclist[i].vlan = vdp22_get_vlanid(p->fdata[i].vlan); -+ vsi->maclist[i].qos = vdp22_get_qos(p->fdata[i].vlan); -+ vsi->maclist[i].changed = 1; -+ } -+ vsi->macsz = i; -+} -+ -+/* -+ * Query a VSI request from buddy and report its progress. Use the interface -+ * name to determine the VSI profile list. Return one entry in parameter 'vsi' -+ * use the structure members response and vsi_uuid. -+ * Returns -+ * 1 valid VSI data returned -+ * 0 end of queue (no VSI data returned) -+ * <0 errno -+ */ -+int vdp22_status(int number, struct vdpnl_vsi *vsi) -+{ -+ struct vdp22 *vdp; -+ struct vsi22 *p; -+ int i = 0, ret = 0; -+ -+ LLDPAD_DBG("%s:%s\n", __func__, vsi->ifname); -+ vdp = vdp22_findif(vsi->ifname, NULL); -+ if (!vdp) { -+ LLDPAD_ERR("%s:%s has not yet been configured\n", __func__, -+ vsi->ifname); -+ return -ENODEV; -+ } -+ /* Iterate to queue element number */ -+ LIST_FOREACH(p, &vdp->vsi22_que, node) { -+ if (++i == number) { -+ ret = 1; -+ break; -+ } -+ } -+ if (ret) { -+ vdp22_showvsi(p); -+ vsi->response = p->status; -+ memcpy(vsi->vsi_uuid, p->vsi, sizeof(vsi->vsi_uuid)); -+ p->flags &= ~VDP22_NLCMD; -+ if (p->flags & VDP22_RETURN_VID) { -+ copy_fid(vsi, p); -+ p->flags &= ~VDP22_RETURN_VID; -+ } -+ if (vsi->response != VDP22_RESP_NONE && -+ (p->flags & VDP22_DELETE_ME)) -+ vdp22_listdel_vsi(p); -+ } -+ LLDPAD_DBG("%s: entry:%d more:%d\n", __func__, number, ret); -+ return ret; -+} -+ -+/* -+ * Convert and VSI22 to VDP netlink format and send it back to the originator. -+ */ -+int vdp22_nlback(struct vsi22 *vsi) -+{ -+ int i; -+ struct vdpnl_vsi nl; -+ struct vdpnl_mac nlmac[vsi->no_fdata]; -+ -+ LLDPAD_DBG("%s:%s vsi:%p(%#2x)\n", __func__, vsi->vdp->ifname, -+ vsi, vsi->vsi[0]); -+ -+ memset(&nl, 0, sizeof(nl)); -+ memset(nlmac, 0, sizeof(nlmac)); -+ nl.maclist = nlmac; -+ nl.macsz = vsi->no_fdata; -+ memcpy(nl.ifname, vsi->vdp->ifname, sizeof(nl.ifname)); -+ nl.request = vsi->vsi_mode - 1; /* Maintain old number */ -+ nl.response = vsi->status; -+ nl.vsi_mgrid = atoi((const char *)vsi->mgrid); -+ nl.vsi_typeversion = vsi->type_ver; -+ nl.vsi_typeid = vsi->type_id; -+ nl.vsiid_fmt = VDP22_ID_UUID; -+ memcpy(nl.vsi_uuid, vsi->vsi, sizeof(nl.vsi_uuid)); -+ nl.filter_fmt = vsi->fif; -+ for (i = 0; i < nl.macsz; ++i) { -+ nlmac[i].vlan = vsi->fdata[i].vlan; -+ memcpy(nlmac[i].mac, vsi->fdata[i].mac, sizeof(nlmac[i].mac)); -+ nl.req_pid = vsi->fdata[i].requestor.req_pid; -+ nl.req_seq = vsi->fdata[i].requestor.req_seq; -+ } -+ -+ vdpnl_send(&nl); -+ if (vsi->flags & VDP22_DELETE_ME) -+ vdp22_listdel_vsi(vsi); -+ return 0; -+} -+ -diff --git a/qbg/vdp22br.c b/qbg/vdp22br.c -new file mode 100644 -index 0000000..a3cee9c ---- /dev/null -+++ b/qbg/vdp22br.c -@@ -0,0 +1,189 @@ -+/****************************************************************************** -+ -+ Implementation of VDP 2.2 bridge resource allocation simulator for LLDP -+ (c) Copyright IBM Corp. 2013 -+ -+ Author(s): Thomas Richter -+ -+ This program is free software; you can redistribute it and/or modify it -+ under the terms and conditions of the GNU General Public License, -+ version 2, as published by the Free Software Foundation. -+ -+ This program is distributed in the hope it will be useful, but WITHOUT -+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ more details. -+ -+ You should have received a copy of the GNU General Public License along with -+ this program; if not, write to the Free Software Foundation, Inc., -+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. -+ -+ The full GNU General Public License is included in this distribution in -+ the file called "COPYING". -+ -+******************************************************************************/ -+ -+/* -+ * VDP22 bridge simulation code. For now return true all the time. -+ * When configured with --enable-debug option -+ * special combination of input parameters trigger errors decribed -+ * below. -+ * -+ * TODO -+ * Will be replaced by lldpad configuration file section to allow -+ * rejection and acception of VSI profiles on a configurable bases. -+ * For now this is good enough for basic state machine testing. -+ */ -+ -+#define _GNU_SOURCE -+#include -+ -+#include -+#include -+ -+#include "messages.h" -+#include "config.h" -+#include "eloop.h" -+ -+#include "qbg22.h" -+#include "qbg_vdp22.h" -+#include "qbg_utils.h" -+ -+#ifdef BUILD_DEBUG -+static unsigned char deassoc_buf[256]; -+static unsigned char ifname_buf[16]; -+static struct qbg22_imm deassoc_qbg; -+ -+static void deassoc(void *ctx, void *parm) -+{ -+ struct qbg22_imm *qbg = (struct qbg22_imm *)parm; -+ char *ifname = (char *)ctx; -+ int rc; -+ -+ rc = modules_notify(LLDP_MOD_ECP22, LLDP_MOD_VDP22, ifname, qbg); -+ LLDPAD_DBG("%s:%s leave rc:%d\n", __func__, ifname, rc); -+} -+ -+static void trigger_deassoc(struct vdp22 *vdp) -+{ -+ deassoc_qbg.data_type = VDP22_TO_ECP22; -+ deassoc_qbg.u.c.len = vdp->input_len - 2; -+ deassoc_qbg.u.c.data = deassoc_buf; -+ memcpy(deassoc_buf, vdp->input, vdp->input_len - 2); -+ deassoc_buf[18] = VDP22_DEASSOC << 1; /* Offset of TLV */ -+ deassoc_buf[18 + 2] = 0; -+ memcpy(ifname_buf, vdp->ifname, sizeof(ifname_buf)); -+ eloop_register_timeout(35, 0, deassoc, ifname_buf, &deassoc_qbg); -+ LLDPAD_DBG("%s:%s\n", __func__, vdp->ifname); -+} -+ -+static void change_vlan0(struct vsi22 *p, unsigned short idx, int with_qos) -+{ -+ if (p->fif == VDP22_FFMT_MACVID) -+ p->fdata[idx].vlan = vdp22_set_vlanid(p->type_id); -+ else -+ p->fdata[idx].vlan = vdp22_set_vlanid(p->fdata[idx].grpid); -+ if (with_qos) -+ p->fdata[idx].vlan |= vdp22_set_qos(8 + (p->type_ver & 7)); -+} -+ -+static int change_fid(struct vsi22 *p) -+{ -+ unsigned short idx = p->type_ver >> 4 & 0xf; -+ -+ if (idx >= p->no_fdata) -+ return VDP22_RESP_NOADDR; -+ if (p->type_id == 204) { -+ p->fdata[idx].vlan = vdp22_set_vlanid(p->fdata[idx].grpid) -+ | vdp22_set_qos(8 + (p->type_ver & 7)); -+ } else if (p->type_id == 205) { -+ p->fdata[idx].vlan = vdp22_set_vlanid(p->type_id); -+ } else if (p->type_id == 206) { -+ p->fdata[idx].vlan = vdp22_get_vlanid(p->fdata[idx].vlan) -+ | vdp22_set_qos(8 + (p->type_ver & 7)); -+ } else if (p->type_id == 207) { -+ p->fdata[idx].vlan = vdp22_set_vlanid(p->fdata[idx].grpid); -+ } else if (p->type_id == 208 && p->fif != VDP22_FFMT_VID) { -+ int i; -+ -+ for (i = 0; i < p->no_fdata; ++i) -+ if (!vdp22_get_vlanid(p->fdata[i].vlan)) -+ change_vlan0(p, i, idx); -+ } -+ return 0; -+} -+#endif -+ -+int vdp22br_resources(struct vsi22 *p, int *error) -+{ -+ int rc = VDP22_RESP_SUCCESS; -+ static unsigned long called; -+ -+ *error = 0; -+ ++called; -+ LLDPAD_DBG("%s:%s vsi:%p(%02x) called:%ld id:%ld\n", __func__, -+ p->vdp->ifname, p, p->vsi[0], called, p->type_id); -+ rc = (p->vsi_mode == VDP22_DEASSOC) ? VDP22_RESP_DEASSOC : -+ VDP22_RESP_SUCCESS; -+#ifdef BUILD_DEBUG -+ /* -+ * Trigger errors -+ * Typeid 199 trigger delayed bridge resource availability -+ * Typeid 200 trigger de-assoc -+ * Typeid 201 trigger de-assoc error response -+ * Typeid 202 trigger keep error response with keep bit set -+ * Typeid 203 trigger de-assoc error response with hard bit set -+ * Typeid 199-202 type_ver determines when fired. -+ * -+ * Typeid 204 replace VLAN with groupid as VLAN ID and type_ver as QoS -+ * Typeid 205 replace VLAN 0 with typeid as VLAN ID -+ * Typeid 206 replace QoS 0 with type_ver as QoS -+ * Typeid 207 replace VLAN with groupid as VLAN ID -+ * For typeid 204-207 use upper nipple of type_ver as index into fid -+ * array. -+ * -+ * Typeid 208 replace all VLAN 0 -+ * - with typeid as VLAN ID (filter format MAC/VID) -+ * - with group identifier as VLAN ID (filter format GROUP/[MAC/]VID) -+ * - use upper nibble of type_ver to indicate a QoS change (true), -+ * lower nibble of type_ver is QoS value. -+ */ -+ switch (p->type_id) { -+ case 199: -+ if (called == p->type_ver) { -+ rc = VDP22_RESP_TIMEOUT; -+ } -+ break; -+ case 200: -+ trigger_deassoc(p->vdp); -+ break; -+ case 201: -+ case 203: -+ if (called == p->type_ver) { -+ *error = VDP22_RESP_NO_RESOURCES; -+ rc = VDP22_RESP_DEASSOC; -+ if (p->type_id == 203) -+ *error |= 0x10; -+ } -+ break; -+ case 202: -+ if (called == p->type_ver) { -+ *error = VDP22_RESP_NO_VSIMGR; -+ rc = VDP22_RESP_KEEP; -+ } -+ break; -+ case 204: -+ case 205: -+ case 206: -+ case 207: -+ case 208: -+ *error = change_fid(p); -+ if (*error == VDP22_RESP_NOADDR) -+ rc = VDP22_RESP_DEASSOC; -+ break; -+ } -+#endif -+ LLDPAD_DBG("%s:%s resp_vsi_mode:%d rc:%d error:%d\n", __func__, -+ p->vdp->ifname, p->resp_vsi_mode, rc, *error); -+ return rc; -+} -diff --git a/qbg/vdp22sm.c b/qbg/vdp22sm.c -new file mode 100644 -index 0000000..62fa5a3 ---- /dev/null -+++ b/qbg/vdp22sm.c -@@ -0,0 +1,1718 @@ -+/****************************************************************************** -+ -+ Implementation of VDP 2.2 bridge and station state machines for -+ IEEE 802.1 Qbg ratified standard. -+ (c) Copyright IBM Corp. 2013 -+ -+ Author(s): Thomas Richter -+ -+ This program is free software; you can redistribute it and/or modify it -+ under the terms and conditions of the GNU General Public License, -+ version 2, as published by the Free Software Foundation. -+ -+ This program is distributed in the hope it will be useful, but WITHOUT -+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ more details. -+ -+ You should have received a copy of the GNU General Public License along with -+ this program; if not, write to the Free Software Foundation, Inc., -+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. -+ -+ The full GNU General Public License is included in this distribution in -+ the file called "COPYING". -+ -+******************************************************************************/ -+ -+/* -+ * Implement the IEEE 802.1Qbg ratified standard VDP Protocol state machines. -+ */ -+ -+#define _GNU_SOURCE -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include "messages.h" -+#include "config.h" -+#include "eloop.h" -+ -+#include "qbg22.h" -+#include "qbg_vdp22.h" -+#include "qbg_utils.h" -+ -+struct vdp22_ptlv { /* Packed TLV for VDP data exchange */ -+ unsigned short head; /* TLV 16 bit header */ -+ unsigned char data[]; /* TLV Data buffer */ -+}; -+ -+enum { /* VDP22 Protocol command responses */ -+ USEC_PER_SEC = 1000000, /* Microseconds per second */ -+ VDP22_RESBIT = 1, /* VSI reserved bit */ -+ VDP22_ACKBIT = 2, /* VSI Acknowledgement bit */ -+ VDP22_KEEPBIT = 4, /* VSI keep error bit */ -+ VDP22_HARDBIT = 8, /* VSI hard error bit */ -+ VDP22_STATUS_MASK = 0xf0, /* Status mask */ -+ VDP22_STATUS_SHIFT = 4, /* Status offset */ -+}; -+ -+/* -+ * Set status code -+ */ -+static inline unsigned char make_status(int x) -+{ -+ return (x << VDP22_STATUS_SHIFT) & VDP22_STATUS_MASK; -+} -+ -+enum vdp22br_states { /* State for VDP22 bridge processing */ -+ VDP22_BR_START = 100, /* Start state */ -+ VDP22_BR_BEGIN, /* Begin state */ -+ VDP22_BR_INIT, /* Init state */ -+ VDP22_BR_PROCESS, /* Process command from station */ -+ VDP22_BR_SEND, /* Send result to station */ -+ VDP22_BR_WAITCMD, /* Wait for cmd from station */ -+ VDP22_BR_WAITCMD_2, /* End of wait for cmd from station */ -+ VDP22_BR_KEEP, /* Send keep result to station */ -+ VDP22_BR_DEASSOC, /* Send de-assoc result to station */ -+ VDP22_BR_ALIVE, /* Process keep alive from station state */ -+ VDP22_BR_DEASSOCIATED, /* Deassoc state */ -+ VDP22_BR_END /* End state */ -+}; -+ -+/* VDP22 bridge states verbatim */ -+static const char *const vdp22br_states_n[] = { -+ "unknown", -+ "VDP22_BR_BEGIN", -+ "VDP22_BR_INIT", -+ "VDP22_BR_PROCESS", -+ "VDP22_BR_SEND", -+ "VDP22_BR_WAITCMD", -+ "VDP22_BR_WAITCMD_2", -+ "VDP22_BR_KEEP", -+ "VDP22_BR_DEASSOC", -+ "VDP22_BR_ALIVE", -+ "VDP22_BR_DEASSOCIATED", -+ "VDP22_BR_END" -+}; -+ -+static inline const char *vdp22br_state_name(enum vdp22br_states x) -+{ -+ return vdp22br_states_n[x - VDP22_BR_START]; -+} -+ -+enum vdp22_states { /* VDP22 station states */ -+ VDP22_BEGIN = 1, -+ VDP22_INIT, -+ VDP22_STATION_PROC, /* Station processing */ -+ VDP22_STATION_PROCWAIT, /* Station processing, wait for reply */ -+ VDP22_STATION_PROCWAIT_2, /* Station processing, received reply */ -+ VDP22_ASSOC_NEW, -+ VDP22_ASSOC_COMPL, /* Assoc complete */ -+ VDP22_PREASSOC_NEW, -+ VDP22_WAIT_SYSCMD, -+ VDP22_WAIT_SYSCMD_2, -+ VDP22_TXMIT_KA, /* Transmit keep alive */ -+ VDP22_TXMIT_KAWAIT, /* Transmit keep alive, wait for reply */ -+ VDP22_TXMIT_KAWAIT_2, /* Transmit keep alive, received message */ -+ VDP22_TXMIT_DEASSOC, /* Transmit Deassociation */ -+ VDP22_TXMIT_DEAWAIT, /* Transmit Deassociation, wait for reply */ -+ VDP22_TXMIT_DEAWAIT_2, /* Transmit Deassociation, received reply */ -+ VDP22_END -+}; -+ -+/* VDP22 station states verbatim */ -+static const char *const vdp22_states_n[] = { -+ "unknown", -+ "VDP22_BEGIN", -+ "VDP22_INIT", -+ "VDP22_STATION_PROC", -+ "VDP22_STATION_PROCWAIT", -+ "VDP22_STATION_PROCWAIT_2", -+ "VDP22_ASSOC_NEW", -+ "VDP22_ASSOC_COMPL", -+ "VDP22_PREASSOC_NEW", -+ "VDP22_WAIT_SYSCMD", -+ "VDP22_WAIT_SYSCMD_2", -+ "VDP22_TXMIT_KA", -+ "VDP22_TXMIT_KAWAIT", -+ "VDP22_TXMIT_KAWAIT_2", -+ "VDP22_TXMIT_DEASSOC", -+ "VDP22_TXMIT_DEAWAIT", -+ "VDP22_TXMIT_DEAWAIT_2", -+ "VDP22_END" -+}; -+ -+/* -+ * Forward definition of function prototypes. -+ */ -+static void vdp22st_run(struct vsi22 *); -+static void vdp22br_run(struct vsi22 *); -+static void vdp22_station_info(struct vsi22 *); -+ -+/* -+ * Return size of packed and unpacked VSI tlv. -+ */ -+static inline size_t mgr22_tlv_sz(void) -+{ -+ return 16; -+} -+ -+static inline size_t mgr22_ptlv_sz(void) -+{ -+ return 2 + mgr22_tlv_sz(); -+} -+ -+/* Return size for each filter data format */ -+static inline size_t vsi22_fdata_sz(unsigned char fif) -+{ -+ switch (fif) { -+ case VDP22_FFMT_VID: -+ return 2; -+ case VDP22_FFMT_MACVID: -+ return 8; -+ case VDP22_FFMT_GROUPVID: -+ return 6; -+ case VDP22_FFMT_GROUPMACVID: -+ return 12; -+ } -+ return 0; -+} -+ -+static inline size_t vsi22_tlv_fifsz(struct vsi22 *vp) -+{ -+ return vp->no_fdata * vsi22_fdata_sz(vp->fif); -+} -+ -+static inline size_t vsi22_tlv_sz(struct vsi22 *vp) -+{ -+ return 23 + 2 + vsi22_tlv_fifsz(vp); -+} -+ -+static inline size_t vsi22_ptlv_sz(struct vsi22 *vp) -+{ -+ return 2 + vsi22_tlv_sz(vp); -+} -+ -+/* -+ * Extract 1, 2, 3, 4 byte integers in network byte format. -+ * Extract n bytes. -+ * Assume enough space available. -+ * Return number of bytes extracted. -+ */ -+static inline size_t extract_1o(unsigned char *data, const unsigned char *cp) -+{ -+ *data = *cp; -+ return 1; -+} -+ -+static inline size_t extract_2o(unsigned short *data, const unsigned char *cp) -+{ -+ *data = (*cp << 8) | *(cp + 1); -+ return 2; -+} -+ -+static inline size_t extract_3o(unsigned long *data, const unsigned char *cp) -+{ -+ *data = (*cp << 16) | (*(cp + 1) << 8) | *(cp + 2); -+ return 3; -+} -+ -+static inline size_t extract_4o(unsigned long *data, const unsigned char *cp) -+{ -+ *data = (*cp << 24) | (*(cp + 1) << 16) | (*(cp + 2) << 8) | *(cp + 3); -+ return 4; -+} -+static inline size_t extract_no(unsigned char *data, const unsigned char *cp, -+ const size_t len) -+{ -+ memcpy(data, cp, len); -+ return len; -+} -+ -+/* -+ * Append 1, 2, 3, 4 byte integers in network byte format. -+ * Append n bytes. -+ * Assume enough space available. -+ * Return number of bytes written. -+ */ -+static inline size_t append_1o(unsigned char *cp, const unsigned char data) -+{ -+ *cp = data; -+ return 1; -+} -+ -+static inline size_t append_2o(unsigned char *cp, const unsigned short data) -+{ -+ *cp = (data >> 8) & 0xff; -+ *(cp + 1) = data & 0xff; -+ return 2; -+} -+ -+static inline size_t append_3o(unsigned char *cp, const unsigned long data) -+{ -+ *cp = (data >> 16) & 0xff; -+ *(cp + 1) = (data >> 8) & 0xff; -+ *(cp + 2) = data & 0xff; -+ return 3; -+} -+ -+static inline size_t append_4o(unsigned char *cp, const unsigned long data) -+{ -+ *cp = (data >> 24) & 0xff; -+ *(cp + 1) = (data >> 16) & 0xff; -+ *(cp + 2) = (data >> 8) & 0xff; -+ *(cp + 3) = data & 0xff; -+ return 4; -+} -+ -+static inline size_t append_nb(unsigned char *cp, const unsigned char *data, -+ const size_t nlen) -+{ -+ memcpy(cp, data, nlen); -+ return nlen; -+} -+ -+/* -+ * Packed TLV header manipulation. -+ */ -+static inline unsigned short ptlv_head(unsigned short type, unsigned short len) -+{ -+ return (type & 0x7f) << 9 | (len & 0x1ff); -+} -+ -+static inline unsigned short ptlv_length(unsigned short header) -+{ -+ return 2 + (header & 0x1ff); -+} -+ -+static inline unsigned short ptlv_type(unsigned short header) -+{ -+ return (header >> 9) & 0x7f; -+} -+ -+/* -+ * Build a VSI tlv. -+ */ -+static size_t vsi22_2tlv_fdata(unsigned char *cp, struct fid22 *p, -+ unsigned char fif) -+{ -+ size_t nbytes = 0; -+ -+ switch (fif) { -+ case VDP22_FFMT_VID: -+ nbytes = append_2o(cp, p->vlan); -+ break; -+ case VDP22_FFMT_MACVID: -+ nbytes = append_nb(cp, p->mac, sizeof(p->mac)); -+ nbytes += append_2o(cp + nbytes, p->vlan); -+ break; -+ case VDP22_FFMT_GROUPVID: -+ nbytes = append_4o(cp, p->grpid); -+ nbytes += append_2o(cp + nbytes, p->vlan); -+ break; -+ case VDP22_FFMT_GROUPMACVID: -+ nbytes = append_4o(cp, p->grpid); -+ nbytes += append_nb(cp + nbytes, p->mac, sizeof(p->mac)); -+ nbytes += append_2o(cp + nbytes, p->vlan); -+ break; -+ } -+ return nbytes; -+} -+ -+static void vsi22_2tlv(struct vsi22 *vp, char unsigned *cp, unsigned char stat) -+{ -+ size_t offset = 0, i; -+ unsigned short head = ptlv_head(vp->vsi_mode, vsi22_tlv_sz(vp)); -+ -+ offset = append_2o(cp, head); -+ offset += append_1o(cp + offset, stat); -+ offset += append_3o(cp + offset, vp->type_id); -+ offset += append_1o(cp + offset, vp->type_ver); -+ offset += append_1o(cp + offset, vp->vsi_fmt); -+ offset += append_nb(cp + offset, vp->vsi, sizeof(vp->vsi)); -+ offset += append_1o(cp + offset, vp->fif); -+ offset += append_2o(cp + offset, vp->no_fdata); -+ for (i = 0; i < vp->no_fdata; ++i) -+ offset += vsi22_2tlv_fdata(cp + offset, &vp->fdata[i], vp->fif); -+} -+ -+static void mgr22_2tlv(struct vsi22 *vp, unsigned char *cp) -+{ -+ unsigned short head = ptlv_head(VDP22_MGRID, mgr22_tlv_sz()); -+ size_t offset; -+ -+ offset = append_2o(cp, head); -+ append_nb(cp + offset, vp->mgrid, sizeof(vp->mgrid)); -+} -+ -+/* -+ * Code for VSI station state machine -+ */ -+/* -+ * VSI ACK time out handler -+ */ -+static void vdp22st_handle_kato(UNUSED void *ctx, void *data) -+{ -+ struct vsi22 *p = data; -+ -+ LLDPAD_DBG("%s:%s timeout keep alive timer for %p(%02x)\n", -+ __func__, p->vdp->ifname, p, p->vsi[0]); -+ p->smi.kato = true; -+ vdp22st_run(p); -+} -+ -+/* -+ * Start the VSI station keep alive timer when a VSI state has been agreed upon. -+ */ -+static int vdp22st_start_katimer(struct vsi22 *p) -+{ -+ unsigned long long towait = (1 << p->vdp->vdp_rka) * 10; -+ unsigned int secs, usecs; -+ -+ secs = towait / USEC_PER_SEC; -+ usecs = towait % USEC_PER_SEC; -+ p->smi.kato = false; -+ LLDPAD_DBG("%s:%s start keep alive timer for %p(%02x) [%i,%i]\n", -+ __func__, p->vdp->ifname, p, p->vsi[0], secs, usecs); -+ return eloop_register_timeout(secs, usecs, vdp22st_handle_kato, NULL, -+ (void *)p); -+} -+ -+/* -+ * Stops the VSI ack timer -+ * Returns the number of removed handlers -+ */ -+static int vdp22st_stop_katimer(struct vsi22 *p) -+{ -+ LLDPAD_DBG("%s:%s stop keep alive timer for %p(%02x)\n", __func__, -+ p->vdp->ifname, p, p->vsi[0]); -+ return eloop_cancel_timeout(vdp22st_handle_kato, NULL, (void *)p); -+} -+ -+/* -+ * VSI ACK time out handler -+ */ -+static void vdp22st_handle_ackto(UNUSED void *ctx, void *data) -+{ -+ struct vsi22 *p = data; -+ -+ LLDPAD_DBG("%s:%s timeout ack timer for %p(%02x) ackreceived:%d\n", -+ __func__, p->vdp->ifname, p, p->vsi[0], p->smi.ackreceived); -+ if (!p->smi.ackreceived) { -+ p->smi.kato = true; -+ vdp22st_run(p); -+ } -+} -+ -+/* -+ * Calculate VDP22 keep alive/response wait delay timeout. See 41.5.5.9. -+ */ -+static void vdp22_timeout(struct vdp22 *p, unsigned char exp, -+ unsigned int *secs, unsigned int *usecs) -+{ -+ unsigned long long towait; -+ -+ towait = (1 + 2 * p->ecp_retries) * (1 << p->ecp_rte) * 10; -+ towait += (1 << exp) * 10; -+ towait += towait / 2; -+ *secs = towait / USEC_PER_SEC; -+ *usecs = towait % USEC_PER_SEC; -+} -+ -+/* -+ * Starts the VPD22 station response wait delay timer. See 41.5.5.9. -+ */ -+static int vdp22st_start_acktimer(struct vsi22 *p) -+{ -+ unsigned int secs, usecs; -+ -+ p->smi.txmit = true; -+ p->smi.txmit_error = 0; -+ p->smi.ackreceived = false; -+ p->smi.acktimeout = false; -+ p->smi.resp_ok = false; -+ p->smi.localchg = false; -+ vdp22_timeout(p->vdp, p->vdp->vdp_rwd, &secs, &usecs); -+ LLDPAD_DBG("%s:%s start ack timer for %p(%02x) [%i,%i]\n", -+ __func__, p->vdp->ifname, p, p->vsi[0], secs, usecs); -+ return eloop_register_timeout(secs, usecs, vdp22st_handle_ackto, NULL, -+ (void *)p); -+} -+ -+/* -+ % Stops the VSI ack timer -+ * Returns the number of removed handlers -+ */ -+static int vdp22st_stop_acktimer(struct vsi22 *p) -+{ -+ LLDPAD_DBG("%s:%s stop ack timer for %p(%02x)\n", __func__, -+ p->vdp->ifname, p, p->vsi[0]); -+ return eloop_cancel_timeout(vdp22st_handle_ackto, NULL, (void *)p); -+} -+ -+/* -+ * Station init state -+ */ -+static void vdp22st_init(struct vsi22 *vsip) -+{ -+ vsip->smi.state = VDP22_INIT; -+ vsip->status = VDP22_RESP_NONE; -+} -+ -+/* -+ * Station association new and complete state -+ */ -+static void vdp22st_assoc_compl(struct vsi22 *vsip) -+{ -+ vsip->flags &= ~VDP22_BUSY; -+ vsip->resp_vsi_mode = 0; -+} -+ -+static void vdp22st_assoc_new(struct vsi22 *vsip, enum vdp22_modes x) -+{ -+ vdp22st_assoc_compl(vsip); -+ vsip->cc_vsi_mode = x; -+} -+ -+/* -+ * Station wait system command state -+ */ -+static void vdp22st_wait_syscmd(struct vsi22 *vsip) -+{ -+ vdp22st_start_katimer(vsip); -+} -+ -+/* -+ * Station processing state, send packed tlvs to bridge. Allocate send buffer -+ * on stack and create packed TLVs. -+ */ -+static void vdp22st_process(struct vsi22 *vsi) -+{ -+ unsigned short len = mgr22_ptlv_sz() + vsi22_ptlv_sz(vsi); -+ unsigned char buf[len]; -+ struct qbg22_imm qbg; -+ -+ qbg.data_type = VDP22_TO_ECP22; -+ qbg.u.c.len = len; -+ qbg.u.c.data = buf; -+ mgr22_2tlv(vsi, buf); -+ vsi22_2tlv(vsi, buf + mgr22_ptlv_sz(), vsi->hints); -+ vsi->smi.txmit_error = modules_notify(LLDP_MOD_ECP22, LLDP_MOD_VDP22, -+ vsi->vdp->ifname, &qbg); -+ if (!vsi->smi.txmit_error) { -+ vdp22st_stop_katimer(vsi); /* Could still be running */ -+ vdp22st_start_acktimer(vsi); -+ } -+ LLDPAD_DBG("%s:%s len:%hd rc:%d\n", __func__, vsi->vdp->ifname, len, -+ vsi->smi.txmit_error); -+} -+ -+/* -+ * Station transmit deassociate state. -+ */ -+static void vdp22st_txdea(struct vsi22 *vsip) -+{ -+ vsip->vsi_mode = VDP22_DEASSOC; -+ vsip->flags |= VDP22_BUSY; -+ vdp22st_process(vsip); -+} -+ -+/* -+ * Station transmit keep alive state. -+ */ -+static void vdp22st_txka(struct vsi22 *vsip) -+{ -+ vdp22st_process(vsip); -+} -+ -+/* -+ * Station remove a VSI from the VDP22 protocol state machine. -+ */ -+static void vdp22st_end(struct vsi22 *vsi) -+{ -+ vdp22st_stop_acktimer(vsi); -+ vdp22st_stop_katimer(vsi); -+ LLDPAD_DBG("%s:%s vsi:%p(%02x) flags:%#lx vsi_mode:%d,%d" -+ " resp_vsi_mode:%d\n", __func__, -+ vsi->vdp->ifname, vsi, vsi->vsi[0], vsi->flags, -+ vsi->vsi_mode, vsi->cc_vsi_mode, vsi->resp_vsi_mode); -+ vsi->vsi_mode = vsi->cc_vsi_mode = VDP22_DEASSOC; -+ vsi->flags |= VDP22_DELETE_ME; -+ vsi->flags &= ~VDP22_BUSY; -+ if (vsi->flags & VDP22_NOTIFY) -+ vdp22_nlback(vsi); -+} -+ -+/* -+ * Station change into a new state. -+ */ -+static void vdp22st_change_state(struct vsi22 *vsi, enum vdp22_states newstate) -+{ -+ switch (newstate) { -+ case VDP22_INIT: -+ assert(vsi->smi.state == VDP22_BEGIN); -+ break; -+ case VDP22_STATION_PROC: -+ assert(vsi->smi.state == VDP22_INIT -+ || vsi->smi.state == VDP22_WAIT_SYSCMD_2); -+ break; -+ case VDP22_STATION_PROCWAIT: -+ assert(vsi->smi.state == VDP22_STATION_PROC); -+ break; -+ case VDP22_STATION_PROCWAIT_2: -+ assert(vsi->smi.state == VDP22_STATION_PROCWAIT); -+ break; -+ case VDP22_PREASSOC_NEW: -+ assert(vsi->smi.state == VDP22_STATION_PROCWAIT_2); -+ break; -+ case VDP22_ASSOC_NEW: -+ assert(vsi->smi.state == VDP22_STATION_PROCWAIT_2); -+ break; -+ case VDP22_ASSOC_COMPL: -+ assert(vsi->smi.state == VDP22_ASSOC_NEW -+ || vsi->smi.state == VDP22_STATION_PROCWAIT_2); -+ break; -+ case VDP22_WAIT_SYSCMD: -+ assert(vsi->smi.state == VDP22_ASSOC_COMPL -+ || vsi->smi.state == VDP22_PREASSOC_NEW -+ || vsi->smi.state == VDP22_TXMIT_KAWAIT_2); -+ break; -+ case VDP22_WAIT_SYSCMD_2: -+ assert(vsi->smi.state == VDP22_WAIT_SYSCMD); -+ break; -+ case VDP22_TXMIT_KA: -+ assert(vsi->smi.state == VDP22_WAIT_SYSCMD_2); -+ break; -+ case VDP22_TXMIT_KAWAIT: -+ assert(vsi->smi.state == VDP22_TXMIT_KA); -+ break; -+ case VDP22_TXMIT_KAWAIT_2: -+ assert(vsi->smi.state == VDP22_TXMIT_KAWAIT); -+ break; -+ case VDP22_TXMIT_DEASSOC: -+ assert(vsi->smi.state == VDP22_TXMIT_KAWAIT_2); -+ break; -+ case VDP22_TXMIT_DEAWAIT: -+ assert(vsi->smi.state == VDP22_TXMIT_DEASSOC); -+ break; -+ case VDP22_TXMIT_DEAWAIT_2: -+ assert(vsi->smi.state == VDP22_TXMIT_DEAWAIT); -+ break; -+ case VDP22_END: -+ assert(vsi->smi.state == VDP22_STATION_PROCWAIT -+ || vsi->smi.state == VDP22_STATION_PROCWAIT_2 -+ || vsi->smi.state == VDP22_TXMIT_KAWAIT -+ || vsi->smi.state == VDP22_TXMIT_KAWAIT_2 -+ || vsi->smi.state == VDP22_WAIT_SYSCMD_2 -+ || vsi->smi.state == VDP22_TXMIT_DEASSOC -+ || vsi->smi.state == VDP22_TXMIT_DEAWAIT -+ || vsi->smi.state == VDP22_TXMIT_DEAWAIT_2); -+ break; -+ default: -+ LLDPAD_ERR("%s:%s VDP station machine INVALID STATE %d\n", -+ __func__, vsi->vdp->ifname, newstate); -+ } -+ LLDPAD_DBG("%s:%s state change %s -> %s\n", __func__, -+ vsi->vdp->ifname, vdp22_states_n[vsi->smi.state], -+ vdp22_states_n[newstate]); -+ vsi->smi.state = newstate; -+} -+ -+/* -+ * Check for hard and soft errors. -+ */ -+static inline bool bad_error(unsigned char x) -+{ -+ return (x && (x & VDP22_KEEPBIT) == 0) ? true : false; -+} -+ -+static inline bool keep_error(unsigned char x) -+{ -+ return (x && (x & VDP22_KEEPBIT)) ? true : false; -+} -+ -+/* -+ * Return error code. Check for HARDBIT/KEEPBIT set and no error code. -+ */ -+static inline unsigned char get_error(unsigned char x) -+{ -+ return (x & VDP22_STATUS_MASK) ? x & ~(VDP22_RESBIT|VDP22_ACKBIT) : 0; -+} -+ -+/* -+ * vdp22st_move_state - advances the VDP station state machine state -+ * -+ * Switches the state machine to the next state depending on the input -+ * variables. returns true or false depending on wether the state machine -+ * can be run again with the new state or can stop at the current state. -+ */ -+static bool vdp22st_move_state(struct vsi22 *vsi) -+{ -+ enum vdp22_states newstate; -+ -+ LLDPAD_DBG("%s:%s state %s\n", __func__, vsi->vdp->ifname, -+ vdp22_states_n[vsi->smi.state]); -+ switch (vsi->smi.state) { -+ case VDP22_BEGIN: -+ vdp22st_change_state(vsi, VDP22_INIT); -+ return true; -+ case VDP22_INIT: -+ vdp22st_change_state(vsi, VDP22_STATION_PROC); -+ return true; -+ case VDP22_STATION_PROC: -+ vdp22st_change_state(vsi, VDP22_STATION_PROCWAIT); -+ return true; -+ case VDP22_STATION_PROCWAIT: -+ if (vsi->smi.txmit_error || vsi->smi.acktimeout) { -+ /* Error handover to ECP22 or no VDP22 ack */ -+ vdp22st_change_state(vsi, VDP22_END); -+ return true; -+ } -+ if (vsi->smi.ackreceived) { -+ vdp22st_change_state(vsi, VDP22_STATION_PROCWAIT_2); -+ return true; -+ } -+ return false; -+ case VDP22_STATION_PROCWAIT_2: -+ if (!vsi->smi.resp_ok /* Mismatch in response */ -+ || bad_error(vsi->status)) { /* Error without KEEP */ -+ vdp22st_change_state(vsi, VDP22_END); -+ return true; -+ } -+ if (keep_error(vsi->status)) { /* Error with KEEP on */ -+ if (vsi->resp_vsi_mode == VDP22_ASSOC) -+ newstate = VDP22_ASSOC_COMPL; -+ else -+ newstate = VDP22_END; -+ } else if (vsi->resp_vsi_mode == VDP22_PREASSOC -+ || vsi->resp_vsi_mode == VDP22_PREASSOC_WITH_RR) -+ newstate = VDP22_PREASSOC_NEW; -+ else if (vsi->resp_vsi_mode == VDP22_DEASSOC) -+ newstate = VDP22_END; -+ else -+ newstate = VDP22_ASSOC_NEW; -+ vdp22st_change_state(vsi, newstate); -+ return true; -+ case VDP22_ASSOC_NEW: -+ vdp22st_change_state(vsi, VDP22_ASSOC_COMPL); -+ return true; -+ case VDP22_ASSOC_COMPL: -+ case VDP22_PREASSOC_NEW: -+ vdp22st_change_state(vsi, VDP22_WAIT_SYSCMD); -+ return true; -+ case VDP22_WAIT_SYSCMD: -+ vdp22st_change_state(vsi, VDP22_WAIT_SYSCMD_2); -+ return true; -+ case VDP22_WAIT_SYSCMD_2: -+ if (vsi->smi.kato) { -+ vdp22st_change_state(vsi, VDP22_TXMIT_KA); -+ return true; -+ } -+ if (vsi->smi.localchg) { -+ vdp22st_change_state(vsi, VDP22_STATION_PROC); -+ return true; -+ } -+ if (vsi->smi.deassoc) { -+ vdp22st_change_state(vsi, VDP22_END); -+ return true; -+ } -+ return false; -+ case VDP22_TXMIT_KA: -+ vdp22st_change_state(vsi, VDP22_TXMIT_KAWAIT); -+ return true; -+ case VDP22_TXMIT_KAWAIT: -+ if (vsi->smi.txmit_error || vsi->smi.acktimeout) { -+ /* Error handover to ECP22 or no VDP22 ack */ -+ vdp22st_change_state(vsi, VDP22_END); -+ return true; -+ } -+ if (vsi->smi.ackreceived) { -+ vdp22st_change_state(vsi, VDP22_TXMIT_KAWAIT_2); -+ return true; -+ } -+ return false; -+ case VDP22_TXMIT_KAWAIT_2: -+ if (!vsi->smi.resp_ok /* Mismatch in response */ -+ || bad_error(vsi->status)) { /* Error without KEEP */ -+ vdp22st_change_state(vsi, VDP22_END); -+ return true; -+ } -+ if (keep_error(vsi->status) -+ && vsi->resp_vsi_mode == VDP22_ASSOC) -+ vdp22st_change_state(vsi, VDP22_TXMIT_DEASSOC); -+ else if (vsi->resp_vsi_mode == VDP22_DEASSOC) -+ vdp22st_change_state(vsi, VDP22_END); -+ else -+ vdp22st_change_state(vsi, VDP22_WAIT_SYSCMD); -+ return true; -+ case VDP22_TXMIT_DEASSOC: -+ vdp22st_change_state(vsi, VDP22_TXMIT_DEAWAIT); -+ return true; -+ case VDP22_TXMIT_DEAWAIT: -+ if (vsi->smi.txmit_error || vsi->smi.acktimeout) { -+ /* Error handover to ECP22 or no VDP22 ack */ -+ vdp22st_change_state(vsi, VDP22_END); -+ return true; -+ } -+ if (vsi->smi.ackreceived) { -+ vdp22st_change_state(vsi, VDP22_TXMIT_DEAWAIT_2); -+ return true; -+ } -+ return false; -+ case VDP22_TXMIT_DEAWAIT_2: -+ vdp22st_change_state(vsi, VDP22_END); -+ return true; -+ case VDP22_END: -+ return false; -+ } -+ return false; -+} -+ -+/* -+ * Start state machine for VSI station -+ * @vsi: pointer to currently used vsi data structure -+ * -+ * No return value -+ */ -+static void vdp22st_run(struct vsi22 *vsi) -+{ -+ vdp22st_move_state(vsi); -+ do { -+ LLDPAD_DBG("%s:%s state %s\n", __func__, -+ vsi->vdp->ifname, vdp22_states_n[vsi->smi.state]); -+ -+ switch (vsi->smi.state) { -+ case VDP22_INIT: -+ vdp22st_init(vsi); -+ break; -+ case VDP22_STATION_PROC: -+ vdp22st_process(vsi); -+ break; -+ case VDP22_STATION_PROCWAIT: -+ case VDP22_STATION_PROCWAIT_2: -+ break; -+ case VDP22_ASSOC_NEW: -+ case VDP22_PREASSOC_NEW: -+ vdp22st_assoc_new(vsi, vsi->resp_vsi_mode); -+ break; -+ case VDP22_ASSOC_COMPL: -+ vdp22st_assoc_compl(vsi); -+ break; -+ case VDP22_WAIT_SYSCMD: -+ vdp22st_wait_syscmd(vsi); -+ break; -+ case VDP22_WAIT_SYSCMD_2: -+ break; -+ case VDP22_TXMIT_KA: -+ vdp22st_txka(vsi); -+ break; -+ case VDP22_TXMIT_KAWAIT: -+ case VDP22_TXMIT_KAWAIT_2: -+ break; -+ case VDP22_TXMIT_DEASSOC: -+ vdp22st_txdea(vsi); -+ break; -+ case VDP22_TXMIT_DEAWAIT: -+ break; -+ case VDP22_TXMIT_DEAWAIT_2: -+ vdp22st_assoc_compl(vsi); -+ break; -+ case VDP22_END: -+ break; -+ default: -+ LLDPAD_DBG("%s:%s state %d unknown\n", __func__, -+ vsi->vdp->ifname, vsi->smi.state); -+ break; -+ } -+ } while (vdp22st_move_state(vsi) == true); -+ if (vsi->smi.state == VDP22_END) -+ vdp22st_end(vsi); -+} -+ -+/* -+ * Checks if 2 VSI records are identical. -+ * -+ * returns true if equal, false if not -+ * -+ * compares mgrid, type id, type version, id format, id and filter info format -+ * returns true if they are equal. -+ */ -+static bool vdp22_vsi_equal(struct vsi22 *p1, struct vsi22 *p2) -+{ -+ if (memcmp(p1->mgrid, p2->mgrid, sizeof(p2->mgrid))) -+ return false; -+ if (p1->type_id != p2->type_id) -+ return false; -+ if (p1->type_ver != p2->type_ver) -+ return false; -+ if (p1->vsi_fmt != p2->vsi_fmt) -+ return false; -+ if (memcmp(p1->vsi, p2->vsi, sizeof(p1->vsi))) -+ return false; -+ if (p1->fif != p2->fif) -+ return false; -+ return true; -+} -+ -+/* -+ * Find a VSI in the list of VSIs already allocated -+ * -+ * Returns pointer to already allocated VSI in list, 0 if not. -+ */ -+static struct vsi22 *vdp22_findvsi(struct vdp22 *vdp, struct vsi22 *me) -+{ -+ struct vsi22 *p; -+ -+ LIST_FOREACH(p, &vdp->vsi22_que, node) { -+ if (vdp22_vsi_equal(p, me)) -+ return p; -+ } -+ return NULL; -+} -+ -+/* -+ * Modify VSI22 information and trigger state machine. -+ * Parameter me identifies the VSI to be modified. -+ */ -+static int vdp22_modvsi(struct vsi22 *me, enum vdp22_modes x) -+{ -+ LLDPAD_DBG("%s:%s me:%p flags:%#lx mode change %d --> %d\n", __func__, -+ me->vdp->ifname, me, me->flags, me->vsi_mode, x); -+ if (me->flags & VDP22_DELETE_ME) -+ return -ENODEV; -+ if (me->vsi_mode > x) -+ return -EINVAL; -+ me->vsi_mode = x; -+ me->smi.localchg = true; -+ me->flags |= VDP22_BUSY | VDP22_NLCMD; -+ vdp22st_run(me); -+ return 0; -+} -+ -+/* -+ * Insert in queue and enter state machine. -+ */ -+static void vdp22_addvsi(struct vsi22 *vsip, struct vdp22 *vdp) -+{ -+ vsip->smi.state = VDP22_BEGIN; -+ LIST_INSERT_HEAD(&vdp->vsi22_que, vsip, node); -+ LLDPAD_DBG("%s:%s vsip:%p\n", __func__, vsip->vdp->ifname, vsip); -+ vdp22st_run(vsip); -+} -+ -+/* -+ * Compare VSI filter data. Return true if they match. -+ * All fields are compared, even if some are not used. Unused field are -+ * initialized to zeros and always match. -+ */ -+static bool cmp_fdata1(struct fid22 *p1, struct fid22 *p2, unsigned char fif) -+{ -+ bool is_good = true; -+ -+ if (fif == VDP22_FFMT_MACVID || fif == VDP22_FFMT_GROUPMACVID) -+ is_good = !memcmp(p1->mac, p2->mac, sizeof(p1->mac)); -+ if (fif == VDP22_FFMT_GROUPVID || fif == VDP22_FFMT_GROUPMACVID) -+ is_good = (p1->grpid == p2->grpid); -+ if (is_good) { -+ if (vdp22_get_vlanid(p1->vlan)) -+ is_good = (vdp22_get_vlanid(p1->vlan) == -+ vdp22_get_vlanid(p2->vlan)); -+ if (is_good && vdp22_get_ps(p1->vlan)) -+ is_good = (p1->vlan == p2->vlan); -+ } -+ return is_good; -+} -+ -+static bool vdp22_cmp_fdata(struct vsi22 *p, struct vsi22 *vsip) -+{ -+ int i; -+ -+ if (p->no_fdata != vsip->no_fdata) -+ return false; -+ for (i = 0; i < p->no_fdata; ++i) { -+ struct fid22 *p1 = &p->fdata[i]; -+ struct fid22 *p2 = &vsip->fdata[i]; -+ -+ if (!cmp_fdata1(p1, p2, p->fif)) { -+ p->status = VDP22_RESP_NOADDR; -+ return false; -+ } -+ } -+ return true; -+} -+ -+/* -+ * Update a current/existing VSI instance. -+ * The next table describes the transition diagram for the VSI instance update: -+ * -+ * Current mode -+ * New Mode | none preassoc preassoc-RR assoc -+ * ===========|================================================================= -+ * preassoc | do_preassoc do_preassoc do_preassoc error -+ * preassoc-RR| do_preassoc-RR do_preassoc-RR do_preassoc-RR error -+ * assoc | do_assoc do_assoc do_assoc do-assoc -+ * deassoc | error do_deassoc do_deassoc do-deassoc -+ * -+ * These operations get more complicated because the filter data may differ: -+ * ============================================================================= -+ * Transitions: -+ * If the filter data of the current VSI node and the new VSI node -+ * matches completely, resend TLVs -+ * -+ * TODO: -+ * If the new mode changes only part of the currently active -+ * filter data, then do: -+ * 1. Clone the filter data which is undergoing a mode change and -+ * create a new VSI node -+ * 2. Delete the filter data in the currently active VSI node. -+ * 3. Search for a VSI node with the same key and new mode: -+ * a. If such a node is found append filter data and resent TLVs -+ * b. If no such node is found, append the new VSI node with -+ * the new mode to the list of cloned VSIs. Send TLV for the -+ * new VSI node. -+ * -+ * If the key matches and the VSI mode is also identical and the filter data -+ * in the new request does not match any filter data element in the current -+ * request, then add the new filter data and resent the TLVs. -+ * -+ * Without the TODO items we currently support an exact match of the -+ * filter data information. This is the same behavior as in the currently -+ * supported IEEE 802.1 QBG draft version 0.2. -+ */ -+ -+/* -+ * Handle a new request. -+ */ -+int vdp22_addreq(struct vsi22 *vsip, struct vdp22 *vdp) -+{ -+ int rc = 0; -+ struct vsi22 *p; -+ -+ LLDPAD_DBG("%s:%s mode:%d\n", __func__, vsip->vdp->ifname, -+ vsip->vsi_mode); -+ if (vsip->vsi_mode > VDP22_DEASSOC || vsip->vsi_mode < VDP22_PREASSOC) -+ return -EINVAL; -+ p = vdp22_findvsi(vdp, vsip); -+ if (!p) { /* New VSI */ -+ if (vsip->vsi_mode == VDP22_DEASSOC) { -+ /* -+ * Disassociate of unknown VSI. Return error. -+ * Nothing to send to switch. -+ */ -+ rc = -EINVAL; -+ LLDPAD_DBG("%s:%s dis-assoc without assoc [%02x]\n", -+ __func__, vsip->vdp->ifname, vsip->vsi[0]); -+ } else -+ vdp22_addvsi(vsip, vdp); /* Add new VSI */ -+ } else { /* Profile on list --> change state */ -+ /* -+ * Request is still busy, do not accept another one. -+ */ -+ if (p->flags & VDP22_BUSY) { -+ rc = -EBUSY; -+ goto out; -+ } -+ /* -+ * Check if filter data is identical. Right now support -+ * for exact filter data is implemented (as in draft 0.2) -+ * -+ * TODO -+ * Support for different filter data information. -+ */ -+ if (!vdp22_cmp_fdata(p, vsip)) { -+ LLDPAD_DBG("%s:%s TODO mismatch filter data [%02x]\n", -+ __func__, vsip->vdp->ifname, vsip->vsi[0]); -+ rc = -EINVAL; -+ } else -+ rc = vdp22_modvsi(p, vsip->vsi_mode); -+ } -+out: -+ LLDPAD_DBG("%s:%s rc:%d\n", __func__, vsip->vdp->ifname, rc); -+ return rc; -+} -+ -+/* -+ * Test for returned filter information. -+ * Set VDP22_RETURN_VID bit in flags when VLAN id or QoS change is detected. -+ */ -+static void vdp22_cpfid(struct vsi22 *hit, struct vsi22 *from) -+{ -+ int i; -+ struct fid22 *hitm = hit->fdata, *fromm = from->fdata; -+ -+ LLDPAD_DBG("%s:%s no_fdata:%hd,%hd\n", __func__, hit->vdp->ifname, -+ from->no_fdata, hit->no_fdata); -+ if (hit->no_fdata != from->no_fdata) -+ return; -+ for (i = 0; i < hit->no_fdata; ++i, ++hitm, ++fromm) { -+ LLDPAD_DBG("%s:%s vlan:%#hx,%#hx\n", __func__, -+ hit->vdp->ifname, hitm->vlan, fromm->vlan); -+ if (hitm->vlan != fromm->vlan) { -+ hitm->vlan = fromm->vlan; -+ hit->flags |= VDP22_RETURN_VID; -+ } -+ } -+ LLDPAD_DBG("%s:%s flags:%#lx\n", __func__, hit->vdp->ifname, -+ hit->flags); -+} -+ -+/* -+ * Input from bridge side. -+ * -+ * NOTE: -+ * - Parameter vsip and associated fid data is on stack memory. -+ */ -+static void vdp22_bridge_info(struct vsi22 *vsip) -+{ -+ struct vsi22 *hit = vdp22_findvsi(vsip->vdp, vsip); -+ -+ if (!hit) { -+ LLDPAD_DBG("%s:%s station received TLV not found:\n", __func__, -+ vsip->vdp->ifname); -+ vdp22_showvsi(vsip); -+ return; -+ } -+ hit->smi.ackreceived = true; -+ hit->smi.deassoc = hit->smi.acktimeout = false; -+ vdp22st_stop_acktimer(hit); -+ hit->status = get_error(vsip->status); -+ if (!(vsip->status & VDP22_ACKBIT) && vsip->vsi_mode == VDP22_DEASSOC) { -+ /* Unsolicited de-assoc request from switch */ -+ hit->smi.deassoc = true; -+ hit->status = 0; -+ } -+ /* -+ * We have already tested some fields of the TLV. Now test the -+ * filter data. -+ */ -+ if (vdp22_cmp_fdata(hit, vsip)) { -+ hit->smi.resp_ok = true; -+ hit->resp_vsi_mode = vsip->vsi_mode; /* Take response */ -+ vdp22_cpfid(hit, vsip); /* Take filter */ -+ if (hit->cc_vsi_mode != VDP22_DEASSOC -+ && (hit->resp_vsi_mode == VDP22_DEASSOC -+ || bad_error(hit->status)) -+ && !(hit->flags & VDP22_NLCMD)) -+ hit->flags |= VDP22_NOTIFY; /* Notify originator */ -+ } -+ LLDPAD_DBG("%s:%s found:%p resp_ok:%d vsi_mode:%d,%d resp_vsi_mode:%d " -+ "flags:%#lx status:%#x deassoc:%d\n", -+ __func__, vsip->vdp->ifname, hit, hit->smi.resp_ok, -+ hit->vsi_mode, hit->cc_vsi_mode, hit->resp_vsi_mode, -+ hit->flags, hit->status, hit->smi.deassoc); -+ vdp22st_run(hit); -+} -+ -+/* -+ * vdp22 input processing from ECP22 received data. Check if data is valid -+ * and do some basic checks. -+ */ -+/* -+ * Advance to next packed tlv location. -+ */ -+static inline struct vdp22_ptlv *next_ptlv(struct vdp22_ptlv *p, -+ const unsigned short len) -+{ -+ return (struct vdp22_ptlv *)((unsigned char *)p + len); -+} -+ -+/* -+ * Convert a VDP22 packed TLV to vsi22 filter data. -+ * Return number of bytes (in input packed TLV) processed. -+ */ -+static size_t ptlv_2_fdata(struct fid22 *fidp, const unsigned char *cp, -+ const unsigned char ffmt) -+{ -+ size_t offset = 0; -+ -+ memset(fidp, 0, sizeof(*fidp)); -+ switch (ffmt) { -+ case VDP22_FFMT_VID: -+ offset = extract_2o(&fidp->vlan, cp); -+ break; -+ case VDP22_FFMT_MACVID: -+ offset = extract_no(fidp->mac, cp, sizeof(fidp->mac)); -+ offset += extract_2o(&fidp->vlan, cp + offset); -+ break; -+ case VDP22_FFMT_GROUPVID: -+ offset = extract_4o(&fidp->grpid, cp); -+ offset += extract_2o(&fidp->vlan, cp + offset); -+ break; -+ case VDP22_FFMT_GROUPMACVID: -+ offset = extract_4o(&fidp->grpid, cp); -+ offset += extract_no(fidp->mac, cp + offset, sizeof(fidp->mac)); -+ offset += extract_2o(&fidp->vlan, cp + offset); -+ break; -+ } -+ return offset; -+} -+ -+/* -+ * Bridge sends replies with ACK bit set or DEASSOC request. -+ * Station sends requests, ignore error bits, ACK bit must be cleared. -+ */ -+static inline bool response_ok(struct vsi22 *vsip) -+{ -+ if (vsip->vdp->myrole == VDP22_BRIDGE) -+ return (vsip->status & VDP22_ACKBIT) ? false : true; -+ if ((vsip->status & VDP22_ACKBIT) || -+ (!(vsip->status & VDP22_ACKBIT) && vsip->vsi_mode == VDP22_DEASSOC)) -+ return true; -+ return false; -+} -+ -+/* -+ * Convert a VDP22 packed TLV to vsi22 to struct vsi22 data format. -+ */ -+static void ptlv_2_vsi22(struct vsi22 *vsip, struct vdp22_ptlv *ptlv) -+{ -+ int i; -+ size_t offset; -+ unsigned char *cp = ptlv->data; -+ -+ offset = extract_1o(&vsip->status, cp); -+ offset += extract_3o(&vsip->type_id, cp + offset); -+ offset += extract_1o(&vsip->type_ver, cp + offset); -+ offset += extract_1o(&vsip->vsi_fmt, cp + offset); -+ offset += extract_no(vsip->vsi, cp + offset, sizeof(vsip->vsi)); -+ offset += extract_1o(&vsip->fif, cp + offset); -+ offset += extract_2o(&vsip->no_fdata, cp + offset); -+ -+ if (ptlv_length(ntohs(ptlv->head)) == vsi22_ptlv_sz(vsip) -+ && vsip->no_fdata && response_ok(vsip)) { -+ struct fid22 fid[vsip->no_fdata]; -+ -+ vsip->fdata = fid; -+ for (i = 0; i < vsip->no_fdata; ++i) -+ offset += ptlv_2_fdata(&fid[i], cp + offset, vsip->fif); -+ if (vsip->vdp->myrole == VDP22_STATION) -+ vdp22_bridge_info(vsip); -+ else -+ vdp22_station_info(vsip); -+ return; -+ } -+ LLDPAD_DBG("%s:%s TLV ignored\n", __func__, vsip->vdp->ifname); -+ vdp22_showvsi(vsip); -+} -+ -+/* -+ * Interate along the packed TLVs and extract information. Packed TLV has -+ * passed basic consistency checking. -+ */ -+static void vdp22_input(struct vdp22 *vdp) -+{ -+ struct vsi22 vsi; -+ struct vdp22_ptlv *ptlv = (struct vdp22_ptlv *)vdp->input; -+ enum vdp22_modes mode; -+ -+ LLDPAD_DBG("%s:%s input_len:%d\n", __func__, vdp->ifname, -+ vdp->input_len); -+ memset(&vsi, 0, sizeof(vsi)); -+ vsi.vdp = vdp; -+ for (; (mode = ptlv_type(ntohs(ptlv->head))) != 0; -+ ptlv = next_ptlv(ptlv, ptlv_length(ntohs(ptlv->head)))) { -+ switch (mode) { -+ default: -+ case VDP22_ENDTLV: -+ break; -+ case VDP22_MGRID: -+ memcpy(&vsi.mgrid, ptlv->data, sizeof(vsi.mgrid)); -+ break; -+ case VDP22_PREASSOC: -+ case VDP22_PREASSOC_WITH_RR: -+ case VDP22_ASSOC: -+ case VDP22_DEASSOC: -+ vsi.vsi_mode = mode; -+ ptlv_2_vsi22(&vsi, ptlv); -+ break; -+ } -+ } -+} -+ -+/* -+ * Receive data from the ECP22 module. Check for valid input data. -+ */ -+static void vdp22_ecp22in(UNUSED void *ctx, void *parm) -+{ -+ struct vdp22 *vdp = (struct vdp22 *)parm; -+ struct vdp22_ptlv *ptlv = (struct vdp22_ptlv *)vdp->input; -+ int total_len = vdp->input_len; -+ unsigned short ptlv_len; -+ -+ if (vdp->myrole == VDP22_BRIDGE && vdp->br_down) { -+ LLDPAD_DBG("%s:%s bridge down\n", __func__, vdp->ifname); -+ return; -+ } -+ /* Verify 1st TLV is a manager id TLV */ -+ if (ptlv_type(ntohs(ptlv->head)) != VDP22_MGRID) { -+ LLDPAD_ERR("%s:%s No Manager ID TLV -- packet dropped\n", -+ __func__, vdp->ifname); -+ return; -+ } -+ ptlv_len = ptlv_length(ntohs(ptlv->head)); -+ if (ptlv_len > total_len) { -+ LLDPAD_ERR("%s:%s Invalid Manager ID TLV length -- " -+ "packet dropped\n", __func__, vdp->ifname); -+ return; -+ } -+ total_len -= ptlv_len; -+ do { /* Iterrate over all packed TLVs */ -+ ptlv = (struct vdp22_ptlv *)((unsigned char *)ptlv + ptlv_len); -+ ptlv_len = ptlv_length(ntohs(ptlv->head)); -+ -+ switch (ptlv_type(ntohs(ptlv->head))) { -+ case VDP22_ENDTLV: -+ total_len = 0; -+ break; -+ case VDP22_MGRID: -+ LLDPAD_ERR("%s:%s Duplicate Manager ID TLV -- " -+ "packet dropped\n", __func__, vdp->ifname); -+ return; -+ case VDP22_PREASSOC: -+ case VDP22_PREASSOC_WITH_RR: -+ case VDP22_ASSOC: -+ case VDP22_DEASSOC: -+ if (ptlv_len > total_len) { -+ LLDPAD_ERR("%s:%s Invalid TLV length -- " -+ "packet dropped\n", __func__, -+ vdp->ifname); -+ return; -+ } -+ total_len -= ptlv_len; -+ break; -+ default: -+ LLDPAD_DBG("%s:%s Unknown TLV ID (%#hx) -- " -+ "ignored\n", __func__, vdp->ifname, -+ ptlv_type(ptlv->head)); -+ if (!ptlv_len) -+ ptlv_len = 2; /* Keep TLVs moving */ -+ total_len -= ptlv_len; -+ } -+ } while (total_len > 0); -+ -+ if (total_len < 0) { -+ LLDPAD_ERR("%s:%s Received packed TLV length error (%d)\n", -+ __func__, vdp->ifname, total_len); -+ return; -+ } -+ return vdp22_input(vdp); -+} -+ -+/* -+ * Called when ECP22 module delivers data. Wait a very short time to allow -+ * the ECP module to return its acknowledgement before data is processed. -+ */ -+int vdp22_from_ecp22(struct vdp22 *vdp) -+{ -+ return eloop_register_timeout(0, 100 * 1000, vdp22_ecp22in, NULL, vdp); -+} -+ -+/* -+ * Bridge state machine code starts here. -+ */ -+static void vdp22br_init(struct vsi22 *p) -+{ -+ LLDPAD_DBG("%s:%s vsi:%p(%02x)\n", __func__, p->vdp->ifname, p, -+ p->vsi[0]); -+ p->flags = 0; -+ p->cc_vsi_mode = VDP22_DEASSOC; -+ p->resp_vsi_mode = VDP22_RESP_NONE; -+ p->smi.localchg = true; /* Change triggered by station */ -+ p->smi.kato = false; -+ p->smi.resp_ok = false; /* Response from VSI manager */ -+ /* FOLLOWING MEMBERS NOT USED BY BRIDGE STATE MACHINE */ -+ p->smi.deassoc = p->smi.acktimeout = p->smi.ackreceived = false; -+ p->smi.txmit = false; -+ p->smi.txmit_error = 0; -+} -+ -+/* -+ * VSI bridge time out handler. -+ */ -+static void vdp22br_handle_kato(UNUSED void *ctx, void *data) -+{ -+ struct vsi22 *p = data; -+ -+ LLDPAD_DBG("%s:%s timeout keep alive timer for %#02x\n", -+ __func__, p->vdp->ifname, p->vsi[0]); -+ p->smi.kato = true; -+ vdp22br_run(p); -+} -+ -+/* -+ * Starts the VSI bridge keep alive timer. -+ */ -+static int vdp22br_start_katimer(struct vsi22 *p) -+{ -+ unsigned int usecs, secs; -+ -+ p->smi.kato = false; -+ vdp22_timeout(p->vdp, p->vdp->vdp_rka, &secs, &usecs); -+ LLDPAD_DBG("%s:%s start keep alive timer for %p(%02x) [%i,%i]\n", -+ __func__, p->vdp->ifname, p, p->vsi[0], secs, usecs); -+ return eloop_register_timeout(secs, usecs, vdp22br_handle_kato, NULL, -+ (void *)p); -+} -+ -+/* -+ * Stops the bridge keep alive timer. -+ */ -+static int vdp22br_stop_katimer(struct vsi22 *p) -+{ -+ LLDPAD_DBG("%s:%s stop keep alive timer for %p(%02x)\n", __func__, -+ p->vdp->ifname, p, p->vsi[0]); -+ return eloop_cancel_timeout(vdp22br_handle_kato, NULL, (void *)p); -+} -+ -+/* -+ * Bridge resource processing timers. -+ */ -+static void vdp22br_handle_resto(UNUSED void *ctx, void *data) -+{ -+ struct vsi22 *p = data; -+ -+ LLDPAD_DBG("%s:%s timeout resource wait delay for %p(%#02x)\n", -+ __func__, p->vdp->ifname, p, p->vsi[0]); -+ p->smi.resp_ok = true; -+ vdp22br_run(p); -+} -+ -+static int vdp22br_stop_restimer(struct vsi22 *p) -+{ -+ LLDPAD_DBG("%s:%s stop resource wait timer for %p(%02x)\n", -+ __func__, p->vdp->ifname, p, p->vsi[0]); -+ return eloop_cancel_timeout(vdp22br_handle_resto, NULL, (void *)p); -+} -+ -+/* -+ * Start resource wait delay timer. -+ */ -+static int vdp22br_start_restimer(struct vsi22 *p) -+{ -+ unsigned long long towait = (1 << p->vdp->vdp_rwd) * 10; -+ unsigned int secs, usecs; -+ -+ p->smi.resp_ok = false; -+ p->resp_vsi_mode = VDP22_RESP_NONE; -+ secs = towait / USEC_PER_SEC; -+ usecs = towait % USEC_PER_SEC; -+ LLDPAD_DBG("%s:%s start resource wait timer for %p(%02x) [%i,%i]\n", -+ __func__, p->vdp->ifname, p, p->vsi[0], secs, usecs); -+ return eloop_register_timeout(secs, usecs, vdp22br_handle_resto, NULL, -+ (void *)p); -+} -+ -+static void vdp22br_process(struct vsi22 *p) -+{ -+ int rc, error = 0; -+ -+ LLDPAD_DBG("%s:%s vsi:%p(%02x) id:%ld\n", __func__, -+ p->vdp->ifname, p, p->vsi[0], p->type_id); -+ vdp22br_start_restimer(p); -+ p->status = 0; -+ p->resp_vsi_mode = VDP22_RESP_SUCCESS; -+ rc = vdp22br_resources(p, &error); -+ switch (rc) { -+ case VDP22_RESP_TIMEOUT: -+ break; -+ case VDP22_RESP_KEEP: -+ p->status = VDP22_KEEPBIT; -+ goto rest; -+ case VDP22_RESP_DEASSOC: -+ if (error >= (1 << VDP22_STATUS_SHIFT)) -+ p->status = VDP22_HARDBIT; -+ /* Fall through intended */ -+ case VDP22_RESP_SUCCESS: -+rest: -+ p->status |= VDP22_ACKBIT | make_status(error); -+ vdp22br_stop_restimer(p); -+ p->smi.resp_ok = true; -+ break; -+ } -+ p->resp_vsi_mode = rc; -+ LLDPAD_DBG("%s:%s resp_vsi_mode:%d status:%#x\n", __func__, -+ p->vdp->ifname, p->resp_vsi_mode, p->status); -+} -+ -+static void vdp22br_end(struct vsi22 *p) -+{ -+ LLDPAD_DBG("%s:%s vsi:%p(%02x)\n", __func__, p->vdp->ifname, p, -+ p->vsi[0]); -+ vdp22_listdel_vsi(p); -+} -+ -+/* -+ * Add a VSI to bridge state machine. -+ */ -+static void vdp22br_addvsi(struct vsi22 *p) -+{ -+ LLDPAD_DBG("%s:%s vsi:%p(%02x)\n", __func__, p->vdp->ifname, p, -+ p->vsi[0]); -+ p->smi.state = VDP22_BR_BEGIN; -+ p->flags = VDP22_BUSY; -+ LIST_INSERT_HEAD(&p->vdp->vsi22_que, p, node); -+ vdp22br_run(p); -+} -+ -+/* -+ * Send a bridge reply. Allocate send buffer on stack and create packed TLVs. -+ */ -+static void vdp22br_reply(struct vsi22 *vsi) -+{ -+ unsigned short len = mgr22_ptlv_sz() + vsi22_ptlv_sz(vsi); -+ unsigned char buf[len]; -+ struct qbg22_imm qbg; -+ -+ qbg.data_type = VDP22_TO_ECP22; -+ qbg.u.c.len = len; -+ qbg.u.c.data = buf; -+ mgr22_2tlv(vsi, buf); -+ vsi22_2tlv(vsi, buf + mgr22_ptlv_sz(), vsi->status); -+ modules_notify(LLDP_MOD_ECP22, LLDP_MOD_VDP22, vsi->vdp->ifname, &qbg); -+ vsi->flags &= ~VDP22_BUSY; -+ vsi->smi.localchg = false; -+ LLDPAD_DBG("%s:%s len:%hd rc:%d\n", __func__, vsi->vdp->ifname, len, -+ vsi->smi.txmit_error); -+} -+ -+/* -+ * Send a keep status TLV as bridge reply. -+ */ -+static void vdp22br_sendack(struct vsi22 *p, unsigned char status) -+{ -+ LLDPAD_DBG("%s:%s vsi:%p(%02x)\n", __func__, p->vdp->ifname, p, -+ p->vsi[0]); -+ p->status = status; -+ vdp22br_reply(p); -+} -+ -+/* -+ * Send a de-associate TLV as bridge reply. -+ */ -+static void vdp22br_deassoc(struct vsi22 *p, unsigned char status) -+{ -+ LLDPAD_DBG("%s:%s vsi:%p(%02x)\n", __func__, p->vdp->ifname, p, -+ p->vsi[0]); -+ p->vsi_mode = VDP22_DEASSOC; -+ vdp22br_sendack(p, status); -+} -+ -+/* -+ * Change bridge state machine into a new state. -+ */ -+static void vdp22br_change_state(struct vsi22 *p, enum vdp22br_states new) -+{ -+ switch (new) { -+ case VDP22_BR_INIT: -+ assert(p->smi.state == VDP22_BR_BEGIN); -+ break; -+ case VDP22_BR_PROCESS: -+ assert(p->smi.state == VDP22_BR_WAITCMD_2 -+ || p->smi.state == VDP22_BR_INIT); -+ break; -+ case VDP22_BR_SEND: -+ assert(p->smi.state == VDP22_BR_PROCESS); -+ break; -+ case VDP22_BR_KEEP: -+ assert(p->smi.state == VDP22_BR_PROCESS); -+ break; -+ case VDP22_BR_DEASSOC: -+ assert(p->smi.state == VDP22_BR_PROCESS); -+ break; -+ case VDP22_BR_WAITCMD: -+ assert(p->smi.state == VDP22_BR_SEND -+ || p->smi.state == VDP22_BR_KEEP -+ || p->smi.state == VDP22_BR_ALIVE); -+ break; -+ case VDP22_BR_WAITCMD_2: -+ assert(p->smi.state == VDP22_BR_WAITCMD); -+ break; -+ case VDP22_BR_ALIVE: -+ assert(p->smi.state == VDP22_BR_WAITCMD_2); -+ break; -+ case VDP22_BR_DEASSOCIATED: -+ assert(p->smi.state == VDP22_BR_PROCESS -+ || p->smi.state == VDP22_BR_WAITCMD); -+ break; -+ case VDP22_BR_END: -+ assert(p->smi.state == VDP22_BR_DEASSOC -+ || p->smi.state == VDP22_BR_DEASSOCIATED); -+ break; -+ default: -+ LLDPAD_ERR("%s:%s VDP bridge machine INVALID STATE %d\n", -+ __func__, p->vdp->ifname, new); -+ } -+ LLDPAD_DBG("%s:%s state change %s -> %s\n", __func__, -+ p->vdp->ifname, vdp22br_state_name(p->smi.state), -+ vdp22br_state_name(new)); -+ p->smi.state = new; -+} -+ -+/* -+ * vdp22br_move_state - advances the VDP bridge state machine state -+ * -+ * returns true or false -+ * -+ * Switches the state machine to the next state depending on the input -+ * variables. Returns true or false depending on wether the state machine -+ * can be run again with the new state or has to stop at the current state. -+ */ -+static bool vdp22br_move_state(struct vsi22 *p) -+{ -+ LLDPAD_DBG("%s:%s state %s\n", __func__, p->vdp->ifname, -+ vdp22br_state_name(p->smi.state)); -+ switch (p->smi.state) { -+ case VDP22_BR_BEGIN: -+ vdp22br_change_state(p, VDP22_BR_INIT); -+ return true; -+ case VDP22_BR_INIT: -+ vdp22br_change_state(p, VDP22_BR_PROCESS); -+ return true; -+ case VDP22_BR_PROCESS: -+ if (!p->smi.resp_ok) /* No resource wait response */ -+ return false; -+ /* Assumes status and error bits set accordingly */ -+ if (p->resp_vsi_mode == VDP22_RESP_NONE) { /* Timeout */ -+ if (p->cc_vsi_mode == VDP22_ASSOC) -+ vdp22br_change_state(p, VDP22_BR_KEEP); -+ else -+ vdp22br_change_state(p, VDP22_BR_DEASSOCIATED); -+ } else if (p->resp_vsi_mode == VDP22_RESP_SUCCESS) -+ vdp22br_change_state(p, VDP22_BR_SEND); -+ else if (p->resp_vsi_mode == VDP22_RESP_KEEP) -+ vdp22br_change_state(p, VDP22_BR_KEEP); -+ else -+ vdp22br_change_state(p, VDP22_BR_DEASSOC); -+ return true; -+ case VDP22_BR_SEND: -+ case VDP22_BR_KEEP: -+ vdp22br_change_state(p, VDP22_BR_WAITCMD); -+ return true; -+ case VDP22_BR_DEASSOC: -+ vdp22br_change_state(p, VDP22_BR_END); -+ return true; -+ case VDP22_BR_WAITCMD: -+ if (p->smi.localchg) { /* New station request */ -+ vdp22br_change_state(p, VDP22_BR_WAITCMD_2); -+ return true; -+ } -+ if (p->smi.kato) { /* Keep alive timeout */ -+ vdp22br_change_state(p, VDP22_BR_DEASSOCIATED); -+ return true; -+ } -+ return false; -+ case VDP22_BR_WAITCMD_2: /* Handle station msg */ -+ if (p->cc_vsi_mode == p->vsi_mode) -+ vdp22br_change_state(p, VDP22_BR_ALIVE); -+ else -+ vdp22br_change_state(p, VDP22_BR_PROCESS); -+ return true; -+ case VDP22_BR_DEASSOCIATED: -+ vdp22br_change_state(p, VDP22_BR_END); -+ return true; -+ case VDP22_BR_ALIVE: -+ vdp22br_change_state(p, VDP22_BR_WAITCMD); -+ return true; -+ case VDP22_BR_END: -+ return false; -+ default: -+ LLDPAD_DBG("%s:%s unhandled state %s\n", __func__, -+ p->vdp->ifname, vdp22br_state_name(p->smi.state)); -+ } -+ return false; -+} -+ -+/* -+ * Run bridge state machine. -+ */ -+static void vdp22br_run(struct vsi22 *p) -+{ -+ vdp22br_move_state(p); -+ do { -+ LLDPAD_DBG("%s:%s state %s\n", __func__, -+ p->vdp->ifname, -+ vdp22br_state_name(p->smi.state)); -+ -+ switch (p->smi.state) { -+ case VDP22_BR_INIT: -+ vdp22br_init(p); -+ break; -+ case VDP22_BR_PROCESS: -+ vdp22br_process(p); -+ break; -+ case VDP22_BR_SEND: -+ vdp22br_reply(p); -+ break; -+ case VDP22_BR_KEEP: -+ vdp22br_sendack(p, p->status); -+ break; -+ case VDP22_BR_DEASSOC: -+ vdp22br_deassoc(p, p->status); -+ break; -+ case VDP22_BR_WAITCMD: -+ vdp22br_start_katimer(p); -+ break; -+ case VDP22_BR_WAITCMD_2: -+ break; -+ case VDP22_BR_ALIVE: -+ vdp22br_sendack(p, VDP22_ACKBIT); -+ break; -+ case VDP22_BR_DEASSOCIATED: -+ vdp22br_deassoc(p, 0); -+ break; -+ case VDP22_BR_END: -+ vdp22br_end(p); -+ break; -+ } -+ } while (vdp22br_move_state(p) == true); -+} -+ -+/* -+ * Process the request from the station. -+ * -+ * NOTE: -+ * - Parameter vsip and associated fid data is on stack memory. -+ * - New filter information data assigned to new_fdata/new_no_fdata. -+ */ -+static void vdp22_station_info(struct vsi22 *vsip) -+{ -+ struct vdp22 *vdp = vsip->vdp; -+ struct vsi22 *hit = vdp22_findvsi(vsip->vdp, vsip); -+ -+ LLDPAD_DBG("%s:%s received VSI hit:%p\n", __func__, vdp->ifname, hit); -+ vdp22_showvsi(vsip); -+ if (!hit) { -+ if (vsip->vsi_mode == VDP22_DEASSOC) { -+ /* Nothing allocated and de-assoc --> return ack */ -+ vsip->status = VDP22_ACKBIT; -+ } else { -+ /* Create VSI & enter init state */ -+ struct vsi22 *new = vdp22_copy_vsi(vsip); -+ -+ if (new) -+ return vdp22br_addvsi(new); -+ vsip->status = VDP22_ACKBIT -+ | make_status(VDP22_RESP_NO_RESOURCES); -+ } -+ /* Send back response without state machine resources */ -+ return vdp22br_reply(vsip); -+ } -+ LLDPAD_DBG("%s:%s vsi_mode:%d flags:%#lx\n", __func__, vdp->ifname, -+ hit->vsi_mode, hit->flags); -+ if (hit->flags & VDP22_BUSY) -+ return; -+ vdp22br_stop_katimer(hit); -+ if (!vdp22_cmp_fdata(hit, vsip)) { -+ LLDPAD_DBG("%s:%s TODO mismatch filter data [%02x]\n", -+ __func__, vsip->vdp->ifname, vsip->vsi[0]); -+ return; -+ } -+ hit->smi.localchg = true; -+ hit->vsi_mode = vsip->vsi_mode; /* Take new request */ -+ vdp22br_run(hit); -+} -diff --git a/qbg/vdp_clif.c b/qbg/vdp_clif.c -new file mode 100644 -index 0000000..89f0645 ---- /dev/null -+++ b/qbg/vdp_clif.c -@@ -0,0 +1,193 @@ -+/******************************************************************************* -+ -+ Implementation of VDP according to IEEE 802.1Qbg -+ (c) Copyright IBM Corp. 2010, 2012 -+ -+ Author(s): Jens Osterkamp -+ Author(s): Thomas Richter -+ -+ This program is free software; you can redistribute it and/or modify it -+ under the terms and conditions of the GNU General Public License, -+ version 2, as published by the Free Software Foundation. -+ -+ This program is distributed in the hope it will be useful, but WITHOUT -+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ more details. -+ -+ You should have received a copy of the GNU General Public License along with -+ this program; if not, write to the Free Software Foundation, Inc., -+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. -+ -+ The full GNU General Public License is included in this distribution in -+ the file called "COPYING". -+ -+*******************************************************************************/ -+ -+#include -+#include -+#include -+#include -+#include -+#include "lldp_mod.h" -+#include "clif_msgs.h" -+#include "lldp.h" -+#include "qbg_vdp.h" -+#include "qbg_vdp_cmds.h" -+#include "qbg_vdp_clif.h" -+#include "lldp_mand_clif.h" -+ -+static const char *mode_state(int mode) -+{ -+ switch (mode) { -+ case VDP_MODE_PREASSOCIATE_WITH_RR: -+ return "Preassociated with RR"; -+ case VDP_MODE_DEASSOCIATE: -+ return "Disassociated"; -+ case VDP_MODE_ASSOCIATE: -+ return "Associated"; -+ case VDP_MODE_PREASSOCIATE: -+ return "Preassociated"; -+ default: return "unknown"; -+ } -+} -+ -+/* -+ * Print a complete VDP TLV. Data string constructed in function -+ * vdp_clif_profile(). -+ */ -+static void vdp_show_tlv(UNUSED u16 len, char *info) -+{ -+ int rc, role, enabletx, vdpbit, mode, response, mgrid, id, idver; -+ unsigned int x[16]; -+ -+ rc = sscanf(info, "%02x%02x%02x%02x%02x%02x%06x%02x", -+ &role, &enabletx, &vdpbit, &mode, &response, &mgrid, -+ &id, &idver); -+ if (rc != 3 && rc != 8) -+ return; -+ printf("Role:%s\n", role ? VAL_BRIDGE : VAL_STATION); -+ printf("\tEnabled:%s\n", enabletx ? VAL_YES : VAL_NO); -+ printf("\tVDP Bit:%s\n", vdpbit ? VAL_YES : VAL_NO); -+ if (rc == 3) /* No active VSI profile */ -+ return; -+ printf("\tMode:%d (%s)\n", mode, mode_state(mode)); -+ printf("\tMgrid:%d\n", mgrid); -+ printf("\tTypeid:%d\n", id); -+ printf("\tTypeidversion:%d\n", idver); -+ rc = sscanf(info + 20, "%02x%02x%02x%02x%02x%02x%02x%02x" -+ "%02x%02x%02x%02x%02x%02x%02x%02x", -+ &x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &x[6], &x[7], -+ &x[8], &x[9], &x[10], &x[11], &x[12], &x[13], &x[14], -+ &x[15]); -+ if (rc != 16) -+ return; -+ printf("\tUUID:%02x%02x%02x%02x-%02x%02x-%02x%02x" -+ "-%02x%02x-%02x%02x%02x%02x%02x%02x\n", x[0], x[1], x[2], x[3], -+ x[4], x[5], x[6], x[7], x[8], x[9], x[10], x[11], x[12], x[13], -+ x[14], x[15]); -+ mode = 52; -+ rc = sscanf(info + mode, "%02x%04x", &role, &vdpbit); -+ if (rc != 2) -+ return; -+ printf("\tFilter Format:%d\n", role); -+ printf("\tEntries:%d\n", vdpbit); -+ mode += 6; -+ while (--vdpbit >= 0) { -+ rc = sscanf(info + mode, "%02x%02x%02x%02x%02x%02x%04x", -+ &x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &x[6]); -+ if (rc != 7) -+ return; -+ printf("\t\tMAC:%02x:%02x:%02x:%02x:%02x:%02x\tVlanid:%d\n", -+ x[0], x[1], x[2], x[3], x[4], x[5], x[6]); -+ mode += 16; -+ } -+} -+ -+static struct type_name_info vdp_tlv_names[] = { -+ { -+ .type = ((LLDP_MOD_VDP) << 8) | LLDP_VDP_SUBTYPE, -+ .name = "VDP draft 0.2 protocol configuration", -+ .key = "vdp", -+ .print_info = vdp_show_tlv -+ }, -+ { -+ .type = INVALID_TLVID -+ } -+}; -+ -+static int vdp_print_help() -+{ -+ struct type_name_info *tn = &vdp_tlv_names[0]; -+ -+ while (tn->type != INVALID_TLVID) { -+ if (tn->key && strlen(tn->key) && tn->name) { -+ printf(" %s", tn->key); -+ if (strlen(tn->key)+3 < 8) -+ printf("\t"); -+ printf("\t: %s\n", tn->name); -+ } -+ tn++; -+ } -+ return 0; -+} -+ -+static u32 vdp_lookup_tlv_name(char *tlvid_str) -+{ -+ struct type_name_info *tn = &vdp_tlv_names[0]; -+ -+ while (tn->type != INVALID_TLVID) { -+ if (!strcasecmp(tn->key, tlvid_str)) -+ return tn->type; -+ tn++; -+ } -+ return INVALID_TLVID; -+} -+ -+static void vdp_cli_unregister(struct lldp_module *mod) -+{ -+ free(mod); -+} -+ -+/* return 1: if it printed the TLV -+ * 0: if it did not -+ */ -+static int vdp_print_tlv(u32 tlvid, u16 len, char *info) -+{ -+ struct type_name_info *tn = &vdp_tlv_names[0]; -+ -+ while (tn->type != INVALID_TLVID) { -+ if (tlvid == tn->type) { -+ printf("%s\n", tn->name); -+ if (tn->print_info) { -+ printf("\t"); -+ tn->print_info(len-4, info); -+ } -+ return 1; -+ } -+ tn++; -+ } -+ return 0; -+} -+ -+static const struct lldp_mod_ops vdp_ops_clif = { -+ .lldp_mod_register = vdp_cli_register, -+ .lldp_mod_unregister = vdp_cli_unregister, -+ .print_tlv = vdp_print_tlv, -+ .lookup_tlv_name = vdp_lookup_tlv_name, -+ .print_help = vdp_print_help, -+}; -+ -+struct lldp_module *vdp_cli_register(void) -+{ -+ struct lldp_module *mod; -+ -+ mod = malloc(sizeof(*mod)); -+ if (!mod) { -+ fprintf(stderr, "failed to malloc module data\n"); -+ return NULL; -+ } -+ mod->id = (LLDP_MOD_VDP << 8) | LLDP_VDP_SUBTYPE; -+ mod->ops = &vdp_ops_clif; -+ return mod; -+} -diff --git a/qbg/vdp_cmds.c b/qbg/vdp_cmds.c -new file mode 100644 -index 0000000..95bcfb1 ---- /dev/null -+++ b/qbg/vdp_cmds.c -@@ -0,0 +1,632 @@ -+/****************************************************************************** -+ -+ Implementation of VDP according to IEEE 802.1Qbg -+ (c) Copyright IBM Corp. 2010, 2012 -+ -+ Author(s): Jens Osterkamp -+ Author(s): Thomas Richter -+ -+ This program is free software; you can redistribute it and/or modify it -+ under the terms and conditions of the GNU General Public License, -+ version 2, as published by the Free Software Foundation. -+ -+ This program is distributed in the hope it will be useful, but WITHOUT -+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ more details. -+ -+ You should have received a copy of the GNU General Public License along with -+ this program; if not, write to the Free Software Foundation, Inc., -+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. -+ -+ The full GNU General Public License is included in this distribution in -+ the file called "COPYING". -+ -+******************************************************************************/ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include "lldpad.h" -+#include "ctrl_iface.h" -+#include "lldp.h" -+#include "qbg_vdp.h" -+#include "lldp_mand_clif.h" -+#include "qbg_vdp_cmds.h" -+#include "qbg_utils.h" -+#include "lldp/ports.h" -+#include "lldp_tlv.h" -+#include "messages.h" -+#include "libconfig.h" -+#include "config.h" -+#include "clif_msgs.h" -+#include "lldpad_status.h" -+#include "lldp/states.h" -+ -+static char *check_and_update(size_t *total, size_t *length, char *s, int c) -+{ -+ if (c < 0) -+ return NULL; -+ *total += c; -+ if ((unsigned)c >= *length) -+ return NULL; -+ *length -= c; -+ return s + c; -+} -+ -+static char *print_mode(char *s, size_t length, struct vsi_profile *p) -+{ -+ int c; -+ size_t total = 0; -+ char *r = s; -+ struct mac_vlan *mac_vlan; -+ char instance[VDP_UUID_STRLEN + 2]; -+ -+ vdp_uuid2str(p->instance, instance, sizeof(instance)); -+ c = snprintf(s, length, "%d,%d,%d,%d,%s,%d", -+ p->state, p->mgrid, p->id, p->version, instance, -+ p->format); -+ s = check_and_update(&total, &length, s, c); -+ if (!s) -+ return r; -+ -+ LIST_FOREACH(mac_vlan, &p->macvid_head, entry) { -+ char macbuf[MAC_ADDR_STRLEN + 1]; -+ -+ mac2str(mac_vlan->mac, macbuf, MAC_ADDR_STRLEN); -+ c = snprintf(s, length, ",%s,%d", macbuf, mac_vlan->vlan); -+ s = check_and_update(&total, &length, s, c); -+ if (!s) -+ return r; -+ } -+ return s; -+} -+ -+static int vdp_cmdok(struct cmd *cmd, cmd_status expected) -+{ -+ if (cmd->cmd != expected) -+ return cmd_invalid; -+ -+ switch (cmd->tlvid) { -+ case ((LLDP_MOD_VDP) << 8) | LLDP_VDP_SUBTYPE: -+ if (cmd->type != NEAREST_CUSTOMER_BRIDGE) -+ return cmd_agent_not_supported; -+ -+ return cmd_success; -+ case INVALID_TLVID: -+ return cmd_invalid; -+ default: -+ return cmd_not_applicable; -+ } -+} -+ -+static int -+get_arg_tlvtxenable(struct cmd *cmd, char *arg, UNUSED char *argvalue, -+ char *obuf, int obuf_len) -+{ -+ cmd_status good_cmd = vdp_cmdok(cmd, cmd_gettlv); -+ int value; -+ char *s; -+ char arg_path[VDP_BUF_SIZE]; -+ -+ if (good_cmd != cmd_success) -+ return good_cmd; -+ -+ snprintf(arg_path, sizeof(arg_path), "%s.%s", VDP_PREFIX, arg); -+ -+ if (get_cfg(cmd->ifname, cmd->type, arg_path, &value, -+ CONFIG_TYPE_BOOL)) -+ value = false; -+ -+ if (value) -+ s = VAL_YES; -+ else -+ s = VAL_NO; -+ -+ snprintf(obuf, obuf_len, "%02zx%s%04zx%s", -+ strlen(arg), arg, strlen(s), s); -+ -+ return cmd_success; -+} -+ -+static int _set_arg_tlvtxenable(struct cmd *cmd, char *arg, char *argvalue, -+ bool test) -+{ -+ cmd_status good_cmd = vdp_cmdok(cmd, cmd_settlv); -+ int value, err; -+ char arg_path[VDP_BUF_SIZE]; -+ -+ if (good_cmd != cmd_success) -+ return good_cmd; -+ -+ if (!strcasecmp(argvalue, VAL_YES)) -+ value = 1; -+ else if (!strcasecmp(argvalue, VAL_NO)) -+ value = 0; -+ else -+ return cmd_invalid; -+ -+ if (test) -+ return cmd_success; -+ -+ snprintf(arg_path, sizeof(arg_path), "%s.%s", VDP_PREFIX, arg); -+ -+ err = set_cfg(cmd->ifname, cmd->type, arg_path, -+ &value, CONFIG_TYPE_BOOL); -+ if (err) -+ return cmd_failed; -+ -+ return cmd_success; -+ -+} -+ -+static int set_arg_tlvtxenable(struct cmd *cmd, char *arg, char *argvalue, -+ UNUSED char *obuf, UNUSED int obuf_len) -+{ -+ return _set_arg_tlvtxenable(cmd, arg, argvalue, false); -+} -+ -+static int test_arg_tlvtxenable(struct cmd *cmd, char *arg, char *argvalue, -+ UNUSED char *obuf, UNUSED int obuf_len) -+{ -+ return _set_arg_tlvtxenable(cmd, arg, argvalue, true); -+} -+ -+static int get_arg_mode(struct cmd *cmd, char *arg, UNUSED char *argvalue, -+ char *obuf, int obuf_len) -+{ -+ struct vsi_profile *np; -+ struct vdp_data *vd; -+ char mode_str[VDP_BUF_SIZE], *t = mode_str; -+ int filled = 0; -+ -+ if (cmd->cmd != cmd_gettlv) -+ return cmd_invalid; -+ -+ switch (cmd->tlvid) { -+ case ((LLDP_MOD_VDP) << 8) | LLDP_VDP_SUBTYPE: -+ break; -+ case INVALID_TLVID: -+ return cmd_invalid; -+ default: -+ return cmd_not_applicable; -+ } -+ -+ vd = vdp_data(cmd->ifname); -+ if (!vd) { -+ LLDPAD_ERR("%s: vdp_data for %s not found !\n", -+ __func__, cmd->ifname); -+ return cmd_device_not_found; -+ } -+ -+ memset(mode_str, 0, sizeof mode_str); -+ LIST_FOREACH(np, &vd->profile_head, profile) { -+ t = print_mode(t, sizeof(mode_str) - filled, np); -+ filled = t - mode_str; -+ } -+ -+ snprintf(obuf, obuf_len, "%02x%s%04x%s", -+ (unsigned int)strlen(arg), arg, (unsigned int)strlen(mode_str), -+ mode_str); -+ return cmd_success; -+} -+ -+static void str2instance(struct vsi_profile *profile, char *buffer) -+{ -+ unsigned int i, j = 0; -+ -+ for (i = 0; i <= strlen(buffer); i++) { -+ if (buffer[i] == '-') -+ continue; -+ -+ if (sscanf(&buffer[i], "%02hhx", &profile->instance[j]) == 1) { -+ i++; -+ j++; -+ } -+ } -+} -+ -+static void vdp_fill_profile(struct vsi_profile *profile, char *buffer, -+ int field) -+{ -+ LLDPAD_DBG("%s: parsed %s\n", __func__, buffer); -+ -+ switch(field) { -+ case MODE: -+ profile->mode = atoi(buffer); -+ break; -+ case MGRID: -+ profile->mgrid = atoi(buffer); -+ break; -+ case TYPEID: -+ profile->id = atoi(buffer); -+ break; -+ case TYPEIDVERSION: -+ profile->version = atoi(buffer); -+ break; -+ case INSTANCEID: -+ str2instance(profile, buffer); -+ break; -+ case FORMAT: -+ profile->format = atoi(buffer); -+ break; -+ default: -+ LLDPAD_ERR("Unknown field in buffer !\n"); -+ break; -+ } -+} -+ -+static struct vsi_profile *vdp_parse_mode_line(char *argvalue) -+{ -+ int field; -+ char *cmdstring, *parsed; -+ struct vsi_profile *profile; -+ -+ profile = vdp_alloc_profile(); -+ if (!profile) -+ return NULL; -+ -+ cmdstring = strdup(argvalue); -+ if (!cmdstring) -+ goto out_free; -+ -+ field = 0; -+ -+ parsed = strtok(cmdstring, ","); -+ -+ while (parsed != NULL) { -+ vdp_fill_profile(profile, parsed, field); -+ field++; -+ if (field > FORMAT) -+ break; -+ parsed = strtok(NULL, ","); -+ } -+ -+ if ((field <= FORMAT) || (parsed == NULL)) -+ goto out_free; -+ -+ parsed = strtok(NULL, ","); -+ -+ while (parsed != NULL) { -+ struct mac_vlan *mac_vlan; -+ -+ mac_vlan = calloc(1, sizeof(struct mac_vlan)); -+ if (mac_vlan == NULL) -+ goto out_free; -+ -+ if (str2mac(parsed, &mac_vlan->mac[0], MAC_ADDR_LEN)) { -+ free(mac_vlan); -+ goto out_free; -+ } -+ -+ parsed = strtok(NULL, ","); -+ if (parsed == NULL) { -+ free(mac_vlan); -+ goto out_free; -+ } -+ -+ mac_vlan->vlan = atoi(parsed); -+ LIST_INSERT_HEAD(&profile->macvid_head, mac_vlan, entry); -+ profile->entries++; -+ parsed = strtok(NULL, ","); -+ } -+ -+ free(cmdstring); -+ return profile; -+ -+out_free: -+ free(cmdstring); -+ vdp_delete_profile(profile); -+ return NULL; -+} -+ -+static int _set_arg_mode(struct cmd *cmd, char *argvalue, bool test) -+{ -+ cmd_status good_cmd = vdp_cmdok(cmd, cmd_settlv); -+ struct vsi_profile *profile, *p; -+ struct vdp_data *vd; -+ -+ if (good_cmd != cmd_success) -+ return good_cmd; -+ -+ profile = vdp_parse_mode_line(argvalue); -+ if (profile == NULL) -+ return cmd_failed; -+ -+ profile->port = port_find_by_ifindex(get_ifidx(cmd->ifname)); -+ -+ if (!profile->port) { -+ vdp_delete_profile(profile); -+ return cmd_device_not_found; -+ } -+ -+ vd = vdp_data(cmd->ifname); -+ if (!vd) { -+ vdp_delete_profile(profile); -+ return cmd_device_not_found; -+ } -+ -+ if (test) { -+ vdp_delete_profile(profile); -+ return cmd_success; -+ } -+ -+ p = vdp_add_profile(vd, profile); -+ if (profile != p) -+ vdp_delete_profile(profile); -+ -+ return cmd_success; -+} -+ -+static int set_arg_mode(struct cmd *cmd, UNUSED char *arg, char *argvalue, -+ UNUSED char *obuf, UNUSED int obuf_len) -+{ -+ return _set_arg_mode(cmd, argvalue, false); -+} -+ -+static int test_arg_mode(struct cmd *cmd, UNUSED char *arg, char *argvalue, -+ UNUSED char *obuf, UNUSED int obuf_len) -+{ -+ return _set_arg_mode(cmd, argvalue, true); -+} -+ -+static int get_arg_role(struct cmd *cmd, char *arg, UNUSED char *argvalue, -+ char *obuf, int obuf_len) -+{ -+ cmd_status good_cmd = vdp_cmdok(cmd, cmd_gettlv); -+ char arg_path[VDP_BUF_SIZE]; -+ const char *p; -+ -+ if (good_cmd != cmd_success) -+ return good_cmd; -+ -+ snprintf(arg_path, sizeof(arg_path), "%s.%s", VDP_PREFIX, arg); -+ if (get_cfg(cmd->ifname, cmd->type, -+ arg_path, &p, CONFIG_TYPE_STRING)) -+ p = VAL_STATION; -+ -+ snprintf(obuf, obuf_len, "%02x%s%04x%s", -+ (unsigned int) strlen(arg), arg, -+ (unsigned int) strlen(p), p); -+ -+ return cmd_success; -+} -+ -+static int _set_arg_role(struct cmd *cmd, char *arg, char *argvalue, bool test) -+{ -+ cmd_status good_cmd = vdp_cmdok(cmd, cmd_settlv); -+ struct vdp_data *vd; -+ char arg_path[VDP_BUF_SIZE]; -+ -+ if (good_cmd != cmd_success) -+ return good_cmd; -+ -+ vd = vdp_data(cmd->ifname); -+ -+ if (!strcasecmp(argvalue, VAL_BRIDGE)) { -+ if (!test && vd) -+ vd->role = VDP_ROLE_BRIDGE; -+ } else if (!strcasecmp(argvalue, VAL_STATION)) { -+ if (!test && vd) -+ vd->role = VDP_ROLE_STATION; -+ } else { -+ return cmd_invalid; -+ } -+ -+ if (test) -+ return cmd_success; -+ -+ snprintf(arg_path, sizeof(arg_path), "%s.%s", VDP_PREFIX, arg); -+ -+ const char *p = &argvalue[0]; -+ if (set_cfg(cmd->ifname, cmd->type, arg_path, &p, CONFIG_TYPE_STRING)) -+ return cmd_failed; -+ -+ return cmd_success; -+} -+ -+static int set_arg_role(struct cmd *cmd, char *arg, char *argvalue, -+ UNUSED char *obuf, UNUSED int obuf_len) -+{ -+ return _set_arg_role(cmd, arg, argvalue, false); -+} -+ -+static int test_arg_role(struct cmd *cmd, char *arg, char *argvalue, -+ UNUSED char *obuf, UNUSED int obuf_len) -+{ -+ return _set_arg_role(cmd, arg, argvalue, true); -+} -+ -+static struct arg_handlers arg_handlers[] = { -+ { -+ .arg = ARG_VDP_MODE, -+ .arg_class = TLV_ARG, -+ .handle_get = get_arg_mode, -+ .handle_set = set_arg_mode, -+ .handle_test = test_arg_mode -+ }, -+ { -+ .arg = ARG_VDP_ROLE, -+ .arg_class = TLV_ARG, -+ .handle_get = get_arg_role, -+ .handle_set = set_arg_role, -+ .handle_test = test_arg_role -+ }, -+ { -+ .arg = ARG_TLVTXENABLE, -+ .arg_class = TLV_ARG, -+ .handle_get = get_arg_tlvtxenable, -+ .handle_set = set_arg_tlvtxenable, -+ .handle_test = test_arg_tlvtxenable -+ }, -+ { -+ .arg = 0 -+ } -+}; -+ -+struct arg_handlers *vdp_get_arg_handlers() -+{ -+ return &arg_handlers[0]; -+} -+ -+/* -+ * Interface to build information for lldptool -V vdp -+ */ -+struct tlv_info_vdp_nopp { /* VSI information without profile data */ -+ u8 oui[3]; /* OUI */ -+ u8 sub; /* Subtype */ -+ u8 role; /* Role: station or bridge */ -+ u8 enabletx; -+ u8 vdpbit_on; -+} __attribute__ ((__packed__)); -+ -+/* -+ * Flatten a profile stored as TLV and append it. Skip the first 4 bytes. -+ * They contain the OUI already stored. -+ * Returns the number of bytes added to the buffer. -+ */ -+static int add_profile(unsigned char *pdu, size_t pdusz, struct vdp_data *vdp) -+{ -+ size_t size = 0; -+ -+ if (!vdp->vdp) -+ return size; -+ size = (unsigned)TLVSIZE(vdp->vdp) - 4; -+ if (pdusz >= size) -+ memcpy(pdu, vdp->vdp->info + 4, size); -+ else { -+ LLDPAD_ERR("%s: %s buffer size too small (need %d bytes)\n", -+ __func__, vdp->ifname, TLVSIZE(vdp->vdp)); -+ return -1; -+ } -+ return size; -+} -+ -+/* -+ * Create unpacked VDP tlv for VSI profile when active. -+ */ -+static int make_vdp_tlv(unsigned char *pdu, size_t pdusz, struct vdp_data *vdp) -+{ -+ struct unpacked_tlv *tlv = (struct unpacked_tlv *)pdu; -+ struct tlv_info_vdp_nopp *vdpno; -+ size_t pduoff; -+ int rc; -+ -+ tlv->info = (unsigned char *)(tlv + 1); -+ vdpno = (struct tlv_info_vdp_nopp *)tlv->info; -+ tlv->type = ORG_SPECIFIC_TLV; -+ tlv->length = sizeof(struct tlv_info_vdp_nopp); -+ hton24(vdpno->oui, LLDP_MOD_VDP); -+ vdpno->sub = LLDP_VDP_SUBTYPE; -+ vdpno->role = vdp->role; -+ vdpno->enabletx = vdp->enabletx; -+ vdpno->vdpbit_on = vdp->vdpbit_on; -+ pduoff = sizeof(*tlv) + tlv->length; -+ pdusz -= pduoff; -+ rc = add_profile(pdu + pduoff, pdusz - pduoff, vdp); -+ if (rc > 0) { -+ tlv->length += rc; -+ rc = 0; -+ } -+ return rc; -+} -+ -+/* -+ * Flatten a VDP TLV into a byte stream. -+ */ -+static int vdp_clif_profile(char *ifname, char *rbuf, size_t rlen) -+{ -+ unsigned char pdu[VDP_BUF_SIZE]; /* Buffer for unpacked TLV */ -+ int i, c, rstatus = cmd_success; -+ size_t sum = 0; -+ struct vdp_data *vd; -+ struct unpacked_tlv *tlv = (struct unpacked_tlv *)pdu; -+ struct packed_tlv *ptlv; -+ -+ LLDPAD_DBG("%s: %s rlen:%zu\n", __func__, ifname, rlen); -+ vd = vdp_data(ifname); -+ if (!vd) -+ return cmd_device_not_found; -+ -+ if (make_vdp_tlv(pdu, sizeof pdu, vd)) -+ return cmd_failed; -+ -+ /* Convert to packed TLV */ -+ ptlv = pack_tlv(tlv); -+ if (!ptlv) -+ return cmd_failed; -+ for (i = 0; i < TLVSIZE(tlv); ++i) { -+ c = snprintf(rbuf, rlen, "%02x", ptlv->tlv[i]); -+ rbuf = check_and_update(&sum, &rlen, rbuf, c); -+ if (!rbuf) { -+ rstatus = cmd_failed; -+ break; -+ } -+ } -+ free_pkd_tlv(ptlv); -+ return rstatus; -+} -+ -+/* -+ * Module function to extract all VSI profile data on a given interface. It -+ * is invoked via 'lldptool -t -i ethx -g ncb -V vdp' without any configuration -+ * options. -+ * This function does not support arguments and its values. They are handled -+ * using the lldp_mand_cmds.c interfaces. -+ */ -+int vdp_clif_cmd(char *ibuf, UNUSED int ilen, char *rbuf, int rlen) -+{ -+ struct cmd cmd; -+ u8 len, version; -+ int c, ioff; -+ size_t roff = 0, outlen = rlen; -+ char *here; -+ int rstatus = cmd_invalid; -+ -+ /* Pull out the command elements of the command message */ -+ hexstr2bin(ibuf + MSG_VER, (u8 *)&version, sizeof(u8)); -+ version >>= 4; -+ hexstr2bin(ibuf + CMD_CODE, (u8 *)&cmd.cmd, sizeof(cmd.cmd)); -+ hexstr2bin(ibuf + CMD_OPS, (u8 *)&cmd.ops, sizeof(cmd.ops)); -+ cmd.ops = ntohl(cmd.ops); -+ hexstr2bin(ibuf + CMD_IF_LEN, &len, sizeof(len)); -+ ioff = CMD_IF; -+ if (len < sizeof(cmd.ifname)) -+ memcpy(cmd.ifname, ibuf + CMD_IF, len); -+ else -+ return cmd_failed; -+ cmd.ifname[len] = '\0'; -+ ioff += len; -+ -+ memset(rbuf, 0, rlen); -+ c = snprintf(rbuf, rlen, "%c%1x%02x%08x%02x%s", -+ CMD_REQUEST, CLIF_MSG_VERSION, cmd.cmd, cmd.ops, -+ (unsigned int)strlen(cmd.ifname), cmd.ifname); -+ here = check_and_update(&roff, &outlen, rbuf, c); -+ if (!here) -+ return cmd_failed; -+ -+ if (version == CLIF_MSG_VERSION) { -+ hexstr2bin(ibuf+ioff, &cmd.type, sizeof(cmd.type)); -+ ioff += 2 * sizeof(cmd.type); -+ } else /* Command valid only for nearest customer bridge */ -+ goto out; -+ -+ if (cmd.cmd == cmd_gettlv) { -+ hexstr2bin(ibuf+ioff, (u8 *)&cmd.tlvid, sizeof(cmd.tlvid)); -+ cmd.tlvid = ntohl(cmd.tlvid); -+ ioff += 2 * sizeof(cmd.tlvid); -+ } else -+ goto out; -+ -+ c = snprintf(here, outlen, "%08x", cmd.tlvid); -+ here = check_and_update(&roff, &outlen, here, c); -+ if (!here) -+ return cmd_failed; -+ rstatus = vdp_clif_profile(cmd.ifname, here, outlen); -+out: -+ return rstatus; -+} -diff --git a/qbg/vdpnl.c b/qbg/vdpnl.c -new file mode 100644 -index 0000000..61b6a2b ---- /dev/null -+++ b/qbg/vdpnl.c -@@ -0,0 +1,527 @@ -+/****************************************************************************** -+ -+ Implementation of VDP according to IEEE 802.1Qbg -+ (c) Copyright IBM Corp. 2013 -+ -+ Author(s): Thomas Richter -+ -+ This program is free software; you can redistribute it and/or modify it -+ under the terms and conditions of the GNU General Public License, -+ version 2, as published by the Free Software Foundation. -+ -+ This program is distributed in the hope it will be useful, but WITHOUT -+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ more details. -+ -+ You should have received a copy of the GNU General Public License along with -+ this program; if not, write to the Free Software Foundation, Inc., -+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. -+ -+ The full GNU General Public License is included in this distribution in -+ the file called "COPYING". -+ -+******************************************************************************/ -+ -+/* -+ * Contains netlink message parsing for VDP protocol from libvirtd or other -+ * buddies. -+ */ -+ -+#include -+#include -+#include -+ -+#include -+ -+#include -+#include -+#include -+ -+#include "messages.h" -+#include "qbg_vdp.h" -+#include "qbg_vdp22.h" -+#include "qbg_vdpnl.h" -+#include "qbg_utils.h" -+#include "lldp_rtnl.h" -+ -+static struct nla_policy ifla_vf_policy[IFLA_VF_MAX + 1] = { -+ [IFLA_VF_MAC] = { -+ .minlen = sizeof(struct ifla_vf_mac), -+ .maxlen = sizeof(struct ifla_vf_mac) -+ }, -+ [IFLA_VF_VLAN] = { -+ .minlen = sizeof(struct ifla_vf_vlan), -+ .maxlen = sizeof(struct ifla_vf_vlan) -+ } -+}; -+ -+static struct nla_policy ifla_port_policy[IFLA_PORT_MAX + 1] = { -+ [IFLA_PORT_VF] = { .type = NLA_U32 }, -+ [IFLA_PORT_PROFILE] = { .type = NLA_STRING }, -+ [IFLA_PORT_VSI_TYPE] = { .minlen = sizeof(struct ifla_port_vsi) }, -+ [IFLA_PORT_INSTANCE_UUID] = { .minlen = PORT_UUID_MAX, -+ .maxlen = PORT_UUID_MAX, }, -+ [IFLA_PORT_HOST_UUID] = { .minlen = PORT_UUID_MAX, -+ .maxlen = PORT_UUID_MAX, }, -+ [IFLA_PORT_REQUEST] = { .type = NLA_U8 }, -+ [IFLA_PORT_RESPONSE] = { .type = NLA_U16 }, -+}; -+ -+/* -+ * Retrieve name of interface and its index value from the netlink messaage -+ * and store it in the data structure. -+ * The GETLINK message may or may not contain the IFLA_IFNAME attribute. -+ * Return 0 on success and errno on error. -+ */ -+static int vdpnl_get(struct nlmsghdr *nlh, struct vdpnl_vsi *p) -+{ -+ struct nlattr *tb[IFLA_MAX + 1]; -+ struct ifinfomsg *ifinfo; -+ -+ if (nlmsg_parse(nlh, sizeof(struct ifinfomsg), -+ (struct nlattr **)&tb, IFLA_MAX, NULL)) { -+ LLDPAD_ERR("%s:error parsing GETLINK request\n", __func__); -+ return -EINVAL; -+ } -+ -+ ifinfo = (struct ifinfomsg *)NLMSG_DATA(nlh); -+ p->ifindex = ifinfo->ifi_index; -+ if (tb[IFLA_IFNAME]) { -+ memcpy(p->ifname, (char *)RTA_DATA(tb[IFLA_IFNAME]), -+ sizeof p->ifname); -+ } else if (!if_indextoname(p->ifindex, p->ifname)) { -+ LLDPAD_ERR("%s:ifindex %d without interface name\n", __func__, -+ p->ifindex); -+ return -EINVAL; -+ } -+ LLDPAD_DBG("%s:IFLA_IFNAME:%s ifindex:%d\n", __func__, p->ifname, -+ p->ifindex); -+ return 0; -+} -+ -+static void vdpnl_show(struct vdpnl_vsi *vsi) -+{ -+ char instance[VDP_UUID_STRLEN + 2]; -+ struct vdpnl_mac *mac; -+ int i; -+ -+ LLDPAD_DBG("%s:IFLA_IFNAME:%s index:%d\n", __func__, vsi->ifname, -+ vsi->ifindex); -+ for (i = 0, mac = vsi->maclist; i < vsi->macsz; ++i, ++mac) { -+ LLDPAD_DBG("%s:IFLA_VF_MAC:%2x:%2x:%2x:%2x:%2x:%2x\n", -+ __func__, mac->mac[0], mac->mac[1], mac->mac[2], -+ mac->mac[3], mac->mac[4], mac->mac[5]); -+ LLDPAD_DBG("%s:IFLA_VF_VLAN:%d QOS:%d\n", __func__, mac->vlan, -+ mac->qos); -+ } -+ LLDPAD_DBG("%s:IFLA_PORT_VSI_TYPE:mgr_id:%d type_id:%ld " -+ "typeid_version:%d\n", -+ __func__, vsi->vsi_mgrid, vsi->vsi_typeid, -+ vsi->vsi_typeversion); -+ vdp_uuid2str(vsi->vsi_uuid, instance, sizeof(instance)); -+ LLDPAD_DBG("%s:IFLA_PORT_INSTANCE_UUID:%s\n", __func__, instance); -+ LLDPAD_DBG("%s:IFLA_PORT_REQUEST:%d\n", __func__, vsi->request); -+ LLDPAD_DBG("%s:IFLA_PORT_RESPONSE:%d\n", __func__, vsi->response); -+} -+ -+/* -+ * Parse the IFLA_IFLA_VF_PORTIFLA_VF_PORTS block of the netlink message. -+ * Return zero on success and errno else. -+ */ -+static int vdpnl_vfports(struct nlattr *vfports, struct vdpnl_vsi *vsi) -+{ -+ char instance[VDP_UUID_STRLEN + 2]; -+ struct nlattr *tb_vf_ports, *tb3[IFLA_PORT_MAX + 1]; -+ int rem; -+ -+ if (!vfports) { -+ LLDPAD_DBG("%s:FOUND NO IFLA_VF_PORTS\n", __func__); -+ return -EINVAL; -+ } -+ -+ nla_for_each_nested(tb_vf_ports, vfports, rem) { -+ if (nla_type(tb_vf_ports) != IFLA_VF_PORT) { -+ LLDPAD_DBG("%s:not a IFLA_VF_PORT skipping\n", -+ __func__); -+ continue; -+ } -+ if (nla_parse_nested(tb3, IFLA_PORT_MAX, tb_vf_ports, -+ ifla_port_policy)) { -+ LLDPAD_ERR("%s:IFLA_PORT_MAX parsing failed\n", -+ __func__); -+ return -EINVAL; -+ } -+ if (tb3[IFLA_PORT_VF]) -+ LLDPAD_DBG("%s:IFLA_PORT_VF:%d\n", __func__, -+ *(uint32_t *) RTA_DATA(tb3[IFLA_PORT_VF])); -+ if (tb3[IFLA_PORT_PROFILE]) -+ LLDPAD_DBG("%s:IFLA_PORT_PROFILE:%s\n", __func__, -+ (char *)RTA_DATA(tb3[IFLA_PORT_PROFILE])); -+ if (tb3[IFLA_PORT_HOST_UUID]) { -+ unsigned char *uuid; -+ -+ uuid = (unsigned char *) -+ RTA_DATA(tb3[IFLA_PORT_HOST_UUID]); -+ vdp_uuid2str(uuid, instance, sizeof(instance)); -+ LLDPAD_DBG("%s:IFLA_PORT_HOST_UUID:%s\n", __func__, -+ instance); -+ } -+ if (tb3[IFLA_PORT_VSI_TYPE]) { -+ struct ifla_port_vsi *pvsi; -+ int tid = 0; -+ -+ pvsi = (struct ifla_port_vsi *) -+ RTA_DATA(tb3[IFLA_PORT_VSI_TYPE]); -+ tid = pvsi->vsi_type_id[2] << 16 | -+ pvsi->vsi_type_id[1] << 8 | -+ pvsi->vsi_type_id[0]; -+ vsi->vsi_mgrid = pvsi->vsi_mgr_id; -+ vsi->vsi_typeversion = pvsi->vsi_type_version; -+ vsi->vsi_typeid = tid; -+ } -+ if (tb3[IFLA_PORT_INSTANCE_UUID]) { -+ unsigned char *uuid = (unsigned char *) -+ RTA_DATA(tb3[IFLA_PORT_INSTANCE_UUID]); -+ memcpy(vsi->vsi_uuid, uuid, sizeof vsi->vsi_uuid); -+ } -+ if (tb3[IFLA_PORT_REQUEST]) -+ vsi->request = -+ *(uint8_t *) RTA_DATA(tb3[IFLA_PORT_REQUEST]); -+ if (tb3[IFLA_PORT_RESPONSE]) -+ vsi->response = -+ *(uint16_t *) RTA_DATA(tb3[IFLA_PORT_RESPONSE]); -+ } -+ return 0; -+} -+ -+/* -+ * Parse the IFLA_VFINFO_LIST block of the netlink message. -+ * Return zero on success and errno else. -+ */ -+static int vdpnl_vfinfolist(struct nlattr *vfinfolist, struct vdpnl_vsi *vsi) -+{ -+ struct nlattr *le1, *vf[IFLA_VF_MAX + 1]; -+ int rem; -+ -+ if (!vfinfolist) { -+ LLDPAD_ERR("%s:IFLA_VFINFO_LIST missing\n", __func__); -+ return -EINVAL; -+ } -+ nla_for_each_nested(le1, vfinfolist, rem) { -+ bool have_mac = false, have_vid = false; -+ -+ if (nla_type(le1) != IFLA_VF_INFO) { -+ LLDPAD_ERR("%s:parsing of IFLA_VFINFO_LIST failed\n", -+ __func__); -+ return -EINVAL; -+ } -+ if (nla_parse_nested(vf, IFLA_VF_MAX, le1, ifla_vf_policy)) { -+ LLDPAD_ERR("%s:parsing of IFLA_VF_INFO failed\n", -+ __func__); -+ return -EINVAL; -+ } -+ -+ if (vf[IFLA_VF_MAC]) { -+ struct ifla_vf_mac *mac = RTA_DATA(vf[IFLA_VF_MAC]); -+ -+ memcpy(vsi->maclist->mac, mac->mac, ETH_ALEN); -+ have_mac = true; -+ } -+ -+ if (vf[IFLA_VF_VLAN]) { -+ struct ifla_vf_vlan *vlan = RTA_DATA(vf[IFLA_VF_VLAN]); -+ -+ vsi->maclist->vlan = vlan->vlan; -+ vsi->maclist->qos = vlan->qos; -+ have_vid = true; -+ } -+ LLDPAD_DBG("%s:have_vid:%d have_mac:%d\n", __func__, have_vid, -+ have_mac); -+ if (have_vid && have_mac) -+ vsi->filter_fmt = VDP22_FFMT_MACVID; -+ else if (have_vid) -+ vsi->filter_fmt = VDP22_FFMT_VID; -+ else -+ return -EINVAL; -+ } -+ return 0; -+} -+ -+/* -+ * Convert the SETLINK message into internal data structure. -+ */ -+static int vdpnl_set(struct nlmsghdr *nlh, struct vdpnl_vsi *vsi) -+{ -+ struct nlattr *tb[IFLA_MAX + 1]; -+ struct ifinfomsg *ifinfo = (struct ifinfomsg *)NLMSG_DATA(nlh); -+ int rc; -+ -+ if (nlmsg_parse(nlh, sizeof(struct ifinfomsg), -+ (struct nlattr **)&tb, IFLA_MAX, NULL)) { -+ LLDPAD_ERR("%s:error parsing SETLINK request\n", __func__); -+ return -EINVAL; -+ } -+ -+ vsi->ifindex = ifinfo->ifi_index; -+ if (tb[IFLA_IFNAME]) -+ strncpy(vsi->ifname, (char *)RTA_DATA(tb[IFLA_IFNAME]), -+ sizeof vsi->ifname); -+ else { -+ if (!if_indextoname(ifinfo->ifi_index, vsi->ifname)) { -+ LLDPAD_ERR("%s:can not find name for interface %i\n", -+ __func__, ifinfo->ifi_index); -+ return -ENXIO; -+ } -+ } -+ vsi->req_pid = nlh->nlmsg_pid; -+ vsi->req_seq = nlh->nlmsg_seq; -+ rc = vdpnl_vfinfolist(tb[IFLA_VFINFO_LIST], vsi); -+ if (!rc) { -+ rc = vdpnl_vfports(tb[IFLA_VF_PORTS], vsi); -+ if (!rc) -+ vdpnl_show(vsi); -+ } -+ return rc; -+} -+ -+/* -+ * Return the error code (can be zero) to the sender. Assume buffer is -+ * large enough to hold the information. -+ * Construct the netlink response on the input buffer. -+ */ -+static int vdpnl_error(int err, struct nlmsghdr *from, size_t len) -+{ -+ struct nlmsgerr nlmsgerr; -+ -+ LLDPAD_DBG("%s:error %d\n", __func__, err); -+ nlmsgerr.error = err; -+ nlmsgerr.msg = *from; -+ memset(from, 0, len); -+ from->nlmsg_type = NLMSG_ERROR; -+ from->nlmsg_seq = nlmsgerr.msg.nlmsg_seq; -+ from->nlmsg_pid = nlmsgerr.msg.nlmsg_pid; -+ from->nlmsg_flags = 0; -+ from->nlmsg_len = NLMSG_SPACE(sizeof nlmsgerr); -+ memcpy(NLMSG_DATA(from), &nlmsgerr, sizeof nlmsgerr); -+ return from->nlmsg_len; -+} -+ -+/* -+ * Build the first part of the netlink reply message for status inquiry. -+ * It contains the header and the ifinfo data structure. -+ */ -+static void vdpnl_reply1(struct vdpnl_vsi *p, struct nlmsghdr *nlh, size_t len) -+{ -+ struct nlmsghdr to; -+ struct ifinfomsg ifinfo; -+ -+ to.nlmsg_type = NLMSG_DONE; -+ to.nlmsg_seq = nlh->nlmsg_seq; -+ to.nlmsg_pid = nlh->nlmsg_pid; -+ to.nlmsg_flags = 0; -+ to.nlmsg_len = NLMSG_SPACE(sizeof ifinfo); -+ -+ memset(&ifinfo, 0, sizeof ifinfo); -+ ifinfo.ifi_index = p->ifindex; -+ memset(nlh, 0, len); -+ memcpy(nlh, &to, sizeof to); -+ memcpy(NLMSG_DATA(nlh), &ifinfo, sizeof ifinfo); -+} -+ -+/* -+ * Build the variable part of the netlink reply message for status inquiry. -+ * It contains the UUID and the response field for the VSI profile. -+ */ -+static void vdpnl_reply2(struct vdpnl_vsi *p, struct nlmsghdr *nlh) -+{ -+ char instance[VDP_UUID_STRLEN + 2]; -+ -+ mynla_put(nlh, IFLA_PORT_INSTANCE_UUID, sizeof p->vsi_uuid, -+ p->vsi_uuid); -+ vdp_uuid2str(p->vsi_uuid, instance, sizeof instance); -+ LLDPAD_DBG("%s:IFLA_PORT_INSTANCE_UUID:%s\n", __func__, instance); -+ mynla_put_u32(nlh, IFLA_PORT_VF, PORT_SELF_VF); -+ LLDPAD_DBG("%s:IFLA_PORT_VF:%d\n", __func__, PORT_SELF_VF); -+ if (p->response != VDP_RESPONSE_NO_RESPONSE) { -+ mynla_put_u16(nlh, IFLA_PORT_RESPONSE, p->response); -+ LLDPAD_DBG("%s:IFLA_PORT_RESPONSE:%d\n", __func__, -+ p->response); -+ } -+} -+ -+/* -+ * Extract the interface name and loop over all VSI profile entries. -+ * Find UUID and response field for each active profile and construct a -+ * netlink response message. -+ * -+ * Return message size. -+ */ -+static int vdpnl_getlink(struct nlmsghdr *nlh, size_t len) -+{ -+ struct vdpnl_vsi p; -+ struct vdpnl_mac mac; -+ int i = 0, rc; -+ struct nlattr *vf_ports, *vf_port; -+ -+ memset(&p, 0, sizeof p); -+ memset(&mac, 0, sizeof mac); -+ p.macsz = 1; -+ p.maclist = &mac; -+ rc = vdpnl_get(nlh, &p); -+ if (rc) -+ return vdpnl_error(rc, nlh, len); -+ vdpnl_reply1(&p, nlh, len); -+ vf_ports = mynla_nest_start(nlh, IFLA_VF_PORTS); -+ /* Iterate over all profiles */ -+ do { -+ rc = vdp22_query(p.ifname) ? vdp22_status(++i, &p) -+ : vdp_status(++i, &p); -+ if (rc == 1) { -+ vf_port = mynla_nest_start(nlh, IFLA_VF_PORT); -+ vdpnl_reply2(&p, nlh); -+ mynla_nest_end(nlh, vf_port); -+ } -+ if (rc == 0) -+ mynla_nest_end(nlh, vf_ports); -+ } while (rc == 1); -+ if (rc < 0) -+ return vdpnl_error(rc, nlh, len); -+ LLDPAD_DBG("%s:message-size:%d\n", __func__, nlh->nlmsg_len); -+ return nlh->nlmsg_len; -+} -+ -+/* -+ * Parse incoming command and create a data structure to store the VSI data. -+ */ -+static int vdpnl_setlink(struct nlmsghdr *nlh, size_t len) -+{ -+ int rc = -ENOMEM; -+ struct vdpnl_mac mac; -+ struct vdpnl_vsi p; -+ -+ memset(&p, 0, sizeof p); -+ memset(&mac, 0, sizeof mac); -+ p.vsiid_fmt = VDP22_ID_UUID; -+ p.macsz = 1; -+ p.maclist = &mac; -+ rc = vdpnl_set(nlh, &p); -+ if (!rc) -+ rc = vdp22_query(p.ifname) ? vdp22_request(&p) -+ : vdp_request(&p); -+ return vdpnl_error(rc, nlh, len); -+} -+ -+/* -+ * Process the netlink message. Parameters are the socket, the message and -+ * its length in bytes. -+ * The message buffer 'buf' is used for parsing the incoming message. -+ * After parsing and decoding, the outgoing message is stored in 'buf'. -+ * -+ * Returns: -+ * < 0: Errno number when message parsing failed. -+ * == 0: Message ok and no response. -+ * > 0: Message ok and response returned in buf parameter. Returns bytes -+ * of response. -+ */ -+int vdpnl_recv(unsigned char *buf, size_t buflen) -+{ -+ struct nlmsghdr *nlh = (struct nlmsghdr *)buf; -+ -+ LLDPAD_DBG("%s:buflen:%zd nlh.nl_pid:%d nlh_type:%d nlh_seq:%d " -+ "nlh_len:%d\n", __func__, buflen, nlh->nlmsg_pid, -+ nlh->nlmsg_type, nlh->nlmsg_seq, nlh->nlmsg_len); -+ -+ switch (nlh->nlmsg_type) { -+ case RTM_SETLINK: -+ return vdpnl_setlink(nlh, buflen); -+ case RTM_GETLINK: -+ return vdpnl_getlink(nlh, buflen); -+ default: -+ LLDPAD_ERR("%s:unknown type %d\n", __func__, nlh->nlmsg_type); -+ } -+ return -ENODEV; -+} -+ -+/* -+ * Add one entry in the list of MAC,VLAN pairs. -+ */ -+static void add_pair(struct vdpnl_mac *mac, struct nlmsghdr *nlh) -+{ -+ struct nlattr *vfinfo; -+ struct ifla_vf_mac ifla_vf_mac = { -+ .vf = PORT_SELF_VF, -+ .mac = { 0, } -+ }; -+ struct ifla_vf_vlan ifla_vf_vlan = { -+ .vf = PORT_SELF_VF, -+ .vlan = mac->vlan, -+ .qos = mac->qos -+ }; -+ -+ vfinfo = mynla_nest_start(nlh, IFLA_VF_INFO); -+ memcpy(ifla_vf_mac.mac, mac->mac, sizeof mac->mac); -+ mynla_put(nlh, IFLA_VF_MAC, sizeof ifla_vf_mac, &ifla_vf_mac); -+ mynla_put(nlh, IFLA_VF_VLAN, sizeof ifla_vf_vlan, &ifla_vf_vlan); -+ mynla_nest_end(nlh, vfinfo); -+} -+ -+/* -+ * Walk along the MAC,VLAN ID list and add each entry into the message. -+ */ -+static void add_mac_vlan(struct vdpnl_vsi *vsi, struct nlmsghdr *nlh) -+{ -+ struct nlattr *vfinfolist; -+ int i; -+ -+ vfinfolist = mynla_nest_start(nlh, IFLA_VFINFO_LIST); -+ for (i = 0; i < vsi->macsz; ++i) -+ add_pair(&vsi->maclist[i], nlh); -+ mynla_nest_end(nlh, vfinfolist); -+} -+ -+/* -+ * Build an unsolicited netlink message to the VSI requestor. The originator -+ * is the switch abondoning the VSI profile. -+ * Assumes the messages fits into an 4KB buffer. -+ * Returns the message size in bytes. -+ */ -+int vdpnl_send(struct vdpnl_vsi *vsi) -+{ -+ unsigned char buf[MAX_PAYLOAD]; -+ struct nlmsghdr *nlh = (struct nlmsghdr *)buf; -+ struct nlattr *vf_ports, *vf_port; -+ struct ifinfomsg ifinfo; -+ struct ifla_port_vsi portvsi; -+ -+ memset(buf, 0, sizeof buf); -+ nlh->nlmsg_pid = getpid(); -+ nlh->nlmsg_seq = vsi->req_seq; -+ nlh->nlmsg_type = RTM_SETLINK; -+ nlh->nlmsg_len = NLMSG_SPACE(sizeof ifinfo); -+ -+ memset(&ifinfo, 0, sizeof ifinfo); -+ ifinfo.ifi_index = vsi->ifindex; -+ memcpy(NLMSG_DATA(nlh), &ifinfo, sizeof ifinfo); -+ mynla_put(nlh, IFLA_IFNAME, 1 + strlen(vsi->ifname), vsi->ifname); -+ -+ add_mac_vlan(vsi, nlh); -+ portvsi.vsi_mgr_id = vsi->vsi_mgrid; -+ portvsi.vsi_type_id[0] = vsi->vsi_typeid & 0xff; -+ portvsi.vsi_type_id[1] = (vsi->vsi_typeid >> 8) & 0xff; -+ portvsi.vsi_type_id[2] = (vsi->vsi_typeid >> 16) & 0xff; -+ portvsi.vsi_type_version = vsi->vsi_typeversion; -+ vf_ports = mynla_nest_start(nlh, IFLA_VF_PORTS); -+ vf_port = mynla_nest_start(nlh, IFLA_VF_PORT); -+ mynla_put(nlh, IFLA_PORT_VSI_TYPE, sizeof portvsi, &portvsi); -+ mynla_put(nlh, IFLA_PORT_INSTANCE_UUID, PORT_UUID_MAX, vsi->vsi_uuid); -+ mynla_put_u32(nlh, IFLA_PORT_VF, PORT_SELF_VF); -+ mynla_put_u16(nlh, IFLA_PORT_REQUEST, vsi->request); -+ mynla_nest_end(nlh, vf_port); -+ mynla_nest_end(nlh, vf_ports); -+ vdpnl_show(vsi); -+ LLDPAD_DBG("%s:nlh.nl_pid:%d nlh_type:%d nlh_seq:%d nlh_len:%d\n", -+ __func__, nlh->nlmsg_pid, nlh->nlmsg_type, nlh->nlmsg_seq, -+ nlh->nlmsg_len); -+ return event_trigger(nlh, vsi->req_pid); -+} -diff --git a/qbg_utils.c b/qbg_utils.c -new file mode 100644 -index 0000000..b23d700 ---- /dev/null -+++ b/qbg_utils.c -@@ -0,0 +1,95 @@ -+/****************************************************************************** -+ -+ Implementation of ECP according to 802.1Qbg -+ (c) Copyright IBM Corp. 2010, 2013 -+ -+ Author(s): Thomas Richter -+ -+ This program is free software; you can redistribute it and/or modify it -+ under the terms and conditions of the GNU General Public License, -+ version 2, as published by the Free Software Foundation. -+ -+ This program is distributed in the hope it will be useful, but WITHOUT -+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ more details. -+ -+ You should have received a copy of the GNU General Public License along with -+ this program; if not, write to the Free Software Foundation, Inc., -+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. -+ -+ The full GNU General Public License is included in this distribution in -+ the file called "COPYING". -+ -+******************************************************************************/ -+ -+/* -+ * This file contains common support utilities for the ECP protocols. -+ */ -+ -+#include -+#include -+ -+#include "lldp.h" -+#include "lldp_mod.h" -+#include "messages.h" -+#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 -+ */ -+void hexdump_frame(const char *ifname, char *txt, const unsigned char *buf, -+ size_t len) -+{ -+ size_t i; -+ int left = 0; -+ char buffer[ETH_FRAME_LEN * 3]; -+ -+ /* Only collect data when the loglvl ensures data printout */ -+ if (LOG_DEBUG < loglvl) -+ return; -+ for (i = 0; i < len; i++) { -+ int c; -+ c = snprintf(buffer + left, sizeof buffer - left, "%02x%c", -+ buf[i], !((i + 1) % 16) ? '\n' : ' '); -+ if (c > 0 && (c < (int)sizeof buffer - left)) -+ left += c; -+ } -+ LLDPAD_DBG("%s:%s %s\n%s\n", __func__, ifname, txt, buffer); -+} -+ -+/* -+ * Function to advertise changed variables to other modules. -+ * -+ * Parameters are interface name, target module id and data. -+ * When sending the data, the module call back function contains the -+ * module id of the sender. -+ * -+ * Return 0 when no addressee found or addressess found but addressee was -+ * unable to handle data. -+ */ -+int modules_notify(int id, int sender_id, char *ifname, void *data) -+{ -+ struct lldp_module *mp = find_module_by_id(&lldp_head, id); -+ int rc = 0; -+ -+ if (mp && mp->ops->lldp_mod_notify) -+ rc = mp->ops->lldp_mod_notify(sender_id, ifname, data); -+ LLDPAD_DBG("%s:%s target-id:%#x rc:%d\n", __func__, ifname, id, rc); -+ return rc; -+} -+ -+int vdp_uuid2str(const u8 *p, char *dst, size_t size) -+{ -+ if (dst && size > VDP_UUID_STRLEN) { -+ snprintf(dst, size, "%02x%02x%02x%02x-%02x%02x-%02x%02x" -+ "-%02x%02x-%02x%02x%02x%02x%02x%02x", -+ p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], -+ p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); -+ return 0; -+ } -+ return -1; -+} -diff --git a/test/nltest.c b/test/nltest.c -index 7ace3b1..da05463 100644 ---- a/test/nltest.c -+++ b/test/nltest.c -@@ -1156,12 +1156,14 @@ void print_pfc(struct ieee_pfc *pfc) - - printf("\t requests: "); - for (i = 0; i < 8; i++) -- printf("%lli ", pfc->requests[i]); -+ printf("%llu ", -+ (unsigned long long)pfc->requests[i]); - printf("\n"); - - printf("\t requests: "); - for (i = 0; i < 8; i++) -- printf("%lli ", pfc->indications[i]); -+ printf("%llu ", -+ (unsigned long long)pfc->indications[i]); - printf("\n"); - } - -diff --git a/test/vdptest.1 b/test/vdptest.1 -index 81a2e60..5f1a1b9 100644 ---- a/test/vdptest.1 -+++ b/test/vdptest.1 -@@ -1,5 +1,5 @@ - .PU --.TH vdptest 1 "LLDPAD" "Revision: 0.1" -+.TH vdptest 1 "LLDPAD" "Revision: 0.2" - .SH NAME - vdptest \- VDP/VSI Protocol Test Program for LLDPAD - .SH SYNOPSIS -@@ -89,12 +89,16 @@ terminates. - .br - .B vdptest - should be used for testing and debug purposes only. -+It should be noted that there is no state stored in vdptest between calls, but -+will be stored in lldpad (until the process restarts). -+A profile must be created and acted upon on in the same vdptest command. - .SS Profiles - .br - Profile is a comma separated list of key '=' value - pairs describing the VSI profile data. - Profiles consists of the following keywords, --they are all mandatory: -+they are all mandatory with the execption of -+hints: - .TP - name: - Defines the name of the entry. -@@ -105,10 +109,20 @@ starting - with a character. - .TP - mgrid: --Defines the manager identifier for this entry. -+Defines the 1 byte manager identifier for this entry -+as defined by the IEEE 802.1 Qbg draft version 0.2. - The value should be a number in the - range of 0..255 inclusive. - .TP -+2mgrid: -+Defines the 16 byte manager identifier for this entry -+as defined by the IEEE 802.1 Qbg ratified standard. -+Either the -+.B mgrid -+or the -+.B 2mgrid -+should be used for an entry. -+.TP - typeid: - Defines the type identifier for this entry. - The value should be a number in the -@@ -130,26 +144,77 @@ The string is converted into 16 byte UUID - with 2 nibbles converted into one byte. - .TP - map: --Defines a VLAN-MAC address pair for this entry. -+Defines a VLAN-MAC-GROUP address triple for this entry. - The value is of the following format: - .EX --vlanid-aa:bb:cc:dd:ee:ff -+vlanid[/newvid][-[aa:bb:cc:dd:ee:ff][-grid]] - .EE - Vlandid is converted into a number ranging --from 0..4095. --Following the vlanid is a dash (\-) and --an MAC address. -+from 0..65535. -+If the vlanid is followed by an option slash ('/') -+the number following the slash is the new vlan identifier -+expected from the switch. -+Following the vlanid is an optional dash (\-) and -+a MAC address. - The MAC address is a 6 byte value, each byte - delimited by a colon (':'). -+A second optional dash (\-) can be -+specified to supply a group identifier. -+If omitted the group identifier is assumed to -+be zero and is ignored. - This keyword can be listed several times to allow --multiple MAC-VLAN pairs per entry. -+multiple MAC-VLAN-GROUP triples per entry. -+.sp 1 -+The form of this entry determines the format of the -+filter information data send to the switch. -+The input -+.EX -+map=1 -+.EE -+is converted to filter information format -+.IR VID . -+The input -+.EX -+map=1--123 -+.EE -+is converted to filter information format -+.IR GROUP/VID . -+The input -+.EX -+map=1-11:22:33:44:55:66 -+.EE -+is converted to filter information format -+.IR VID/MAC . -+The input -+.EX -+map=1-11:22:33:44:55:66-123 -+.EE -+is converted to filter information format -+.IR GROUP/VID/MAC . -+Note that filter information formats can not be mixed in -+a single entry. Multiple -+map entries have to be of the same format. -+.TP -+hints: -+This keyword is optional and if omitted defaults to -+.IR none . -+Indicates support for IEEE 802.1 Qbg ratified standard -+virtual machine migration. -+Valid keywords are -+.I none -+(no indicate no migration support), -+.I to -+(to indicate the virtual machine is migrating to this VSI) -+and -+.I from -+(to indicate the virtual machine is migrating from this VSI). - .TP - Example: - Here is an example of a profile definition: - .EX --name=thomas2,mgrid=1,typeid=123452,typeidver=1,\(rs -+name=thomas2,mgrid=1,typeid=123452,typeidver=1,hints=none\(rs - uuid=a1412857-60f7-4ce1-e95a-2164943f53dd,\(rs -- map=2-52:54:00:8e:50:53 -+ map=2-52:54:00:8e:50:53-9999,map=0/10-52:54:00:8e:50:54-8888 - .EE - .SS Commands - Command is an option character followed -@@ -272,12 +337,12 @@ Several definitions using the same - .I name - are not allowed. - .TP --.B "\-C\fIname,new=new-name,changes\fP" -+.B "\-C\fInew=new-name,name=old-name,changes\fP" - Copy the profile entry named --.I name --and assign it -+.I old-name -+and assign it to - .IR new-name. --After the first comma, list the fields which -+After the second comma list the fields which - are to be changed using the same syntax as in - the profile definition. - If an error is encountered during keyword parsing -@@ -401,15 +466,11 @@ flag. If this option is not set then the following default values - are used: delaytime (1 second), waittime (1 second) and number of acknowledgements - reads (1). - .SH "EXAMPLES" --.EX --vdptest -Aname=thomas2,mgrid=1,typeid=123452,typeidver=1, -- uuid=a1412857-60f7-4ce1-e95a-2164943f53dd,map=2-52:54:00:8e:50:53 -S --.EE --.sp 1 - Define a profile and show its definition. - .sp 1 - .EX --vdptest -C thomas2,new=unknown,typeid=99999 -+vdptest -Aname=thomas2,mgrid=1,typeid=123452,typeidver=1, -+ uuid=a1412857-60f7-4ce1-e95a-2164943f53dd,map=2-52:54:00:8e:50:53 -S - .EE - .sp 1 - Copies the entry named -@@ -425,7 +486,7 @@ is the - field. - .sp 1 - .EX --vdptest -i eth2 -F vdptest.cfg -a unknown,w=10,r=2,e=3 -s -+vdptest -Cnew=unknown,name=thomas2,typeid=99999 - .EE - .sp 1 - Use interface eth2 and read the VSI configuration from file -@@ -434,12 +495,13 @@ Use the VSI definition named - .I unknown - and send an ASSOCIATION command to the switch. - Wait up to 10 seconds for the status confirmation 2 --times and expected the error code 3 from the switch. -+times and expected the error code 3 from the switch -+(NOTE that this will cause vdptest to return FAILURE under -+normal conditions). - Wait one second before termintation. - .sp 1 - .EX --vdptest -i eth2 -F vdptest.cfg -Cthomas2,new=x1,mgrid=2 \(rs -- -athomas2,w=10,r=2,e=3 -s -a x1,w=5 -+vdptest -i eth2 -F vdptest.cfg -a unknown,w=10,r=2,e=3 -s - .EE - .sp 1 - Use interface eth2 and read the VSI configuration from file -@@ -455,12 +517,17 @@ Send an ASSOCIATION command with parameters stored in - wait one second and - send an ASSOCIATION command with parameters stored in - .IR x1 . -+.sp 1 -+.EX -+vdptest -i eth2 -F vdptest.cfg -Cnew=x1,name=thomas2,2mgrid=blabla \(rs -+ -a thomas2,w=10,r=2,e=3 -s -a x1,w=5 -+.EE - .SH FILES --/var/run/lldpad.pid -+/var/run/lldpad.pid, /var/lib/lldpad/lldpad.conf - .SH "ENVIRONMENT" --Linux RHEL -+Linux - .SH "SEE ALSO" --lldpad(8), lldptool(8) -+lldpad(8), lldptool(8), libvirtd(8) - .SH DIAGNOSTICS - Exit status is zero on success and non zero on failure or mismatch. - .SH AUTHOR -diff --git a/test/vdptest.c b/test/vdptest.c -index 8447c6c..e93fed0 100644 ---- a/test/vdptest.c -+++ b/test/vdptest.c -@@ -67,21 +67,38 @@ - #define CMD_EXTERN 'E' /* External command */ - #define CMD_SETDF 'X' /* Change defaults */ - -+#define FIF_VID 1 /* Vlan id */ -+#define FIF_VIDMAC 2 /* Vlan+mac id */ -+#define FIF_GRPVID 3 /* Group+Vlan id */ -+#define FIF_GRPVIDMAC 4 /* group+Vlan+mac id */ -+ -+#define MIGTO 16 /* M-bit migrate to indicator */ -+#define MIGFROM 32 /* S-bit migrate from indicator */ -+ - /* - * Set the define MYDEBUG to any value for detailed debugging - */ - -+enum { /* Netlink message format for lldpad */ -+ nlmsg_v0 = 1, /* IEEE 802.1 QBG version 0.2 */ -+ nlmsg_v2 /* IEEE 802.1 QBG version 2.2 */ -+}; -+ - enum { - f_map, - f_mgrid, - f_typeid, - f_typeidver, -- f_uuid -+ f_uuid, -+ f_hints, -+ f_2mgrid - }; - - struct macvlan { - unsigned char mac[ETH_ALEN]; /* MAC address */ -- unsigned short vlanid; /* VLAN Id */ -+ unsigned short vlanid; /* VLAN Id */ -+ unsigned long gpid; /* Group */ -+ unsigned short newvid; /* New vlan id returned from switch */ - }; - - static struct vdpdata { -@@ -92,7 +109,11 @@ static struct vdpdata { - unsigned char typeidver; /* Type ID version */ - unsigned int typeid; /* Type ID */ - unsigned char uuid[UUIDLEN]; /* Instance ID */ -+ unsigned char mgrid2[UUIDLEN]; /* Manager ID VDP22 */ - struct macvlan addr[10]; /* Pairs of MAC/VLAN */ -+ unsigned char fif; /* Filter info format */ -+ unsigned char hints; /* Migrate to/from hits */ -+ unsigned char nlmsg_v; /* Version of netlink messaage to use */ - } vsidata[32]; - - static struct command { /* Command structure */ -@@ -483,6 +504,8 @@ static int addvfs(struct nl_msg *nl_msg, struct vdpdata *vdp, unsigned char cmd) - op = PORT_REQUEST_PREASSOCIATE_RR; - break; - } -+ if (vdp->hints) -+ op |= vdp->hints; - - vsi.vsi_mgr_id = vdp->mgrid; - vsi.vsi_type_version = vdp->typeidver; -@@ -505,6 +528,9 @@ static int addvfs(struct nl_msg *nl_msg, struct vdpdata *vdp, unsigned char cmd) - return 0; - } - -+/* -+ * Add filter information and use SPOOFCHK to send group information -+ */ - static int addmacs(struct nl_msg *nl_msg, struct vdpdata *vdp) - { - int i; -@@ -518,7 +544,7 @@ static int addmacs(struct nl_msg *nl_msg, struct vdpdata *vdp) - if (!(vfinfo = nla_nest_start(nl_msg, IFLA_VF_INFO))) - return -ENOMEM; - -- if (vdp->addr[i].mac) { -+ if (vdp->fif == FIF_VIDMAC || vdp->fif == FIF_GRPVIDMAC) { - struct ifla_vf_mac ifla_vf_mac; - - ifla_vf_mac.vf = PORT_SELF_VF; -@@ -528,11 +554,11 @@ static int addmacs(struct nl_msg *nl_msg, struct vdpdata *vdp) - return -ENOMEM; - } - -- if (vdp->addr[i].vlanid) { -+ if (vdp->fif) { - struct ifla_vf_vlan ifla_vf_vlan = { - .vf = PORT_SELF_VF, -- .vlan = vdp->addr[i].vlanid, -- .qos = 0, -+ .vlan = vdp->addr[i].vlanid & 0xfff, -+ .qos = (vdp->addr[i].vlanid >> 12) & 7 - }; - - if (nla_put(nl_msg, IFLA_VF_VLAN, sizeof ifla_vf_vlan, -@@ -759,37 +785,78 @@ static struct vdpdata *nextfree() - - static int check_map(char *value, struct vdpdata *profile) - { -- char *delim = strchr(value, '-'); -- unsigned long vlan; -- int i, ec, x[ETH_ALEN]; -+ char *delim2 = 0, *slash, *delim = strchr(value, '-'); -+ unsigned long vlan, newvlan = 0, gpid = 0; -+ int fif, i, ec, x[ETH_ALEN]; -+ int have_mac = 1, have_gpid = 1; - -- if (!delim) { -- fprintf(stderr, "%s invalid map format %s\n", progname, value); -- return -1; -+ if (!delim) -+ have_gpid = have_mac = 0; -+ else { -+ *delim = '\0'; -+ delim2 = strchr(delim + 1, '-'); -+ if (!delim2) -+ have_gpid = 0; -+ else { -+ *delim2 = '\0'; -+ if (delim + 1 == delim2) /* -- and no mac */ -+ have_mac = 0; -+ } -+ } -+ memset(x, 0, sizeof(x)); -+ slash = strchr(value, '/'); -+ if (slash) { /* Expect replacement vid */ -+ *slash = '\0'; -+ newvlan = getnumber("map", slash + 1, '\0', &ec); -+ if (ec) { -+ fprintf(stderr, "%s invalid new vlanid %s\n", progname, -+ value); -+ return -1; -+ } -+ if (newvlan >= 0x10000) { -+ fprintf(stderr, "%s new vlanid %ld too high\n", -+ progname, newvlan); -+ return -1; -+ } -+ profile->nlmsg_v = nlmsg_v2; - } -- vlan = getnumber("map", value, '-', &ec); -+ vlan = getnumber("map", value, '\0', &ec); - if (ec) { - fprintf(stderr, "%s invalid vlanid %s\n", progname, value); - return -1; - } -- if (vlan >= 4095) { -+ if (vlan >= 0x10000) { - fprintf(stderr, "%s vlanid %ld too high\n", progname, vlan); - return -1; - } -- ++delim; -- ec = sscanf(delim, "%02x:%02x:%02x:%02x:%02x:%02x", &x[0], &x[1], -- &x[2], &x[3], &x[4], &x[5]); -- if (ec != ETH_ALEN) { -- fprintf(stderr, "%s mac %s invalid\n", progname, delim); -- return -1; -+ fif = FIF_VID; -+ if (have_mac) { -+ ec = sscanf(delim + 1, "%02x:%02x:%02x:%02x:%02x:%02x", &x[0], -+ &x[1], &x[2], &x[3], &x[4], &x[5]); -+ if (ec != ETH_ALEN) { -+ fprintf(stderr, "%s mac %s invalid\n", progname, delim); -+ return -1; -+ } -+ /* Check for last character */ -+ delim = strrchr(delim + 1, ':') + 2; -+ if (*delim && (strchr("0123456789abcdefABCDEF", *delim) == 0 -+ || *(delim + 1) != '\0')) { -+ fprintf(stderr, "%s last mac part %s invalid\n", -+ progname, delim); -+ return -1; -+ } -+ fif = FIF_VIDMAC; - } -- /* Check for last character */ -- delim = strrchr(value, ':') + 2; -- if (*delim && (strchr("0123456789abcdefABCDEF", *delim) == 0 -- || *(delim + 1) != '\0')) { -- fprintf(stderr, "%s last mac part %s invalid\n", progname, -- delim); -- return -1; -+ /* Check for optional group identifier */ -+ if (have_gpid && *(delim2 + 1)) { -+ gpid = getnumber("group", delim2 + 1, '\0', &ec); -+ if (ec) { -+ fprintf(stderr, "%s invalid groupid %s\n", progname, -+ delim2 + 1); -+ return -1; -+ } -+ fif += 2; -+ profile->nlmsg_v = nlmsg_v2; - } - #ifdef MYDEBUG - for (i = 0; i < ETH_ALEN; ++i) -@@ -797,7 +864,18 @@ static int check_map(char *value, struct vdpdata *profile) - puts(""); - - #endif -+ if (profile->fif && profile->fif != fif) { -+ fprintf(stderr, "%s invalid filter info format %d use %d\n", -+ progname, FIF_VIDMAC, profile->fif); -+ return -1; -+ } -+ profile->fif = fif; - for (ec = 0; ec < profile->pairs; ++ec) { -+ if (DIM(profile->addr) == i) { -+ fprintf(stderr, "%s too many mac addresses\n", -+ progname); -+ return -1; -+ } - for (i = 0; i < ETH_ALEN; ++i) - if (profile->addr[ec].mac[i] != x[i]) - break; -@@ -809,6 +887,8 @@ static int check_map(char *value, struct vdpdata *profile) - } - ec = profile->pairs++; - profile->addr[ec].vlanid = vlan; -+ profile->addr[ec].newvid = newvlan; -+ profile->addr[ec].gpid = gpid; - for (i = 0; i < ETH_ALEN; ++i) - profile->addr[ec].mac[i] = x[i]; - profile->modified |= 1 << f_map; -@@ -858,7 +938,7 @@ static int check_typeid(char *value, struct vdpdata *profile) - progname, no); - } - #ifdef MYDEBUG -- printf("%s:typeid:%d ec:%d\n", __func__, profile->mgrid, ec); -+ printf("%s:typeid:%d ec:%d\n", __func__, profile->typeid, ec); - #endif - } - return ec; -@@ -880,7 +960,8 @@ static int check_typeidversion(char *value, struct vdpdata *profile) - progname, no); - } - #ifdef MYDEBUG -- printf("%s:typeidver:%d ec:%d\n", __func__, profile->mgrid, ec); -+ printf("%s:typeidver:%d ec:%d\n", __func__, profile->typeidver, -+ ec); - #endif - } - return ec; -@@ -891,11 +972,17 @@ static int check_mgrid(char *value, struct vdpdata *profile) - unsigned long no; - int ec; - -+ if (profile->nlmsg_v == nlmsg_v2) { -+ fprintf(stderr, "%s: mgrid and 2mgrid specified\n", progname); -+ return -1; -+ } - no = getnumber("mgrid", value, '\0', &ec); - if (!ec) { -- if (no <= 255) { -+ if (no <= 255 && no > 0) { -+ profile->nlmsg_v = nlmsg_v0; - profile->mgrid = no; - profile->modified |= 1 << f_mgrid; -+ memset(profile->mgrid2, 0, UUIDLEN); - } else { - ec = -1; - fprintf(stderr, "%s: invalid mgrid %ld\n", progname, -@@ -908,6 +995,44 @@ static int check_mgrid(char *value, struct vdpdata *profile) - return ec; - } - -+static int check_2mgrid(char *value, struct vdpdata *profile) -+{ -+ if (profile->nlmsg_v == nlmsg_v0) { -+ fprintf(stderr, "%s: mgrid and 2mgrid specified\n", progname); -+ return -1; -+ } -+ strncpy((char *)profile->mgrid2, value, UUIDLEN - 1); -+ profile->mgrid2[UUIDLEN - 1] = '\0'; -+ profile->mgrid = 0; -+ profile->modified |= 1 << f_mgrid; -+ profile->nlmsg_v = nlmsg_v2; -+ return 0; -+} -+ -+static int check_hints(char *value, struct vdpdata *profile) -+{ -+ int rc = 0; -+ -+ if (!strcmp(value, "to")) { -+ profile->hints = MIGTO; -+ profile->modified |= 1 << f_hints; -+ profile->nlmsg_v = nlmsg_v2; -+ } else if (!strcmp(value, "from")) { -+ profile->hints = MIGFROM; -+ profile->modified |= 1 << f_hints; -+ profile->nlmsg_v = nlmsg_v2; -+ } else if (!strcmp(value, "none")) { -+ profile->hints = 0; -+ profile->modified |= 1 << f_hints; -+ profile->nlmsg_v = nlmsg_v2; -+ } else { -+ fprintf(stderr, "%s: invalid hints %s\n", progname, value); -+ rc = -1; -+ } -+ return rc; -+} -+ -+ - /* - * Return true if the character is valid for a key - */ -@@ -956,7 +1081,9 @@ static char *keytable[] = { - "typeidver", - "typeid", - "uuid", -- "name" -+ "name", -+ "2mgrid", -+ "hints" - }; - - static int findkeyword(char *word) -@@ -995,6 +1122,12 @@ static int checkword(char *word, char *value, struct vdpdata *profile) - case 5: - rc = check_name(value, profile); - break; -+ case 6: -+ rc = check_2mgrid(value, profile); -+ break; -+ case 7: -+ rc = check_hints(value, profile); -+ break; - } - #ifdef MYDEBUG - printf("%s word:%s value:%s rc:%d\n", __func__, word, value, rc); -@@ -1034,14 +1167,20 @@ static int has_key(struct vdpdata *found) - static void print_pairs(struct vdpdata *found) - { - int i; -- char buf[32]; - - for (i = 0; i < found->pairs; ++i) { -- unsigned char *xp = found->addr[i].mac; -- -- sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x", -- xp[0], xp[1], xp[2], xp[3], xp[4], xp[5]); -- printf("\t%hd %s\n", found->addr[i].vlanid, buf); -+ printf("\t%hd", found->addr[i].vlanid); -+ if (found->addr[i].newvid) -+ printf("/%hd", found->addr[i].newvid); -+ if (found->fif == FIF_VIDMAC || found->fif == FIF_GRPVIDMAC) { -+ unsigned char *xp = found->addr[i].mac; -+ -+ printf(" %02x:%02x:%02x:%02x:%02x:%02x", -+ xp[0], xp[1], xp[2], xp[3], xp[4], xp[5]); -+ } -+ if (found->fif == FIF_GRPVID || found->fif == FIF_GRPVIDMAC) -+ printf(" %ld", found->addr[i].gpid); -+ printf("\n"); - } - } - -@@ -1049,8 +1188,16 @@ static void print_profile(struct vdpdata *found) - { - char uuid[64]; - -- printf("key:%s mgrid:%d typeid:%#x typeidver:%d\n", -- found->key, found->mgrid, found->typeid, found->typeidver); -+ if (found->mgrid) -+ sprintf(uuid, "%d", found->mgrid); -+ else -+ strcpy(uuid, (char *)found->mgrid2); -+ printf("key:%s version:%d fif:%d mgrid:%s typeid:%#x typeidver:%d", -+ found->key, found->nlmsg_v, found->fif, uuid, found->typeid, -+ found->typeidver); -+ if (found->hints) -+ printf(" hints:%s", found->hints == MIGTO ? "to" : "from"); -+ printf("\n"); - uuid2buf(found->uuid, uuid); - printf("\tuuid:%s\n", uuid); - if (found->pairs) -@@ -1063,17 +1210,23 @@ static int change_profile(struct vdpdata *change, struct vdpdata *alter) - printf("%s alter->modified:%#x\n", __func__, alter->modified); - #endif - if ((alter->modified & (1 << f_map))) { -+ change->fif = alter->fif; - change->pairs = alter->pairs; - memcpy(change->addr, alter->addr, sizeof alter->addr); - } -- if ((alter->modified & (1 << f_mgrid))) -+ if ((alter->modified & (1 << f_mgrid))) { - change->mgrid = alter->mgrid; -+ memcpy(change->mgrid2, alter->mgrid2, UUIDLEN); -+ } - if ((alter->modified & (1 << f_typeid))) - change->typeid = alter->typeid; - if ((alter->modified & (1 << f_typeidver))) - change->typeidver = alter->typeidver; - if ((alter->modified & (1 << f_uuid))) - memcpy(change->uuid, alter->uuid, sizeof change->uuid); -+ if ((alter->modified & (1 << f_hints))) -+ change->hints = alter->hints; -+ change->nlmsg_v = alter->nlmsg_v; - return 0; - } - -@@ -1094,7 +1247,7 @@ static void show_profiles(char *thisone) - - /* - * Parse the profile string of the form -- * key=###,mgrid=###,typeid=###,typeidver=###,uuid=###,mac=xxx,vlan=xxx{1,10} -+ * key=###,mgrid=###|2mgrid=xxx,typeid=###,typeidver=###,uuid=xxx,map=xxx{1,10} - */ - static int parse_profile(char *profile, struct vdpdata *target) - { -@@ -1158,15 +1311,21 @@ static void find_field(unsigned char mode, char *buf) - strcat(buf, ","); - strcat(buf, "uuid"); - } -+ if ((mode & (1 << f_hints)) == 0) { -+ if (comma) -+ strcat(buf, ","); -+ strcat(buf, "hints"); -+ } - } - - static void isvalid_profile(struct vdpdata *vdp) - { - char buf[64]; - unsigned char mode = 1 << f_map | 1 << f_mgrid | -- 1 << f_typeid | 1 << f_typeidver | 1 << f_uuid; -+ 1 << f_typeid | 1 << f_typeidver | 1 << f_uuid; -+ unsigned char optmode = 1 << f_hints; - -- if (vdp->modified != mode) { -+ if ((vdp->modified & ~optmode) != mode) { - find_field(vdp->modified, buf); - fprintf(stderr, "%s key %s misses profile fields %s\n", - progname, vdp->key, buf); -@@ -1199,6 +1358,11 @@ static int make_profiles(char *profile, char *newkey) - progname, nextone.key); - return -1; - } -+ if (!strcmp(newkey, found->key)) { -+ fprintf(stderr, "%s profile key %s already exits\n", -+ progname, newkey); -+ return -1; -+ } - if (!(vdp = nextfree())) { - fprintf(stderr, "%s too many profiles\n", progname); - return -1; diff --git a/open-lldp-git-update.patch.bz2 b/open-lldp-git-update.patch.bz2 new file mode 100644 index 0000000..dc50ebf --- /dev/null +++ b/open-lldp-git-update.patch.bz2 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0a639f549eef3d59d67c84a6cbe28767cdfea887050e054a2f3f23c4f72523ab +size 137330 diff --git a/open-lldp.changes b/open-lldp.changes index a5207ba..bba7e55 100644 --- a/open-lldp.changes +++ b/open-lldp.changes @@ -1,3 +1,12 @@ +------------------------------------------------------------------- +Fri Mar 21 15:28:19 CET 2014 - hare@suse.de + +- Fix VEPA migration issue (bnc#866282) +- Remove mkinitrd support +- Use bzip2 for open-lldp-git-update.patch + * Add open-lldp-git-update.patch.bz2 + * Delete open-lldp-git-update.patch + ------------------------------------------------------------------- Tue Nov 19 12:52:45 CET 2013 - hare@suse.de diff --git a/open-lldp.spec b/open-lldp.spec index 03fff24..fc28929 100644 --- a/open-lldp.spec +++ b/open-lldp.spec @@ -1,7 +1,7 @@ # # spec file for package open-lldp # -# Copyright (c) 2013 SUSE LINUX Products GmbH, Nuernberg, Germany. +# Copyright (c) 2014 SUSE LINUX Products GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -32,16 +32,12 @@ BuildRequires: pkgconfig BuildRequires: readline-devel Url: http://open-lldp.org/ Source: http://ftp-osl.osuosl.org/pub/%{name}/%{name}-%{version}.tar.gz -Source20: mkinitrd-boot.sh -Source22: mkinitrd-setup.sh -Patch0: %{name}-git-update.patch +Patch0: %{name}-git-update.patch.bz2 BuildRoot: %{_tmppath}/%{name}-%{version}-build Provides: dcbd = %{version} Obsoletes: dcbd < %{version} Provides: lldpad = %{version} Obsoletes: lldpad < %{version} -Requires(post): mkinitrd -Requires(postun): mkinitrd BuildRequires: systemd %systemd_requires @@ -88,15 +84,11 @@ make check %{?_smp_mflags} %install mkdir -p %{buildroot}/var/lib/lldpad %makeinstall -install -d %{buildroot}/lib/mkinitrd/scripts/ -install -m 755 %{S:20} %{buildroot}/lib/mkinitrd/scripts/boot-lldpad.sh -install -m 755 %{S:22} %{buildroot}/lib/mkinitrd/scripts/setup-lldpad.sh # remove la archives rm -rf %{buildroot}/%{_libdir}/*.la -ln -s %{_sbindir}/service %{buildroot}%{_sbindir}/rclldpad +ln -s service %{buildroot}%{_sbindir}/rclldpad %post -[ -x /sbin/mkinitrd_setup ] && mkinitrd_setup %{fillup_and_insserv -n -i lldpad} %service_add_post lldpad.service @@ -104,7 +96,6 @@ ln -s %{_sbindir}/service %{buildroot}%{_sbindir}/rclldpad %service_del_preun lldpad.service %postun -[ -x /sbin/mkinitrd_setup ] && mkinitrd_setup %{insserv_cleanup lldpad} %post -n %libname -p /sbin/ldconfig @@ -119,7 +110,6 @@ ln -s %{_sbindir}/service %{buildroot}%{_sbindir}/rclldpad %{_sbindir}/* %{_mandir}/man8/* %config /etc/bash_completion.d/* -/lib/mkinitrd %files -n %libname %defattr(-,root,root)