[lldpad] sync to upstream v0.9.46-123-g48a5f38

Chris Leech cleech at fedoraproject.org
Thu Oct 23 22:38:18 UTC 2014


commit 9e5b5a082f1b71fa6d454059fd22cf4773a3fe12
Author: Chris Leech <cleech at redhat.com>
Date:   Thu Oct 23 15:37:29 2014 -0700

    sync to upstream v0.9.46-123-g48a5f38

 lldpad-0.9.46-123-g48a5f38.patch   |45882 ++++++++++++++++++++++++++++++++++++
 lldpad-0.9.46-libnl3.patch         |  328 -
 lldpad-0.9.46-subdir-objects.patch |   11 -
 lldpad.spec                        |   24 +-
 4 files changed, 45894 insertions(+), 351 deletions(-)
---
diff --git a/lldpad-0.9.46-123-g48a5f38.patch b/lldpad-0.9.46-123-g48a5f38.patch
new file mode 100644
index 0000000..c2d8fdd
--- /dev/null
+++ b/lldpad-0.9.46-123-g48a5f38.patch
@@ -0,0 +1,45882 @@
+v0.9.46-123-g48a5f38
+---
+48a5f38 Move to libnl3
+fa42d01 lldpad: print verbose error messages
+cb1ae28 lldpad: do not use absolute pathname for sys/queue.h
+d3706f0 Interop issues with Juniper QFX3500 switch & firmware managed dcbx
+8f78907 clif.c use correct include file
+d36de79 vdp22_cmds scan vdp22 module for configuration
+4ace840 liblldp_clif docuementation update clif_vsi and clif_vsiwait
+844ddd9 clif and vdp22_clif_cmd send correct tlvid
+1c52e87 vdp22 client command interface definition
+990044c vdp22 add missing information for client
+9064813 vdp22 bridge mode simulation fix for commit 61b69da
+272c4f4 veth-setup.sh create veth0 with fixed mac address
+c5cf1d3 crtl_iface remove trailing blanks and newlines
+3b8cb17 gitignore add new files
+ce66e20 Disambiguate TX/RX sum error messages
+b8f7583 Add missing newlines in dcb_protocol.c log messages
+4f6e8cb Add missing newlines in dcb_rule_chk.c log messages
+61b69da ecp22 : Do not send end tlv.
+3ef96bc lldp: Fix some spelling errors
+8f877b3 Fixed automake error
+da964f8 vdp22 test remove obsolete file
+522ae1b evb/evb22 test cases
+abe2bc7 evb/evb22 make sure one protocol only
+ed02ef9 vdp22: Restore vsi profile after link down/up event
+5cf5850 Fix the build with recent autotools
+9b71e95 vdp22 add test suite
+745b8f2 vdp22 bridge mode error simulation fix
+9cfda55 vdp handle dis-assoc comand without profile
+3bc8b0d evb22 test case 26
+66f229b lldpad: Fixes for the flag values in VDP responses
+c8f94ee vdp22 check for evb22.enabletx value
+22af9bc trivial: upper-case some enum values
+04c7179 vethsetup shell script for qbg22 testing
+cc573cf evb22 add test case 25
+ca36254 qbg22sim fix typo in comment
+808a677 ecp22 protocol test suite
+f997f75 evb22 protocol test suite
+95b45b2 qbg22sim fix ecp22 ethertype value
+3fc974d liblldp_clif add documentation for new functions
+6ea9f8a vdp22 reduce delay before executing vdp22
+727eafa lldpad: fix ECP 2.2 ethertype and allow VDP to support VEB mode
+9294969 lldptool update for EVB22
+bc3ebd8 vdptest use liblldp_clif library for vdp22 test cases
+f676ad2 clif support for sending vdp22 commands to lldpad
+9ae3138 clif add clif_pending_wait function
+e7e80bc vdp22 call back to client support
+2827f1a vdp22 support for command messages from attached client
+f32d041 vdp22 add support for command line interface
+155576c vdp22 add vdp22_info function
+87cd148 vdp22 set vlanid to include qos
+81b43e5 vdp22 define protocol subtype
+87cfde3 evb22 fix define values
+f5cd6eb crtl_iface minor fixes
+bf92b65 lldp_rtnl remove mynla_xxx functions
+ee8b4d2 vdpnl remove mynla_xxx functions
+796ec98 vdpnl rename vsiid_fmt to vsi_idfmt
+4d44957 lldpad: stop dcbx from overwriting adminstatus
+354fd12 vdp22 support variable number of VLAN/QoS returns
+a3e642c vdp22 make function vdp22_local2str static
+5d6b8f3 COPYING: Update FSF address
+82bc127 dcbnl.h: Update FSF address
+027931b Do not install systemd files as executable
+cd7f197 lldpad: do not set rx state from TX initialization
+09f7b9f vdptest: add additional notes to man page
+106f9c0 vdpnl: initialize vdpnl_mac to prevent segfault
+bbd83e0 vdp22-bridge support for error generation
+2bddc48 vdpnl add support for new netlink message format
+2534205 vdp22 add support for KEEP bit and KEEP state transition
+346a427 vdp22 remove default error status on VSI end
+c070198 vdp22 returned changed filter information from switch
+326fcd2 vdp22 remove pcp and ps from structure definition
+1c96e28 vdp22 support tracing for manager id
+3c9f390 vdp set size of filter data list to zero
+e9d8430 rtnl netlink message construction support
+e026e9f liblldp_clif function clif_getpid fix wrong buffer length
+c901b23 vdpnl regression support of multiple VSIs broken
+6efa72c vdptest add support for IEEE 802.1 Qbg ratified standard
+4794c01 vdp22 introduce new header files for common defines
+345492b lldp: lldptool evb example man page typo fix
+b79bf42 vdp22 protocol support for bridge state machine
+3c9f82a vdp22 include bridge resource allocation code
+915a2f8 vdp22 add bridge resource allocation code
+49a522f Fixup definition of dcbx_get_arg_handlers
+180f5df lldpad: Option '-t' to omit timestamps in messages
+c321645 lldp: Do not print 'l2_packet_receive - recvfrom' when network is down
+bc0c53f lldpad: Fixup pid file handling
+90c8224 lldpad: remove check_cfg_file()
+d8a997f lldpad: systemd integration
+88f02e8 nltest: use correct format for pfc messages
+eeff6d4 vdp22 protocol support for station state machine
+0f5f66f EVB and VDP are only supported on the nearest customer bridge agent. This patch adds code to fail set commands from lldptool gracefully with a string that users might understand.
+1a3cb98 lldpad: refactor VDP cmd interpretor with vdp_cmdok
+42f731c vdptest print wrong values in trace
+091c203 qbg_utils increase buffer to store uuid
+d1b9702 vdpnl add trace statement on filter information
+c4da57d vdpnl pretty indentation
+edbfec0 vdpnl determine filter information format from netlink msg
+bc1a19c vdpnl remove blank after colon in trace
+0762554 vdptest man page minor fixes
+3c93fd7 lldpad: check for existence of device before allowing set
+11cea1c lldptool: update bridge scope long form options
+e4d564d lldptool: man page fixes for MED and DCBX TLVs
+1beda0b ecp22 ecp22_data_from_evb function rename
+7060df3 vdp22 get role from evb22 protocol
+b4a1407 vdp22 add VSI format identifier
+0313734 lldpad: correct IEEE DCBX capabilities check
+8a44162 lldpad: do not require active TLVs to configure attributes
+cc83dce vdptest fix and clearify documentation
+66ebbb5 lldp: Simplify set_lldp_agent_admin() to fix RHEL 6.4 compiler error
+76e794c lldpad: Avoid accessing removed port structure
+67ca45d qbg22 rename header files lldp_qbg22 to qbg22
+5fcf657 qbg22 rename header files lldp_vdp22
+d544f05 qbg22 rename source files lldp_vdp22
+1017dbd qbg rename source and header files lldp_qbg_utils
+7d4c77c qbg rename source and header files lldp_vdp
+99ded5b lldp move files lldp_evb22*.c to parent directory
+92bdc90 qbg rename source and header file lldp_ecp
+859fab6 qbg22 rename source and header file lldp_ecp22
+5994fa7 vdp22 add timeout calcuation
+60c35b7 vdp22 add more support for vdp22 protocol
+201e6fe vdp22 add netlink support for filter format field
+3375ff9 vdp22 add vsi22 profile data structure
+c0fe8bc lldpad: Primarily identify netdevs by ifindex
+
+diff --git a/.gitignore b/.gitignore
+index 9289e11..c2ac5d7 100644
+--- a/.gitignore
++++ b/.gitignore
+@@ -1,3 +1,5 @@
++*/.dirstamp
++compile
+ parse_cli.c
+ *.o
+ *.lo
+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..4889d32 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -16,8 +16,8 @@ ACLOCAL_AMFLAGS = -I m4
+ parse_cli.o: CFLAGS+=-U_FORTIFY_SOURCE -Wno-error
+ 
+ ## system requires a shared libconfig
+-AM_CFLAGS = -Wall -Werror -Wextra -Wformat=2 $(LIBCONFIG_CFLAGS)
+-AM_LDFLAGS = $(LIBCONFIG_LIBS)
++AM_CFLAGS = -Wall -Werror -Wextra -Wformat=2 $(LIBCONFIG_CFLAGS) $(LIBNL_CFLAGS)
++AM_LDFLAGS = $(LIBCONFIG_LIBS) $(LIBNL_LIBS)
+ 
+ ## header files to be installed, for programs using the client interface to lldpad 
+ lldpad_includedir= ${includedir}/lldpad
+@@ -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 qbg/vdp22_cmds.c qbg/vdp_ascii.c
+ 
+ lib_LTLIBRARIES = liblldp_clif.la
+ liblldp_clif_la_LDFLAGS = -version-info 1:0:0
+@@ -83,11 +84,11 @@ 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
++lldptool_LDFLAGS = -ldl -llldp_clif $(LIBNL_LIBS)
+ 
+ if BUILD_DEBUG
+ nltest_SOURCES = test/nltest.c test/nltest.h
+@@ -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..cad6f75 100644
+--- a/clif.c
++++ b/clif.c
+@@ -1,6 +1,6 @@
+ /*******************************************************************************
+ 
+-  LLDP Agent Daemon (LLDPAD) Software 
++  LLDP Agent Daemon (LLDPAD) Software
+   Copyright(c) 2007-2010 Intel Corporation.
+ 
+   Substantially modified from:
+@@ -179,7 +179,7 @@ static int clif_attach_helper(struct clif *clif, char *tlvs_hex, int attach)
+ 			return -1;
+ 		sprintf(buf, "D");
+ 	}
+-		
++
+ 	ret = clif_request(clif, buf, strlen(buf), rbuf, &len, NULL);
+ 	free(buf);
+ 	if (ret < 0)
+@@ -215,11 +215,11 @@ int clif_recv(struct clif *clif, char *reply, size_t *reply_len)
+ }
+ 
+ 
+-int clif_pending(struct clif *clif)
++int clif_pending_wait(struct clif *clif, int waittime)
+ {
+ 	struct timeval tv;
+ 	fd_set rfds;
+-	tv.tv_sec = 0;
++	tv.tv_sec = waittime;
+ 	tv.tv_usec = 0;
+ 	FD_ZERO(&rfds);
+ 	FD_SET(clif->s, &rfds);
+@@ -227,6 +227,10 @@ int clif_pending(struct clif *clif)
+ 	return FD_ISSET(clif->s, &rfds);
+ }
+ 
++int clif_pending(struct clif *clif)
++{
++	return clif_pending_wait(clif, 0);
++}
+ 
+ int clif_get_fd(struct clif *clif)
+ {
+@@ -240,7 +244,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 */
+@@ -275,3 +279,155 @@ out:
+ 	clif_close(clif_conn);
+ 	return lldpad;
+ }
++
++/*
++ * Command line interface for vdp22 module.
++ * Includes for lldptool like access to lldpad
++ */
++#include <stdbool.h>
++#include <ctype.h>
++#include <errno.h>
++#include "include/qbg22.h"
++#include "include/qbg_vdp22_clif.h"	/* Defines op_XXXX */
++#include <sys/queue.h>			/* Needed by agent.h */
++#include "lldp/agent.h"			/* Nearest customer bridge define */
++
++/*
++ * Send a command via clif_xxx to lldpad.
++ * Return negavite numbers when a send/reply error occurs.
++ * Lldpad returns cmd_success for success and cmd_xxx for failure.
++ */
++static int tool_send(struct clif *connp, char *cmd, size_t cmd_len,
++		     char *reply, size_t *reply_len, int *lldpad_rc)
++{
++	int rc;
++
++	*lldpad_rc = 0;
++	rc = clif_request(connp, cmd, cmd_len, reply, reply_len, NULL);
++	if (!rc) {
++		if (1 != sscanf(reply, "R%02x", lldpad_rc))
++			rc = -3;
++	}
++	return rc;
++}
++
++/*
++ * Prepend the lldpad fan out information in front of the command.
++ * We use the vsi parameter.
++ */
++static int hdr_set(char *ifname, char *s, size_t sz, unsigned int tlvid,
++		   char *cmd, size_t cmd_len)
++{
++	int rc;
++
++	/* All command messages begin this way */
++	rc = snprintf(s, sz, "%c%08x%c%1x%02x%08x%02zx%s%02x%08x03vsi%04zx%s",
++		MOD_CMD, LLDP_MOD_VDP22, CMD_REQUEST, CLIF_MSG_VERSION,
++		cmd_settlv, op_arg | op_argval | op_config,
++		strlen(ifname), ifname, NEAREST_CUSTOMER_BRIDGE, tlvid,
++		cmd_len, cmd);
++	return (rc < 0 || rc > (int)sz) ? -EFBIG : 0;
++}
++
++/*
++ * Remove all whitespace and nonprintable characters from string.
++ */
++static void kill_white(char *s)
++{
++	char *cp = s;
++
++	for (; *s != '\0'; ++s) {
++		if (isspace(*s))
++			continue;
++		if (isprint(*s))
++			*cp++ = *s;
++	}
++	*cp = '\0';
++}
++
++/*
++ * Send a VSI command to the vdp22 module and expect a reply. The reply can be
++ * an aknowledgement (error code 0) or an error code != 0 which means the
++ * command contained an error and was not accepted.
++ */
++int clif_vsi(struct clif *connp, char *ifname, unsigned int tlvid,
++	     char *cmd, char *reply, size_t *reply_len)
++{
++	int rc, resp;
++	char cmd2[MAX_CLIF_MSGBUF];
++
++	kill_white(cmd);
++	rc = hdr_set(ifname, cmd2, sizeof(cmd2), tlvid, cmd, strlen(cmd));
++	if (rc)
++		return rc;
++	rc = tool_send(connp, cmd2, strlen(cmd2), reply, reply_len, &resp);
++	if (!rc)
++		rc = resp;
++	return rc;
++}
++
++/*
++ * Test if this is an event message from vdp22 module.
++ */
++static bool test_evt(char *msg, size_t *msg_len)
++{
++	bool is_evt = true;
++	unsigned int module;
++
++	if (*msg_len < 12 || msg[MSG_TYPE] != MOD_CMD
++	    || msg[MOD_MSG_TYPE] != EVENT_MSG
++	    || sscanf(&msg[MSG_TYPE + 1], "%08x", &module) != 1
++	    || module != LLDP_MOD_VDP22)
++		is_evt = false;
++	return is_evt;
++}
++
++/*
++ * Wait for an event message from lldpad module. After checking for the correct
++ * event message, the header of the event message is removed.
++ *
++ * Returns
++ * <0 on error or time out.
++ * =0 number of bytes on successful message reception (in reply_len parameter).
++ */
++#define	EVTHEADER	12		/* # of bytes in event message as hdr */
++int clif_vsievt(struct clif *clif, char *reply, size_t *reply_len, int wait)
++{
++	if (clif == NULL || wait < 0)
++		return -EINVAL;
++	if (clif_pending_wait(clif, wait)) {
++		if (clif_recv(clif, reply, reply_len) == 0) {
++			if (test_evt(reply, reply_len)) {
++				*reply_len -= EVTHEADER;
++				memmove(reply, reply + EVTHEADER, *reply_len);
++				reply[*reply_len] = '\0';
++				return 0;
++			} else
++				return -EBADF;
++		} else
++			return -EIO;
++	}
++	return -EAGAIN;
++}
++/*
++ * Send a VSI command to the vdp22 mode and expect a reply. The reply can
++ * an aknowledgement (error code 0) or an error code != 0 which means the
++ * command contained an error and was not accepted.
++ *
++ * Wait for the event message from lldpad to return the VSI association data
++ * from the switch
++ */
++int clif_vsiwait(struct clif *connp, char *ifname, unsigned int tlvid,
++		 char *cmd, char *reply, size_t *reply_len, int wait)
++{
++	int rc;
++	size_t reply_len2 = *reply_len;
++
++	rc = clif_vsi(connp, ifname, tlvid, cmd, reply, reply_len);
++	if (!rc) {
++		rc = clif_vsievt(connp, reply, &reply_len2, wait);
++		if (!rc)
++			*reply_len = reply_len2;
++	}
++	return rc;
++}
+diff --git a/config.c b/config.c
+index 7229b91..5fc6f58 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_ifindex(p->if_index);
++		if (!port) {
++			port = add_port(p->if_index, p->if_name);
+ 			continue;
+ 		}
+ 
+-		port = port_find_by_name(p->if_name);
+-		if (!port)
+-			port = add_port(p->if_name);
+-
+-		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;
+@@ -265,7 +261,7 @@ static bool check_int(int int_setting)
+ 
+ static bool check_priority(int priority_setting)
+ {
+-	if (priority_setting < dcb_none || priority_setting >= dcb_invalid)
++	if (priority_setting < DCB_NONE || priority_setting >= DCB_INVALID)
+ 		return false;
+ 	else
+ 		return true;
+@@ -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);
++			continue;
++		}
++		if (!check_link_status(p->if_name))
++			continue;
+ 
+-			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);
+-				}
++		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/configure.ac b/configure.ac
+index 119ab58..8d65d26 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -1,5 +1,5 @@
+ AC_INIT([lldpad], [0.9.46], [lldp-devel at open-lldp.org])
+-AM_INIT_AUTOMAKE([-Wall -Werror foreign])
++AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects])
+ 
+ m4_pattern_allow([AM_PROG_AR])
+ AM_PROG_AR
+@@ -13,6 +13,7 @@ fi
+ AM_CONDITIONAL([BUILD_DEBUG], [test "$enable_debug" = "yes"])
+ 
+ AC_PROG_CC
++AM_PROG_CC_C_O
+ AC_PROG_CXX
+ AC_PROG_LEX
+ AC_PROG_LIBTOOL
+@@ -25,12 +26,12 @@ then
+ fi
+ 
+ PKG_CHECK_MODULES([LIBCONFIG], [libconfig >= 1.3.2])
+-PKG_CHECK_MODULES([LIBNL], [libnl-1 >= 1.1])
++PKG_CHECK_MODULES([LIBNL], [libnl-3.0 >= 3.2])
+ 
+ AC_SUBST(LIBNL_CFLAGS)
+ AC_SUBST(LIBNL_LIBS)
+ 
+-AC_CHECK_LIB(nl, rtnl_link_get_by_name)
++AC_CHECK_LIB(nl3, rtnl_link_get_by_name)
+ 
+ AC_CHECK_FUNCS([alarm])
+ AC_CHECK_FUNCS([gettimeofday])
+diff --git a/ctrl_iface.c b/ctrl_iface.c
+index e02f036..e4fd0b7 100644
+--- a/ctrl_iface.c
++++ b/ctrl_iface.c
+@@ -1,6 +1,6 @@
+ /*******************************************************************************
+ 
+-  LLDP Agent Daemon (LLDPAD) Software 
++  LLDP Agent Daemon (LLDPAD) Software
+   Copyright(c) 2007-2010 Intel Corporation.
+ 
+   Substantially modified from:
+@@ -73,7 +73,7 @@ struct clif_cmds {
+ 			   socklen_t fromlen,
+ 			   char *ibuf, int ilen,
+ 			   char *rbuf, int rlen);
+-};	
++};
+ 
+ static const struct clif_cmds cmd_tbl[] = {
+ 	{ DCB_CMD,     clif_iface_module },
+@@ -117,7 +117,6 @@ int clif_iface_module(struct clif_data *clifd,
+ 	}
+ 
+ 	mod = find_module_by_id(&lldp_head, module_id);
+-
+ 	if (mod && mod->ops && mod->ops->client_cmd)
+ 		return  (mod->ops->client_cmd)(clifd, from, fromlen,
+ 			 cmd_start, cmd_len, rbuf+strlen(rbuf), rlen);
+@@ -156,17 +155,14 @@ int clif_iface_attach(struct clif_data *clifd,
+ 	char *tlv, *str, *tokenize;
+ 	const char *delim = ",";
+ 	int i, tlv_count = 0;
+-	u8 *ptr;
+ 
+ 	dst = malloc(sizeof(*dst));
+ 	if (dst == NULL)
+-		return 1;
++		return cmd_failed;
+ 	memset(dst, 0, sizeof(*dst));
+ 	memcpy(&dst->addr, from, sizeof(struct sockaddr_un));
+ 	dst->addrlen = fromlen;
+ 	dst->debug_level = MSG_INFO;
+-	dst->next = clifd->ctrl_dst;
+-	clifd->ctrl_dst = dst;
+ 
+ 	/*
+ 	 * There are two cases here one, the user provided
+@@ -175,7 +171,6 @@ int clif_iface_attach(struct clif_data *clifd,
+ 	 * user sent a comma seperated string of tlv module
+ 	 * ids it expects events from
+ 	 */
+-
+ 	/* set default string to DCBX Events */
+ 	if (ibuf[1] == '\0') {
+ 		u32 hex = LLDP_MOD_DCBX;
+@@ -197,7 +192,7 @@ int clif_iface_attach(struct clif_data *clifd,
+ 		tokenize = strtok(NULL, delim);
+ 		tlv_count++;
+ 	} while (tokenize);
+-			
++
+ 	dst->tlv_types = malloc(sizeof(u32) * tlv_count);
+ 	if (!dst->tlv_types)
+ 		goto err_types;
+@@ -206,8 +201,11 @@ int clif_iface_attach(struct clif_data *clifd,
+ 	/* Populate tlv_types from comma separated string */
+ 	tokenize = strtok(str, delim);
+ 	for (i=0; tokenize; i++) {
+-		ptr = (u8*)&dst->tlv_types[i];
+-		hexstr2bin(tokenize, ptr, 4);
++		char *myend;
++
++		dst->tlv_types[i] = strtol(tokenize, &myend, 16);
++		if (*myend)		/* No hexnumber for module id */
++			goto err_types;
+ 		tokenize = strtok(NULL, delim);
+ 	}
+ 
+@@ -215,13 +213,17 @@ int clif_iface_attach(struct clif_data *clifd,
+ 	dst->tlv_types[i] = ~0;
+ 	free(tlv);
+ 
++	/* Insert new node at beginning */
++	dst->next = clifd->ctrl_dst;
++	clifd->ctrl_dst = dst;
+ 	LLDPAD_DBG("CTRL_IFACE monitor attached\n");
+ 	snprintf(rbuf, rlen, "%c", ATTACH_CMD);
+ 
+-	return 0;
++	return cmd_success;
+ err_types:
+ 	free(tlv);
+ err_tlv:
++	free(dst);
+ 	LLDPAD_DBG("CTRL_IFACE monitor attach error\n");
+ 	snprintf(rbuf, rlen, "%c", ATTACH_CMD);
+ 
+@@ -278,7 +280,7 @@ int clif_iface_level(struct clif_data *clifd,
+ 	level = ibuf+1;
+ 	snprintf(rbuf, rlen, "%c", LEVEL_CMD);
+ 
+-	LLDPAD_DBG("CTRL_IFACE LEVEL %s", level);
++	LLDPAD_DBG("CTRL_IFACE LEVEL %s\n", level);
+ 
+ 	dst = clifd->ctrl_dst;
+ 	while (dst) {
+@@ -326,7 +328,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);
+ }
+@@ -371,14 +373,14 @@ static void ctrl_iface_receive(int sock, void *eloop_ctx,
+ 	cred = (struct ucred *)CMSG_DATA(cmsg);
+ 
+ 	if (cmsg == NULL || cmsg->cmsg_type != SCM_CREDENTIALS) {
+-		LLDPAD_INFO("%s: No sender credentials, ignoring",
++		LLDPAD_INFO("%s: No sender credentials, ignoring\n",
+ 			   __FUNCTION__);
+ 		sprintf(buf,"R%02x", cmd_bad_params);
+ 		sendto(sock, buf, 3, 0, (struct sockaddr *) &from, fromlen);
+ 		return;
+ 	}
+ 	if (cred->uid != 0) {
+-		LLDPAD_INFO("%s: sender uid=%i, ignoring",
++		LLDPAD_INFO("%s: sender uid=%i, ignoring\n",
+ 			   __FUNCTION__, cred->uid);
+ 		sprintf(buf,"R%02x", cmd_no_access);
+ 		sendto(sock, buf, 3, 0, (struct sockaddr *) &from,
+@@ -411,6 +413,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,9 +459,14 @@ 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)");
++		LLDPAD_WARN("failed to create CLI socket: %m\n");
+ 		goto fail;
+ 	}
+ 	/* enable receiving of the sender credentials */
+@@ -436,7 +479,10 @@ int ctrl_iface_init(struct clif_data *clifd)
+ 		 "%s", LLDP_CLIF_SOCK);
+ 	addrlen = sizeof(sa_family_t) + strlen(addr.sun_path + 1) + 1;
+ 	if (bind(s, (struct sockaddr *) &addr, addrlen) < 0) {
+-		perror("bind(AF_LOCAL)");
++		if (errno == EADDRINUSE)
++			LLDPAD_WARN("another lldpad instance is running\n");
++		else
++			LLDPAD_WARN("failed to bind CLI socket address: %m");
+ 		goto fail;
+ 	}
+ 	/* enable receiving of the sender credentials */
+@@ -444,6 +490,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;
+@@ -481,7 +528,7 @@ int is_ctrl_listening(struct ctrl_dst *dst, u32 type)
+ 	u32 term = ~0;
+ 	u32 all = 0;
+ 	u32 dcbx = LLDP_MOD_DCBX;
+-	
++
+ 	if (!dst)
+ 		return 0;
+ 
+@@ -530,8 +577,7 @@ void ctrl_iface_send(struct clif_data *clifd, int level, u32 moduleid,
+ 		next = dst->next;
+ 		send = 0;
+ 		/* Does dst receive these event messages? */
+-		send = is_ctrl_listening(dst, moduleid); 
+-
++		send = is_ctrl_listening(dst, moduleid);
+ 		/* Yes */
+ 		if (send && level >= dst->debug_level) {
+ 			msg.msg_name = &dst->addr;
+diff --git a/dcb_protocol.c b/dcb_protocol.c
+index 1e110a6..61b504d 100644
+--- a/dcb_protocol.c
++++ b/dcb_protocol.c
+@@ -45,7 +45,7 @@
+ #include "linux/dcbnl.h"
+ 
+ static void handle_opermode_true(char *device_name);
+-u8        gdcbx_subtype = dcbx_subtype2;
++u8        gdcbx_subtype = DCBX_SUBTYPE2;
+ 
+ int set_configuration(char *device_name, u32 EventFlag);
+ 
+@@ -1213,7 +1213,7 @@ int dcbx_remove_adapter(char *device_name)
+ 			LLDPAD_DBG("remove_adapter: oper llink not found\n");
+ 	}
+ 
+-	lldpad_shm_set_dcbx(device_name, dcbx_subtype0);
++	lldpad_shm_set_dcbx(device_name, DCBX_SUBTYPE0);
+ 	return true;
+ }
+ 
+@@ -1343,7 +1343,7 @@ bool add_pg_defaults()
+ 		pg_data.tx.up[index].pgid = (u8)(index);
+ 		pg_data.tx.up[index].bwgid = (u8)index;
+ 		pg_data.tx.up[index].percent_of_pg_cap = BW_PERCENT;
+-		pg_data.tx.up[index].strict_priority = dcb_none;
++		pg_data.tx.up[index].strict_priority = DCB_NONE;
+ 	}
+ 	temp = rmndr;
+ 	for (index=0; index < MAX_BANDWIDTH_GROUPS; index++) {
+@@ -1357,7 +1357,7 @@ bool add_pg_defaults()
+ 		pg_data.rx.up[index].pgid = (u8)(index);
+ 		pg_data.rx.up[index].bwgid = (u8)index;
+ 		pg_data.rx.up[index].percent_of_pg_cap = BW_PERCENT;
+-		pg_data.rx.up[index].strict_priority = dcb_none;
++		pg_data.rx.up[index].strict_priority = DCB_NONE;
+ 	}
+ 
+ 	snprintf(sTmp, MAX_DESCRIPTION_LEN, DEF_CFG_STORE);
+@@ -1391,7 +1391,7 @@ bool add_pfc_defaults()
+ 	pfc_data.protocol.Advertise = 1;
+ 
+ 	for (index=0; index < MAX_TRAFFIC_CLASSES; index++)
+-		pfc_data.admin[index] = pfc_disabled;
++		pfc_data.admin[index] = PFC_DISABLED;
+ 
+ 	snprintf(sTmp, MAX_DESCRIPTION_LEN, DEF_CFG_STORE);
+ 	/* Create pfc default data store for the device. */
+@@ -1599,9 +1599,9 @@ cmd_status put_pg(char *device_name, pg_attribs *pg_data, pfc_attribs *pfc_data)
+ 		feature_protocol_attribs *dStore = &(it->second->protocol);
+ 
+ 		if (dStore->Enable && !(pg_data->protocol.Enable))
+-			LLDPAD_INFO("%s PG disabled", device_name);
++			LLDPAD_INFO("%s PG disabled\n", device_name);
+ 		else if (!(dStore->Enable) && pg_data->protocol.Enable)
+-			LLDPAD_INFO("%s PG enabled", device_name);
++			LLDPAD_INFO("%s PG enabled\n", device_name);
+ 
+ 		dStore->Advertise_prev  = dStore->Advertise;
+ 		dStore->Advertise       = pg_data->protocol.Advertise;
+@@ -1611,7 +1611,7 @@ cmd_status put_pg(char *device_name, pg_attribs *pg_data, pfc_attribs *pfc_data)
+ 
+ 		memcpy(&(it->second->rx), &(pg_data->rx), sizeof(pg_data->rx));
+ 		memcpy(&(it->second->tx), &(pg_data->tx), sizeof(pg_data->tx));
+-		if (it->second->protocol.dcbx_st == dcbx_subtype2)
++		if (it->second->protocol.dcbx_st == DCBX_SUBTYPE2)
+ 			it->second->num_tcs = pg_data->num_tcs;
+ 
+ 		DCB_SET_FLAGS(EventFlag, DCB_LOCAL_CHANGE_PG);
+@@ -1653,7 +1653,7 @@ cmd_status put_peer_pg(char *device_name,  pg_attribs *peer_pg_data)
+ 		goto Exit;
+ 	}
+ 
+-	if (peer_pg_data->protocol.dcbx_st == dcbx_subtype2)
++	if (peer_pg_data->protocol.dcbx_st == DCBX_SUBTYPE2)
+ 		rebalance_uppcts(peer_pg_data);
+ 
+ 	/* detect config change */
+@@ -1677,7 +1677,7 @@ cmd_status put_peer_pg(char *device_name,  pg_attribs *peer_pg_data)
+ 		sizeof(peer_pg_data->rx));
+ 	memcpy(&(peer_it->second->tx), &(peer_pg_data->tx),
+ 		sizeof(peer_pg_data->tx));
+-	if (peer_it->second->protocol.dcbx_st == dcbx_subtype2)
++	if (peer_it->second->protocol.dcbx_st == DCBX_SUBTYPE2)
+ 		peer_it->second->num_tcs = peer_pg_data->num_tcs;
+ Exit:
+ 	return result;
+@@ -1765,9 +1765,9 @@ cmd_status put_pfc(char *device_name, pfc_attribs *pfc_data)
+ 		feature_protocol_attribs *dStore = &(it->second->protocol);
+ 
+ 		if (dStore->Enable && !(pfc_data->protocol.Enable))
+-			LLDPAD_INFO("%s PFC disabled", device_name);
++			LLDPAD_INFO("%s PFC disabled\n", device_name);
+ 		else if (!(dStore->Enable) && pfc_data->protocol.Enable)
+-			LLDPAD_INFO("%s PFC enabled", device_name);
++			LLDPAD_INFO("%s PFC enabled\n", device_name);
+ 
+ 		dStore->Advertise_prev  = dStore->Advertise;
+ 		dStore->Advertise       = pfc_data->protocol.Advertise;
+@@ -1777,7 +1777,7 @@ cmd_status put_pfc(char *device_name, pfc_attribs *pfc_data)
+ 
+ 		memcpy(it->second->admin, pfc_data->admin,
+ 			sizeof(pfc_data->admin));
+-		if (it->second->protocol.dcbx_st == dcbx_subtype2)
++		if (it->second->protocol.dcbx_st == DCBX_SUBTYPE2)
+ 			it->second->num_tcs = pfc_data->num_tcs;
+ 
+ 		/* Run the protocol */
+@@ -1835,7 +1835,7 @@ cmd_status put_peer_pfc(char *device_name, pfc_attribs *peer_pfc_data)
+ 
+ 	memcpy(peer_it->second->admin, &peer_pfc_data->admin,
+ 		sizeof(peer_pfc_data->admin));
+-	if (peer_it->second->protocol.dcbx_st == dcbx_subtype2)
++	if (peer_it->second->protocol.dcbx_st == DCBX_SUBTYPE2)
+ 		peer_it->second->num_tcs = peer_pfc_data->num_tcs;
+ Exit:
+ 	return result;
+@@ -1934,9 +1934,9 @@ cmd_status put_app(char *device_name, u32 subtype, app_attribs *app_data)
+ 
+ 		feature_protocol_attribs *dStore = &(it->second->protocol);
+ 		if (dStore->Enable && !(app_data->protocol.Enable))
+-			LLDPAD_INFO("%s APP disabled", device_name);
++			LLDPAD_INFO("%s APP disabled\n", device_name);
+ 		else if (!(dStore->Enable) && app_data->protocol.Enable)
+-			LLDPAD_INFO("%s APP enabled", device_name);
++			LLDPAD_INFO("%s APP enabled\n", device_name);
+ 		dStore->Advertise_prev  = dStore->Advertise;
+ 		dStore->Advertise       = app_data->protocol.Advertise;
+ 		dStore->Enable          = app_data->protocol.Enable;
+@@ -2040,9 +2040,9 @@ cmd_status put_llink(char *device_name, u32 subtype, llink_attribs *llink_data)
+ 		}
+ 		feature_protocol_attribs *dStore = &(it->second->protocol);
+ 		if (dStore->Enable && !(llink_data->protocol.Enable))
+-			LLDPAD_INFO("%s LLINK disabled", device_name);
++			LLDPAD_INFO("%s LLINK disabled\n", device_name);
+ 		else if (!(dStore->Enable) && llink_data->protocol.Enable)
+-			LLDPAD_INFO("%s LLINK enabled", device_name);
++			LLDPAD_INFO("%s LLINK enabled\n", device_name);
+ 		dStore->Advertise_prev  = dStore->Advertise;
+ 		dStore->Advertise       = llink_data->protocol.Advertise;
+ 		dStore->Enable          = llink_data->protocol.Enable;
+@@ -2575,7 +2575,7 @@ bool LocalPeerCompatible(char *device_name, u32 EventFlag, u32 Subtype)
+ 		ppg = Peer->second;
+ 
+ 		match = true;
+-		if (ppg->protocol.dcbx_st == dcbx_subtype1) {
++		if (ppg->protocol.dcbx_st == DCBX_SUBTYPE1) {
+ 			for (i = 0; i < MAX_USER_PRIORITIES; i++) {
+ 				if (lpg->tx.up[i].bwgid !=
+ 					ppg->tx.up[i].bwgid)
+@@ -3180,7 +3180,7 @@ cmd_status run_feature_protocol(char *device_name, u32 EventFlag, u32 Subtype)
+ 				goto ErrBadVersion;
+ 			}
+ 
+-			if (feat_prot->dcbx_st == dcbx_subtype2) {
++			if (feat_prot->dcbx_st == DCBX_SUBTYPE2) {
+ 				/* Handle Peer expiration */
+ 				if (peer_ctrl_prot->second->RxDCBTLVState ==
+ 						DCB_PEER_EXPIRED) {
+@@ -3210,7 +3210,7 @@ cmd_status run_feature_protocol(char *device_name, u32 EventFlag, u32 Subtype)
+ 					feat_prot->Syncd, __LINE__);
+ 				feat_prot->Oper_version =
+ 					feat_prot->Max_version;
+-				if (feat_prot->dcbx_st == dcbx_subtype2) {
++				if (feat_prot->dcbx_st == DCBX_SUBTYPE2) {
+ 					feat_prot->Error = true;
+ 				} else {
+ 					feat_prot->Error = false;
+@@ -3295,7 +3295,7 @@ cmd_status run_feature_protocol(char *device_name, u32 EventFlag, u32 Subtype)
+ 				feat_prot->Error_Flag = FEAT_ERR_NONE;
+ 				Err = feat_prot->Error;
+ 				/* Set_configuration to driver. */
+-				if (feat_prot->dcbx_st == dcbx_subtype2) {
++				if (feat_prot->dcbx_st == DCBX_SUBTYPE2) {
+ 					feat_prot->Syncd = !(feat_prot->Error);
+ 					feat_prot->Error = false;
+ 					if (set_configuration(device_name,
+@@ -3323,7 +3323,7 @@ cmd_status run_feature_protocol(char *device_name, u32 EventFlag, u32 Subtype)
+ 				feat_prot->Error_Flag = FEAT_ERR_NONE;
+ 				Err = feat_prot->Error;
+ 
+-				if (feat_prot->dcbx_st == dcbx_subtype2) {
++				if (feat_prot->dcbx_st == DCBX_SUBTYPE2) {
+ 					feat_prot->OperMode =
+ 						!(peer_feat_prot->Error);
+ 					if (feat_prot->OperMode) {
+@@ -3375,7 +3375,7 @@ cmd_status run_feature_protocol(char *device_name, u32 EventFlag, u32 Subtype)
+ 				Err = feat_prot->Error;
+ 
+ 				/* Set_configuration to driver. */
+-				if (feat_prot->dcbx_st == dcbx_subtype2) {
++				if (feat_prot->dcbx_st == DCBX_SUBTYPE2) {
+ 					feat_prot->OperMode =
+ 						!peer_feat_prot->Error;
+ 					feat_prot->Syncd = !(feat_prot->Error);
+@@ -3412,7 +3412,7 @@ cmd_status run_feature_protocol(char *device_name, u32 EventFlag, u32 Subtype)
+ 				Err = feat_prot->Error;
+ 				/* Set_configuration to driver. */
+ 
+-				if (feat_prot->dcbx_st == dcbx_subtype2) {
++				if (feat_prot->dcbx_st == DCBX_SUBTYPE2) {
+ 					feat_prot->OperMode =
+ 						!peer_feat_prot->Error;
+ 					feat_prot->Syncd = !(feat_prot->Error);
+@@ -3442,7 +3442,7 @@ cmd_status run_feature_protocol(char *device_name, u32 EventFlag, u32 Subtype)
+ 				Err = feat_prot->Error;
+ 
+ 				/* Set default configuration */
+-				if (feat_prot->dcbx_st == dcbx_subtype2) {
++				if (feat_prot->dcbx_st == DCBX_SUBTYPE2) {
+ 					feat_prot->Syncd = feat_prot->Error;
+ 					feat_prot->Error = true;
+ 					if (set_configuration(device_name,
+@@ -3464,7 +3464,7 @@ ErrProt:
+ 			if (peer_feat_prot->Error)
+ 				feat_prot->Error_Flag |= FEAT_ERR_PEER;
+ 
+-			if (feat_prot->dcbx_st == dcbx_subtype1) {
++			if (feat_prot->dcbx_st == DCBX_SUBTYPE1) {
+ 				if (feat_prot->Error || peer_feat_prot->Error){
+ 					LLDPAD_DBG("  ## FEATURE ERROR: "
+ 						"%d, %d (Error_Flag 0x%x"
+@@ -3483,7 +3483,7 @@ ErrProt:
+ 			}
+ 			if (ErrorChanged) {
+ 				LLDPAD_DBG("  ErrorChanged \n");
+-				if (feat_prot->dcbx_st == dcbx_subtype1) {
++				if (feat_prot->dcbx_st == DCBX_SUBTYPE1) {
+ 					feat_prot->Syncd = false;
+ 					LLDPAD_DBG("  Set Syncd to %u [%u]\n",
+ 						feat_prot->Syncd, __LINE__);
+@@ -3509,10 +3509,10 @@ OperChange:
+ 			if (feat_prot->OperMode != old_pg_opmode) {
+ 				pg_events = pg_events | EVENT_OPERMODE;
+ 				if (feat_prot->OperMode) {
+-					LLDPAD_INFO("%s PG oper mode true",
++					LLDPAD_INFO("%s PG oper mode true\n",
+ 						device_name);
+ 				} else {
+-					LLDPAD_INFO("%s PG oper mode false",
++					LLDPAD_INFO("%s PG oper mode false\n",
+ 						device_name);
+ 				}
+ 			}
+@@ -3534,10 +3534,10 @@ OperChange:
+ 			if (feat_prot->OperMode != old_pfc_opmode) {
+ 				pfc_events = pfc_events | EVENT_OPERMODE;
+ 				if (feat_prot->OperMode) {
+-					LLDPAD_INFO("%s PFC oper mode true",
++					LLDPAD_INFO("%s PFC oper mode true\n",
+ 						device_name);
+ 				} else {
+-					LLDPAD_INFO("%s PFC oper mode false",
++					LLDPAD_INFO("%s PFC oper mode false\n",
+ 						device_name);
+ 				}
+ 			}
+@@ -3563,10 +3563,10 @@ OperChange:
+ 			if (feat_prot->OperMode != old_app_opmode) {
+ 				app_events = app_events | EVENT_OPERMODE;
+ 				if (feat_prot->OperMode) {
+-					LLDPAD_INFO("%s APP oper mode true",
++					LLDPAD_INFO("%s APP oper mode true\n",
+ 						device_name);
+ 				} else {
+-					LLDPAD_INFO("%s APP oper mode false",
++					LLDPAD_INFO("%s APP oper mode false\n",
+ 						device_name);
+ 				}
+ 			}
+@@ -3836,7 +3836,7 @@ cmd_status run_control_protocol(char *device_name, u32 EventFlag)
+ 						return cmd_device_not_found;
+ 					}
+ 					if (pg_dstore.protocol.dcbx_st ==
+-						dcbx_subtype2) {
++						DCBX_SUBTYPE2) {
+ 						return cmd_success;
+ 					} else {
+ 						/* Send the updated DCB TLV */
+diff --git a/dcb_rule_chk.c b/dcb_rule_chk.c
+index ee644f6..bd6d2f2 100644
+--- a/dcb_rule_chk.c
++++ b/dcb_rule_chk.c
+@@ -144,9 +144,9 @@ static int dcb_fixup_pg(struct pg_attribs *fixpg, struct pfc_attribs *fixpfc)
+ 			if (!entry)
+ 				continue;
+ 
+-			if (entry->strict_priority == dcb_link)
++			if (entry->strict_priority == DCB_LINK)
+ 				strict++;
+-			else if (fixpfc && fixpfc->admin[j] == pfc_enabled)
++			else if (fixpfc && fixpfc->admin[j] == PFC_ENABLED)
+ 				pfc++;
+ 			else
+ 				be++;
+@@ -188,11 +188,11 @@ static int dcb_fixup_pg(struct pg_attribs *fixpg, struct pfc_attribs *fixpfc)
+ 				continue;
+ 
+ 			if (pgid < 0) {
+-				if (entry->strict_priority == dcb_link) {
++				if (entry->strict_priority == DCB_LINK) {
+ 					pgid = cbe + cpfc + strict;
+ 					strict++;
+ 				} else if (fixpfc &&
+-					   fixpfc->admin[j] == pfc_enabled) {
++					   fixpfc->admin[j] == PFC_ENABLED) {
+ 					pgid = cbe + pfc;
+ 					pfc++;
+ 				} else {
+@@ -252,7 +252,7 @@ static int dcb_fixup_pg(struct pg_attribs *fixpg, struct pfc_attribs *fixpfc)
+ 	for (i = 0; i < MAX_USER_PRIORITIES; i++) {
+ 		fixpg->tx.up[i].bwgid = i;
+ 
+-		if (fixpg->tx.up[i].strict_priority == dcb_link) {
++		if (fixpg->tx.up[i].strict_priority == DCB_LINK) {
+ 			fixpg->tx.up[i].percent_of_pg_cap = 0;
+ 			fixpg->rx.up[i].percent_of_pg_cap = 0;
+ 		} else {
+@@ -314,7 +314,7 @@ dcb_check_config (full_dcb_attrib_ptrs *attribs)
+ 
+ 		/* Internally in the pg_attribs structure, a link strict PGID is 
+ 		 * maintained as a PGID value (0-7) with a corresponding
+-		 * strict_priority field value of 'dcb_link'.  Only one link strict
++		 * strict_priority field value of 'DCB_LINK'.  Only one link strict
+ 		 * PGID is allowed.
+ 		*/
+ 		link_strict_pgid = LINK_STRICT_PGID;
+@@ -323,7 +323,7 @@ dcb_check_config (full_dcb_attrib_ptrs *attribs)
+ 			tx_bw = tx_bw + pg->tx.pg_percent[i];
+ 
+ 			/* check for >1 link strict PGID */
+-			if (pg->tx.up[i].strict_priority == dcb_link) {
++			if (pg->tx.up[i].strict_priority == DCB_LINK) {
+ 				if (link_strict_pgid == LINK_STRICT_PGID) {
+ 					link_strict_pgid = pg->tx.up[i].pgid;
+ 				} else if (pg->tx.up[i].pgid != link_strict_pgid) {
+@@ -343,7 +343,7 @@ dcb_check_config (full_dcb_attrib_ptrs *attribs)
+ 			 */
+ 			for (i = 0; i < MAX_BW_GROUP; i++) {
+ 				if ((tx_bw != 0) || (pg->tx.up[i].strict_priority !=
+-					dcb_link)) {
++					DCB_LINK)) {
+ 					LLDPAD_INFO("Invalid tx total BWG %d\n",
+ 							(int)tx_bw);
+ 					return cmd_bad_params;
+@@ -356,7 +356,7 @@ dcb_check_config (full_dcb_attrib_ptrs *attribs)
+ 			rx_bw = rx_bw + pg->rx.pg_percent[i];
+ 
+ 			/* check for >1 link strict PGID */
+-			if (pg->rx.up[i].strict_priority == dcb_link) {
++			if (pg->rx.up[i].strict_priority == DCB_LINK) {
+ 				if (link_strict_pgid == LINK_STRICT_PGID) {
+ 					link_strict_pgid = pg->rx.up[i].pgid;
+ 				} else if (pg->rx.up[i].pgid != link_strict_pgid) {
+@@ -376,7 +376,7 @@ dcb_check_config (full_dcb_attrib_ptrs *attribs)
+ 			 */
+ 			for (i = 0; i < MAX_BW_GROUP; i++) {
+ 				if ((rx_bw != 0) || (pg->rx.up[i].strict_priority !=
+-					dcb_link)) {
++					DCB_LINK)) {
+ 					LLDPAD_INFO("Invalid RX total BWG %d\n",
+ 							(int)rx_bw);
+ 					return cmd_bad_params;
+@@ -403,7 +403,7 @@ dcb_check_config (full_dcb_attrib_ptrs *attribs)
+ 					(int)tx_bw_id);
+ 				return  cmd_bad_params;
+ 			}
+-			if (pg->tx.up[i].strict_priority == dcb_link) {
++			if (pg->tx.up[i].strict_priority == DCB_LINK) {
+ 				tx_link_strict[tx_bw_id] = true;
+ 				/* Link strict should have zero bandwidth */
+ 				if (tx_bw){
+@@ -412,7 +412,7 @@ dcb_check_config (full_dcb_attrib_ptrs *attribs)
+ 					return cmd_bad_params;
+ 				}
+ 			} else if (!tx_bw) {
+-				LLDPAD_INFO("Zero BW on non LSP tc %i", i);
++				LLDPAD_INFO("Zero BW on non LSP tc %i\n", i);
+ 				/* Non link strict should have non zero bandwidth*/
+ 				return cmd_bad_params;
+ 			}
+@@ -422,10 +422,10 @@ dcb_check_config (full_dcb_attrib_ptrs *attribs)
+ 			rx_bw_id = (u8)(pg->rx.up[i].bwgid);
+ 
+ 			if (rx_bw_id >= MAX_BW_GROUP) {
+-				LLDPAD_INFO("Invalid RX BW %i", rx_bw_id);
++				LLDPAD_INFO("Invalid RX BW %i\n", rx_bw_id);
+ 				return cmd_bad_params;
+ 			}	   
+-			if (pg->rx.up[i].strict_priority == dcb_link) {
++			if (pg->rx.up[i].strict_priority == DCB_LINK) {
+ 				rx_link_strict[rx_bw_id] = true;
+ 				/* Link strict class should have zero bandwidth */
+ 				if (rx_bw){
+@@ -434,7 +434,7 @@ dcb_check_config (full_dcb_attrib_ptrs *attribs)
+ 					return cmd_bad_params;
+ 				}
+ 			} else if (!rx_bw) {
+-				LLDPAD_INFO("Zero BW on no LSP tc %i", i);
++				LLDPAD_INFO("Zero BW on no LSP tc %i\n", i);
+ 				/* Non link strict class should have non-zero bw */
+ 				return cmd_bad_params; /* DCB_RX_ERR_TC_BW_ZERO; */
+ 			}
+@@ -451,13 +451,13 @@ dcb_check_config (full_dcb_attrib_ptrs *attribs)
+ 			 */
+ 			if (tx_link_strict[i]) {
+ 				if (tx_bw_sum[i] && pg->tx.pg_percent[i]) {
+-					LLDPAD_INFO("Non-zero LSP BW %d %d\n",
++					LLDPAD_INFO("Non-zero TX LSP BW %d %d\n",
+ 						i, (int)tx_bw_sum[i]);
+ 					/* Link strict group should have zero bw */
+ 					return cmd_bad_params;
+ 				}
+ 			} else if (tx_bw_sum[i] != BW_PERCENT && tx_bw_sum[i] != 0) {
+-				LLDPAD_INFO("Invalid BW sum on BWG %i %i",
++				LLDPAD_INFO("Invalid TX BW sum on BWG %i %i\n",
+ 						i, (int)tx_bw_sum[i]);
+ 				return cmd_bad_params;
+ 			}
+@@ -470,13 +470,13 @@ dcb_check_config (full_dcb_attrib_ptrs *attribs)
+ 			 */
+ 			if (rx_link_strict[i]) {
+ 				if (rx_bw_sum[i] && pg->rx.pg_percent[i]) {
+-					LLDPAD_INFO("Non-zero BW on LSP tc "
+-						"%u %u\n", i, rx_bw_sum[i]);
++					LLDPAD_INFO("Non-zero RX LSP BW %d %d\n",
++						i, (int)rx_bw_sum[i]);
+ 					/* Link strict group should have zero bw */
+ 					return cmd_bad_params;
+ 				}
+ 			} else if (rx_bw_sum[i] != BW_PERCENT && rx_bw_sum[i] != 0) {
+-				LLDPAD_INFO("Invalid BW sum on BWG %i %i",
++				LLDPAD_INFO("Invalid RX BW sum on BWG %i %i\n",
+ 						i, (int)rx_bw_sum[i]);
+ 				return cmd_bad_params;
+ 			}
+@@ -517,7 +517,7 @@ void rebalance_uppcts(pg_attribs *pg)
+ 		for (i = 0; i < MAX_USER_PRIORITIES; i++) {
+ 			if (pg->tx.up[i].bwgid == bwgid) {
+ 				uplist[num_found++] = (u8)i;
+-				if (pg->tx.up[i].strict_priority == dcb_link) {
++				if (pg->tx.up[i].strict_priority == DCB_LINK) {
+ 					link_strict = true;
+ 					pg->tx.up[i].percent_of_pg_cap = 0;
+ 					pg->rx.up[i].percent_of_pg_cap = 0;
+@@ -535,8 +535,8 @@ void rebalance_uppcts(pg_attribs *pg)
+ 				}
+ 				pg->tx.up[uplist[i]].percent_of_pg_cap = (u8)value;
+ 				pg->rx.up[uplist[i]].percent_of_pg_cap = (u8)value;
+-				pg->tx.up[uplist[i]].strict_priority = dcb_none;
+-				pg->rx.up[uplist[i]].strict_priority = dcb_none;
++				pg->tx.up[uplist[i]].strict_priority = DCB_NONE;
++				pg->rx.up[uplist[i]].strict_priority = DCB_NONE;
+ 			}
+ 		}
+ 	}
+diff --git a/dcbtool_cmds.c b/dcbtool_cmds.c
+index b36c522..a5cd0fe 100644
+--- a/dcbtool_cmds.c
++++ b/dcbtool_cmds.c
+@@ -465,7 +465,7 @@ void print_dcb_cmd_response(char *buf, int status)
+ 	int version;
+ 	int dcb_cmd;
+ 	int feature;
+-	int dcbx_st = dcbx_subtype1;
++	int dcbx_st = DCBX_SUBTYPE1;
+ 	int subtype = 0;
+ 	int plen = 0;
+ 	int doff;
+@@ -634,16 +634,16 @@ void print_dcb_cmd_response(char *buf, int status)
+ 	case FEATURE_DCBX:
+ 		printf("DCBX Version:\t");
+ 		switch (*(buf+doff+DCBX_VERSION) ^ '0') {
+-		case dcbx_subtype1:
++		case DCBX_SUBTYPE1:
+ 			printf("CIN\n");
+ 			break;
+-		case dcbx_subtype2:
++		case DCBX_SUBTYPE2:
+ 			printf("CEE\n");
+ 			break;
+-		case dcbx_force_subtype1:
++		case DCBX_FORCE_SUBTYPE1:
+ 			printf("FORCED CIN\n");
+ 			break;
+-		case dcbx_force_subtype2:
++		case DCBX_FORCE_SUBTYPE2:
+ 			printf("FORCED CEE\n");
+ 			break;
+ 		default:
+@@ -680,7 +680,7 @@ void print_dcb_cmd_response(char *buf, int status)
+ 		printf("\n");
+ 
+ 		if ((dcb_cmd != CMD_GET_PEER) ||
+-			(dcb_cmd == CMD_GET_PEER && dcbx_st == dcbx_subtype1)) {
++			(dcb_cmd == CMD_GET_PEER && dcbx_st == DCBX_SUBTYPE1)) {
+ 			printf("uppct:     \t");
+ 			for (i=0; i<MAX_USER_PRIORITIES; i++) {
+ 				n = hex2int(buf+doff+PG_UP_PCNT(i));
+diff --git a/docs/liblldp_clif-vdp22.3 b/docs/liblldp_clif-vdp22.3
+new file mode 100644
+index 0000000..f237aa0
+--- /dev/null
++++ b/docs/liblldp_clif-vdp22.3
+@@ -0,0 +1,311 @@
++.TH liblldp_clif 3 "February 2014" "open-lldp" "Linux"
++.SH NAME
++clif_vsi,clif_vsievt,clif_vsiwait \- Manipulate VDP IEEE 802.1 Ratified Standard Assocications
++.SH SYNOPSIS
++#include "include/clif.h"
++.sp 1
++.B "int clif_vsi(struct clif *connp, char *ifname, unsigned int tlvid, char *cmd, char *reply, size_t *reply_len);"
++.sp 1
++.B "int clif_vsievt(struct clif *connp, char *reply, size_t *reply_len, int wait);"
++.sp 1
++.B "int clif_vsiwait(struct clif *connp, char *ifname, unsigned int tlvid, char *cmd, char *reply, size_t *reply_len, int wait);"
++.sp 1
++.SH DESCRIPTION
++The Virtual station interface Discovery Protocol
++is a protocol to manage the association and deassociation of virtual
++machine network interfaces (VSIs) between the station and an adjacent switch.
++VDP is typically used with the local switch in VEPA mode and the adjacent
++switch port in reflective relay (also called haripin) mode.
++This allows all traffic to be sent to the switch for processing.
++Reflective relay mode is negotiated via EVB TLVs (see lldptool-evb).
++.P
++This man pages describes the IEEE 802.1 Qbg ratified standard
++dated from July 5th, 2012. This differs from the draft 0.2 which is
++implemented as well, see
++.BR lldptool-vdp (8).
++For clarification in this man page
++the version complying to the ratified standard is
++called VDP22 and the version complying to the draft 0.2 is called VDP.
++.SS VSI Parameter
++Each VDP22 TLVs contains a command mode, manager identifier,
++type identifier, type identifier version, VSI instance identifier,
++migiration hints and filter information.
++The fields are explained next:
++.TP
++.B "Command Mode:"
++The command mode determines the type 
++of the VSI association to be established.
++It is an ascii string can be one of:
++.RS
++.IP assoc:
++Create an VSI association.
++.IP preassoc:
++Create an VSI preassociation. The association
++is only announced to the switch.
++.IP preassoc-rr:
++Create an VSI preassociation. The association
++is only announced to the switch and the 
++switch should reserve the resources.
++.IP deassoc:
++Delete an VSI association.
++.RE
++Other strings are not recognized and return an error.
++.TP
++.B "Manager identifier:"
++The manager identifier is a string of up to 16
++alphanumeric characters.
++It can also be an UUID according to RFC 4122
++with optional dashes in between.
++.TP
++.B "Type Identifier:"
++The type identifier is a number in the range
++of 0 to 2^24 - 1.
++.TP
++.B "Type Identifier Version:"
++The type identifer version is a number
++in the range of 0 to 255.
++.TP
++.B "VSI Instance Identifier:"
++The VSI instance identifier is
++an UUID according to RFC 4122
++with optional dashes in between.
++.TP
++.B "Migration Hints:"
++The migiration hints is a string aiding in 
++migration of virtual machines:
++.RS
++.IP none:
++No hints available.
++.IP from:
++The virtual machine is migriting away.
++.IP to:
++The virtual machine is migriting to.
++.RE
++.TP
++.B "Filter Information Data:"
++The filter information data can be supplied in four
++different formats:
++.RS
++.IP "vlan (1)"
++A vlan number only, also known as filter information format 1.
++The vlan identifier is a number in the range of 1 to 2^16 - 1.
++The high order 4 bits are used as quality of service bits.
++The vlan identifier can be zero, a vlan identifier is then
++selected by the switch. Refer to IEEE 802.1 Qbg ratified
++standard for details.
++.IP "vlan-mac (2)"
++A vlan number and MAC address delimited by a slash ('-'),
++also known as filter information format 2.
++The MAC address is specified in the format xx:xx:xx:xx:xx:xx.
++The colons are mandatory.
++For vlan details see (1).
++.IP "vlan-mac-group (4)"
++A vlan number, MAC address and group identifier, 
++each delimited by a slash ('-'),
++also known as filter information format 4.
++The group identifier is a 32 bit number.
++For vlan and MAC address details see (1) and (2).
++.IP "vlan--group (3)"
++A vlan number and group identifier, 
++delimited by two slashes ('--'),
++also known as filter information format 3.
++For vlan and group details see (1) and (4).
++.RE
++Several filter information fields can be supplied.
++The have to be separated by comma (',') and must be
++of the same format.
++.SS clif_vsi
++This function sends a VSI command to
++.BR lldpad (8).
++Parameter 
++.I connp
++is a pointer to the connection information.
++This information is obtained by calling
++.I clif_open
++and
++.IR clif_attach .
++Parameter 
++.I ifname
++is the interface name 
++.B lldpad 
++(8) uses to send the VSI data.
++Paramenter
++.I tlvid
++is the number of the VSI request.
++Valid numbers are
++1 (for Preassociation),
++2 (for Preassociation with resource reservation) and
++3 (for association),
++4 (for Deassociation).
++Parameter 
++.I cmd
++points to a character string containing the VSI command.
++The layout of the VSI command has been explained above.
++All VSI fields are concatenated together and separated to
++by commas (',') to form one large string.
++Parameter
++.I reply
++is a pointer to a character array to receive the reply from 
++.BR lldpad (8).
++Parameter
++.I reply_len
++holds the maximum number of characters available in the array 
++pointed to by
++.IR reply .
++On successful return of the call, 
++.I reply_len
++contains the number of characters stored by 
++.BR lldpad (8)
++as the response of the command.
++.P
++The functions returns zero on success and the 
++.I reply
++and
++.I reply_len
++parameters are set.
++.I Reply_len
++contains the number of bytes in the
++memory area pointed to by
++.IR reply .
++.I Reply
++contains the same information and format as the 
++.I cmd
++parameter with several exceptions:
++.RS
++.IP "Command Mode:"
++This field should be the same as in 
++.I cmd
++parameter. If it contains
++.I deassoc
++then the command failed and the field
++.I ",igration hints"
++contains an error numner.
++.IP "Migration Hints:"
++This field contains the error number on why the command
++was not accepted by
++.BR lldpad (8).
++This command failed to pass the 
++.BR lldpad (8)
++sanity checks.
++Note that the command was not even sent to the switch
++for processing.
++If no error occured, this field contains a dash ('-').
++.IP "Filter Information Data:"
++If parameter
++.I cmd
++contained the a 
++.I "vlan identifier"
++of value zero or a
++.I "group identifier"
++the switch is allowed to assign a 
++different 
++.IR "vlan identifier" ,
++which is saved and returned in the reply buffer.
++.RE
++All the other fields should be returned unchanged.
++.P
++The function returns zero when the command was accepted by
++.BR lldpad (8).
++Otherwise it returns a positive number on why the command was not
++accepted.
++.SS clif_vsievt
++After a successful return of
++.IR clif_vsi ,
++.BR lldpad (8)
++has sent the command to the switch and waits for a response from the switch.
++The switch can still deny the request.
++Function
++.I clif_vsievt
++waits for
++parameter
++.I wait
++seconds for a reply from
++.BR lldpad (8).
++Parameter
++.I reply_len
++specifies the maximum buffer size pointed to by parameter
++.IR reply.
++If a response was received in
++.I wait 
++seconds, the function
++returns zero and sets
++.I reply_len
++to the number of bytes received and
++.I reply
++contains the response.
++The format is the same as in 
++.IR clif_vsi .
++.P
++Since the switch can disassociate an established
++VSI association any time, it is recommended
++to call 
++.I clif_vsievt
++periodically to check for disassociate event
++messages from 
++.IR lldpad (8).
++.P
++If the functions fails it returns
++.IP -EINVAL
++No attachment to
++.BR lldpad (8)
++or 
++.I wait
++is negative.
++.IP -EAGAIN
++No message was received during the wait.
++.IP -EIO
++Message was received but could not be read.
++.IP -EBADF
++Message was received but was not an event message.
++.SS clif_vsiwait
++This function combines
++.I clif_vsi 
++and 
++.I clif_vsievt
++into one function call.
++.SH EXAMPLE & USAGE
++Code sample to create an VSI association on 
++.IR eth0 :
++.P
++.nf
++.DS
++char ok[MAX_CLIF_MSGBUF];
++int rc;
++size_t ok_len = sizeof(ok);
++char *cmd ="assoc,blabla,12345,1,00000000-1111-2222-3333-aabbccddeeff"
++		",none,10-aa:bb:00:00:00:10,11-aa:bb:00:00:00:11";
++struct clif *tool_conn = clif_open();
++
++if (!tool_conn) {
++	 fprintf(stderr, "%s can not open connection to LLDPAD\n",
++		 progname);
++	 exit(5);
++}
++
++/* Attach to the vdp22 module */
++if (clif_attach(tool_conn, "80c4")) {
++	fprintf(stderr, "%s can not attach to LLDPAD\n", progname);
++	clif_close(tool_conn);
++	tool_conn = NULL;
++	exit(5);
++}
++
++rc = clif_vsiwait(tool_conn, "eth0", 1, cmd, ok, &ok_len, 5);
++if (!rc) {
++	/* Parse the response in ok */
++	....
++}
++clif_detach(tool_conn));
++clif_close(tool_conn);
++.DE
++.fi
++.SH SEE ALSO
++.BR lldptool-vdp (8),
++.BR lldptool-evb (8),
++.BR lldptool-evb22 (8),
++.BR lldptool (8),
++.BR lldpad (8)
++.br
++IEEE 802.1Qbg (http://www.ieee802.org/1/pages/802.1bg.html)
++.SH AUTHOR
++Thomas Richter
+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-dcbx.8 b/docs/lldptool-dcbx.8
+index a0960a2..e7afdb6 100644
+--- a/docs/lldptool-dcbx.8
++++ b/docs/lldptool-dcbx.8
+@@ -42,7 +42,7 @@ The DCBX mode can be queried and configured by using the special tlvid
+ There is not an actual TLV which corresponds to this tlvid.  Its use is to query and reset the IEEE DCBX mode.  When queried,
+ IEEE DCBX mode can take the following values:
+ 
+-.BR auto " - IEEE DCBX will be used (intially) if lldpad is restarted.  An exception is if the DCBX mode has been forced to a
++.BR auto " - IEEE DCBX will be used (initially) if lldpad is restarted.  An exception is if the DCBX mode has been forced to a
+ legacy DCBX mode, then the specified legacy mode will be used.  See information about the 'dcbx' parameter in dcbtool(8) for
+ more information about this exception."
+ .sp
+diff --git a/docs/lldptool-ets.8 b/docs/lldptool-ets.8
+index b123b9a..4608bbf 100644
+--- a/docs/lldptool-ets.8
++++ b/docs/lldptool-ets.8
+@@ -58,17 +58,17 @@ Enables the ETS TLV to be transmitted
+ Sets the ETS-CFG willing bit 
+ .TP
+ .B tsa 
+-Transmission selection algorithm, sets a comma seperated list \
++Transmission selection algorithm, sets a comma separated list \
+ of traffic classes to the corresponding selection algorithm. Valid algorithms \
+ include "ets", "strict" and "vendor".
+ .sp
+ .TP
+ .B up2tc
+-Comma seperated list mapping user priorities to traffic classes.
++Comma separated list mapping user priorities to traffic classes.
+ .sp
+ .TP
+ .B tcbw
+-Comma separated list of bandwiths for each traffic class the first value
++Comma separated list of bandwidths for each traffic class the first value
+ being assigned to traffic class 0 and the second to traffic class 1 and so
+ on. Undefined bandwidths are presumed to be 0.
+ .sp
+diff --git a/docs/lldptool-evb22.8 b/docs/lldptool-evb22.8
+index 8a05a7f..4414f65 100644
+--- a/docs/lldptool-evb22.8
++++ b/docs/lldptool-evb22.8
+@@ -4,10 +4,14 @@ evb22 \- Show / manipulate EVB IEEE 802.1 Ratified Standard TLV configuration
+ .SH SYNOPSIS
+ .B lldptool -t -i ethx -g ncb -V evb
+ .sp
+-.B lldptool -t -i ethx -g ncb -V evb -c evbmode
++.B lldptool -t -i ethx -g ncb -V evb -c
++.sp
++.B lldptool -t -i ethx -g ncb -V evb -c enabletx
+ .sp
+ .B lldptool -T -i ethx -g ncb -V evb -c enabletx=[yes|no]
+ .sp
++.B lldptool -t -i ethx -g ncb -V evb -c evbmode
++.sp
+ .B lldptool -T -i ethx -g ncb -V evb -c evbmode=[bridge|station]
+ .sp
+ .B lldptool -t -i ethx -g ncb -V evb -c evbrrreq
+@@ -76,7 +80,7 @@ determines which version will be used.
+ The switch port configuration should select only one
+ protocol version, never both.
+ .sp 1 
+-The command line options and arugments are explained in the 
++The command line options and arguments are explained in the 
+ .BR lldptool (8)
+ man pages. 
+ Only the EVB, ECP and VDP protocol specific parameters are 
+@@ -84,11 +88,18 @@ detailed in this manual page.
+ .SH ARGUMENTS
+ The invocation without command line option '-c' and
+ argument displays the
+-complete EVB, ECP and VDP protocol settings.
++complete EVB, ECP and VDP protocol settings
++in a pretty print out.
+ See below for a detailed description 
+ on how to interpret the output.
+ .TP
+ \fB\-c\fP \fItext\fP
++Use of the command line option '-c' without
++any argument displays all known parameters
++in the format of
++.IR  key = value ,
++which is suitable
++for post processing.
+ Use command line option '-c' and one of the
+ following arguments to display and
+ set individual parameters.
+@@ -143,17 +154,17 @@ Shows or sets the local run time exponent (RTE).
+ The RTE will be used as the
+ base for the timing of the ECP protocol time outs and
+ retransmits.
+-The wait time is calcuated as 10*2\u\fIecprte\fP\d micro seconds.
++The wait time is calculated as 10*2\u\fIecprte\fP\d micro seconds.
+ .TP
+ .B vdprwd
+ Shows or sets the number of resource wait delay value.
+-This value is calcuated as 10*2\u\fIvdprwd\fP\d micro seconds
++This value is calculated as 10*2\u\fIvdprwd\fP\d micro seconds
+ and determines the
+ maximum  wait time for VDP protocol acknowledgements.
+ .TP
+ .B vdprka
+ Shows or sets the number of re-init keep alive value.
+-This value is calcuated as 10*2\u\fIvdprka\fP\d micro seconds
++This value is calculated as 10*2\u\fIvdprka\fP\d micro seconds
+ and determines the wait time for VDP protocol 
+ to send a keep alive message.
+ .SH Theory of Operation
+@@ -180,6 +191,7 @@ EVB Configuration TLV
+ 	r/l:0 rka:8
+ .fi
+ .DE
++.P
+ This output is displayed when enabletx has been enabled.
+ The first line shows the currently known status
+ of the bridge.
+@@ -211,8 +223,7 @@ Display the locally configured value for RTE
+ Set the value for RTE to its maximum value
+ .B lldptool -T -g ncb -i eth0 -V evb -c rte=7
+ .TP
+-Set the value for enabletx to yes to transmit EVB TLV
+-to the switch.
++Set the value for enabletx to yes
+ .B lldptool -T -g ncb -i eth0 -V evb -c enabletx=yes
+ .SH NOTES
+ Currently the code in lldpad reflects 
+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/clif.h b/include/clif.h
+index fa19149..648eedf 100644
+--- a/include/clif.h
++++ b/include/clif.h
+@@ -152,8 +152,12 @@ int clif_recv(struct clif *clif, char *reply, size_t *reply_len);
+  * message available to be received with clif_recv(). clif_pending() is
+  * only used for event messages, i.e., clif_attach() must have been used to
+  * register the client interface as an event monitor.
++ *
++ * clif_pending_wait - Same as clif_pending, but allows the specification
++ *			of maximum wait time in seconds.
+  */
+ int clif_pending(struct clif *clif);
++int clif_pending_wait(struct clif *clif, int waittime);
+ 
+ 
+ /**
+@@ -180,4 +184,70 @@ int clif_get_fd(struct clif *clif);
+  * its PID. Extract the PID and return it to the caller.
+  */
+ pid_t clif_getpid(void);
++
++/**
++ * clif_vsi - Send a VDP22 association command to the running lldpad process
++ * @clif: Control interface data from clif_open()
++ * @ifname: Name of the interface to apply the VSI command
++ * @tlvid: Number of tlv identifier
++ * @cmd: Buffer containing the VSI command
++ * @reply: Buffer for the reply data
++ * @reply_len: Length of the reply buffer
++ * Returns: cmd_success when VSI command was accepted and cmd_failure if not.
++ *
++ * This commands sends an VSI association command encoded as ascii string
++ * to the lldpad VPD22 module. The module decodes the ascii string and checks
++ * for consistency. Any white space in the ascii string is removed. The
++ * format of the ascii string is explained in the man page.
++ *
++ * If the command is invalid cmd_failure is returned.
++ * Other cmd_success is returned. In this case the command was accepted and
++ * sent to the switch. The switch may still deny the request. The switch
++ * response is sent via an event message.
++ *
++ * Note: This command can only be sent when the clif_attach() functions has
++ * been called with successful return code.
++ */
++int clif_vsi(struct clif *clif, char *ifname, unsigned int tlvid, char *cmd,
++	     char *reply, size_t *reply_len);
++
++/**
++ * clif_vsievt - Wait for event message from lldpad after clif_vsi()
++ * @clif: Control interface data from clif_open()
++ * @reply: Buffer for the reply data
++ * @reply_len: Length of the reply buffer
++ * @waittime: Maximum number of seconds to wait for event message
++ * Returns:
++ * 0: on success (a message was received and reply_len contains the number
++ *    of bytes of the message)
++ * -EINVAL: Invalid parameters, for example negative wait time.
++ * -EAGAIN: No message received.
++ * -EIO: Message pending but receive function failed.
++ * -EBADF: Message received but was no event message.
++ *
++ * This function waits up to waittime seconds for an event message from
++ * lldpad. An event message is expected when the clif_vsi() successfully
++ * submitted an VSI command. The event message contains the reply from the
++ * switch. The event message is in acsii and the format is explained in the
++ * man page.
++ */
++int clif_vsievt(struct clif *clif, char *reply, size_t *reply_len, int waitime);
++
++/**
++ * clif_vsiwait - Send VSI command and wait for event message.
++ * @clif: Control interface data from clif_open()
++ * @ifname: Name of the interface to apply the VSI command
++ * @tlvid: Number of tlv identifier
++ * @cmd: Buffer containing the VSI command
++ * @reply: Buffer for the reply data
++ * @reply_len: Length of the reply buffer
++ * @waittime: Maximum number of seconds to wait for event message
++ * Returns: see clif_vsi() and clif_vsievt().
++ *
++ * This function is a combination of clif_vsi() and clif_vsievt(). It sends
++ * the vsi command and on successful reception of the VSI command calls
++ * clif_vsievt() to receive the response.
++ */
++int clif_vsiwait(struct clif *clif, char *ifname, unsigned int tlvid,
++		 char *cmd, char *reply, size_t *reply_len, int waittime);
+ #endif /* CLIF_H */
+diff --git a/include/dcb_types.h b/include/dcb_types.h
+index 34d88d6..23cf264 100644
+--- a/include/dcb_types.h
++++ b/include/dcb_types.h
+@@ -41,11 +41,11 @@
+ 
+ /* DCBX subtypes */
+ typedef enum {
+-	dcbx_subtype0 = 0,	/* auto IEEE */
+-	dcbx_subtype1 = 1,	/* CIN */
+-	dcbx_subtype2 = 2,	/* CEE */
+-	dcbx_force_subtype1 = 5,/* FORCE CIN */
+-	dcbx_force_subtype2 = 6,/* FORCE CEE */
++	DCBX_SUBTYPE0 = 0,	/* auto IEEE */
++	DCBX_SUBTYPE1 = 1,	/* CIN */
++	DCBX_SUBTYPE2 = 2,	/* CEE */
++	DCBX_FORCE_SUBTYPE1 = 5,/* FORCE CIN */
++	DCBX_FORCE_SUBTYPE2 = 6,/* FORCE CEE */
+ } dcbx_subtype;
+ 
+ 
+@@ -54,9 +54,9 @@ typedef enum {
+ 
+ /* PFC configuration */
+ typedef enum {
+-	pfc_disabled   = 0x000,
+-	pfc_enabled,
+-	pfc_invalid,
++	PFC_DISABLED   = 0x000,
++	PFC_ENABLED,
++	PFC_INVALID,
+ } pfc_type;
+ 
+ /* Peer DCB TLV States */
+@@ -70,10 +70,10 @@ typedef enum {
+ typedef pfc_type dcb_pfc_type;
+ 
+ typedef enum {
+-	dcb_none       = 0x0000,
+-	dcb_group,
+-	dcb_link,
+-	dcb_invalid,
++	DCB_NONE       = 0x0000,
++	DCB_GROUP,
++	DCB_LINK,
++	DCB_INVALID,
+ } dcb_strict_priority_type;
+ 
+ typedef pfc_type dcb_pfc_list_type[MAX_USER_PRIORITIES];
+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 <lucy.liu at intel.com>
+  */
+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 <stdbool.h>
+ #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 <jens at linux.vnet.ibm.com>
+-  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
+-
+-  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 <linux/if_ether.h>
+-
+-#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 <tmricht at linux.vnet.ibm.com>
+-
+-  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 <linux/if_ether.h>
+-
+-#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..36fcc13 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 }
+@@ -38,9 +38,9 @@ enum {				/* EVB bit definitions defines */
+ 	EVB_RRCTR = 0x1,	/* Bridge reflective relay control */
+ 	EVB_SGID = 0x8,		/* Station group ID */
+ 	EVB_RRREQ = 0x4,	/* Station reflective relay request */
+-	EVB_RRSTAT_YES = 0x2,	/* Station reflective relay status TRUE */
++	EVB_RRSTAT_YES = 0x1,	/* Station reflective relay status TRUE */
+ 	EVB_RRSTAT_NO = 0x0,	/* Station reflective relay status NO */
+-	EVB_RRSTAT_DONT = 0x1,	/* Station reflective relay status unknown */
++	EVB_RRSTAT_DONT = 0x3,	/* Station reflective relay status unknown */
+ 	EVB_ROL = 0x20,		/* Remote or local indicator */
+ 	EVB_BRIDGE = 0x1,	/* EVB Bridge */
+ 	EVB_STATION = 0x2	/* EVB Station */
+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 <tmricht at linux.vnet.ibm.com>
+-
+-  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 <tmricht at linux.vnet.ibm.com>
+-
+-  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..c21236d 100644
+--- a/include/lldp_rtnl.h
++++ b/include/lldp_rtnl.h
+@@ -31,19 +31,8 @@
+ #define IFNAMSIZ 16
+ #endif
+ 
+-#include "include/linux/netlink.h"
+-
+-/*
+- * Helper functions to construct a netlink message.
+- */
+-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_u16(struct nlmsghdr *, int, __u16);
+-void mynla_put_u32(struct nlmsghdr *, int, __u32);
+-
+ 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 <jens at linux.vnet.ibm.com>
+-  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
+-
+-  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 <tmricht at linux.vnet.ibm.com>
+-
+-  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	<sys/queue.h>
+-#include	<linux/if_ether.h>
+-
+-#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 <jens at linux.vnet.ibm.com>
+-  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
+-
+-  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 <jens at linux.vnet.ibm.com>
+-
+-  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 <tmricht at linux.vnet.ibm.com>
+-
+-  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 <linux/if_link.h>
+-#include <linux/if_ether.h>
+-
+-#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..eb3eb4d
+--- /dev/null
++++ b/include/qbg22.h
+@@ -0,0 +1,91 @@
++/*******************************************************************************
++
++  Implementation of EVB TLVs for LLDP
++  (c) Copyright IBM Corp. 2013
++
++  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++
++  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
++#define	LLDP_MOD_VDP22_SUBTYPE	0
++
++
++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 */
++	unsigned char evbon;	/* EVB TLV transmits enabled */
++};
++
++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 <jens at linux.vnet.ibm.com>
++  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++
++  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 <linux/if_ether.h>
++
++#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 <tmricht at linux.vnet.ibm.com>
++
++  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 <linux/if_ether.h>
++
++#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..6033556
+--- /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 <tmricht at linux.vnet.ibm.com>
++
++  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 unsigned char *, 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 <jens at linux.vnet.ibm.com>
++  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++
++  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..b345602
+--- /dev/null
++++ b/include/qbg_vdp22.h
+@@ -0,0 +1,210 @@
++/*******************************************************************************
++
++  Implementation of VDP protocol for IEEE 802.1 Qbg Ratified Standard
++  (c) Copyright IBM Corp. 2013
++
++  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++
++  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	<sys/queue.h>
++#include	<linux/if_ether.h>
++#include	<linux/if_link.h>
++
++#include	<qbg_vdp22def.h>
++
++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 evbon;		/* True on EVB22 txmit enabled */
++	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 *);
++int vdp22_clntback(struct vsi22 *);
++struct vsi22 *vdp22_copy_vsi(struct vsi22 *);
++void vdp22_listdel_vsi(struct vsi22 *);
++int vdp22br_resources(struct vsi22 *, int *);
++int vdp22_info(const char *);
++void vdp22_stop_timers(struct vsi22 *);
++int vdp22_start_localchange_timer(struct vsi22 *);
++
++/*
++ * 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_vdp22_clif.h b/include/qbg_vdp22_clif.h
+new file mode 100644
+index 0000000..20330b8
+--- /dev/null
++++ b/include/qbg_vdp22_clif.h
+@@ -0,0 +1,55 @@
++/*******************************************************************************
++
++  Implementation of VDP 22 (ratified standard) according to IEEE 802.1Qbg
++  (c) Copyright IBM Corp. 2014
++
++  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++
++  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".
++
++*******************************************************************************/
++
++/*
++ * Client command interface for vdp22 module.
++ */
++
++#ifndef QBG_VDP22_CLIF_H
++#define QBG_VDP22_CLIF_H
++typedef enum {
++	cmd_getstats,
++	cmd_gettlv,
++	cmd_settlv,
++	cmd_get_lldp,
++	cmd_set_lldp,
++	cmd_quit,
++	cmd_license,
++	cmd_version,
++	cmd_help,
++	cmd_ping,
++	cmd_nop
++} vdp22_cmd;
++
++typedef enum {
++	op_local = 0x1,
++	op_neighbor = 0x2,
++	op_arg = 0x4,
++	op_argval = 0x8,
++	op_config = 0x10,
++	op_delete = 0x20,
++	op_key = 0x40
++} vdp22_op;
++#endif
+diff --git a/include/qbg_vdp22_cmds.h b/include/qbg_vdp22_cmds.h
+new file mode 100644
+index 0000000..8cfd32a
+--- /dev/null
++++ b/include/qbg_vdp22_cmds.h
+@@ -0,0 +1,40 @@
++/*******************************************************************************
++
++  Implementation of VDP 22 (ratified standard) according to IEEE 802.1Qbg
++  (c) Copyright IBM Corp. 2014
++
++  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++
++  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".
++
++*******************************************************************************/
++
++/*
++ * Command interface for vdp22 module.
++ */
++
++#ifndef QBG_VDP22_CMDS_H
++#define QBG_VDP22_CMDS_H
++
++struct arg_handlers *vdp22_arg_handlers();
++int vdp22_clif_cmd(void *, struct sockaddr_un *, socklen_t, char *, int, char *,
++		   int);
++#define VAL_STATION		"station"
++#define VAL_BRIDGE		"bridge"
++#define ARG_VDP22_VSI		"vsi"
++
++#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 <tmricht at linux.vnet.ibm.com>
++
++  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 <jens at linux.vnet.ibm.com>
++  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++
++  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 <jens at linux.vnet.ibm.com>
++
++  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..7b26bc7
+--- /dev/null
++++ b/include/qbg_vdpnl.h
+@@ -0,0 +1,81 @@
++/*******************************************************************************
++
++  Implementation of EVB TLVs for LLDP
++  (c) Copyright IBM Corp. 2013
++
++  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++
++  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 <linux/if_link.h>
++#include <linux/if_ether.h>
++
++#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 vsi_idfmt;
++	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);
++int vdp_status(int, struct vdpnl_vsi *);
++int vdp22_status(int, struct vdpnl_vsi *, int);
++int event_trigger(struct nlmsghdr *, pid_t);
++int vdp_str2vdpnl(char *, struct vdpnl_vsi *, char *);
++int vdp_vdpnl2str(struct vdpnl_vsi *, char *, size_t);
++int vdp22_sendevent(struct vdpnl_vsi *);
++#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.h b/lldp/l2_packet.h
+index 737ae54..b82b894 100644
+--- a/lldp/l2_packet.h
++++ b/lldp/l2_packet.h
+@@ -40,7 +40,7 @@
+ #define ETH_P_LLDP 0x88cc
+ 
+ #define ETH_P_ECP	0x88b7		/* Draft 0.2 */
+-#define ETH_P_ECP22	0x8890		/* Ratified standard */
++#define ETH_P_ECP22	0x8940		/* Ratified standard */
+ 
+ #ifndef ETH_MIN_DATA_LEN
+ #define ETH_MIN_DATA_LEN	(ETH_ZLEN - ETH_HLEN)
+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 <linux/if_packet.h>
+ #include <linux/pkt_sched.h>
+ #include <net/if.h>
++#include <errno.h>
+ #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;
++	int ifindex = get_ifidx(ifname);
+ 
+-	all = !strlen(ifname);
++	if (!ifindex)
++		return;
+ 
+-	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;
+-			}
++	for (port = porthead; port; port = port->next) {
++		if (ifindex == port->ifindex)
++			break;
++	}
+ 
+-			agent = lldp_agent_find_by_type(port->ifname, type);
+-			if (!agent) {
+-				port = port->next;
+-				continue;
+-			}
++	if (!port)
++		return;
+ 
+-			if (agent->adminStatus != admin) {
+-				agent->adminStatus = admin;
+-				somethingChangedLocal(ifname, type);
+-				run_tx_sm(port, agent);
+-				run_rx_sm(port, agent);
+-			}
++	agent = lldp_agent_find_by_type(port->ifname, type);
++	if (!agent)
++		return;
+ 
+-			if (!all)
+-				break;
+-		}
+-		port = port->next;
++	/* 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;
++	struct port *port = port_find_by_ifindex(get_ifidx(ifname));
+ 
+-	port = port_find_by_name(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/tx.c b/lldp/tx.c
+index 67933a7..69c1a1a 100644
+--- a/lldp/tx.c
++++ b/lldp/tx.c
+@@ -118,8 +118,6 @@ void txInitializeLLDP(struct lldp_agent *agent)
+ 	}
+ 
+ 	agent->tx.state  = TX_LLDP_INITIALIZE;
+-	agent->rx.state = LLDP_WAIT_PORT_OPERATIONAL;
+-
+ 	agent->tx.localChange = false;
+ 	agent->stats.statsFramesOutTotal = 0;
+ 	agent->timers.reinitDelay   = REINIT_DELAY;
+diff --git a/lldp_8021qaz.c b/lldp_8021qaz.c
+index b3da01b..094676d 100644
+--- a/lldp_8021qaz.c
++++ b/lldp_8021qaz.c
+@@ -419,12 +419,12 @@ 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;
+ 	struct sockaddr_nl dest_addr;
+-	static struct nl_handle *nlhandle;
++	static struct nl_sock *nlsocket;
+ 	struct nl_msg *nlm = NULL;
+ 	unsigned char *msg = NULL;
+ 	struct nlmsghdr *hdr;
+@@ -434,28 +434,28 @@ static int get_dcbx_hw(const char *ifname, __u8 *dcbx)
+ 			   .dcb_pad = 0
+ 			  };
+ 
+-	if (!nlhandle) {
+-		nlhandle = nl_handle_alloc();
+-		if (!nlhandle) {
+-			LLDPAD_WARN("%s: %s: nl_handle_alloc failed, %s\n",
+-				    __func__, ifname, nl_geterror());
++	if (!nlsocket) {
++		nlsocket = nl_socket_alloc();
++		if (!nlsocket) {
++			LLDPAD_WARN("%s: %s: nl_socket_alloc failed\n",
++				    __func__, ifname);
+ 			err = -ENOMEM;
+ 			goto out;
+ 		}
+-		nl_socket_set_local_port(nlhandle, 0);
++		nl_socket_set_local_port(nlsocket, 0);
+ 	}
+ 
+-	err = nl_connect(nlhandle, NETLINK_ROUTE);
++	err = nl_connect(nlsocket, NETLINK_ROUTE);
+ 	if (err < 0) {
+ 		LLDPAD_WARN("%s: %s nlconnect failed abort get ieee, %s\n",
+-			    __func__, ifname, nl_geterror());
++			    __func__, ifname, nl_geterror(err));
+ 		goto out;
+ 	}
+ 
+ 	nlm = nlmsg_alloc_simple(RTM_GETDCB, NLM_F_REQUEST);
+ 	if (!nlm) {
+-		LLDPAD_WARN("%s: %s nlmsg_alloc failed abort get ieee, %s\n",
+-			    __func__, ifname, nl_geterror());
++		LLDPAD_WARN("%s: %s nlmsg_alloc failed abort get ieee\n",
++			    __func__, ifname);
+ 		err = -ENOMEM;
+ 		goto out;
+ 	}
+@@ -472,14 +472,14 @@ static int get_dcbx_hw(const char *ifname, __u8 *dcbx)
+ 	if (err < 0)
+ 		goto out;
+ 
+-	err = nl_send_auto_complete(nlhandle, nlm);
++	err = nl_send_auto_complete(nlsocket, nlm);
+ 	if (err <= 0) {
+ 		LLDPAD_WARN("%s: %s 802.1Qaz get app attributes failed\n",
+ 			    __func__, ifname);
+ 		goto out;
+ 	}
+ 
+-	err = nl_recv(nlhandle, &dest_addr, &msg, NULL);
++	err = nl_recv(nlsocket, &dest_addr, &msg, NULL);
+ 	if (err <= 0) {
+ 		LLDPAD_WARN("%s: %s: nl_recv returned %d\n", __func__, ifname,
+ 			    err);
+@@ -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;
+ 	}
+ 
+@@ -499,8 +500,8 @@ static int get_dcbx_hw(const char *ifname, __u8 *dcbx)
+ out:
+ 	nlmsg_free(nlm);
+ 	free(msg);
+-	if (nlhandle)
+-		nl_close(nlhandle);
++	if (nlsocket)
++		nl_close(nlsocket);
+ 	return err;
+ }
+ 
+@@ -524,7 +525,7 @@ void ieee8021qaz_ifup(char *ifname, struct lldp_agent *agent)
+ 	struct ieee_ets *ets = NULL;
+ 	struct ieee_pfc *pfc = NULL;
+ 	struct app_prio *data = NULL;
+-	int err;
++	int err, no_set_status;
+ 
+ 	if (agent->type != NEAREST_BRIDGE)
+ 		return;
+@@ -537,12 +538,19 @@ void ieee8021qaz_ifup(char *ifname, struct lldp_agent *agent)
+ 	if (err < 0)
+ 		return;
+ 
++	/* If admin has explicitly enabled Rx/Tx, don't override it */
++	no_set_status = get_config_setting(ifname, agent->type, ARG_ADMINSTATUS,
++						&adminstatus, CONFIG_TYPE_INT);
++
+ 	/* 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) {
++		if (no_set_status)
++			set_lldp_agent_admin(ifname, agent->type,
++					     (adminstatus & enabledRxOnly));
+ 		return;
++	}
+ 
+ 	/* If 802.1Qaz is already configured no need to continue */
+ 	tlvs = ieee8021qaz_data(ifname);
+@@ -552,17 +560,11 @@ void ieee8021qaz_ifup(char *ifname, struct lldp_agent *agent)
+ 	/* if there is no persistent adminStatus setting then set to enabledRx
+ 	 * but do not persist that as a setting.
+ 	 */
+-	if (get_config_setting(ifname, agent->type, ARG_ADMINSTATUS,
+-			       &adminstatus, CONFIG_TYPE_INT))
++	if (no_set_status)
+ 		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 +635,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 +648,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;
+@@ -786,7 +790,7 @@ static int get_ieee_hw(const char *ifname, struct ieee_ets **ets,
+ 	int rem;
+ 	int itr = 0;
+ 	struct sockaddr_nl dest_addr;
+-	static struct nl_handle *nlhandle;
++	struct nl_sock *nlsocket = NULL;
+ 	struct nl_msg *nlm;
+ 	unsigned char *msg = NULL;
+ 	struct nlmsghdr *hdr;
+@@ -797,20 +801,19 @@ static int get_ieee_hw(const char *ifname, struct ieee_ets **ets,
+ 			   .dcb_pad = 0
+ 			  };
+ 
+-	if (!nlhandle) {
+-		nlhandle = nl_handle_alloc();
+-		if (!nlhandle) {
+-			LLDPAD_WARN("%s: %s: nl_handle_alloc failed, %s\n",
+-				    __func__, ifname, nl_geterror());
+-			*cnt = 0;
+-			return -ENOMEM;
+-		}
+-		nl_socket_set_local_port(nlhandle, 0);
++	nlsocket = nl_socket_alloc();
++	if (!nlsocket) {
++		LLDPAD_WARN("%s: %s: nl_handle_alloc failed\n",
++			    __func__, ifname);
++		*cnt = 0;
++		return -ENOMEM;
+ 	}
++	nl_socket_set_local_port(nlsocket, 0);
+ 
+-	if (nl_connect(nlhandle, NETLINK_ROUTE) < 0) {
++	err = nl_connect(nlsocket, NETLINK_ROUTE);
++	if (err < 0) {
+ 		LLDPAD_WARN("%s: %s nlconnect failed abort get ieee, %s\n",
+-			    __func__, ifname, nl_geterror());
++			    __func__, ifname, nl_geterror(err));
+ 		goto out1;
+ 	}
+ 
+@@ -832,14 +835,14 @@ static int get_ieee_hw(const char *ifname, struct ieee_ets **ets,
+ 	if (err < 0)
+ 		goto out;
+ 
+-	err = nl_send_auto_complete(nlhandle, nlm);
++	err = nl_send_auto_complete(nlsocket, nlm);
+ 	if (err <= 0) {
+ 		LLDPAD_WARN("%s: %s 802.1Qaz get app attributes failed\n",
+ 			    __func__, ifname);
+ 		goto out;
+ 	}
+ 
+-	err = nl_recv(nlhandle, &dest_addr, &msg, NULL);
++	err = nl_recv(nlsocket, &dest_addr, &msg, NULL);
+ 	if (err <= 0) {
+ 		LLDPAD_WARN("%s: %s: nl_recv returned %d\n", __func__, ifname,
+ 			    err);
+@@ -936,7 +939,8 @@ static int get_ieee_hw(const char *ifname, struct ieee_ets **ets,
+ out:
+ 	nlmsg_free(nlm);
+ 	free(msg);
+-	nl_close(nlhandle);
++	nl_close(nlsocket);
++	nl_socket_free(nlsocket);
+ out1:
+ 	*cnt = itr;
+ 	return err;
+@@ -947,7 +951,7 @@ static int del_ieee_hw(const char *ifname, struct dcb_app *app_data)
+ 	int err = 0;
+ 	struct nlattr *ieee, *app;
+ 	struct sockaddr_nl dest_addr;
+-	static struct nl_handle *nlhandle;
++	struct nl_sock *nlsocket;
+ 	struct nl_msg *nlm;
+ 	struct dcbmsg d = {
+ 			   .dcb_family = AF_UNSPEC,
+@@ -955,19 +959,18 @@ static int del_ieee_hw(const char *ifname, struct dcb_app *app_data)
+ 			   .dcb_pad = 0
+ 			  };
+ 
+-	if (!nlhandle) {
+-		nlhandle = nl_handle_alloc();
+-		if (!nlhandle) {
+-			LLDPAD_WARN("%s: %s: nl_handle_alloc failed, %s\n",
+-				    __func__, ifname, nl_geterror());
+-			return -ENOMEM;
+-		}
+-		nl_socket_set_local_port(nlhandle, 0);
++	nlsocket = nl_socket_alloc();
++	if (!nlsocket) {
++		LLDPAD_WARN("%s: %s: nl_handle_alloc failed\n",
++			    __func__, ifname);
++		return -ENOMEM;
+ 	}
++	nl_socket_set_local_port(nlsocket, 0);
+ 
+-	if (nl_connect(nlhandle, NETLINK_ROUTE) < 0) {
++	err = nl_connect(nlsocket, NETLINK_ROUTE);
++	if (err < 0) {
+ 		LLDPAD_WARN("%s: %s nlconnect failed abort hardware set, %s\n",
+-			    __func__, ifname, nl_geterror());
++			    __func__, ifname, nl_geterror(err));
+ 		err = -EIO;
+ 		goto out1;
+ 	}
+@@ -1009,7 +1012,7 @@ static int del_ieee_hw(const char *ifname, struct dcb_app *app_data)
+ 		nla_nest_end(nlm, app);
+ 	}
+ 	nla_nest_end(nlm, ieee);
+-	err = nl_send_auto_complete(nlhandle, nlm);
++	err = nl_send_auto_complete(nlsocket, nlm);
+ 	if (err <= 0)
+ 		LLDPAD_WARN("%s: %s 802.1Qaz set attributes failed\n",
+ 			    __func__, ifname);
+@@ -1017,7 +1020,8 @@ static int del_ieee_hw(const char *ifname, struct dcb_app *app_data)
+ out:
+ 	nlmsg_free(nlm);
+ out2:
+-	nl_close(nlhandle);
++	nl_close(nlsocket);
++	nl_socket_free(nlsocket);
+ out1:
+ 	return err;
+ 
+@@ -1030,7 +1034,7 @@ static int set_ieee_hw(const char *ifname, struct ieee_ets *ets_data,
+ 	int err = 0;
+ 	struct nlattr *ieee, *app;
+ 	struct sockaddr_nl dest_addr;
+-	static struct nl_handle *nlhandle;
++	struct nl_sock *nlsocket;
+ 	struct nl_msg *nlm;
+ 	struct dcbmsg d = {
+ 			   .dcb_family = AF_UNSPEC,
+@@ -1038,15 +1042,13 @@ static int set_ieee_hw(const char *ifname, struct ieee_ets *ets_data,
+ 			   .dcb_pad = 0
+ 			  };
+ 
+-	if (!nlhandle) {
+-		nlhandle = nl_handle_alloc();
+-		if (!nlhandle) {
+-			LLDPAD_WARN("%s: %s: nl_handle_alloc failed, %s\n",
+-				    __func__, ifname, nl_geterror());
+-			return -ENOMEM;
+-		}
+-		nl_socket_set_local_port(nlhandle, 0);
++	nlsocket = nl_socket_alloc();
++	if (!nlsocket) {
++		LLDPAD_WARN("%s: %s: nl_handle_alloc failed\n",
++			    __func__, ifname);
++		return -ENOMEM;
+ 	}
++	nl_socket_set_local_port(nlsocket, 0);
+ 
+ 	if (!ets_data && !pfc_data && !app_data) {
+ 		err = 0;
+@@ -1060,9 +1062,10 @@ static int set_ieee_hw(const char *ifname, struct ieee_ets *ets_data,
+ 		print_pfc(pfc_data);
+ #endif
+ 
+-	if (nl_connect(nlhandle, NETLINK_ROUTE) < 0) {
++	err = nl_connect(nlsocket, NETLINK_ROUTE);
++	if (err < 0) {
+ 		LLDPAD_WARN("%s: %s nlconnect failed abort hardware set, %s\n",
+-			    __func__, ifname, nl_geterror());
++			    __func__, ifname, nl_geterror(err));
+ 		err = -EIO;
+ 		goto out1;
+ 	}
+@@ -1118,7 +1121,7 @@ static int set_ieee_hw(const char *ifname, struct ieee_ets *ets_data,
+ 		nla_nest_end(nlm, app);
+ 	}
+ 	nla_nest_end(nlm, ieee);
+-	err = nl_send_auto_complete(nlhandle, nlm);
++	err = nl_send_auto_complete(nlsocket, nlm);
+ 	if (err <= 0)
+ 		LLDPAD_WARN("%s: %s 802.1Qaz set attributes failed\n",
+ 			    __func__, ifname);
+@@ -1126,7 +1129,8 @@ static int set_ieee_hw(const char *ifname, struct ieee_ets *ets_data,
+ out:
+ 	nlmsg_free(nlm);
+ out2:
+-	nl_close(nlhandle);
++	nl_close(nlsocket);
++	nl_socket_free(nlsocket);
+ out1:
+ 	return err;
+ }
+@@ -2146,29 +2150,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..c2c270f 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,18 +146,14 @@ 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:
++	case DCBX_SUBTYPE0:
+ 		snprintf(buf, sizeof(buf), "auto");
+ 		break;
+-	case dcbx_subtype1:
++	case DCBX_SUBTYPE1:
+ 		snprintf(buf, sizeof(buf), "CIN");
+ 		break;
+-	case dcbx_subtype2:
++	case DCBX_SUBTYPE2:
+ 		snprintf(buf, sizeof(buf), "CEE");
+ 		break;
+ 	default:
+@@ -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,14 +206,14 @@ 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);
++	lldpad_shm_set_dcbx(cmd->ifname, DCBX_SUBTYPE0);
+ 	snprintf(obuf, obuf_len, "mode = %s\n", arg_value);
+ 
+ 	return cmd_success;
+@@ -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;
+-	}
++	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);
+ 
+-	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(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(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, &pfc,
++				 CONFIG_TYPE_INT);
++
++	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..9999e33 100644
+--- a/lldp_dcbx.c
++++ b/lldp_dcbx.c
+@@ -210,7 +210,7 @@ int dcbx_bld_tlv(struct port *newport, struct lldp_agent *agent)
+ 		goto fail_add;
+ 	}
+ 
+-	if (tlvs->dcbx_st == dcbx_subtype2) {
++	if (tlvs->dcbx_st == DCBX_SUBTYPE2) {
+ 		tlvs->pg2 = bld_dcbx2_pg_tlv(tlvs, &success);
+ 		if (!success) {
+ 			LLDPAD_INFO("bld_dcbx2_pg_tlv: failed\n");
+@@ -224,7 +224,7 @@ int dcbx_bld_tlv(struct port *newport, struct lldp_agent *agent)
+ 		}
+ 	}
+ 
+-	if (tlvs->dcbx_st == dcbx_subtype2) {
++	if (tlvs->dcbx_st == DCBX_SUBTYPE2) {
+ 		tlvs->pfc2 = bld_dcbx2_pfc_tlv(tlvs, &success);
+ 		if (!success) {
+ 			LLDPAD_INFO("bld_dcbx2_pfc_tlv: failed\n");
+@@ -238,7 +238,7 @@ int dcbx_bld_tlv(struct port *newport, struct lldp_agent *agent)
+ 		}
+ 	}
+ 
+-	if (tlvs->dcbx_st == dcbx_subtype2) {
++	if (tlvs->dcbx_st == DCBX_SUBTYPE2) {
+ 		tlvs->app2 = bld_dcbx2_app_tlv(tlvs, &success);
+ 		if (!success) {
+ 			LLDPAD_INFO("bld_dcbx2_app_tlv: failed\n");
+@@ -259,7 +259,7 @@ int dcbx_bld_tlv(struct port *newport, struct lldp_agent *agent)
+ 		goto fail_add;
+ 	}
+ 
+-	if (tlvs->dcbx_st == dcbx_subtype2) {
++	if (tlvs->dcbx_st == DCBX_SUBTYPE2) {
+ 		tlvs->dcbx2 = bld_dcbx2_tlv(tlvs);
+ 		if (tlvs->dcbx2 == NULL) {
+ 			LLDPAD_INFO("add_port:  bld_dcbx2_tlv failed\n");
+@@ -364,7 +364,7 @@ struct packed_tlv* dcbx_gettlv(struct port *port, struct lldp_agent *agent)
+ 	dcbx_free_tlv(tlvs);
+ 
+ 	dcbx_bld_tlv(port, agent);
+-	if (tlvs->dcbx_st == dcbx_subtype2) {
++	if (tlvs->dcbx_st == DCBX_SUBTYPE2) {
+ 		/* Load Type127 - dcbx subtype 2*/
+ 		if (tlv_ok(tlvs->dcbx2))
+ 			ptlv =  pack_tlv(tlvs->dcbx2);
+@@ -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, ret;
++	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
+@@ -529,14 +531,12 @@ void dcbx_ifup(char *ifname, struct lldp_agent *agent)
+ 	if (dcb_support.dcbx && !(dcb_support.dcbx & DCB_CAP_DCBX_HOST))
+ 		return;
+ 
+-	/* if no adminStatus setting or wrong setting for adminStatus,
+-	 * then set adminStatus to enabledRxTx.
+-	 */
+-	if (get_config_setting(ifname, agent->type, ARG_ADMINSTATUS,
+-			       &adminstatus, CONFIG_TYPE_INT) ||
+-				adminstatus == enabledTxOnly ||
+-				adminstatus == enabledRxOnly) {
+-
++	/* if no adminStatus setting default to enabled for DCBX */
++	ret = get_config_setting(ifname, agent->type,
++				 ARG_ADMINSTATUS,
++				 &adminstatus,
++				 CONFIG_TYPE_INT);
++	if (ret != cmd_success) {
+ 		/* set enableTx to true if it is not already set */
+ 		snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", TLVID_PREFIX,
+ 			(OUI_CEE_DCBX << 8) | 1, ARG_TLVTXENABLE);
+@@ -634,7 +634,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 +643,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)
+@@ -745,12 +733,12 @@ int dcbx_rchange(struct port *port, struct lldp_agent *agent, struct unpacked_tl
+ 		if ((memcmp(tlv->info, &oui, DCB_OUI_LEN) != 0))
+ 			return SUBTYPE_INVALID;
+ 
+-		if ((tlv->info[DCB_OUI_LEN] == dcbx_subtype2)
++		if ((tlv->info[DCB_OUI_LEN] == DCBX_SUBTYPE2)
+ 			&& (agent->lldpdu & RCVD_LLDP_DCBX2_TLV)) {
+ 			LLDPAD_INFO("Received duplicate DCBX2 TLVs\n");
+ 			return TLV_ERR;
+ 		}
+-		if ((tlv->info[DCB_OUI_LEN] == dcbx_subtype1)
++		if ((tlv->info[DCB_OUI_LEN] == DCBX_SUBTYPE1)
+ 			&& (agent->lldpdu & RCVD_LLDP_DCBX1_TLV)) {
+ 			LLDPAD_INFO("Received duplicate DCBX1 TLVs\n");
+ 			return TLV_ERR;
+@@ -760,14 +748,14 @@ int dcbx_rchange(struct port *port, struct lldp_agent *agent, struct unpacked_tl
+ 		 * the currently configured legacy dcbx mode.
+ 		 * However, capture if any legacy DCBX TLVs are recieved.
+ 		*/
+-		if (tlv->info[DCB_OUI_LEN] == dcbx_subtype2) {
+-			if (dcbx->dcbx_st == dcbx_subtype2)
++		if (tlv->info[DCB_OUI_LEN] == DCBX_SUBTYPE2) {
++			if (dcbx->dcbx_st == DCBX_SUBTYPE2)
+ 				dcbx->manifest->dcbx2 = tlv;
+ 			agent->lldpdu |= RCVD_LLDP_DCBX2_TLV;
+ 			dcbx->rxed_tlvs = true;
+ 			return TLV_OK;
+-		} else if (tlv->info[DCB_OUI_LEN] == dcbx_subtype1) {
+-			if (dcbx->dcbx_st == dcbx_subtype1)
++		} else if (tlv->info[DCB_OUI_LEN] == DCBX_SUBTYPE1) {
++			if (dcbx->dcbx_st == DCBX_SUBTYPE1)
+ 				dcbx->manifest->dcbx1 = tlv;
+ 			agent->lldpdu |= RCVD_LLDP_DCBX1_TLV;
+ 			dcbx->rxed_tlvs = true;
+@@ -783,10 +771,10 @@ int dcbx_rchange(struct port *port, struct lldp_agent *agent, struct unpacked_tl
+ 
+ 		if (!dcbx->active && !ieee8021qaz_tlvs_rxed(dcbx->ifname) &&
+ 		    dcbx->rxed_tlvs && (not_present || enabled)) {
+-			if (dcbx->dcbx_st == dcbx_subtype2)
++			if (dcbx->dcbx_st == DCBX_SUBTYPE2)
+ 				LLDPAD_DBG("CEE DCBX %s going ACTIVE\n",
+ 					   dcbx->ifname);
+-			else if (dcbx->dcbx_st == dcbx_subtype1)
++			else if (dcbx->dcbx_st == DCBX_SUBTYPE1)
+ 				LLDPAD_DBG("CIN DCBX %s going ACTIVE\n",
+ 					   dcbx->ifname);
+ 			set_dcbx_mode(port->ifname,
+diff --git a/lldp_dcbx_cfg.c b/lldp_dcbx_cfg.c
+index 0dc23ea..f44c653 100644
+--- a/lldp_dcbx_cfg.c
++++ b/lldp_dcbx_cfg.c
+@@ -320,7 +320,7 @@ int dcbx_default_cfg_file(void)
+ 
+ 	tmp_setting = config_setting_add(dcbx_setting, "dcbx_version",
+ 		CONFIG_TYPE_INT);
+-	if (!tmp_setting || !config_setting_set_int(tmp_setting, dcbx_subtype2))
++	if (!tmp_setting || !config_setting_set_int(tmp_setting, DCBX_SUBTYPE2))
+ 		goto error;
+ 
+ 	config_write_file(&lldpad_cfg, cfg_file_name);
+@@ -1104,10 +1104,10 @@ int get_dcbx_version(int *result)
+ 
+ 	if (get_int_config(dcbx_setting, "dcbx_version", TYPE_INT, result)) {
+ 		switch (*result) {
+-		case dcbx_subtype1:
+-		case dcbx_subtype2:
+-		case dcbx_force_subtype1:
+-		case dcbx_force_subtype2:
++		case DCBX_SUBTYPE1:
++		case DCBX_SUBTYPE2:
++		case DCBX_FORCE_SUBTYPE1:
++		case DCBX_FORCE_SUBTYPE2:
+ 			rval = 1;
+ 			break;
+ 		default:
+diff --git a/lldp_dcbx_cmds.c b/lldp_dcbx_cmds.c
+index 1ce4d4c..7fdf6c4 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];
+ }
+@@ -298,10 +298,10 @@ static cmd_status set_dcbx_config(char *ibuf, int ilen)
+ 	if (ilen == DCBX_CFG_OFF + CFG_DCBX_DLEN) {
+ 		version = (*(ibuf+off+DCBX_VERSION)) ^ '0';
+ 		switch (version) {
+-		case dcbx_subtype1:
+-		case dcbx_subtype2:
+-		case dcbx_force_subtype1:
+-		case dcbx_force_subtype2:
++		case DCBX_SUBTYPE1:
++		case DCBX_SUBTYPE2:
++		case DCBX_FORCE_SUBTYPE1:
++		case DCBX_FORCE_SUBTYPE2:
+ 			rval = save_dcbx_version(version);
+ 			break;
+ 		default:
+@@ -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) {
+@@ -789,7 +783,7 @@ static cmd_status get_pg_data(pg_attribs *pg_data, int cmd, char *port_id,
+ 	for (i = 0; i < MAX_BANDWIDTH_GROUPS; i++)
+ 		sprintf(rbuf+PG_PG_PCNT(i), "%02x", pg_data->tx.pg_percent[i]);
+ 	for (i = 0; i < MAX_USER_PRIORITIES; i++) {
+-		if (pg_data->tx.up[i].strict_priority == dcb_link)
++		if (pg_data->tx.up[i].strict_priority == DCB_LINK)
+ 			value = LINK_STRICT_PGID;
+ 		else
+ 			value = pg_data->tx.up[i].pgid;
+@@ -797,27 +791,27 @@ static cmd_status get_pg_data(pg_attribs *pg_data, int cmd, char *port_id,
+ 	}
+ 	for (i = 0; i < MAX_USER_PRIORITIES; i++) {
+ 		if ((cmd != CMD_GET_PEER) ||
+-			(cmd == CMD_GET_PEER && dcbx_st == dcbx_subtype1))
++			(cmd == CMD_GET_PEER && dcbx_st == DCBX_SUBTYPE1))
+ 			sprintf(rbuf+PG_UP_PCNT(i), "%02x",
+ 				pg_data->tx.up[i].percent_of_pg_cap);
+-		else if (cmd == CMD_GET_PEER && dcbx_st == dcbx_subtype2)
++		else if (cmd == CMD_GET_PEER && dcbx_st == DCBX_SUBTYPE2)
+ 			sprintf(rbuf+PG_UP_PCNT(i), "%c%c",
+ 				CLIF_NOT_SUPPLIED, CLIF_NOT_SUPPLIED);
+ 	}
+ 	for (i = 0; i < MAX_USER_PRIORITIES; i++) {
+ 		if ((cmd != CMD_GET_PEER) ||
+-			(cmd == CMD_GET_PEER && dcbx_st == dcbx_subtype1)) {
+-			if (pg_data->tx.up[i].strict_priority == dcb_link)
+-				value = dcb_none;
++			(cmd == CMD_GET_PEER && dcbx_st == DCBX_SUBTYPE1)) {
++			if (pg_data->tx.up[i].strict_priority == DCB_LINK)
++				value = DCB_NONE;
+ 			else
+ 				value = pg_data->tx.up[i].strict_priority;
+ 			sprintf(rbuf+PG_UP_STRICT(i), "%1x", value);
+-		} else if (cmd == CMD_GET_PEER && dcbx_st == dcbx_subtype2) {
++		} else if (cmd == CMD_GET_PEER && dcbx_st == DCBX_SUBTYPE2) {
+ 			sprintf(rbuf+PG_UP_STRICT(i), "%c", CLIF_NOT_SUPPLIED);
+ 		}
+ 	}
+ 
+-	if ((cmd == CMD_GET_PEER && dcbx_st == dcbx_subtype1) ||
++	if ((cmd == CMD_GET_PEER && dcbx_st == DCBX_SUBTYPE1) ||
+ 		(cmd == CMD_GET_OPER))
+ 		sprintf(rbuf+PG_UP_NUM_TC, "%c", CLIF_NOT_SUPPLIED);
+ 	else
+@@ -858,7 +852,7 @@ static int get_pfc_data(pfc_attribs *pfc_data, int cmd, char *port_id,
+ 		sprintf(rbuf+PFC_UP(i), "%1x", pfc_data->admin[i]);
+ 	}
+ 
+-	if ((cmd == CMD_GET_PEER && dcbx_st == dcbx_subtype1) ||
++	if ((cmd == CMD_GET_PEER && dcbx_st == DCBX_SUBTYPE1) ||
+ 		(cmd == CMD_GET_OPER))
+ 		sprintf(rbuf+PFC_NUM_TC, "%c", CLIF_NOT_SUPPLIED);
+ 	else
+@@ -978,7 +972,7 @@ static int set_pg_config(pg_attribs *pg_data, char *port_id, char *ibuf,
+ 			flag = *(ibuf+off+PG_UP_PGID(i));
+ 			if (flag == CLIF_NOT_SUPPLIED) {
+ 				if (pg_data->tx.up[i].strict_priority ==
+-					dcb_link)
++					DCB_LINK)
+ 					flag = LINK_STRICT_PGID;
+ 				else
+ 					flag = pg_data->tx.up[i].pgid;
+@@ -1021,8 +1015,8 @@ static int set_pg_config(pg_attribs *pg_data, char *port_id, char *ibuf,
+ 				pg_data->tx.up[i].strict_priority |= flag;
+ 				pg_data->rx.up[i].strict_priority |= flag;
+ 			} else {
+-				pg_data->tx.up[i].strict_priority &= ~dcb_group;
+-				pg_data->rx.up[i].strict_priority &= ~dcb_group;
++				pg_data->tx.up[i].strict_priority &= ~DCB_GROUP;
++				pg_data->rx.up[i].strict_priority &= ~DCB_GROUP;
+ 			}
+ 		}
+ 
+@@ -1040,14 +1034,14 @@ static int set_pg_config(pg_attribs *pg_data, char *port_id, char *ibuf,
+ 		for (i = 0; i < MAX_USER_PRIORITIES; i++) {
+ 			if (pg_data->tx.up[i].pgid == LINK_STRICT_PGID ||
+ 				(!used[pg_data->tx.up[i].pgid] &&
+-				pg_data->tx.up[i].strict_priority & dcb_link)) {
++				pg_data->tx.up[i].strict_priority & DCB_LINK)) {
+ 				pg_data->tx.up[i].pgid = flag;
+ 				pg_data->rx.up[i].pgid = flag;
+-				pg_data->tx.up[i].strict_priority = dcb_link;
+-				pg_data->rx.up[i].strict_priority = dcb_link;
++				pg_data->tx.up[i].strict_priority = DCB_LINK;
++				pg_data->rx.up[i].strict_priority = DCB_LINK;
+ 			} else {
+-				pg_data->tx.up[i].strict_priority &= ~dcb_link;
+-				pg_data->rx.up[i].strict_priority &= ~dcb_link;
++				pg_data->tx.up[i].strict_priority &= ~DCB_LINK;
++				pg_data->rx.up[i].strict_priority &= ~DCB_LINK;
+ 			}
+ 		}
+ 	} else if (ilen != off) {
+@@ -1104,9 +1098,9 @@ static int set_pfc_config(pfc_attribs *pfc_data, char *port_id, char *ibuf,
+ 			if (flag == CLIF_NOT_SUPPLIED)
+ 				continue;
+ 			if (flag)
+-				pfc_data->admin[i] = pfc_enabled;
++				pfc_data->admin[i] = PFC_ENABLED;
+ 			else
+-				pfc_data->admin[i] = pfc_disabled;
++				pfc_data->admin[i] = PFC_DISABLED;
+ 		}
+ 	} else if (ilen != off) {
+ 		/* at least needs to include the protocol settings */
+diff --git a/lldp_dcbx_nl.c b/lldp_dcbx_nl.c
+index 33cf257..7a2dad2 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",
+@@ -751,9 +753,9 @@ int set_hw_pfc(char *ifname, dcb_pfc_list_type pfc_data,
+ 
+ 	for (i = 0; i < MAX_TRAFFIC_CLASSES; i++) {
+ 		if (pfc_temp[i])
+-			pfc[i] = pfc_enabled;
++			pfc[i] = PFC_ENABLED;
+ 		else
+-			pfc[i] = pfc_disabled;
++			pfc[i] = PFC_DISABLED;
+ 	}
+ 
+ 	rval = set_pfc_cfg(ifname, &pfc[0]);
+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 <jens at linux.vnet.ibm.com>
+-  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
+-
+-  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 <net/if.h>
+-#include <sys/queue.h>
+-#include <sys/socket.h>
+-#include <sys/ioctl.h>
+-#include <sys/utsname.h>
+-#include <assert.h>
+-#include <linux/if_bridge.h>
+-
+-#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 *)&eth, 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..85c6abc
+--- /dev/null
++++ b/lldp_evb22.c
+@@ -0,0 +1,565 @@
++/******************************************************************************
++
++  Implementation of EVB TLVs for LLDP
++  (c) Copyright IBM Corp. 2012
++
++  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++
++  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 <stdio.h>
++#include <stdlib.h>
++
++#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);
++	qbg.u.b.evbon = ed->txmit;
++	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);
++	if (is_tlv_txenabled(ifname, agent->type,
++			     TLVID(OUI_IEEE_8021Qbg, LLDP_EVB_SUBTYPE))) {
++		LLDPAD_ERR("%s:%s evb draft 0.2 protocol already enabled\n",
++			   __func__, ifname);
++		return;
++	}
++
++	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) {
++		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 <tmricht at linux.vnet.ibm.com>
++
++  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 <stdio.h>
++#include <stdlib.h>
++
++#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..cebfeb2
+--- /dev/null
++++ b/lldp_evb22_cmds.c
+@@ -0,0 +1,750 @@
++/******************************************************************************
++
++  Implementation of EVB TLVs for LLDP
++  (c) Copyright IBM Corp. 2012
++
++  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++
++  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 <string.h>
++#include <stdio.h>
++#include <stdlib.h>
++
++#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, &param, 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, &param, 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)
++{
++	/*
++	 * Make sure either evb draft 0.2 or evb ratified standard is
++	 * running at the same time but not both.
++	 */
++	if (!strcasecmp(argvalue, VAL_YES)
++	    && is_tlv_txenabled(cmd->ifname, cmd->type,
++				TLVID(OUI_IEEE_8021Qbg,
++				      LLDP_EVB_SUBTYPE))) {
++		LLDPAD_ERR("%s:%s evb draft 0.2 protocol already enabled\n",
++			   __func__, cmd->ifname);
++		return cmd_failed;
++	}
++	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..eec4f33 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;
+@@ -253,26 +262,37 @@ static int set_arg_tlvtxenable(struct cmd *cmd, char *arg, char *argvalue,
+ static int test_arg_tlvtxenable(struct cmd *cmd, char *arg, char *argvalue,
+ 				UNUSED char *obuf, UNUSED int obuf_len)
+ {
++	/*
++	 * Make sure either evb draft 0.2 or evb ratified standard is
++	 * running at the same time but not both.
++	 */
++	if (!strcasecmp(argvalue, VAL_YES)
++	    && is_tlv_txenabled(cmd->ifname, cmd->type,
++				TLVID(OUI_IEEE_8021Qbg22,
++				      LLDP_EVB22_SUBTYPE))) {
++		LLDPAD_ERR("%s:%s evb protocol already enabled\n",
++			   __func__, cmd->ifname);
++		return cmd_failed;
++	}
+ 	return _set_arg_tlvtxenable(cmd, arg, argvalue, true);
+ }
+ 
+ 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 +316,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 +361,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 +436,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 +478,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 +510,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 +549,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 +579,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 <tmricht at linux.vnet.ibm.com>
+-
+-  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 <stdio.h>
+-#include <linux/if_ether.h>
+-
+-#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..33b4d19 100644
+--- a/lldp_rtnl.c
++++ b/lldp_rtnl.c
+@@ -46,45 +46,6 @@
+ 
+ #define NLMSG_SIZE 1024
+ 
+-/*
+- * Helper functions to construct a netlink message.
+- * The functions assume the nlmsghdr.nlmsg_len is set correctly.
+- */
+-void mynla_nest_end(struct nlmsghdr *nlh, struct nlattr *start)
+-{
+-	start->nla_type |= NLA_F_NESTED;
+-	start->nla_len = (void *)nlh + nlh->nlmsg_len - (void *)start;
+-}
+-
+-struct nlattr *mynla_nest_start(struct nlmsghdr *nlh, int type)
+-{
+-	struct nlattr *ap = (struct nlattr *)((void *)nlh + nlh->nlmsg_len);
+-
+-	ap->nla_type = type;
+-	nlh->nlmsg_len += NLA_HDRLEN;
+-	return ap;
+-}
+-
+-void mynla_put(struct nlmsghdr *nlh, int type, size_t len, void *data)
+-{
+-	struct nlattr *ap = (struct nlattr *)((void *)nlh + nlh->nlmsg_len);
+-
+-	ap->nla_type = type;
+-	ap->nla_len = NLA_HDRLEN + len;
+-	memcpy(ap + 1, data, len);
+-	nlh->nlmsg_len += NLA_HDRLEN + NLA_ALIGN(len);
+-}
+-
+-void mynla_put_u16(struct nlmsghdr *nlh, int type, __u16 data)
+-{
+-	mynla_put(nlh, type, sizeof data, &data);
+-}
+-
+-void mynla_put_u32(struct nlmsghdr *nlh, int type, __u32 data)
+-{
+-	mynla_put(nlh, type, sizeof data, &data);
+-}
+-
+ typedef int rtnl_handler(struct nlmsghdr *nh, void *arg);
+ 
+ /**
+@@ -173,7 +134,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 +262,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 <jens at linux.vnet.ibm.com>
+-  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
+-
+-  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 <stdio.h>
+-#include <stdlib.h>
+-#include <unistd.h>
+-#include <net/if.h>
+-#include <sys/queue.h>
+-#include <sys/socket.h>
+-#include <sys/ioctl.h>
+-#include <sys/utsname.h>
+-#include <linux/if_bridge.h>
+-#include <errno.h>
+-#include <assert.h>
+-#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 <mac,vlan> 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 <jens at linux.vnet.ibm.com>
+-  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
+-
+-  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 <stdio.h>
+-#include <stdlib.h>
+-#include <syslog.h>
+-#include <sys/un.h>
+-#include <sys/stat.h>
+-#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 <jens at linux.vnet.ibm.com>
+-  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
+-
+-  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 <stdlib.h>
+-#include <stdio.h>
+-#include <syslog.h>
+-#include <sys/un.h>
+-#include <sys/stat.h>
+-#include <arpa/inet.h>
+-#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) {
++		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 lock file\n");
+-			exit(1);
++			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/lldpad_shm.c b/lldpad_shm.c
+index bbd001f..4afcf73 100644
+--- a/lldpad_shm.c
++++ b/lldpad_shm.c
+@@ -253,8 +253,8 @@ int lldpad_shm_get_dcbx(const char *device_name)
+ 	for (i = 0; i < num_entries; i++) {
+ 		if (strcmp(shmaddr->ent[i].ifname, device_name) == 0) {
+ 			switch (shmaddr->ent[i].dcbx_mode) {
+-			case dcbx_subtype1:
+-			case dcbx_subtype2:
++			case DCBX_SUBTYPE1:
++			case DCBX_SUBTYPE2:
+ 				rval = shmaddr->ent[i].dcbx_mode;
+ 				break;
+ 			default:
+@@ -303,8 +303,8 @@ int lldpad_shm_set_dcbx(const char *device_name, int dcbx_mode)
+ 	if (num_entries > MAX_LLDPAD_SHM_ENTRIES)
+ 		goto done;
+ 
+-	if ((dcbx_mode != dcbx_subtype0) && (dcbx_mode != dcbx_subtype1) &&
+-	    (dcbx_mode != dcbx_subtype2))
++	if ((dcbx_mode != DCBX_SUBTYPE0) && (dcbx_mode != DCBX_SUBTYPE1) &&
++	    (dcbx_mode != DCBX_SUBTYPE2))
+ 		goto done;
+ 
+ 	/* search for existing entry */
+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/parse_cli.l b/parse_cli.l
+index 529c563..3717aff 100644
+--- a/parse_cli.l
++++ b/parse_cli.l
+@@ -226,19 +226,19 @@ gp	{ if (!cmd) {
+ 				BEGIN(cmddone);
+ 				}
+ 
+-<getdcbxver>cee			{ dcbx_version = dcbx_subtype2;
++<getdcbxver>cee			{ dcbx_version = DCBX_SUBTYPE2;
+ 				BEGIN(cmddone);
+ 				}
+ 
+-<getdcbxver>cin			{ dcbx_version = dcbx_subtype1;
++<getdcbxver>cin			{ dcbx_version = DCBX_SUBTYPE1;
+ 				BEGIN(cmddone);
+ 				}
+ 
+-<getdcbxver>force-cee		{ dcbx_version = dcbx_force_subtype2;
++<getdcbxver>force-cee		{ dcbx_version = DCBX_FORCE_SUBTYPE2;
+ 				BEGIN(cmddone);
+ 				}
+ 
+-<getdcbxver>force-cin		{ dcbx_version = dcbx_force_subtype1;
++<getdcbxver>force-cin		{ dcbx_version = DCBX_FORCE_SUBTYPE1;
+ 				BEGIN(cmddone);
+ 				}
+ 
+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 <jens at linux.vnet.ibm.com>
++  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++
++  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 <net/if.h>
++#include <sys/queue.h>
++#include <sys/socket.h>
++#include <sys/ioctl.h>
++#include <sys/utsname.h>
++#include <assert.h>
++#include <linux/if_bridge.h>
++
++#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 *)&eth, 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..4640701
+--- /dev/null
++++ b/qbg/ecp22.c
+@@ -0,0 +1,1055 @@
++/******************************************************************************
++
++  Implementation of ECP according to 802.1Qbg
++  (c) Copyright IBM Corp. 2010, 2012
++
++  Author(s): Jens Osterkamp <jens at linux.vnet.ibm.com>
++  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++
++  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 <stdio.h>
++#include <assert.h>
++#include <sys/socket.h>
++#include <errno.h>
++
++#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);
++}
++
++static void ecp22_append(u8 *buffer, u32 *pos, void *data, u32 len)
++{
++	if (*pos + len > ETH_FRAME_LEN)
++		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 *)&eth, 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);
++	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 *)&ethdst->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 <jens at linux.vnet.ibm.com>
+-  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
+-
+-  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 <stdio.h>
+-#include <assert.h>
+-#include <sys/socket.h>
+-#include <errno.h>
+-
+-#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 *)&eth, 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 *)&ethdst->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 <tmricht at linux.vnet.ibm.com>
+-
+-  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 <stdio.h>
+-#include <stdlib.h>
+-
+-#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 <tmricht at linux.vnet.ibm.com>
+-
+-  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 <stdio.h>
+-#include <stdlib.h>
+-
+-#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 <tmricht at linux.vnet.ibm.com>
+-
+-  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 <string.h>
+-#include <stdio.h>
+-#include <stdlib.h>
+-
+-#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, &param, 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, &param, 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 <tmricht at linux.vnet.ibm.com>
+-
+-  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 <stdio.h>
+-#include <stdlib.h>
+-#include <errno.h>
+-
+-#include <net/if.h>
+-
+-#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 <tmricht at linux.vnet.ibm.com>
+-
+-  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 <stdlib.h>
+-#include <unistd.h>
+-#include <errno.h>
+-
+-#include <sys/socket.h>
+-
+-#include <net/if.h>
+-#include <netlink/attr.h>
+-#include <netlink/msg.h>
+-
+-#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..074a1e1
+--- /dev/null
++++ b/qbg/vdp.c
+@@ -0,0 +1,1916 @@
++/******************************************************************************
++
++  Implementation of VDP according to IEEE 802.1Qbg
++  (c) Copyright IBM Corp. 2010, 2012
++
++  Author(s): Jens Osterkamp <jens at linux.vnet.ibm.com>
++  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++
++  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 <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <net/if.h>
++#include <sys/queue.h>
++#include <sys/socket.h>
++#include <sys/ioctl.h>
++#include <sys/utsname.h>
++#include <linux/if_bridge.h>
++#include <errno.h>
++#include <assert.h>
++#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 <mac,vlan> 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 {
++
++		/*
++		 * Libvirt sends dis-assoc command and no profile active.
++		 * Add to list with successful status to return the success
++		 * to libvirtd when it queries for results.
++		 */
++		if (profile->mode == VDP_MODE_DEASSOCIATE) {
++			profile->response = VDP_RESPONSE_SUCCESS;
++			LLDPAD_DBG("%s: dis-assoc without profile\n", __func__);
++		} else
++			profile->response = VDP_RESPONSE_NO_RESPONSE;
++
++		LIST_INSERT_HEAD(&vd->profile_head, profile, profile);
++	}
++
++	if (profile->response != VDP_RESPONSE_SUCCESS)
++		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..a3cb7c9
+--- /dev/null
++++ b/qbg/vdp22.c
+@@ -0,0 +1,1081 @@
++/******************************************************************************
++
++  Implementation of VDP22 protocol for IEEE 802.1 Qbg ratified standard
++  (c) Copyright IBM Corp. 2013
++
++  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++
++  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 <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <errno.h>
++#include <ctype.h>
++
++#include <net/if.h>
++
++#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"
++#include "qbg_vdp22_cmds.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;
++}
++
++static 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 fmt, unsigned char *vsi_uuid)
++{
++	bool rc = true;
++
++	switch (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->vsi_idfmt, 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->vsi_idfmt, 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 = vdp22_set_vlanid(from->vlan)
++				| vdp22_set_qos(from->qos);
++		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;
++		vdp->evbon = ptr->evbon;
++		LLDPAD_DBG("%s:%s rwd:%d rka:%d gpid:%d retry:%d rte:%d evb:%d\n",
++			   __func__, ifname, ptr->max_rwd, ptr->max_rka,
++			   ptr->gpid, ptr->max_retry, ptr->max_rte, ptr->evbon);
++		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;
++	struct vsi22 *vsi;
++
++	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;
++	}
++
++	LIST_FOREACH(vsi, &vdp->vsi22_que, node) {
++		vdp22_stop_timers(vsi);
++	}
++}
++
++/*
++ * 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;
++	struct vsi22 *vsi;
++
++	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);
++	} else {
++		LIST_FOREACH(vsi, &vdp->vsi22_que, node) {
++			vsi->smi.localchg = true;
++			vdp22_showvsi(vsi);
++			vdp22_start_localchange_timer(vsi);
++		}
++	}
++}
++
++/*
++ * Handle a VSI request from buddy.
++ */
++int vdp22_request(struct vdpnl_vsi *vsi, int clif)
++{
++	int rc;
++	struct vsi22 *p;
++	struct vdp22 *vdp;
++
++	LLDPAD_DBG("%s:%s clif:%d\n", __func__, vsi->ifname, clif);
++	vdp = vdp22_findif(vsi->ifname, NULL);
++	if (vdp) {
++		if (!vdp->evbon) {
++			rc = -EPROTONOSUPPORT;
++			goto out;
++		}
++		if (vdp->myrole == VDP22_BRIDGE) {
++			rc = -EOPNOTSUPP;
++			goto out;
++		}
++		/* Adjust numbering for VDP 0.2 protocol from netlink */
++		if (!clif)
++			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 int clnt(void *data, struct sockaddr_un *from, socklen_t fromlen,
++		      char *ibuf, int ilen, char *rbuf, int rlen)
++{
++	return vdp22_clif_cmd(data, from, fromlen, ibuf, ilen, rbuf, rlen);
++}
++
++static const struct lldp_mod_ops vdp22_ops =  {
++	.lldp_mod_register	= vdp22_register,
++	.lldp_mod_unregister	= vdp22_unregister,
++	.lldp_mod_notify	= vdp22_notify,
++	.get_arg_handler	= vdp22_arg_handlers,
++	.client_cmd		= clnt,
++};
++
++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->maclist = calloc(p->no_fdata, sizeof(*vsi->maclist));
++	if (!vsi->maclist)
++		return;
++	vsi->macsz = p->no_fdata;
++	vsi->filter_fmt = p->fif;
++	for (i = 0; i < p->no_fdata; ++i) {
++		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;
++		memcpy(vsi->maclist[i].mac, p->fdata[i].mac,
++		       sizeof(vsi->maclist[i].mac));
++	}
++}
++
++/*
++ * Fill the VSI data to return to caller. Currently returned data depends
++ * on requestor:
++ * 1. Via netlink message from libvirtd and vdptest:
++ *    Return UUID, Response when available. changed FID.
++ * 2. Via lldptool:
++ *    All data.
++ */
++static void copy_vsi(struct vdpnl_vsi *vsi, struct vsi22 *p, int clif)
++{
++	/* For netlink reply */
++	vsi->response = p->status;
++	memcpy(vsi->vsi_uuid, p->vsi, sizeof(vsi->vsi_uuid));
++	/* For client interface reply */
++	vsi->request = p->vsi_mode;
++	vsi->vsi_typeid = p->type_id;
++	vsi->vsi_typeversion = p->type_ver;
++	memcpy(vsi->vsi_mgrid2, p->mgrid, sizeof(vsi->vsi_mgrid2));
++	vsi->vsi_idfmt = p->vsi_fmt;
++	vsi->hints = p->cc_vsi_mode;
++	p->flags &= ~VDP22_NLCMD;
++	if (clif || (p->flags & VDP22_RETURN_VID)) {
++		copy_fid(vsi, p);
++		p->flags &= ~VDP22_RETURN_VID;
++	}
++}
++
++/*
++ * 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, int clif)
++{
++	struct vdp22 *vdp;
++	struct vsi22 *p;
++	int i = 0, ret = 0;
++
++	LLDPAD_DBG("%s:%s clif:%d\n", __func__, vsi->ifname, clif);
++	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);
++		copy_vsi(vsi, p, clif);
++		if (vsi->response != VDP22_RESP_NONE &&
++		    (p->flags & VDP22_DELETE_ME))
++			vdp22_listdel_vsi(p);
++	}
++	LLDPAD_DBG("%s:%s entry:%d more:%d\n", __func__, vsi->ifname,
++		   number, ret);
++	return ret;
++}
++
++/*
++ * Find out if vsi command was received via netlink interface or via
++ * attached control interface. Pid equals zero means control interface.
++ */
++static pid_t havepid(struct vsi22 *vsi)
++{
++	pid_t mypid = 0;
++	int i;
++
++	for (i = 0; i < vsi->no_fdata; ++i)
++		mypid = vsi->fdata[i].requestor.req_pid;
++	return mypid;
++}
++
++/*
++ * Convert and VSI22 to VDP netlink format and send it back to the originator.
++ */
++static int vdp22_back(struct vsi22 *vsi, pid_t to,
++		      int (*fct)(struct vdpnl_vsi *))
++{
++	int i;
++	struct vdpnl_vsi nl;
++	struct vdpnl_mac nlmac[vsi->no_fdata];
++
++	LLDPAD_DBG("%s:%s to:%d\n", __func__, vsi->vdp->ifname, to);
++	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;
++	nl.response = vsi->status;
++	nl.vsi_mgrid = vsi->mgrid[0];
++	memcpy(nl.vsi_mgrid2, vsi->mgrid, sizeof(nl.vsi_mgrid2));
++	nl.vsi_typeversion = vsi->type_ver;
++	nl.vsi_typeid = vsi->type_id;
++	nl.vsi_idfmt = 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 = vdp22_get_vlanid(vsi->fdata[i].vlan);
++		nlmac[i].qos = vdp22_get_qos(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;
++	}
++	if (to)
++		nl.request -= 1;		/* Maintain old number */
++	(*fct)(&nl);
++	if (vsi->flags & VDP22_DELETE_ME)
++		vdp22_listdel_vsi(vsi);
++	return 0;
++}
++
++/*
++ * Send information back to netlink clients. When command was received via
++ * control interface do not send back anything.
++ */
++int vdp22_nlback(struct vsi22 *vsi)
++{
++	pid_t nl_pid = havepid(vsi);
++
++	LLDPAD_DBG("%s:%s vsi:%p(%#2x) nl_pid:%d\n", __func__, vsi->vdp->ifname,
++		   vsi, vsi->vsi[0], nl_pid);
++	return (nl_pid) ? vdp22_back(vsi, nl_pid, vdpnl_send) : 0;
++}
++
++/*
++ * Send information back to attached clients. When command was received via
++ * netlink message do not send back anything.
++ */
++int vdp22_clntback(struct vsi22 *vsi)
++{
++	pid_t nl_pid = havepid(vsi);
++
++	LLDPAD_DBG("%s:%s vsi:%p(%#2x) nl_pid:%d\n", __func__, vsi->vdp->ifname,
++		   vsi, vsi->vsi[0], nl_pid);
++	return (!nl_pid) ? vdp22_back(vsi, 0, vdp22_sendevent) : 0;
++}
++
++/*
++ * Query role. Return error when interface not available or interface is
++ * running in bridge mode.
++ */
++int vdp22_info(const char *ifname)
++{
++	int rc = 0;
++	struct vdp22 *vdp = vdp22_findif(ifname, NULL);
++
++	if (!vdp)
++		rc = -ENODEV;
++	else if (vdp->myrole == VDP22_BRIDGE)
++		rc = -EOPNOTSUPP;
++	LLDPAD_DBG("%s:%s rc:%d\n", __func__, ifname, rc);
++	return rc;
++
++}
+diff --git a/qbg/vdp22_cmds.c b/qbg/vdp22_cmds.c
+new file mode 100644
+index 0000000..a75c02d
+--- /dev/null
++++ b/qbg/vdp22_cmds.c
+@@ -0,0 +1,489 @@
++/*******************************************************************************
++
++  Implementation of VDP 22 (ratified standard) according to IEEE 802.1Qbg
++  (c) Copyright IBM Corp. 2014
++
++  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++
++  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".
++
++*******************************************************************************/
++
++/*
++ * Command line interface for vdp22 module. Handle argument parsing and
++ * setting.
++ */
++
++#include <stdio.h>
++#include <string.h>
++#include <stdlib.h>
++#include <syslog.h>
++#include <sys/un.h>
++#include <errno.h>
++#include <stdbool.h>
++
++#include "lldp.h"
++#include "lldpad.h"
++#include "lldp_mod.h"
++#include "clif_msgs.h"
++#include "libconfig.h"
++#include "config.h"
++#include "messages.h"
++#include "qbg22.h"
++#include "qbg_vdp22def.h"
++#include "qbg_vdp22.h"
++#include "qbg_vdpnl.h"
++#include "qbg_vdp22_cmds.h"
++#include "qbg_vdp22_clif.h"
++
++/*
++ * Find module we are called for.
++ */
++static struct lldp_module *get_my_module(int thisid)
++{
++	struct lldp_module *np = NULL;
++
++	LIST_FOREACH(np, &lldp_head, lldp)
++		if (thisid == np->id)
++			break;
++	return np;
++}
++
++/*
++ * Find argument handlers for module we are called for.
++ */
++static struct arg_handlers *get_my_arghndl(int thisid)
++{
++	struct lldp_module *np;
++	struct arg_handlers *ah = NULL;
++
++	np = get_my_module(thisid);
++	if (np)
++		if (np->ops && np->ops->get_arg_handler)
++			ah = np->ops->get_arg_handler();
++	return ah;
++}
++
++static int handle_get_arg(struct cmd *cmd, char *arg, char *argvalue,
++			  char *obuf, int obuf_len)
++{
++	struct arg_handlers *ah;
++	int rval, status = cmd_not_applicable;
++
++	ah = get_my_arghndl(cmd->module_id);
++	if (!ah)
++		return status;
++	for (; ah->arg; ++ah) {
++		if (!ah->handle_get)
++			continue;
++		if (!strncasecmp(ah->arg, arg, strlen(ah->arg))) {
++			rval = ah->handle_get(cmd, arg, argvalue,
++					      obuf, obuf_len);
++			if (rval != cmd_success &&
++			    rval != cmd_not_applicable)
++				return rval;
++			else if (rval == cmd_success)
++				status = rval;
++			break;
++		}
++	}
++	return status;
++}
++
++static int handle_get(struct cmd *cmd, UNUSED char *arg, char *argvalue,
++		      char *obuf, int obuf_len)
++{
++	struct arg_handlers *ah;
++	int rval;
++	char *nbuf;
++	int nbuf_len;
++
++	memset(obuf, 0, obuf_len);
++	nbuf = obuf + 12;
++	nbuf_len = obuf_len - 12;
++
++	ah = get_my_arghndl(cmd->module_id);
++	if (!ah)
++		return cmd_not_applicable;
++	for (; ah->arg; ++ah) {
++		if (strcmp(ah->arg, ARG_VDP22_VSI))
++			continue;
++		if (ah->handle_get && (ah->arg_class == TLV_ARG)) {
++			rval = ah->handle_get(cmd, ah->arg, argvalue,
++					      nbuf, nbuf_len);
++			if (rval != cmd_success && rval != cmd_not_applicable)
++				return rval;
++
++			nbuf_len -= strlen(nbuf);
++			nbuf = nbuf + strlen(nbuf);
++		}
++	}
++	return cmd_success;
++}
++
++static int handle_test_arg(struct cmd *cmd, char *arg, char *argvalue,
++			   char *obuf, int obuf_len)
++{
++	struct arg_handlers *ah;
++	int rval, status = cmd_not_applicable;
++
++	ah = get_my_arghndl(cmd->module_id);
++	if (!ah)
++		return status;
++	for (; ah->arg; ++ah) {
++		if (!strcasecmp(ah->arg, arg) && ah->handle_test) {
++			rval = ah->handle_test(cmd, ah->arg, argvalue,
++					      obuf, obuf_len);
++			if (rval != cmd_not_applicable &&
++			    rval != cmd_success)
++				return rval;
++			else if (rval == cmd_success)
++				status = rval;
++			break;
++		}
++	}
++	return status;
++}
++
++static int handle_set_arg(struct cmd *cmd, char *arg, char *argvalue,
++			  char *obuf, int obuf_len)
++{
++	struct arg_handlers *ah;
++	int rval, status = cmd_not_applicable;
++
++	ah = get_my_arghndl(cmd->module_id);
++	if (!ah)
++		return status;
++	for (; ah->arg; ++ah) {
++		if (!strcasecmp(ah->arg, arg) && ah->handle_set) {
++			rval = ah->handle_set(cmd, ah->arg, argvalue,
++					      obuf, obuf_len);
++			if (rval != cmd_not_applicable &&
++			    rval != cmd_success)
++				return rval;
++			else if (rval == cmd_success)
++				status = rval;
++			break;
++		}
++	}
++	return status;
++}
++
++/*
++ * Interface function called from attached client. This client can receive
++ * events from lldpad.
++ *
++ * The command string has the following format in ascii:
++ * M000080c4C3020000001c05veth0020080c40003vsi004btext
++ *  aaaaaaaabbccddddddddeefffffgghhhhhhhhiijjjkkkkllll
++ *
++ * with
++ * aaaaaaaa: 8 hex digits module identifier (which has been stripped already)
++ * bb:  C for command and 2 or 3 for message version number
++ * cc: 1 for get command and 2 for set command
++ * dddddddd: 8 hex digits options, supported are op_arg, op_argval, op_conifg
++ *           and op_local
++ * ee: 2 hex digit length of interface name
++ * ffff: string for interface name
++ * gg: 2 hex digit for bridge type (nearest customer bridge only)
++ * hhhhhhhh: 8 hex digit TLV identifier
++ * ii: 2 hex digit length of argument name
++ * jjj: string for argument name
++ * kkkk: 4 hex digits for length of argument value
++ * llll: argument value
++ *
++ * Note the kkkk and llll fields may show up more than once. It depends.
++ * The total input length can be used to determine the number of arguaments.
++ *
++ * The member ops of struct cmd settings depends on the invoked with
++ * -T (cmd_gettlv) -a assoc:
++ * -c key      --> ops=(0x15) op_config,op_arg,op_local), numargs > 0
++ * -c key=abc  --> ops=(0x1d) op_config,op_arg,op_argval,op_local), numargs > 0
++ * -c          --> ops=0x11 (op_config,op_local), numargs = 0
++ * without -c --> ops=0x1 (op_local), numargs = 0
++ *
++ * Without flag op_config being set invoke a function which retrieves all
++ * TLVs for pretty printing. This is currently not supported.
++ *
++ * With flag op_config being set return all currently active VSI associations.
++ */
++int vdp22_clif_cmd(UNUSED void *data, UNUSED struct sockaddr_un *from,
++		   UNUSED socklen_t fromlen,
++		   char *ibuf, int ilen, char *rbuf, int rlen)
++{
++	struct cmd cmd;
++	u8 len, version;
++	int ioff, roff;
++	int rstatus = cmd_invalid;
++	char **args;
++	char **argvals;
++	bool test_failed = false;
++	int numargs = 0;
++	int i, offset;
++
++	memset(&cmd, 0, sizeof(cmd));
++	cmd.module_id = LLDP_MOD_VDP22;
++	/* Pull out the command elements of the command message */
++	hexstr2bin(ibuf + MSG_VER, (u8 *)&version, sizeof(u8));
++	version = 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 rstatus;
++
++	cmd.ifname[len] = '\0';
++	ioff += len;
++
++	if (version == CLIF_MSG_VERSION) {
++		hexstr2bin(ibuf+ioff, &cmd.type, sizeof(cmd.type));
++		ioff += 2 * sizeof(cmd.type);
++	} else {
++		return cmd_not_applicable;
++	}
++
++	if (cmd.cmd == cmd_gettlv || cmd.cmd == cmd_settlv) {
++		hexstr2bin(ibuf + ioff, (u8 *)&cmd.tlvid, sizeof(cmd.tlvid));
++		cmd.tlvid = ntohl(cmd.tlvid);
++		ioff += 2 * sizeof(cmd.tlvid);
++		if (cmd.tlvid != VDP22_ASSOC && cmd.tlvid != VDP22_DEASSOC
++		    && cmd.tlvid != VDP22_PREASSOC
++		    && cmd.tlvid != VDP22_PREASSOC_WITH_RR)
++			return cmd_invalid;
++	} else {
++		return cmd_not_applicable;
++	}
++
++	if (!(cmd.ops & op_config))
++		return cmd_invalid;
++
++	/* Count args and argvalues */
++	offset = ioff;
++	for (numargs = 0; (ilen - offset) > 2; numargs++) {
++		offset += 2;
++		if (ilen - offset > 0) {
++			offset++;
++			if (ilen - offset > 4)
++				offset += 4;
++		}
++	}
++
++	args = calloc(numargs, sizeof(char *));
++	if (!args)
++		return cmd_failed;
++
++	argvals = calloc(numargs, sizeof(char *));
++	if (!argvals) {
++		free(args);
++		return cmd_failed;
++	}
++
++	if ((cmd.ops & op_arg) && (cmd.ops & op_argval))
++		numargs = get_arg_val_list(ibuf, ilen, &ioff, args, argvals);
++	else if (cmd.ops & op_arg)
++		numargs = get_arg_list(ibuf, ilen, &ioff, args);
++
++	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);
++	roff = strlen(rbuf);
++
++	/* 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;
++	}
++
++	snprintf(rbuf + roff, rlen - roff, "%08x", cmd.tlvid);
++	roff += 8;
++	if (cmd.cmd == cmd_gettlv) {
++		if (!numargs)
++			rstatus = handle_get(&cmd, NULL, NULL,
++					     rbuf + strlen(rbuf),
++					     rlen - strlen(rbuf));
++		else
++			for (i = 0; i < numargs; i++)
++				rstatus = handle_get_arg(&cmd, args[i], NULL,
++							 rbuf + strlen(rbuf),
++							 rlen - strlen(rbuf));
++	} else {
++		for (i = 0; i < numargs; i++) {
++			rstatus = handle_test_arg(&cmd, args[i], argvals[i],
++						  rbuf + strlen(rbuf),
++						  rlen - strlen(rbuf));
++			if (rstatus != cmd_not_applicable &&
++			    rstatus != cmd_success)
++				test_failed = true;
++		}
++		if (!test_failed)
++			for (i = 0; i < numargs; i++)
++				rstatus = handle_set_arg(&cmd, args[i],
++							 argvals[i],
++							 rbuf + strlen(rbuf),
++							 rlen - strlen(rbuf));
++	}
++
++	free(argvals);
++	free(args);
++	return rstatus;
++}
++
++/*
++ * Trigger an event to an attached client.
++ */
++int vdp22_sendevent(struct vdpnl_vsi *p)
++{
++	char msg[MAX_CLIF_MSGBUF];
++
++	vdp_vdpnl2str(p, msg, sizeof(msg));
++	LLDPAD_DBG("%s:%s vsi:%p(%#2x), len:%zd msg:%s\n", __func__,
++		   p->ifname, p, p->vsi_uuid[0], strlen(msg), msg);
++	send_event(16, LLDP_MOD_VDP22, msg);
++	return 0;
++}
++
++static int vdp22_cmdok(struct cmd *cmd, cmd_status expected)
++{
++	if (cmd->cmd != expected)
++		return cmd_invalid;
++
++	switch (cmd->module_id) {
++	case LLDP_MOD_VDP22:
++		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;
++	}
++}
++
++/*
++ * Test if role is station and VDP protocol supported for this interface.
++ * Needed to enable testing of possible command failure.
++ */
++static int ifok(struct cmd *cmd)
++{
++	cmd_status good_cmd = cmd_success;
++
++	switch (vdp22_info(cmd->ifname)) {
++	case -ENODEV:
++		good_cmd = cmd_device_not_found;
++		break;
++	case -EOPNOTSUPP:
++		good_cmd = cmd_not_applicable;
++		break;
++	}
++	return good_cmd;
++}
++
++static int set_arg_vsi3(struct cmd *cmd, char *argvalue, bool test, int size)
++{
++	cmd_status good_cmd = vdp22_cmdok(cmd, cmd_settlv);
++	int rc;
++	struct vdpnl_vsi vsi;
++	struct vdpnl_mac mac[size];
++
++	if (good_cmd != cmd_success)
++		return good_cmd;
++
++	memset(&vsi, 0, sizeof(vsi));
++	memset(&mac, 0, sizeof(mac));
++	vsi.maclist = mac;
++	vsi.macsz = size;
++	rc = vdp_str2vdpnl(argvalue, &vsi, cmd->ifname);
++	if (rc) {
++		good_cmd = cmd_bad_params;
++		goto out;
++	}
++	if (!port_find_by_ifindex(get_ifidx(cmd->ifname))) {
++		good_cmd = cmd_device_not_found;
++		goto out;
++	}
++	good_cmd = ifok(cmd);
++	if (good_cmd != cmd_success || test)
++		goto out;
++	rc = vdp22_request(&vsi, 1);
++	if (!rc)
++		good_cmd = cmd_success;
++	else if (rc == -ENODEV)
++		good_cmd = cmd_device_not_found;
++	else
++		good_cmd = cmd_failed;
++out:
++	return good_cmd;
++}
++
++/*
++ * Count the number of fid data fields in the argument value.
++ */
++#define	VDP22_FID_IDX	6		/* Min index of fid data */
++static int count_fid(char *argvalue)
++{
++	char *p = argvalue;
++	int i;
++
++	for (i = 0; (p = strchr(p, ',')); ++i, ++p)
++		;
++	return i + 1 - VDP22_FID_IDX;
++}
++
++static int set_arg_vsi2(struct cmd *cmd, char *argvalue, bool test)
++{
++	int no = count_fid(argvalue);
++
++	if (no <= 0)
++		return -EINVAL;
++	return set_arg_vsi3(cmd, argvalue, test, no);
++}
++
++static int set_arg_vsi(struct cmd *cmd, UNUSED char *arg, char *argvalue,
++			UNUSED char *obuf, UNUSED int obuf_len)
++{
++	return set_arg_vsi2(cmd, argvalue, false);
++}
++
++static int test_arg_vsi(struct cmd *cmd, UNUSED char *arg, char *argvalue,
++			 UNUSED char *obuf, UNUSED int obuf_len)
++{
++	return set_arg_vsi2(cmd, argvalue, true);
++}
++
++static struct arg_handlers arg_handlers[] = {
++	{
++		.arg = ARG_VDP22_VSI,
++		.arg_class = TLV_ARG,
++		.handle_set = set_arg_vsi,
++		.handle_test = test_arg_vsi
++	},
++	{
++		.arg = 0
++	}
++};
++
++struct arg_handlers *vdp22_arg_handlers()
++{
++	return &arg_handlers[0];
++}
+diff --git a/qbg/vdp22br.c b/qbg/vdp22br.c
+new file mode 100644
+index 0000000..03bb00b
+--- /dev/null
++++ b/qbg/vdp22br.c
+@@ -0,0 +1,190 @@
++/******************************************************************************
++
++  Implementation of VDP 2.2 bridge resource allocation simulator for LLDP
++  (c) Copyright IBM Corp. 2013
++
++  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++
++  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 <string.h>
++
++#include <net/if.h>
++#include <netinet/in.h>
++
++#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;
++	deassoc_qbg.u.c.data = deassoc_buf;
++	memcpy(deassoc_buf, vdp->input, vdp->input_len);
++	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 vdp->input_len:%d\n", __func__, vdp->ifname,
++		   vdp->input_len);
++}
++
++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..d1f65b4
+--- /dev/null
++++ b/qbg/vdp22sm.c
+@@ -0,0 +1,1752 @@
++/******************************************************************************
++
++  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 <tmricht at linux.vnet.ibm.com>
++
++  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 <assert.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <errno.h>
++
++#include <net/if.h>
++#include <netinet/in.h>
++
++#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 = 0x80,		/* VSI reserved bit */
++	VDP22_ACKBIT = 0x40,		/* VSI Acknowledgement bit */
++	VDP22_KEEPBIT = 0x20,		/* VSI keep error bit */
++	VDP22_HARDBIT = 0x10,		/* VSI hard error bit */
++	VDP22_STATUS_MASK = 0x0f,	/* Status mask */
++	VDP22_STATUS_SHIFT = 0,		/* 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.
++ * Notification of clients depends on the interface used to establish the
++ * association:
++ * 1. When through netlink interface (draft 0.2) the client is polling for some
++ *    time. In this case send a netlink message only when no command pending.
++ * 2. When through attached client (draft 2.2) the client is waiting for
++ *    response (time out in operation on client side) and does not poll.
++ */
++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);	/* Notify netlink when no cmd pending */
++	vdp22_clntback(vsi);		/* Notify attached client */
++}
++
++/*
++ * 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);
++			vdp22_clntback(vsi);
++			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);
++}
++
++static void vdp22_localchange_handler(UNUSED void *eloop_data, void *user_ctx)
++{
++	struct vsi22 *vsi;
++
++	vsi = (struct vsi22 *) user_ctx;
++
++	if ((vsi->smi.localchg)) {
++		LLDPAD_DBG("%s:%s p->localChange %i p->ackReceived %i\n",
++			   __func__, vsi->vdp->ifname, vsi->smi.localchg,
++			  vsi->smi.ackreceived);
++		vdp22st_run(vsi);
++	}
++}
++
++int vdp22_start_localchange_timer(struct vsi22 *p)
++{
++	return eloop_register_timeout(0, 100, vdp22_localchange_handler, NULL,
++				      (void *) p);
++}
++
++/*
++ * 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, 2 * 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 > VDP22_STATUS_MASK)
++			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);
++}
++
++void vdp22_stop_timers(struct vsi22 *vsi)
++{
++	vdp22st_stop_acktimer(vsi);
++	vdp22st_stop_katimer(vsi);
++}
++
++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_ascii.c b/qbg/vdp_ascii.c
+new file mode 100644
+index 0000000..0ace562
+--- /dev/null
++++ b/qbg/vdp_ascii.c
+@@ -0,0 +1,479 @@
++/******************************************************************************
++
++  Implementation of VDP 22 (ratified standard) according to IEEE 802.1Qbg
++  (c) Copyright IBM Corp. 2014
++
++  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++
++  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".
++
++******************************************************************************/
++
++/*
++ * Convertion function for data exchange between lldptool and lldpad.
++ * Get an ascii string and convert it to a vdpnl_vsi structure.
++ * Get a vdpnl_vsi structure and convert it to an ascii string.
++ */
++
++#include <stdlib.h>
++#include <string.h>
++#include <stdio.h>
++#include <ctype.h>
++#include <errno.h>
++#include <unistd.h>
++#include <stdbool.h>
++
++#include <net/if.h>
++
++#include "qbg_vdp22def.h"
++#include "qbg_vdp22.h"
++#include "qbg_vdpnl.h"
++#include "qbg_utils.h"
++
++/*
++ * Check if it is a UUID and consists  of hexadecimal digits and dashes only.
++ * If so convert it to UUID.
++ */
++int vdp_str2uuid(unsigned char *to, char *buffer, size_t max)
++{
++	unsigned int i, j = 0;
++	size_t buffer_len = strlen(buffer);
++
++	if (strspn(buffer, "01234567890AaBbCcDdEeFf-") != buffer_len)
++		return -1;
++	memset(to, 0, max);
++	for (i = 0; i < buffer_len && j < max; i++) {
++		if (buffer[i] == '-')
++			continue;
++		if (sscanf(&buffer[i], "%02hhx", &to[j]) == 1) {
++			i++;
++			j++;
++		}
++	}
++	if (i < buffer_len)
++		return -2;		/* Not enough space */
++	return 0;
++}
++
++/*
++ * Convert a 16byte uuid to string. Insert dashes for better readability.
++ */
++int vdp_uuid2str(const unsigned char *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;
++}
++
++/*
++ * Return true if string is a number between min and max.
++ */
++static bool getnumber(char *s, unsigned int min, unsigned int max,
++		      unsigned int *no)
++{
++	char *myend;
++
++	*no = strtol(s, &myend, 0);
++	if (s && *myend == '\0' && min <= *no && *no <= max)
++		return true;
++	return false;
++}
++
++/*
++ * Read filter information data. The format is an ascii string:
++ * filter-data		filter-format
++ * vlan			1
++ * vlan-mac		2
++ * vlan--group		3
++ * vlan-mac-group	4
++ */
++static bool getfid(struct vdpnl_vsi *p, char *value, long idx)
++{
++	char *delim2 = 0, *delim = strchr(value, '-');
++	unsigned int vlan, gpid = 0;
++	int fif, i, have_mac = 1, have_gpid = 1;
++	unsigned char x[ETH_ALEN];
++
++	memset(x, 0, sizeof(x));
++	if (!delim)		/* No dash --> no mac, no group */
++		have_gpid = have_mac = 0;
++	else {
++		*delim = '\0';
++		delim2 = strchr(delim + 1, '-');
++		if (!delim2)	/* No 2nd dash --> have mac but no group */
++			have_gpid = 0;
++		else {		/* 2 dashes --> check for mac */
++			*delim2 = '\0';
++			if (delim + 1 == delim2)
++				/* -- means vlan and group without mac */
++				have_mac = 0;
++		}
++	}
++	if (!getnumber(value, 0, 0xffff, &vlan))
++		return false;
++	fif = VDP22_FFMT_VID;
++	if (have_mac) {
++		i = sscanf(delim + 1,
++			   "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
++			   &x[0], &x[1], &x[2], &x[3], &x[4], &x[5]);
++		if (i != ETH_ALEN)
++			return false;
++		fif = VDP22_FFMT_MACVID;
++	}
++
++	/* Check for optional group identifier */
++	if (have_gpid && *(delim2 + 1)) {
++		if (!getnumber(delim2 + 1, 1, ~0U, &gpid))
++			return false;
++		fif += 2;
++	}
++
++	/* We already have filter information data, filter format must match */
++	if (p->filter_fmt && p->filter_fmt != fif)
++		return false;
++	p->filter_fmt = fif;
++
++	/* Check if this mac is already in our list */
++	for (i = 0; have_mac && i < p->macsz; ++i) {
++		if (!memcmp(x, p->maclist[i].mac, sizeof(p->maclist[i].mac)))
++			return false;
++	}
++
++	/* Append to end of list */
++	p->maclist[idx].vlan = vdp22_get_vlanid(vlan);
++	p->maclist[idx].qos = vdp22_get_qos(vlan);
++	p->maclist[idx].gpid = gpid;
++	memcpy(p->maclist[idx].mac, x, sizeof(p->maclist[0].mac));
++	return true;
++}
++
++/*
++ * Read manager identifier (max 16 bytes). Check if it is a UUID and consists
++ * of hexadecimal digits only. If so convert it to UUID.
++ */
++static bool getmgr2id(struct vdpnl_vsi *p, char *s)
++{
++	bool is_good;
++	size_t cnt = 0, i, slen = strlen(s);
++	char *s_old = s;
++
++	if (vdp_str2uuid(p->vsi_mgrid2, s, sizeof(p->vsi_mgrid2)) == 0)
++		return true;
++	/* Check for alphanumeric string */
++	for (i = 0; i < slen; ++i, ++s)
++		if (isalnum(*s))
++			++cnt;
++	is_good = cnt == slen && cnt < sizeof(p->vsi_mgrid2);
++	if (is_good)
++		memcpy(p->vsi_mgrid2, s_old, cnt);
++	return is_good;
++}
++
++/*
++ * Read VSI VM hints.
++ */
++static bool gethints(struct vdpnl_vsi *p, char *s)
++{
++	if (!strcasecmp(s, "to"))
++		p->hints = VDP22_MIGTO;
++	else if (!strcasecmp(s, "from"))
++		p->hints = VDP22_MIGFROM;
++	else if (!strcasecmp(s, "none") || !strcasecmp(s, "-"))
++		p->hints = 0;
++	else
++		return false;
++	return true;
++}
++
++/*
++ * Read VSI association mode. If can be followed by an error code in brackets.
++ * For vdp22 protocol the allowed words are assoc, preassoc, preassoc-rr and
++ * deassoc.
++ * For vdp draft 0.2 the allowed commands are 0, 1, 2 and 3.
++ */
++static bool getmode(struct vdpnl_vsi *p, char *s)
++{
++	char *myend, *bracket = strchr(s, '[');
++	int no;
++
++	if (strlen(s) == 1) {
++		switch (*s) {
++		case '0':	p->request = VDP22_PREASSOC;
++				break;
++		case '1':	p->request = VDP22_PREASSOC_WITH_RR;
++				break;
++		case '2':	p->request = VDP22_ASSOC;
++				break;
++		case '3':	p->request = VDP22_DEASSOC;
++				break;
++		default:	return false;
++		}
++		p->request -= 1;
++		p->nl_version = vdpnl_nlf1;
++		return true;
++	}
++
++	if (bracket) {
++		*bracket = '\0';
++		no = strtol(bracket + 1, &myend, 0);
++		if (*myend != ']')
++			return false;
++		p->response = no;
++	}
++	if (!strcasecmp(s, "assoc"))
++		p->request = VDP22_ASSOC;
++	else if (!strcasecmp(s, "preassoc"))
++		p->request = VDP22_PREASSOC;
++	else if (!strcasecmp(s, "preassoc-rr"))
++		p->request = VDP22_PREASSOC_WITH_RR;
++	else if (!strcasecmp(s, "deassoc"))
++		p->request = VDP22_DEASSOC;
++	else
++		return false;
++	p->nl_version = vdpnl_nlf2;
++	return true;
++}
++
++/*
++ * Parse the mode parameter to create/change an VSI assoication.
++ * The format is a comma separated list of tokens:
++ * cmd,mgrid,typeid,typeidversion,vsiid,hints,fid[,fid,fid,...]
++ * with
++ * cmd := "assoc" | "deassoc" | "preassoc" | "preassoc-rr"
++ * mgrid :=  less or equal to 16 byte alphanumeric characters
++ *		| UUID (with dashes in between)
++ * typeid := number in range of 1 - 2^24 -1
++ * typeidversion:= number in range of 1 - 255
++ * vsiid := UUID (with dashes in between)
++ * hints := varies between input (command) and output (event message)
++ *          on input --> dash (-) | "none" | "from" | "to"
++ *          on output --> response (number between 0..255)
++ * fid := vlan
++ *	| vlan-mac
++ *	| vlan--group
++ *	| vlan-mac-group
++ * vlan := number in range of 1..2^16 -1
++ * group := number in range of 1..2^32 - 1
++ * mac := xx:xx:xx:xx:xx:xx
++ */
++
++static int str2vdpnl(char *argvalue, struct vdpnl_vsi *vsi)
++{
++	int rc = -ENOMEM;
++	unsigned int no;
++	unsigned short idx;
++	char *cmdstring, *token;
++
++	cmdstring = strdup(argvalue);
++	if (!cmdstring)
++		goto out_free;
++	rc = -EINVAL;
++	/* 1st field is VSI command */
++	token = strtok(cmdstring, ",");
++	if (!token || !getmode(vsi, token))
++		goto out_free;
++
++	/* 2nd field is VSI Manager Identifer (16 bytes maximum) */
++	token = strtok(NULL, ",");
++	if (!token || !getmgr2id(vsi, token))
++		goto out_free;
++
++	/* 3rd field is type identifier */
++	token = strtok(NULL, ",");
++	if (!token || !getnumber(token, 0, 0xffffff, &no))
++		goto out_free;
++	vsi->vsi_typeid = no;
++
++	/* 4th field is type version identifier */
++	token = strtok(NULL, ",");
++	if (!token || !getnumber(token, 0, 0xff, &no))
++		goto out_free;
++	vsi->vsi_typeversion = no;
++
++	/* 5th field is filter VSI UUID */
++	token = strtok(NULL, ",");
++	if (!token || vdp_str2uuid(vsi->vsi_uuid, token, sizeof(vsi->vsi_uuid)))
++		goto out_free;
++	vsi->vsi_idfmt = VDP22_ID_UUID;
++
++	/* 6th field is migration hints */
++	token = strtok(NULL, ",");
++	if (!token || !gethints(vsi, token))
++		goto out_free;
++
++	/*
++	 * 7th and remaining fields are filter information format data.
++	 * All fields must have the same format. The first fid field determines
++	 * the format.
++	 */
++	for (idx = 0, token = strtok(NULL, ","); token != NULL;
++					++idx, token = strtok(NULL, ",")) {
++		if (idx < vsi->macsz && !getfid(vsi, token, idx))
++			goto out_free;
++	}
++
++	/* Return error if no filter information provided */
++	if (idx)
++		rc = 0;
++out_free:
++	free(cmdstring);
++	return rc;
++}
++
++/*
++ * Fill the vdpnl_vsi structure from the string.
++ * Allocate the maclist. Must be free'ed by caller.
++ */
++int vdp_str2vdpnl(char *argvalue, struct vdpnl_vsi *vsi, char *ifname)
++{
++	if (ifname)
++		strncpy(vsi->ifname, ifname, sizeof(vsi->ifname) - 1);
++	return str2vdpnl(argvalue, vsi);
++}
++
++/*
++ * Convert VSI profile into string. Use the same format as on input.
++ * Return the number of bytes written into buffer. Return zero if not
++ * enough buffer space. This ensures an entry is complete and no partial
++ * entries are in buffer.
++ */
++
++/*
++ * Check if snprintf() result completely fits into buffer.
++ */
++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;
++}
++
++/*
++ * Convert VSI association to string.
++ */
++static const char *mode2str(unsigned char x)
++{
++	if (x == VDP22_ASSOC)
++		return "assoc";
++	else if (x == VDP22_PREASSOC)
++		return "preassoc";
++	else if (x == VDP22_PREASSOC_WITH_RR)
++		return "preassoc-rr";
++	else if (x == VDP22_DEASSOC)
++		return "deassoc";
++	return "unknown";
++}
++
++/*
++ * Convert filter information format into vlan[-mac][-group] string.
++ * Return the number of bytes written into buffer. Return 0 if not
++ * enough buffer space.
++ */
++static int fid2str(char *s, size_t length, int fif, struct vdpnl_mac *p)
++{
++	int c;
++	size_t total = 0;
++
++	c = snprintf(s, length, "%d", vdp22_set_qos(p->qos) |
++		     vdp22_set_vlanid(p->vlan));
++	s = check_and_update(&total, &length, s, c);
++	if (!s)
++		goto out;
++	if (fif == VDP22_FFMT_MACVID || fif == VDP22_FFMT_GROUPMACVID) {
++		c = snprintf(s, length, "-%02x:%02x:%02x:%02x:%02x:%02x",
++			     p->mac[0], p->mac[1], p->mac[2], p->mac[3],
++			     p->mac[4], p->mac[5]);
++		s = check_and_update(&total, &length, s, c);
++		if (!s)
++			goto out;
++	}
++	if (fif == VDP22_FFMT_GROUPVID || fif == VDP22_FFMT_GROUPMACVID) {
++		c = snprintf(s, length, "-%ld", p->gpid);
++		s = check_and_update(&total, &length, s, c);
++		if (!s)
++			goto out;
++	}
++out:
++	return s ? total : 0;
++}
++
++/*
++ * Mgrid can be a one byte number ranging from 0..255 or a 16byte long
++ * identifier.
++ */
++static void mgrid2str(char *to, struct vdpnl_vsi *p, size_t to_len)
++{
++	int c;
++
++	memset(to, 0, to_len);
++	for (c = sizeof(p->vsi_mgrid2); c > 0; )
++		if (p->vsi_mgrid2[--c])
++			break;
++	if (c)
++		memcpy(to, p->vsi_mgrid2, sizeof(p->vsi_mgrid2));
++	else
++		snprintf(to, to_len, "%d", p->vsi_mgrid2[0]);
++}
++
++/*
++ * Convert a vdpnl_vsi to string.
++ */
++int vdp_vdpnl2str(struct vdpnl_vsi *p, char *s, size_t length)
++{
++	int c, i;
++	size_t total = 0;
++	char instance[VDP_UUID_STRLEN + 2];
++
++	mgrid2str(instance, p, sizeof(instance));
++	c = snprintf(s, length, "%s,%s,%ld,%d,",
++		     mode2str(p->request), instance, p->vsi_typeid,
++		     p->vsi_typeversion);
++	s = check_and_update(&total, &length, s, c);
++	if (!s)
++		goto out;
++
++	vdp_uuid2str(p->vsi_uuid, instance, sizeof(instance));
++	c = snprintf(s, length, "%s,%d,", instance, p->response);
++	s = check_and_update(&total, &length, s, c);
++	if (!s)
++		goto out;
++
++	/* Add Filter information data */
++	for (i = 0; i < p->macsz; ++i) {
++		c = fid2str(s, length, p->filter_fmt, &p->maclist[i]);
++		s = check_and_update(&total, &length, s, c);
++		if (!c)
++			goto out;
++		if (p->macsz > 1 && i < p->macsz - 1) {
++			c = snprintf(s, length, ",");
++			s = check_and_update(&total, &length, s, c);
++			if (!s)
++				goto out;
++		}
++	}
++out:
++	return s ? total : 0;
++}
+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 <jens at linux.vnet.ibm.com>
++  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++
++  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 <stdio.h>
++#include <stdlib.h>
++#include <syslog.h>
++#include <sys/un.h>
++#include <sys/stat.h>
++#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 <jens at linux.vnet.ibm.com>
++  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++
++  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 <stdlib.h>
++#include <stdio.h>
++#include <syslog.h>
++#include <sys/un.h>
++#include <sys/stat.h>
++#include <arpa/inet.h>
++#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..5c0ffd4
+--- /dev/null
++++ b/qbg/vdpnl.c
+@@ -0,0 +1,575 @@
++/******************************************************************************
++
++  Implementation of VDP according to IEEE 802.1Qbg
++  (c) Copyright IBM Corp. 2013
++
++  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++
++  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 <stdlib.h>
++#include <unistd.h>
++#include <errno.h>
++
++#include <sys/socket.h>
++
++#include <net/if.h>
++#include <netlink/attr.h>
++#include <netlink/msg.h>
++
++#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 },
++};
++
++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 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 nl_msg *nlh)
++{
++	char instance[VDP_UUID_STRLEN + 2];
++
++	nla_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);
++	nla_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) {
++		nla_put_u16(nlh, IFLA_PORT_RESPONSE, p->response);
++		LLDPAD_DBG("%s:IFLA_PORT_RESPONSE:%d\n", __func__,
++			   p->response);
++	}
++}
++
++/*
++ * Return bytes needed for one VSI in a netlink message.
++ */
++static size_t vdp_nllen(void)
++{
++	size_t needed;
++
++	needed = nla_total_size(sizeof(struct nlattr)) /* IFLA_VF_PORT */
++		+ nla_total_size(4);	/* IFLA_PORT_VF */
++		+ nla_total_size(PORT_UUID_MAX); /* IFLA_PORT_INSTANCE_UUID */
++		+ nla_total_size(2);	/* IFLA_PORT_RESPONSE */
++	return needed;
++}
++
++/*
++ * Get interface name (either from netlink message for from ifi_index).
++ * Return error when no interface available.
++ */
++static int vdpnl_ifname(struct vdpnl_vsi *p, struct nlattr *tb)
++{
++	int rc = 0;
++
++	if (tb)
++		nla_strlcpy(p->ifname, tb, sizeof(p->ifname));
++	else if (!if_indextoname(p->ifindex, p->ifname)) {
++		LLDPAD_ERR("%s:ifindex %d without interface name\n", __func__,
++			   p->ifindex);
++		rc = -EINVAL;
++	}
++	return rc;
++}
++
++/*
++ * Parse a received netlink request message and return a filled VSI data
++ * structure.
++ */
++static struct nla_policy  pc_max[IFLA_MAX + 1] = {
++	[IFLA_IFNAME] = {
++				.minlen = 1,
++				.maxlen = IFNAMSIZ + 1,
++				.type = NLA_STRING
++			}
++};
++
++/*
++ * 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 vdpnl_vsi *p, struct nlmsghdr *nlh)
++{
++	int rc;
++	struct nlattr *tb[IFLA_MAX + 1];
++	struct ifinfomsg *ifinfo = (struct ifinfomsg *)NLMSG_DATA(nlh);
++
++	memset(tb, 0, sizeof(tb));
++	rc = nla_parse(tb, sizeof(tb) / sizeof(tb[0]),
++			 (struct nlattr *)IFLA_RTA(NLMSG_DATA(nlh)),
++			 IFLA_PAYLOAD(nlh), pc_max);
++	if (rc) {
++		LLDPAD_ERR("%s:error parsing GETLINK request\n", __func__);
++		return -EINVAL;
++	}
++	p->ifindex = ifinfo->ifi_index;
++	return vdpnl_ifname(p, tb[IFLA_IFNAME]);
++}
++
++/*
++ * Free an malloc'ed maclist array.
++ */
++void vdp22_freemaclist(struct vdpnl_vsi *vsi)
++{
++	vsi->macsz = 0;
++	free(vsi->maclist);
++	vsi->maclist = NULL;
++}
++
++/*
++ * 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 nlmsghdr *nlh_new;
++	struct nl_msg *msg;
++	struct vdpnl_vsi p;
++	int i = 0, rc = -ENOMEM;
++	struct nlattr *vf_ports, *vf_port;
++	struct ifinfomsg ifinfo;
++	size_t mylen = nla_total_size(sizeof(struct ifinfomsg))
++			+ nla_total_size(sizeof(struct nlattr));
++			/* Header + IFLA_VF_PORTS */
++
++	mylen = nlmsg_total_size(mylen);
++	memset(&ifinfo, 0, sizeof ifinfo);
++	memset(&p, 0, sizeof p);
++	msg = nlmsg_alloc_size(len);
++	if (msg)
++		rc = vdpnl_get(&p, nlh);
++	if (rc) {
++		nlmsg_free(msg);
++		return vdpnl_error(rc, nlh, len);
++	}
++	nlmsg_put(msg, nlh->nlmsg_pid, nlh->nlmsg_seq, NLMSG_DONE, 0, 0);
++	ifinfo.ifi_index = p.ifindex;
++	nlmsg_append(msg, &ifinfo, sizeof(ifinfo), 0);
++
++	vf_ports = nla_nest_start(msg, IFLA_VF_PORTS);
++	/* Iterate over all profiles */
++	do {
++		rc = vdp22_query(p.ifname) ? vdp22_status(++i, &p, 0)
++					   : vdp_status(++i, &p);
++		mylen += vdp_nllen();
++		if (rc == 1 && mylen < len) {
++			vf_port = nla_nest_start(msg, IFLA_VF_PORT);
++			vdpnl_reply2(&p, msg);
++			nla_nest_end(msg, vf_port);
++		}
++		vdp22_freemaclist(&p);
++	} while (rc == 1);
++	nla_nest_end(msg, vf_ports);
++	if (rc < 0) {
++		nlmsg_free(msg);
++		return vdpnl_error(rc, nlh, len);
++	}
++	nlh_new = nlmsg_hdr(msg);
++	rc = nlh_new->nlmsg_len;
++	memcpy((unsigned char *)nlh, nlh_new, rc);
++	nlmsg_free(msg);
++	LLDPAD_DBG("%s:message-size:%d\n", __func__, rc);
++	return rc;
++}
++
++/*
++ * 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.vsi_idfmt = VDP22_ID_UUID;
++	p.macsz = 1;
++	p.maclist = &mac;
++	rc = vdpnl_set(nlh, &p);
++	if (!rc)
++		rc = vdp22_query(p.ifname) ? vdp22_request(&p, 0)
++					   : 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 nl_msg *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 = nla_nest_start(nlh, IFLA_VF_INFO);
++	memcpy(ifla_vf_mac.mac, mac->mac, sizeof mac->mac);
++	nla_put(nlh, IFLA_VF_MAC, sizeof ifla_vf_mac, &ifla_vf_mac);
++	nla_put(nlh, IFLA_VF_VLAN, sizeof ifla_vf_vlan, &ifla_vf_vlan);
++	nla_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 nl_msg *nlh)
++{
++	struct nlattr *vfinfolist;
++	int i;
++
++	vfinfolist = nla_nest_start(nlh, IFLA_VFINFO_LIST);
++	for (i = 0; i < vsi->macsz; ++i)
++		add_pair(&vsi->maclist[i], nlh);
++	nla_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)
++{
++	struct nlmsghdr *nlh;
++	struct nlattr *vf_ports, *vf_port;
++	struct ifinfomsg ifinfo;
++	struct ifla_port_vsi portvsi;
++	struct nl_msg *msg;
++	int rc = -ENOMEM;
++
++	msg = nlmsg_alloc();
++	if (!msg) {
++		LLDPAD_DBG("%s:%s error allocating netlink message memory:\n",
++			   __func__, vsi->ifname);
++		return rc;
++	}
++	nlmsg_put(msg, getpid(), vsi->req_seq, RTM_SETLINK, 0, 0);
++
++	memset(&ifinfo, 0, sizeof ifinfo);
++	ifinfo.ifi_index = vsi->ifindex;
++	nlmsg_append(msg, &ifinfo, sizeof(ifinfo), 0);
++	nla_put_string(msg, IFLA_IFNAME, vsi->ifname);
++
++	add_mac_vlan(vsi, msg);
++	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 = nla_nest_start(msg, IFLA_VF_PORTS);
++	vf_port = nla_nest_start(msg, IFLA_VF_PORT);
++	nla_put(msg, IFLA_PORT_VSI_TYPE, sizeof portvsi, &portvsi);
++	nla_put(msg, IFLA_PORT_INSTANCE_UUID, PORT_UUID_MAX, vsi->vsi_uuid);
++	nla_put_u32(msg, IFLA_PORT_VF, PORT_SELF_VF);
++	nla_put_u16(msg, IFLA_PORT_REQUEST, vsi->request);
++	nla_nest_end(msg, vf_port);
++	nla_nest_end(msg, vf_ports);
++	vdpnl_show(vsi);
++	nlh = nlmsg_hdr(msg);
++	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);
++	rc = event_trigger(nlh, vsi->req_pid);
++	nlmsg_free(msg);
++	return rc;
++}
+diff --git a/qbg_utils.c b/qbg_utils.c
+new file mode 100644
+index 0000000..9daeade
+--- /dev/null
++++ b/qbg_utils.c
+@@ -0,0 +1,83 @@
++/******************************************************************************
++
++  Implementation of ECP according to 802.1Qbg
++  (c) Copyright IBM Corp. 2010, 2013
++
++  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++
++  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 <stdio.h>
++#include <linux/if_ether.h>
++
++#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;
++}
+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/qbg22/README b/test/qbg22/README
+new file mode 100644
+index 0000000..bb0c6e8
+--- /dev/null
++++ b/test/qbg22/README
+@@ -0,0 +1,19 @@
++
++(c) Copyright IBM Corp. 2013
++
++Thomas Richter, IBM Research and Development, Germany, April 2013
++
++Test cases for IEEE802.1Qbg ratified standard QBG22 support.
++
++29-Apr-2013
++===========
++The test cases run on one machine using 2 network name spaces:
++1. Run on one machine using 2 network name spaces (requires linux-3.8 kernel).
++2. Create a pair of virtual network interfaces (veth0 and veth2) and assign
++   veth2 to network name space bridge_ns
++
++lldpad (station rile) uses the default network name space and veth0.
++The qbg22 simulator program qbg22sim uses bridge_ns and veth2 interface.
++The lldpad (bridge role) vor vpd22 protocol testing uses the bridge_ns and
++veth2 interface and creates an unnamed IPC name space to have its on shared
++memory segment.
+diff --git a/test/qbg22/ecp22/1-lldpad.conf b/test/qbg22/ecp22/1-lldpad.conf
+new file mode 100644
+index 0000000..484322a
+--- /dev/null
++++ b/test/qbg22/ecp22/1-lldpad.conf
+@@ -0,0 +1,55 @@
++#
++#  Implementation of ECP according to IEEE 802.1Qbg ratified standard
++#  (c) Copyright IBM Corp. 2014
++#
++#  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++#  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".
++#
++
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "0452540050244E";
++    };
++    tlvid00000002 : 
++    {
++      info = "0352540050244E";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = true;
++      evbmode = "station";
++      evbrrcap = false;
++      evbrrreq = false;
++      evbgpid = false;
++      ecpretries = 3;
++      ecprte = 8;
++      vdprwd = 8;
++      vdprka = 8;
++    };
++  };
++};
+diff --git a/test/qbg22/ecp22/1.chk b/test/qbg22/ecp22/1.chk
+new file mode 100644
+index 0000000..f5bf6df
+--- /dev/null
++++ b/test/qbg22/ecp22/1.chk
+@@ -0,0 +1,45 @@
++#!/bin/bash
++#
++# Execute test case for LLDPAD testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 16-Aug-2013
++# Check of lldpad did start the ecp module, it shound not.
++
++# Note first parameter is the test case number
++tfile=/tmp/$1-lldpad.conf.out
++
++echo "check for ecp22 module not started"
++
++if [ ! -r $tfile ]
++then
++	echo "lldpad trace file not readable"
++	exit 126
++fi
++
++if fgrep -q 'ecp22_start:veth0' $tfile
++then
++	echo "error ecp22 module started"
++	exit 125
++fi
++
++echo SUCCESS
++exit 0
+diff --git a/test/qbg22/ecp22/1.ecp b/test/qbg22/ecp22/1.ecp
+new file mode 100644
+index 0000000..d1f8b95
+--- /dev/null
++++ b/test/qbg22/ecp22/1.ecp
+@@ -0,0 +1,65 @@
++/*
++ *  Implementation of EVB according to IEEE 802.1Qbg
++ *  (c) Copyright IBM Corp. 2014
++ *
++ *  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++ *
++ *  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".
++ *
++ */
++
++/*
++ * ECP Protocol test data. Define a complete ECP DU in hex. One complete set
++ * is needed for each transmission.
++ * The first column defines the run time of the test program  in seconds
++ * when the remaining data on this line will be sent. The rest of the line are
++ * data fields which define the TLVs.
++ * Line limit is 5KB, long lines can be split  with \\ as last character.
++ *
++ * The files are preprocessed with cpp before being read by the test program.
++ *
++ * The data fields per line are
++ * 1. time
++ * 2. destination MAC
++ * 3. source MAC (- is replaced by the senders MAC address)
++ * 4. ethertype
++ * 5. ECP header and paylaod data field according to standard 802.1qbg 
++ * 6. Optional. Several TLVs starting with @ which are expected results.
++ *    Its an error is it is missing in the reply or TLV differs.
++ */
++/*
++ * ECP negotiation
++ * Bridge does not offer reflective relay.
++ * Check that LLDPAD does not start ECP module.
++ */
++
++#include	"defines.ecp"
++
++5	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evb_norr end_tlv @evb_norr_ack
++6	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evb_norr end_tlv @evb_norr_ack
++7	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evb_norr end_tlv @evb_norr_ack
++8	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evb_norr end_tlv @evb_norr_ack
++
++18	lldpad_mac - ecp_type 10:01 12:24 0a:0b:0c:0d
++21	lldpad_mac - ecp_type 10:01 12:25 0a:0b:0c:0d
++24	lldpad_mac - ecp_type 10:01 12:26 0a:0b:0c:0d
++
++35	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv
+diff --git a/test/qbg22/ecp22/10-lldpad.conf b/test/qbg22/ecp22/10-lldpad.conf
+new file mode 100644
+index 0000000..2355662
+--- /dev/null
++++ b/test/qbg22/ecp22/10-lldpad.conf
+@@ -0,0 +1,55 @@
++#
++#  Implementation of ECP according to IEEE 802.1Qbg ratified standard
++#  (c) Copyright IBM Corp. 2014
++#
++#  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++#  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".
++#
++
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "0452540050244E";
++    };
++    tlvid00000002 : 
++    {
++      info = "0352540050244E";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = true;
++      evbmode = "station";
++      evbrrcap = false;
++      evbrrreq = true;
++      evbgpid = false;
++      ecpretries = 3;
++      ecprte = 8;
++      vdprwd = 8;
++      vdprka = 8;
++    };
++  };
++};
+diff --git a/test/qbg22/ecp22/10.ecp b/test/qbg22/ecp22/10.ecp
+new file mode 100644
+index 0000000..9cdbe18
+--- /dev/null
++++ b/test/qbg22/ecp22/10.ecp
+@@ -0,0 +1,64 @@
++/*
++ *  Implementation of EVB according to IEEE 802.1Qbg
++ *  (c) Copyright IBM Corp. 2014
++ *
++ *  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++ *
++ *  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".
++ *
++ */
++
++/*
++ * ECP Protocol test data. Define a complete ECP DU in hex. One complete set
++ * is needed for each transmission.
++ * The first column defines the run time of the test program  in seconds
++ * when the remaining data on this line will be sent. The rest of the line are
++ * data fields which define the TLVs.
++ * Line limit is 5KB, long lines can be split  with \\ as last character.
++ *
++ * The files are preprocessed with cpp before being read by the test program.
++ *
++ * The data fields per line are
++ * 1. time
++ * 2. destination MAC
++ * 3. source MAC (- is replaced by the senders MAC address)
++ * 4. ethertype
++ * 5. ECP header and paylaod data field according to standard 802.1qbg 
++ * 6. Optional. Several TLVs starting with @ which are expected results.
++ *    Its an error is it is missing in the reply or TLV differs.
++ */
++/*
++ * ECP negotiation
++ * Bridge offer reflective relay.
++ * Check that lldpad start ecp transmit state machine.
++ */
++
++#include	"defines.ecp"
++
++5	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evb_brrr end_tlv @evbhead:02:04:def_counts
++6	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:03:04:00:00:00 end_tlv @evbhead:03:05:def_counts
++7	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:03:05:00:00:00 end_tlv @evbhead:03:05:def_counts
++8	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:03:05:00:00:00 end_tlv @evbhead:03:05:def_counts
++9	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:03:05:00:00:00 end_tlv @evbhead:03:05:def_counts
++
++
++60	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv
+diff --git a/test/qbg22/ecp22/11-lldpad.conf b/test/qbg22/ecp22/11-lldpad.conf
+new file mode 100644
+index 0000000..2355662
+--- /dev/null
++++ b/test/qbg22/ecp22/11-lldpad.conf
+@@ -0,0 +1,55 @@
++#
++#  Implementation of ECP according to IEEE 802.1Qbg ratified standard
++#  (c) Copyright IBM Corp. 2014
++#
++#  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++#  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".
++#
++
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "0452540050244E";
++    };
++    tlvid00000002 : 
++    {
++      info = "0352540050244E";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = true;
++      evbmode = "station";
++      evbrrcap = false;
++      evbrrreq = true;
++      evbgpid = false;
++      ecpretries = 3;
++      ecprte = 8;
++      vdprwd = 8;
++      vdprka = 8;
++    };
++  };
++};
+diff --git a/test/qbg22/ecp22/11.ecp b/test/qbg22/ecp22/11.ecp
+new file mode 100644
+index 0000000..937d2f0
+--- /dev/null
++++ b/test/qbg22/ecp22/11.ecp
+@@ -0,0 +1,68 @@
++/*
++ *  Implementation of EVB according to IEEE 802.1Qbg
++ *  (c) Copyright IBM Corp. 2014
++ *
++ *  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++ *
++ *  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".
++ *
++ */
++
++/*
++ * ECP Protocol test data. Define a complete ECP DU in hex. One complete set
++ * is needed for each transmission.
++ * The first column defines the run time of the test program  in seconds
++ * when the remaining data on this line will be sent. The rest of the line are
++ * data fields which define the TLVs.
++ * Line limit is 5KB, long lines can be split  with \\ as last character.
++ *
++ * The files are preprocessed with cpp before being read by the test program.
++ *
++ * The data fields per line are
++ * 1. time
++ * 2. destination MAC
++ * 3. source MAC (- is replaced by the senders MAC address)
++ * 4. ethertype
++ * 5. ECP header and paylaod data field according to standard 802.1qbg 
++ * 6. Optional. Several TLVs starting with @ which are expected results.
++ *    Its an error is it is missing in the reply or TLV differs.
++ */
++/*
++ * ECP negotiation
++ * Bridge offer reflective relay.
++ * Check that lldpad start ecp transmit state machine.
++ * Needs special code that transmits a data packet after some time out
++ * inside ECP module of lldpad !!!!!!!!!!!!!!!!!!!!
++ */
++
++#include	"defines.ecp"
++
++5	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evb_brrr end_tlv @evbhead:02:04:def_counts
++6	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:03:04:00:00:00 end_tlv @evbhead:03:05:def_counts
++7	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:03:05:00:00:00 end_tlv @evbhead:03:05:def_counts
++8	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:03:05:00:00:00 end_tlv @evbhead:03:05:def_counts
++9	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:03:05:00:00:00 end_tlv @evbhead:03:05:def_counts
++11	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:03:05:6f:00:00 end_tlv @evbhead:03:05:6f:88:08
++
++
++60	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv
+diff --git a/test/qbg22/ecp22/2-lldpad.conf b/test/qbg22/ecp22/2-lldpad.conf
+new file mode 100644
+index 0000000..2355662
+--- /dev/null
++++ b/test/qbg22/ecp22/2-lldpad.conf
+@@ -0,0 +1,55 @@
++#
++#  Implementation of ECP according to IEEE 802.1Qbg ratified standard
++#  (c) Copyright IBM Corp. 2014
++#
++#  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++#  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".
++#
++
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "0452540050244E";
++    };
++    tlvid00000002 : 
++    {
++      info = "0352540050244E";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = true;
++      evbmode = "station";
++      evbrrcap = false;
++      evbrrreq = true;
++      evbgpid = false;
++      ecpretries = 3;
++      ecprte = 8;
++      vdprwd = 8;
++      vdprka = 8;
++    };
++  };
++};
+diff --git a/test/qbg22/ecp22/2.chk b/test/qbg22/ecp22/2.chk
+new file mode 100644
+index 0000000..bb9aa41
+--- /dev/null
++++ b/test/qbg22/ecp22/2.chk
+@@ -0,0 +1,54 @@
++#!/bin/bash
++#
++# Execute test case for LLDPAD testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 16-Aug-2013
++# Check of lldpad did start the ecp module, it shound not.
++
++# Note first parameter is the test case number
++
++tfile=/tmp/$1-lldpad.conf.out
++
++if [ ! -r $tfile ]
++then
++	echo "lldpad trace file not readable"
++	exit 126
++fi
++
++echo "check for ecp22 module started"
++
++if ! fgrep -q 'ecp22_start:veth0' $tfile
++then
++	echo "error ecp22 module not started"
++	exit 125
++fi
++
++echo "check for one ULP notification"
++count=$(fgrep 'notify ULP 1 seqno 0x1224' $tfile | wc -l)
++if [ "$count" -ne 1 ]
++then
++	echo "error ecp22 invalid ULP notifications:$count"
++	exit 124
++fi
++
++echo SUCCESS
++exit 0
+diff --git a/test/qbg22/ecp22/2.ecp b/test/qbg22/ecp22/2.ecp
+new file mode 100644
+index 0000000..3fcea5e
+--- /dev/null
++++ b/test/qbg22/ecp22/2.ecp
+@@ -0,0 +1,70 @@
++/*
++ *  Implementation of EVB according to IEEE 802.1Qbg
++ *  (c) Copyright IBM Corp. 2014
++ *
++ *  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++ *
++ *  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".
++ *
++ */
++
++/*
++ * ECP Protocol test data. Define a complete ECP DU in hex. One complete set
++ * is needed for each transmission.
++ * The first column defines the run time of the test program  in seconds
++ * when the remaining data on this line will be sent. The rest of the line are
++ * data fields which define the TLVs.
++ * Line limit is 5KB, long lines can be split  with \\ as last character.
++ *
++ * The files are preprocessed with cpp before being read by the test program.
++ *
++ * The data fields per line are
++ * 1. time
++ * 2. destination MAC
++ * 3. source MAC (- is replaced by the senders MAC address)
++ * 4. ethertype
++ * 5. ECP header and paylaod data field according to standard 802.1qbg 
++ * 6. Optional. Several TLVs starting with @ which are expected results.
++ *    Its an error is it is missing in the reply or TLV differs.
++ */
++/*
++ * ECP negotiation
++ * Bridge offer reflective relay.
++ * Check that LLDPAD starts ECP module and negotiates sequence number exchange.
++ * Use same sequence number and check for acknowledgement. Only ONE!!!! upper
++ * layer notification on the lldpad side
++ */
++
++#include	"defines.ecp"
++
++5	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evb_brrr end_tlv @evbhead:02:04:def_counts
++6	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:03:04:00:00:00 end_tlv @evbhead:03:05:def_counts
++7	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:03:05:00:00:00 end_tlv @evbhead:03:05:def_counts
++8	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:03:05:00:00:00 end_tlv @evbhead:03:05:def_counts
++9	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:03:05:00:00:00 end_tlv @evbhead:03:05:def_counts
++
++15	lldpad_mac - ecp_type 10:01 12:24 end_tlv @14:01:12:24
++16	lldpad_mac - ecp_type 10:01 12:24 end_tlv @14:01:12:24
++17	lldpad_mac - ecp_type 10:01 12:24 end_tlv @14:01:12:24
++
++
++30	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv
+diff --git a/test/qbg22/ecp22/3-lldpad.conf b/test/qbg22/ecp22/3-lldpad.conf
+new file mode 100644
+index 0000000..2355662
+--- /dev/null
++++ b/test/qbg22/ecp22/3-lldpad.conf
+@@ -0,0 +1,55 @@
++#
++#  Implementation of ECP according to IEEE 802.1Qbg ratified standard
++#  (c) Copyright IBM Corp. 2014
++#
++#  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++#  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".
++#
++
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "0452540050244E";
++    };
++    tlvid00000002 : 
++    {
++      info = "0352540050244E";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = true;
++      evbmode = "station";
++      evbrrcap = false;
++      evbrrreq = true;
++      evbgpid = false;
++      ecpretries = 3;
++      ecprte = 8;
++      vdprwd = 8;
++      vdprka = 8;
++    };
++  };
++};
+diff --git a/test/qbg22/ecp22/3.chk b/test/qbg22/ecp22/3.chk
+new file mode 100755
+index 0000000..a70475e
+--- /dev/null
++++ b/test/qbg22/ecp22/3.chk
+@@ -0,0 +1,68 @@
++#!/bin/bash
++#
++# Execute test case for LLDPAD testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 16-Aug-2013
++# Check of lldpad did start the ecp module, it shound not.
++
++# Note first parameter is the test case number
++
++tfile=/tmp/$1-lldpad.conf.out
++
++if [ ! -r $tfile ]
++then
++	echo "lldpad trace file not readable"
++	exit 126
++fi
++
++echo "check for ecp22 module started"
++
++if ! fgrep -q 'ecp22_start:veth0' $tfile
++then
++	echo "error ecp22 module not started"
++	exit 125
++fi
++
++echo "check for one ULP notification seqno 0x1224"
++count=$(fgrep 'notify ULP 1 seqno 0x1224' $tfile | wc -l)
++if [ "$count" -ne 1 ]
++then
++	echo "error ecp22 invalid ULP notifications:$count sequence 0x1224"
++	exit 124
++fi
++echo "check for one ULP notification seqno 0x1225"
++count=$(fgrep 'notify ULP 1 seqno 0x1225' $tfile | wc -l)
++if [ "$count" -ne 1 ]
++then
++	echo "error ecp22 invalid ULP notifications:$count sequence 0x1225"
++	exit 123
++fi
++echo "check for one ULP notification seqno 0x1226"
++count=$(fgrep 'notify ULP 1 seqno 0x1226' $tfile | wc -l)
++if [ "$count" -ne 1 ]
++then
++	echo "error ecp22 invalid ULP notifications:$count sequence 0x1226"
++	exit 122
++fi
++
++echo SUCCESS
++exit 0
+diff --git a/test/qbg22/ecp22/3.ecp b/test/qbg22/ecp22/3.ecp
+new file mode 100644
+index 0000000..d4f7b31
+--- /dev/null
++++ b/test/qbg22/ecp22/3.ecp
+@@ -0,0 +1,70 @@
++/*
++ *  Implementation of EVB according to IEEE 802.1Qbg
++ *  (c) Copyright IBM Corp. 2014
++ *
++ *  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++ *
++ *  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".
++ *
++ */
++
++/*
++ * ECP Protocol test data. Define a complete ECP DU in hex. One complete set
++ * is needed for each transmission.
++ * The first column defines the run time of the test program  in seconds
++ * when the remaining data on this line will be sent. The rest of the line are
++ * data fields which define the TLVs.
++ * Line limit is 5KB, long lines can be split  with \\ as last character.
++ *
++ * The files are preprocessed with cpp before being read by the test program.
++ *
++ * The data fields per line are
++ * 1. time
++ * 2. destination MAC
++ * 3. source MAC (- is replaced by the senders MAC address)
++ * 4. ethertype
++ * 5. ECP header and paylaod data field according to standard 802.1qbg 
++ * 6. Optional. Several TLVs starting with @ which are expected results.
++ *    Its an error is it is missing in the reply or TLV differs.
++ */
++/*
++ * ECP negotiation
++ * Bridge offer reflective relay.
++ * Check that LLDPAD starts ECP module and negotiates sequence number exchange.
++ * Use different sequence number and check for acknowledgement. 3 upper
++ * layer notification on the lldpad side
++ */
++
++#include	"defines.ecp"
++
++5	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evb_brrr end_tlv @evbhead:02:04:def_counts
++6	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:03:04:00:00:00 end_tlv @evbhead:03:05:def_counts
++7	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:03:05:00:00:00 end_tlv @evbhead:03:05:def_counts
++8	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:03:05:00:00:00 end_tlv @evbhead:03:05:def_counts
++9	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:03:05:00:00:00 end_tlv @evbhead:03:05:def_counts
++
++15	lldpad_mac - ecp_type 10:01 12:24 aa:bb:cc:dd end_tlv @14:01:12:24
++17	lldpad_mac - ecp_type 10:01 12:25 00:11:22:33 end_tlv @14:01:12:25
++19	lldpad_mac - ecp_type 10:01 12:26 44:55:66:77 end_tlv @14:01:12:26
++
++
++30	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv
+diff --git a/test/qbg22/ecp22/30-lldpad.conf b/test/qbg22/ecp22/30-lldpad.conf
+new file mode 100644
+index 0000000..2355662
+--- /dev/null
++++ b/test/qbg22/ecp22/30-lldpad.conf
+@@ -0,0 +1,55 @@
++#
++#  Implementation of ECP according to IEEE 802.1Qbg ratified standard
++#  (c) Copyright IBM Corp. 2014
++#
++#  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++#  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".
++#
++
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "0452540050244E";
++    };
++    tlvid00000002 : 
++    {
++      info = "0352540050244E";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = true;
++      evbmode = "station";
++      evbrrcap = false;
++      evbrrreq = true;
++      evbgpid = false;
++      ecpretries = 3;
++      ecprte = 8;
++      vdprwd = 8;
++      vdprka = 8;
++    };
++  };
++};
+diff --git a/test/qbg22/ecp22/30.ecp b/test/qbg22/ecp22/30.ecp
+new file mode 100644
+index 0000000..63e06cf
+--- /dev/null
++++ b/test/qbg22/ecp22/30.ecp
+@@ -0,0 +1,83 @@
++/*
++ *  Implementation of EVB according to IEEE 802.1Qbg
++ *  (c) Copyright IBM Corp. 2014
++ *
++ *  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++ *
++ *  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".
++ *
++ */
++
++/*
++ * ECP Protocol test data. Define a complete ECP DU in hex. One complete set
++ * is needed for each transmission.
++ * The first column defines the run time of the test program  in seconds
++ * when the remaining data on this line will be sent. The rest of the line are
++ * data fields which define the TLVs.
++ * Line limit is 5KB, long lines can be split  with \\ as last character.
++ *
++ * The files are preprocessed with cpp before being read by the test program.
++ *
++ * The data fields per line are
++ * 1. time
++ * 2. destination MAC
++ * 3. source MAC (- is replaced by the senders MAC address)
++ * 4. ethertype
++ * 5. ECP header and paylaod data field according to standard 802.1qbg 
++ * 6. Optional. Several TLVs starting with @ which are expected results.
++ *    Its an error is it is missing in the reply or TLV differs.
++ */
++/*
++ * ECP negotiation
++ * Bridge offer reflective relay.
++ * Check that LLDPAD starts ECP module and negotiates sequence number exchange.
++ */
++
++#include	"defines.ecp"
++
++5	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evb_brrr end_tlv @evbhead:02:04:def_counts
++6	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:03:04:00:00:00 end_tlv @evbhead:03:05:def_counts
++7	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:03:05:00:00:00 end_tlv @evbhead:03:05:def_counts
++8	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:03:05:00:00:00 end_tlv @evbhead:03:05:def_counts
++9	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:03:05:00:00:00 end_tlv @evbhead:03:05:def_counts
++
++20	lldpad_mac - ecp_type 10:01 12:30 44:55:66:77 end_tlv @14:01:12:30
++
++/*
++ * In the mean time disable and enable interface on target machine
++ * via remote executed shell script. Disable happens after 30 seconds and
++ * enable is after 40 seconds.
++ */
++
++45	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evb_brrr end_tlv @evbhead:02:04:def_counts
++46	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:03:04:00:00:00 end_tlv @evbhead:03:05:def_counts
++47	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:03:05:00:00:00 end_tlv @evbhead:03:05:def_counts
++48	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:03:05:00:00:00 end_tlv @evbhead:03:05:def_counts
++49	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:03:05:00:00:00 end_tlv @evbhead:03:05:def_counts
++60	lldpad_mac - ecp_type 10:01 12:31 44:55:66:77 end_tlv @14:01:12:31
++
++80	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv
+diff --git a/test/qbg22/ecp22/30.sh b/test/qbg22/ecp22/30.sh
+new file mode 100755
+index 0000000..875c9ca
+--- /dev/null
++++ b/test/qbg22/ecp22/30.sh
+@@ -0,0 +1,38 @@
++#!/bin/bash
++#
++# Test case for LLDPAD ECP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Configuration file for unknwon vsi data test cases
++#
++
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 16-Nov-2012
++#
++# Execute a single task on the machine running lldpad
++#
++
++# Wait 30 seconds and disable/enable interface
++sleep 30;
++ip l s down dev veth0
++sleep 10
++ip l s up dev veth0
++ip a sh dev veth0 | fgrep -q UP
++exit $?
++
+diff --git a/test/qbg22/ecp22/4-lldpad.conf b/test/qbg22/ecp22/4-lldpad.conf
+new file mode 100644
+index 0000000..2355662
+--- /dev/null
++++ b/test/qbg22/ecp22/4-lldpad.conf
+@@ -0,0 +1,55 @@
++#
++#  Implementation of ECP according to IEEE 802.1Qbg ratified standard
++#  (c) Copyright IBM Corp. 2014
++#
++#  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++#  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".
++#
++
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "0452540050244E";
++    };
++    tlvid00000002 : 
++    {
++      info = "0352540050244E";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = true;
++      evbmode = "station";
++      evbrrcap = false;
++      evbrrreq = true;
++      evbgpid = false;
++      ecpretries = 3;
++      ecprte = 8;
++      vdprwd = 8;
++      vdprka = 8;
++    };
++  };
++};
+diff --git a/test/qbg22/ecp22/4.chk b/test/qbg22/ecp22/4.chk
+new file mode 100644
+index 0000000..d24eca4
+--- /dev/null
++++ b/test/qbg22/ecp22/4.chk
+@@ -0,0 +1,68 @@
++#!/bin/bash
++#
++# Execute test case for LLDPAD testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 16-Aug-2013
++# Check of lldpad did start the ecp module, it shound not.
++
++# Note first parameter is the test case number
++
++tfile=/tmp/$1-lldpad.conf.out
++
++if [ ! -r $tfile ]
++then
++	echo "lldpad trace file not readable"
++	exit 126
++fi
++
++echo "check for ecp22 module started"
++
++if ! fgrep -q 'ecp22_start:veth0' $tfile
++then
++	echo "error ecp22 module not started"
++	exit 125
++fi
++
++echo "check for unknown version 0xf001 seqno 0x1224"
++count=$(fgrep 'unknown version 0xf001 seqno 0x1224' $tfile | wc -l)
++if [ "$count" -ne 1 ]
++then
++	echo "error ecp22 unknown version 0xf001:$count sequence 0x1224"
++	exit 124
++fi
++echo "check for unknown version 0xf001 seqno 0x1225"
++count=$(fgrep 'unknown version 0xf001 seqno 0x1225' $tfile | wc -l)
++if [ "$count" -ne 1 ]
++then
++	echo "error ecp22 unknown version 0xf001:$count sequence 0x1225"
++	exit 123
++fi
++echo "check for unknown version 0xf001 seqno 0x1226"
++count=$(fgrep 'unknown version 0xf001 seqno 0x1226' $tfile | wc -l)
++if [ "$count" -ne 1 ]
++then
++	echo "error ecp22 unknown version 0xf001:$count sequence 0x1226"
++	exit 122
++fi
++
++echo SUCCESS
++exit 0
+diff --git a/test/qbg22/ecp22/4.ecp b/test/qbg22/ecp22/4.ecp
+new file mode 100644
+index 0000000..79bb5ba
+--- /dev/null
++++ b/test/qbg22/ecp22/4.ecp
+@@ -0,0 +1,72 @@
++/*
++ *  Implementation of EVB according to IEEE 802.1Qbg
++ *  (c) Copyright IBM Corp. 2014
++ *
++ *  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++ *
++ *  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".
++ *
++ */
++
++/*
++ * ECP Protocol test data. Define a complete ECP DU in hex. One complete set
++ * is needed for each transmission.
++ * The first column defines the run time of the test program  in seconds
++ * when the remaining data on this line will be sent. The rest of the line are
++ * data fields which define the TLVs.
++ * Line limit is 5KB, long lines can be split  with \\ as last character.
++ *
++ * The files are preprocessed with cpp before being read by the test program.
++ *
++ * The data fields per line are
++ * 1. time
++ * 2. destination MAC
++ * 3. source MAC (- is replaced by the senders MAC address)
++ * 4. ethertype
++ * 5. ECP header and paylaod data field according to standard 802.1qbg 
++ * 6. Optional. Several TLVs starting with @ which are expected results.
++ *    Its an error is it is missing in the reply or TLV differs.
++ */
++/*
++ * ECP negotiation
++ * Bridge offer reflective relay.
++ * Check that LLDPAD starts ECP module and negotiates sequence number exchange.
++ * Use invalid version number. No acknowledgement expected.
++ * Use different sequence number and check for acknowledgement. No upper
++ * layer notification on the lldpad side.
++ */
++
++#include	"defines.ecp"
++
++5	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evb_brrr end_tlv @evbhead:02:04:def_counts
++6	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:03:04:00:00:00 end_tlv @evbhead:03:05:def_counts
++7	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:03:05:00:00:00 end_tlv @evbhead:03:05:def_counts
++8	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:03:05:00:00:00 end_tlv @evbhead:03:05:def_counts
++9	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:03:05:00:00:00 end_tlv @evbhead:03:05:def_counts
++
++15	lldpad_mac - ecp_type f0:01 12:24 aa:bb:cc:dd end_tlv
++17	lldpad_mac - ecp_type f0:01 12:25 00:11:22:33 end_tlv
++19	lldpad_mac - ecp_type f0:01 12:26 44:55:66:77 end_tlv
++
++25	lldpad_mac - ecp_type 10:01 12:27 44:55:66:77 end_tlv @14:01:12:27
++
++30	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv
+diff --git a/test/qbg22/ecp22/5-lldpad.conf b/test/qbg22/ecp22/5-lldpad.conf
+new file mode 100644
+index 0000000..2355662
+--- /dev/null
++++ b/test/qbg22/ecp22/5-lldpad.conf
+@@ -0,0 +1,55 @@
++#
++#  Implementation of ECP according to IEEE 802.1Qbg ratified standard
++#  (c) Copyright IBM Corp. 2014
++#
++#  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++#  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".
++#
++
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "0452540050244E";
++    };
++    tlvid00000002 : 
++    {
++      info = "0352540050244E";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = true;
++      evbmode = "station";
++      evbrrcap = false;
++      evbrrreq = true;
++      evbgpid = false;
++      ecpretries = 3;
++      ecprte = 8;
++      vdprwd = 8;
++      vdprka = 8;
++    };
++  };
++};
+diff --git a/test/qbg22/ecp22/5.chk b/test/qbg22/ecp22/5.chk
+new file mode 100644
+index 0000000..a1e7c9a
+--- /dev/null
++++ b/test/qbg22/ecp22/5.chk
+@@ -0,0 +1,68 @@
++#!/bin/bash
++#
++# Execute test case for LLDPAD testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 16-Aug-2013
++# Check of lldpad did start the ecp module, it shound not.
++
++# Note first parameter is the test case number
++
++tfile=/tmp/$1-lldpad.conf.out
++
++if [ ! -r $tfile ]
++then
++	echo "lldpad trace file not readable"
++	exit 126
++fi
++
++echo "check for ecp22 module started"
++
++if ! fgrep -q 'ecp22_start:veth0' $tfile
++then
++	echo "error ecp22 module not started"
++	exit 125
++fi
++
++echo "check for unknown subtype 0x100f seqno 0x1224"
++count=$(fgrep 'unknown subtype 0x100f seqno 0x1224' $tfile | wc -l)
++if [ "$count" -ne 1 ]
++then
++	echo "error ecp22 unknown subtype 0x100f:$count sequence 0x1224"
++	exit 124
++fi
++echo "check for unknown subtype 0x100f seqno 0x1225"
++count=$(fgrep 'unknown subtype 0x100f seqno 0x1225' $tfile | wc -l)
++if [ "$count" -ne 1 ]
++then
++	echo "error ecp22 unknown subtype 0x100f:$count sequence 0x1225"
++	exit 123
++fi
++echo "check for unknown subtype 0x100f seqno 0x1226"
++count=$(fgrep 'unknown subtype 0x100f seqno 0x1226' $tfile | wc -l)
++if [ "$count" -ne 1 ]
++then
++	echo "error ecp22 unknown subtype 0x100f:$count sequence 0x1226"
++	exit 122
++fi
++
++echo SUCCESS
++exit 0
+diff --git a/test/qbg22/ecp22/5.ecp b/test/qbg22/ecp22/5.ecp
+new file mode 100644
+index 0000000..2d6c15a
+--- /dev/null
++++ b/test/qbg22/ecp22/5.ecp
+@@ -0,0 +1,72 @@
++/*
++ *  Implementation of EVB according to IEEE 802.1Qbg
++ *  (c) Copyright IBM Corp. 2014
++ *
++ *  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++ *
++ *  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".
++ *
++ */
++
++/*
++ * ECP Protocol test data. Define a complete ECP DU in hex. One complete set
++ * is needed for each transmission.
++ * The first column defines the run time of the test program  in seconds
++ * when the remaining data on this line will be sent. The rest of the line are
++ * data fields which define the TLVs.
++ * Line limit is 5KB, long lines can be split  with \\ as last character.
++ *
++ * The files are preprocessed with cpp before being read by the test program.
++ *
++ * The data fields per line are
++ * 1. time
++ * 2. destination MAC
++ * 3. source MAC (- is replaced by the senders MAC address)
++ * 4. ethertype
++ * 5. ECP header and paylaod data field according to standard 802.1qbg 
++ * 6. Optional. Several TLVs starting with @ which are expected results.
++ *    Its an error is it is missing in the reply or TLV differs.
++ */
++/*
++ * ECP negotiation
++ * Bridge offer reflective relay.
++ * Check that LLDPAD starts ECP module and negotiates sequence number exchange.
++ * Use invalid subtype number. No acknowledgement expected.
++ * Use different sequence number and check for acknowledgement. No upper
++ * layer notification on the lldpad side.
++ */
++
++#include	"defines.ecp"
++
++5	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evb_brrr end_tlv @evbhead:02:04:def_counts
++6	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:03:04:00:00:00 end_tlv @evbhead:03:05:def_counts
++7	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:03:05:00:00:00 end_tlv @evbhead:03:05:def_counts
++8	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:03:05:00:00:00 end_tlv @evbhead:03:05:def_counts
++9	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:03:05:00:00:00 end_tlv @evbhead:03:05:def_counts
++
++15	lldpad_mac - ecp_type 10:0f 12:24 aa:bb:cc:dd end_tlv
++17	lldpad_mac - ecp_type 10:0f 12:25 00:11:22:33 end_tlv
++19	lldpad_mac - ecp_type 10:0f 12:26 44:55:66:77 end_tlv
++
++25	lldpad_mac - ecp_type 10:01 12:27 44:55:66:77 end_tlv @14:01:12:27
++
++30	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv
+diff --git a/test/qbg22/ecp22/README b/test/qbg22/ecp22/README
+new file mode 100644
+index 0000000..e0b2137
+--- /dev/null
++++ b/test/qbg22/ecp22/README
+@@ -0,0 +1,80 @@
++
++Implementation of EVB according to IEEE 802.1Qbg
++(c) Copyright IBM Corp. 2014
++
++Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++
++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".
++
++Thomas Richter, IBM Research and Development, Germany, Aug 2012
++
++Test cases for IEEE802.1Qbg ratified standard ECP module.
++
++Files
++=====
++There are 3 shell scripts which are executed on f18a.
++allecp.sh:	Runs all test cases with file names [1-9]*.ecp. Uses
++		runecp.sh to execute one test case.
++		On success the exit code is zero, on failure none zero.
++		A none zero exit code termintes the programme immediately.
++runecp.sh	Runs one test case. Symbolic link to runevb.sh
++3.sh		<Test case number>.sh contain shell scripts to be executed
++		on the remote virtual machine. Usually done to change some
++		lldpad configuration settings during execution of lldpad.
++3.chk		Runs a shell script to scan the lldpad trace file and
++		checks for proper entries.
++
++Tests
++=====
++The following test cases are executed. Each test case has a number.
++All test cases need a lldpad.conf configuration file and an ECP test input
++file:
++- The ECP test input files have the extension .ecp. The test case number
++  is the base file name.
++- The lldpad configuration file has the extension -lldpad.conf.
++
++The purpose is to trigger an ECP DU exchange between qbg22sim and llpdad.
++The exchanged data can be inspected automaticly with little inteligence
++(see qbg22sim.1) or manually.
++
++Test	Description
++1	bridge does not support refective-relay.
++2	bridge supports refective-relay. Use same sequence number
++3	bridge supports refective-relay. Use different sequence numbers
++4	bridge supports refective-relay. Use different invalid version
++5	bridge supports refective-relay. Use different invalid subversion
++30	bridge supports refective-relay. Interface will go down and up
++	again during the ECP module run time.
++
++Remarks:
++
++Test Execution
++==============
++Directory structure:
++
++The following directory structure is assumed:
++/home/richter/dcn/qbg/mywork/open-lldp	--> lldpad to test on target f18b
++/home/richter/dcn/qbg/mywork/testns/qbg22/evb22	--> EVB protocol test cases
++/home/richter/dcn/qbg/mywork/testns/qbg22/ecp22	--> ECP protocol test cases
++
++Select the qbg22sim program by adding the path relative to test directory
++1. cd /home/richter/dcn/qbg/mywork/test/qbg22/ecp22
++2. Symbolic link such as ./qbg22sim --> ../../../lldpad/qbg22sim.
++3. Add the environment variable LLDPAD_DIR=abc to select an different lldpad
++   executable. For example the invocation 
++	LLDPAD_DIR=new ecpall.sh
++   selects the file /home/richter/dcn/qbg/mywork/new/lldpad for execution.
+diff --git a/test/qbg22/ecp22/allecp.sh b/test/qbg22/ecp22/allecp.sh
+new file mode 100755
+index 0000000..6f5a418
+--- /dev/null
++++ b/test/qbg22/ecp22/allecp.sh
+@@ -0,0 +1,68 @@
++#!/bin/bash
++#
++# Test case for LLDPAD ECP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Configuration file for unknwon vsi data test cases
++#
++
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 16-Aug-2012
++#
++# Execute the complete evb test suite.
++#
++
++runcommand()
++{
++	# echo parameter $@
++	cmd=$1
++	file=$2
++
++	echo "start testcase $number"
++	$cmd $file $@ 2>&1
++	rc="$?"
++	if [ "$rc" -ne 0 ]
++	then
++		echo -en "\\033[1;31m"	# Failures in red
++		echo "ERROR $file exit with $rc"
++		echo -en "\\033[0;39m"
++		exit 2
++	fi
++	echo -en "\\033[1;32m"	# Success in green
++	echo "OK testcase $file"
++	echo -en "\\033[0;39m"
++	return 0
++}
++
++# Extract type of test case from the first 3 characters of invocation file
++type=$(basename $0)
++type="${type:3:3}"
++
++if ! which run$type.sh 2>/dev/null
++then
++	export PATH=$PATH:$PWD
++fi
++
++echo "Start testsuite at $(date)"
++for i in $(ls [1-9]*.$type|sort -n)
++do
++	runcommand run$type.sh $i
++done
++echo "Stop testsuite at $(date)"
++exit 0
+diff --git a/test/qbg22/ecp22/defines.ecp b/test/qbg22/ecp22/defines.ecp
+new file mode 100644
+index 0000000..ea53399
+--- /dev/null
++++ b/test/qbg22/ecp22/defines.ecp
+@@ -0,0 +1,52 @@
++/*
++ *  Implementation of EVB according to IEEE 802.1Qbg
++ *  (c) Copyright IBM Corp. 2014
++ *
++ *  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++ *
++ *  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".
++ *
++ */
++
++/*
++ * ECP Protocol test data. Define a complete ECP DU in hex. One complete set
++ * is needed for each transmission.
++ */
++/*
++ * Very common defines
++ */
++
++#define	lldpad_mac	01:80:c2:00:00:00
++#define	lldp_type	88:cc
++#define chassis_tlv	02:07:06:64:75:6d:6d:79:00
++#define	port_tlv	04:05:05:65:74:68:30
++#define	ttl_tlv120	06:02:00:78
++#define	ttl_tlv0	06:02:00:00
++#define	end_tlv		00:00
++
++#define	evbhead		fe:09:00:80:c2:0d
++#define	def_counts	68:88:08		/* Default ECP values */
++
++/* Bridge denies reflective-relay */
++#define	evb_norr	evbhead:00:00:00:40:00
++#define	evb_norr_ack	evbhead:00:00:def_counts
++
++#define	ecp_type	89:40
++
++/* Bridge offers reflective-relay */
++#define	evb_brrr	evbhead:02:00:00:40:00
++#define	evb_brrr_ack	evbhead:02:00:def_counts
+diff --git a/test/qbg22/ecp22/runecp.sh b/test/qbg22/ecp22/runecp.sh
+new file mode 100755
+index 0000000..bf6b0ef
+--- /dev/null
++++ b/test/qbg22/ecp22/runecp.sh
+@@ -0,0 +1,153 @@
++#!/bin/bash
++#
++# Execute test case for LLDPAD testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 16-Aug-2012
++#
++# Execute a single  test. Parameter is the name of the test file
++#
++
++# Check if lldpad is up and running. Return pid or 0 if not running.
++# Note that lldpad may be started without creating a PID file. If no PID file
++# exists, use the lldptool to query the PID of lldpad.
++function lldpad_up()
++{
++	if [ ! -r /var/run/lldpad.pid ]
++	then
++		pidfile=$(../../../lldptool -p 2>/dev/null)
++		if [ "$?" -ne 0 ]
++		then
++			return 0
++		fi
++	else
++		pidfile="$(cat /var/run/lldpad.pid)"
++	fi
++	if [ -z "$pidfile" ]
++	then
++		return 0
++	else
++		ps -p $pidfile -o pid --no-header > /dev/null
++		if [ $? -ne 0 ]
++		then
++			return 0
++		fi
++	fi
++	echo "LLDPAD running pid $pidfile"
++	return $pidfile
++}
++
++function lldpad_down()
++{
++	if [ ! -r /var/run/lldpad.pid ]
++	then
++		pidfile=$(../../../lldptool -p 2>/dev/null)
++		if [ "$?" -ne 0 ]
++		then
++			return 1
++		fi
++	else
++		pidfile="$(cat /var/run/lldpad.pid)"
++	fi
++	if [ -z "$pidfile" ]
++	then
++		return 1
++	fi
++	kill -s SIGTERM $pidfile
++	sleep 1
++	ps -p $pidfile -o pid --no-header > /dev/null
++	if [ $? -ne 1 ]
++	then
++		kill -s SIGKILL $pidfile
++	fi
++	return 0
++}
++
++# Use the correct lldpad configuration file and start lldpad.
++# Parameter 1: path to lldpad to use
++# Parameter 2: name of configuration file
++function lldpad_start()
++{
++	if lldpad_up
++	then
++		rm -f /var/lib/lldpad/lldpad.conf ./lldpad.conf
++		cp $2 /tmp/$2
++		$1/lldpad -V7 -f /tmp/$2 >/tmp/$2.out 2>&1 &
++		sleep 1
++		if lldpad_up
++		then
++			echo "$0:lldpad not started or terminated unexpectedly"
++			exit 1
++		fi
++	else
++		exit 1
++	fi
++	return 0
++}
++
++if ! which runecp.sh 1>/dev/null 2>/dev/null
++then
++	export PATH=$PATH:$PWD
++fi
++
++# Extract type of test case from last 3 characters of invocation
++type=$(basename $0)
++type=".${type:3:3}"
++
++testfile=$1
++no=$(basename $testfile $type)
++
++# Start lldpad using this name space
++if ! lldpad_start ../../.. $no-lldpad.conf
++then
++	echo "$0:can not start lldpad"
++	exit 1
++fi
++
++# Check for shell script to run in parallel
++if [ -r "./$no.sh" -a -x "./$no.sh" ]
++then
++	./$no.sh ../../.. &
++fi
++
++# get the duration fron the last entry in the test file.
++duration=$(cpp $testfile | cut -f1 -d' ' | sed '/^$/d' | tail -1)
++let duration=duration+5
++
++# run the test with output save to /tmp/testfile.out
++ip netns exec bridge_ns ../../../qbg22sim -v -v -v -T 2500000 -d $duration veth2 $testfile > /tmp/$testfile.out
++rc=$?
++
++# Stop lldpad
++if ! lldpad_down
++then
++	echo "$0:can not stop lldpad"
++	exit 1
++fi
++
++# Check for shell script to test result of test case
++if [ -r "./$no.chk" -a -x "./$no.chk" ]
++then
++	./$no.chk $no >/tmp/$no.chk.out
++	rc=$?
++fi
++
++exit $rc
+diff --git a/test/qbg22/evb22/1-lldpad.conf b/test/qbg22/evb22/1-lldpad.conf
+new file mode 100644
+index 0000000..280566b
+--- /dev/null
++++ b/test/qbg22/evb22/1-lldpad.conf
+@@ -0,0 +1,55 @@
++#
++#  Implementation of EVB according to IEEE 802.1Qbg ratified standard
++#  (c) Copyright IBM Corp. 2014
++#
++#  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++#  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".
++#
++
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "041A17CEF5FBBD";
++    };
++    tlvid00000002 : 
++    {
++      info = "031A17CEF5FBBD";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = true;
++      evbmode = "station";
++      evbrrcap = false;
++      evbrrreq = false;
++      evbgpid = false;
++      ecpretries = 3;
++      ecprte = 8;
++      vdprwd = 8;
++      vdprka = 8;
++    };
++  };
++};
+diff --git a/test/qbg22/evb22/1.evb b/test/qbg22/evb22/1.evb
+new file mode 100644
+index 0000000..8c94f60
+--- /dev/null
++++ b/test/qbg22/evb22/1.evb
+@@ -0,0 +1,59 @@
++/*
++ *  Implementation of EVB according to IEEE 802.1Qbg
++ *  (c) Copyright IBM Corp. 2014
++ *
++ *  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++ *
++ *  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".
++ *
++ */
++
++/*
++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set
++ * is needed for each transmission.
++ * The first column defines the run time of the test program  in seconds
++ * when the remaining data on this line will be sent. The rest of the line are
++ * data fields which define the TLVs.
++ * Line limit is 5KB, long lines can be split  with \\ as last character.
++ *
++ * The files are preprocessed with cpp before being read by the test program.
++ *
++ * The data fields per line are
++ * 1. time
++ * 2. destination MAC
++ * 3. source MAC (dash(-) replaced by the senders MAC address)
++ * 4. ethertype
++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are
++ *    chassis-id, port-id, ttl and end)
++ * 6. Optional. Several TLVs starting with @ which are expected results.
++ *    Its an error is it is missing in the reply or TLV differs.
++ */
++/*
++ * EVB negotiation - bridge does not support reflective relay.
++ */
++
++#include	"defines.evb"
++
++5	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evb_norr end_tlv @evb_norr_ack
++6	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evb_norr end_tlv @evb_norr_ack
++7	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evb_norr end_tlv @evb_norr_ack
++8	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evb_norr end_tlv @evb_norr_ack
++15	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv
+diff --git a/test/qbg22/evb22/10-lldpad.conf b/test/qbg22/evb22/10-lldpad.conf
+new file mode 100644
+index 0000000..a219bbf
+--- /dev/null
++++ b/test/qbg22/evb22/10-lldpad.conf
+@@ -0,0 +1,32 @@
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "0452540050244E";
++    };
++    tlvid00000002 : 
++    {
++      info = "0352540050244E";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = true;
++      evbmode = "station";
++      evbrrcap = false;
++      evbrrreq = true;
++      evbgpid = false;
++      ecpretries = 3;
++      ecprte = 8;
++      vdprwd = 8;
++      vdprka = 8;
++    };
++  };
++};
+diff --git a/test/qbg22/evb22/10.evb b/test/qbg22/evb22/10.evb
+new file mode 100644
+index 0000000..e90cd1d
+--- /dev/null
++++ b/test/qbg22/evb22/10.evb
+@@ -0,0 +1,60 @@
++/*
++ *  Implementation of EVB according to IEEE 802.1Qbg
++ *  (c) Copyright IBM Corp. 2014
++ *
++ *  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++ *
++ *  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".
++ *
++ */
++
++/*
++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set
++ * is needed for each transmission.
++ * The first column defines the run time of the test program  in seconds
++ * when the remaining data on this line will be sent. The rest of the line are
++ * data fields which define the TLVs.
++ * Line limit is 5KB, long lines can be split  with \\ as last character.
++ *
++ * The files are preprocessed with cpp before being read by the test program.
++ *
++ * The data fields per line are
++ * 1. time
++ * 2. destination MAC
++ * 3. source MAC (dash(-) replaced by the senders MAC address)
++ * 4. ethertype
++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are
++ *    chassis-id, port-id, ttl and end)
++ * 6. Optional. Several TLVs starting with @ which are expected results.
++ *    Its an error is it is missing in the reply or TLV differs.
++ */
++/*
++ * EVB negotiation - bridge does not support reflective relay but station
++ *	requests it. RKA value is lower than on station.
++ */
++
++#include	"defines.evb"
++
++5	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:00:00:00:40:00 end_tlv @evbhead:00:04:counts
++6	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:00:00:00:40:00 end_tlv @evbhead:00:04:counts
++7	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:00:00:00:40:00 end_tlv @evbhead:00:04:counts
++8	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:00:00:00:40:00 end_tlv @evbhead:00:04:counts
++15	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv
+diff --git a/test/qbg22/evb22/11-lldpad.conf b/test/qbg22/evb22/11-lldpad.conf
+new file mode 100644
+index 0000000..3f86198
+--- /dev/null
++++ b/test/qbg22/evb22/11-lldpad.conf
+@@ -0,0 +1,54 @@
++#
++#  Implementation of EVB according to IEEE 802.1Qbg ratified standard
++#  (c) Copyright IBM Corp. 2014
++#
++#  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++#  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".
++#
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "0452540050244E";
++    };
++    tlvid00000002 : 
++    {
++      info = "0352540050244E";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = true;
++      evbmode = "station";
++      evbrrcap = false;
++      evbrrreq = true;
++      evbgpid = false;
++      ecpretries = 3;
++      ecprte = 8;
++      vdprwd = 8;
++      vdprka = 8;
++    };
++  };
++};
+diff --git a/test/qbg22/evb22/11.evb b/test/qbg22/evb22/11.evb
+new file mode 100644
+index 0000000..45b228a
+--- /dev/null
++++ b/test/qbg22/evb22/11.evb
+@@ -0,0 +1,60 @@
++/*
++ *  Implementation of EVB according to IEEE 802.1Qbg
++ *  (c) Copyright IBM Corp. 2014
++ *
++ *  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++ *
++ *  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".
++ *
++ */
++
++/*
++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set
++ * is needed for each transmission.
++ * The first column defines the run time of the test program  in seconds
++ * when the remaining data on this line will be sent. The rest of the line are
++ * data fields which define the TLVs.
++ * Line limit is 5KB, long lines can be split  with \\ as last character.
++ *
++ * The files are preprocessed with cpp before being read by the test program.
++ *
++ * The data fields per line are
++ * 1. time
++ * 2. destination MAC
++ * 3. source MAC (dash(-) replaced by the senders MAC address)
++ * 4. ethertype
++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are
++ *    chassis-id, port-id, ttl and end)
++ * 6. Optional. Several TLVs starting with @ which are expected results.
++ *    Its an error is it is missing in the reply or TLV differs.
++ */
++/*
++ * EVB negotiation - bridge does not support reflective relay but station
++ *	requests it. RWD value is higher than on station.
++ */
++
++#include	"defines.evb"
++
++5	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:00:00:00:5f:00 end_tlv @evbhead:00:04:68:bf:08
++6	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:00:00:00:5f:00 end_tlv @evbhead:00:04:68:bf:08
++7	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:00:00:00:5f:00 end_tlv @evbhead:00:04:68:bf:08
++8	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:00:00:00:5f:00 end_tlv @evbhead:00:04:68:bf:08
++15	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv
+diff --git a/test/qbg22/evb22/12-lldpad.conf b/test/qbg22/evb22/12-lldpad.conf
+new file mode 100644
+index 0000000..3f86198
+--- /dev/null
++++ b/test/qbg22/evb22/12-lldpad.conf
+@@ -0,0 +1,54 @@
++#
++#  Implementation of EVB according to IEEE 802.1Qbg ratified standard
++#  (c) Copyright IBM Corp. 2014
++#
++#  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++#  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".
++#
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "0452540050244E";
++    };
++    tlvid00000002 : 
++    {
++      info = "0352540050244E";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = true;
++      evbmode = "station";
++      evbrrcap = false;
++      evbrrreq = true;
++      evbgpid = false;
++      ecpretries = 3;
++      ecprte = 8;
++      vdprwd = 8;
++      vdprka = 8;
++    };
++  };
++};
+diff --git a/test/qbg22/evb22/12.evb b/test/qbg22/evb22/12.evb
+new file mode 100644
+index 0000000..0de9daa
+--- /dev/null
++++ b/test/qbg22/evb22/12.evb
+@@ -0,0 +1,60 @@
++/*
++ *  Implementation of EVB according to IEEE 802.1Qbg
++ *  (c) Copyright IBM Corp. 2014
++ *
++ *  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++ *
++ *  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".
++ *
++ */
++
++/*
++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set
++ * is needed for each transmission.
++ * The first column defines the run time of the test program  in seconds
++ * when the remaining data on this line will be sent. The rest of the line are
++ * data fields which define the TLVs.
++ * Line limit is 5KB, long lines can be split  with \\ as last character.
++ *
++ * The files are preprocessed with cpp before being read by the test program.
++ *
++ * The data fields per line are
++ * 1. time
++ * 2. destination MAC
++ * 3. source MAC (dash(-) replaced by the senders MAC address)
++ * 4. ethertype
++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are
++ *    chassis-id, port-id, ttl and end)
++ * 6. Optional. Several TLVs starting with @ which are expected results.
++ *    Its an error is it is missing in the reply or TLV differs.
++ */
++/*
++ * EVB negotiation - bridge does not support reflective relay but station
++ *	requests it. RWD value is lower than on station.
++ */
++
++#include	"defines.evb"
++
++5	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:00:00:00:40:00 end_tlv @evbhead:00:04:counts
++6	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:00:00:00:40:00 end_tlv @evbhead:00:04:counts
++7	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:00:00:00:40:00 end_tlv @evbhead:00:04:counts
++8	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:00:00:00:40:00 end_tlv @evbhead:00:04:counts
++15	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv
+diff --git a/test/qbg22/evb22/13-lldpad.conf b/test/qbg22/evb22/13-lldpad.conf
+new file mode 100644
+index 0000000..3f86198
+--- /dev/null
++++ b/test/qbg22/evb22/13-lldpad.conf
+@@ -0,0 +1,54 @@
++#
++#  Implementation of EVB according to IEEE 802.1Qbg ratified standard
++#  (c) Copyright IBM Corp. 2014
++#
++#  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++#  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".
++#
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "0452540050244E";
++    };
++    tlvid00000002 : 
++    {
++      info = "0352540050244E";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = true;
++      evbmode = "station";
++      evbrrcap = false;
++      evbrrreq = true;
++      evbgpid = false;
++      ecpretries = 3;
++      ecprte = 8;
++      vdprwd = 8;
++      vdprka = 8;
++    };
++  };
++};
+diff --git a/test/qbg22/evb22/13.evb b/test/qbg22/evb22/13.evb
+new file mode 100644
+index 0000000..1b41f46
+--- /dev/null
++++ b/test/qbg22/evb22/13.evb
+@@ -0,0 +1,60 @@
++/*
++ *  Implementation of EVB according to IEEE 802.1Qbg
++ *  (c) Copyright IBM Corp. 2014
++ *
++ *  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++ *
++ *  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".
++ *
++ */
++
++/*
++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set
++ * is needed for each transmission.
++ * The first column defines the run time of the test program  in seconds
++ * when the remaining data on this line will be sent. The rest of the line are
++ * data fields which define the TLVs.
++ * Line limit is 5KB, long lines can be split  with \\ as last character.
++ *
++ * The files are preprocessed with cpp before being read by the test program.
++ *
++ * The data fields per line are
++ * 1. time
++ * 2. destination MAC
++ * 3. source MAC (dash(-) replaced by the senders MAC address)
++ * 4. ethertype
++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are
++ *    chassis-id, port-id, ttl and end)
++ * 6. Optional. Several TLVs starting with @ which are expected results.
++ *    Its an error is it is missing in the reply or TLV differs.
++ */
++/*
++ * EVB negotiation - bridge does not support reflective relay but station
++ *	requests it. Retry value is higher than on station.
++ */
++
++#include	"defines.evb"
++
++5	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:00:00:e0:40:00 end_tlv @evbhead:00:04:e8:88:08
++6	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:00:00:e0:40:00 end_tlv @evbhead:00:04:e8:88:08
++7	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:00:00:e0:40:00 end_tlv @evbhead:00:04:e8:88:08
++8	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:00:00:e0:40:00 end_tlv @evbhead:00:04:e8:88:08
++15	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv
+diff --git a/test/qbg22/evb22/14-lldpad.conf b/test/qbg22/evb22/14-lldpad.conf
+new file mode 100644
+index 0000000..3f86198
+--- /dev/null
++++ b/test/qbg22/evb22/14-lldpad.conf
+@@ -0,0 +1,54 @@
++#
++#  Implementation of EVB according to IEEE 802.1Qbg ratified standard
++#  (c) Copyright IBM Corp. 2014
++#
++#  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++#  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".
++#
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "0452540050244E";
++    };
++    tlvid00000002 : 
++    {
++      info = "0352540050244E";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = true;
++      evbmode = "station";
++      evbrrcap = false;
++      evbrrreq = true;
++      evbgpid = false;
++      ecpretries = 3;
++      ecprte = 8;
++      vdprwd = 8;
++      vdprka = 8;
++    };
++  };
++};
+diff --git a/test/qbg22/evb22/14.evb b/test/qbg22/evb22/14.evb
+new file mode 100644
+index 0000000..0de9daa
+--- /dev/null
++++ b/test/qbg22/evb22/14.evb
+@@ -0,0 +1,60 @@
++/*
++ *  Implementation of EVB according to IEEE 802.1Qbg
++ *  (c) Copyright IBM Corp. 2014
++ *
++ *  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++ *
++ *  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".
++ *
++ */
++
++/*
++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set
++ * is needed for each transmission.
++ * The first column defines the run time of the test program  in seconds
++ * when the remaining data on this line will be sent. The rest of the line are
++ * data fields which define the TLVs.
++ * Line limit is 5KB, long lines can be split  with \\ as last character.
++ *
++ * The files are preprocessed with cpp before being read by the test program.
++ *
++ * The data fields per line are
++ * 1. time
++ * 2. destination MAC
++ * 3. source MAC (dash(-) replaced by the senders MAC address)
++ * 4. ethertype
++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are
++ *    chassis-id, port-id, ttl and end)
++ * 6. Optional. Several TLVs starting with @ which are expected results.
++ *    Its an error is it is missing in the reply or TLV differs.
++ */
++/*
++ * EVB negotiation - bridge does not support reflective relay but station
++ *	requests it. RWD value is lower than on station.
++ */
++
++#include	"defines.evb"
++
++5	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:00:00:00:40:00 end_tlv @evbhead:00:04:counts
++6	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:00:00:00:40:00 end_tlv @evbhead:00:04:counts
++7	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:00:00:00:40:00 end_tlv @evbhead:00:04:counts
++8	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:00:00:00:40:00 end_tlv @evbhead:00:04:counts
++15	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv
+diff --git a/test/qbg22/evb22/2-lldpad.conf b/test/qbg22/evb22/2-lldpad.conf
+new file mode 100644
+index 0000000..0db19ce
+--- /dev/null
++++ b/test/qbg22/evb22/2-lldpad.conf
+@@ -0,0 +1,55 @@
++#
++#  Implementation of EVB according to IEEE 802.1Qbg ratified standard
++#  (c) Copyright IBM Corp. 2014
++#
++#  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++#  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".
++#
++
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "0452540050244E";
++    };
++    tlvid00000002 : 
++    {
++      info = "0352540050244E";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = true;
++      evbmode = "station";
++      evbrrcap = false;
++      evbrrreq = false;
++      evbgpid = false;
++      ecpretries = 3;
++      ecprte = 8;
++      vdprwd = 8;
++      vdprka = 8;
++    };
++  };
++};
+diff --git a/test/qbg22/evb22/2.evb b/test/qbg22/evb22/2.evb
+new file mode 100644
+index 0000000..2059520
+--- /dev/null
++++ b/test/qbg22/evb22/2.evb
+@@ -0,0 +1,60 @@
++/*
++ *  Implementation of EVB according to IEEE 802.1Qbg
++ *  (c) Copyright IBM Corp. 2014
++ *
++ *  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++ *
++ *  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".
++ *
++ */
++
++/*
++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set
++ * is needed for each transmission.
++ * The first column defines the run time of the test program  in seconds
++ * when the remaining data on this line will be sent. The rest of the line are
++ * data fields which define the TLVs.
++ * Line limit is 5KB, long lines can be split  with \\ as last character.
++ *
++ * The files are preprocessed with cpp before being read by the test program.
++ *
++ * The data fields per line are
++ * 1. time
++ * 2. destination MAC
++ * 3. source MAC (dash(-) replaced by the senders MAC address)
++ * 4. ethertype
++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are
++ *    chassis-id, port-id, ttl and end)
++ * 6. Optional. Several TLVs starting with @ which are expected results.
++ *    Its an error is it is missing in the reply or TLV differs.
++ */
++/*
++ * EVB negotiation - bridge offers support for reflective relay but station
++ *	does not request it.
++ */
++
++#include	"defines.evb"
++
++5	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evb_brrr end_tlv @evb_brrr_ack
++6	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evb_brrr end_tlv @evb_brrr_ack
++7	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evb_brrr end_tlv @evb_brrr_ack
++8	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evb_brrr end_tlv @evb_brrr_ack
++15	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv
+diff --git a/test/qbg22/evb22/20-lldpad.conf b/test/qbg22/evb22/20-lldpad.conf
+new file mode 100644
+index 0000000..ebe91e0
+--- /dev/null
++++ b/test/qbg22/evb22/20-lldpad.conf
+@@ -0,0 +1,55 @@
++#
++#  Implementation of EVB according to IEEE 802.1Qbg ratified standard
++#  (c) Copyright IBM Corp. 2014
++#
++#  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++#  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".
++#
++
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "0452540050244E";
++    };
++    tlvid00000002 : 
++    {
++      info = "0352540050244E";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = true;
++      evbmode = "station";
++      evbrrcap = false;
++      evbrrreq = true;
++      evbgpid = false;
++      ecpretries = 3;
++      ecprte = 8;
++      vdprwd = 8;
++      vdprka = 8;
++    };
++  };
++};
+diff --git a/test/qbg22/evb22/20.evb b/test/qbg22/evb22/20.evb
+new file mode 100644
+index 0000000..43cfd94
+--- /dev/null
++++ b/test/qbg22/evb22/20.evb
+@@ -0,0 +1,62 @@
++/*
++ *  Implementation of EVB according to IEEE 802.1Qbg
++ *  (c) Copyright IBM Corp. 2014
++ *
++ *  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++ *
++ *  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".
++ *
++ */
++
++/*
++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set
++ * is needed for each transmission.
++ * The first column defines the run time of the test program  in seconds
++ * when the remaining data on this line will be sent. The rest of the line are
++ * data fields which define the TLVs.
++ * Line limit is 5KB, long lines can be split  with \\ as last character.
++ *
++ * The files are preprocessed with cpp before being read by the test program.
++ *
++ * The data fields per line are
++ * 1. time
++ * 2. destination MAC
++ * 3. source MAC (dash(-) replaced by the senders MAC address)
++ * 4. ethertype
++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are
++ *    chassis-id, port-id, ttl and end)
++ * 6. Optional. Several TLVs starting with @ which are expected results.
++ *    Its an error is it is missing in the reply or TLV differs.
++ */
++/*
++ * EVB negotiation - bridge offers support for reflective relay and station
++ *	requests it. Bridge sets group id bit, but station denies.
++ */
++
++#include	"defines.evb"
++
++5	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:06:00:00:40:00 end_tlv @evbhead:06:04:counts
++6	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:04:00:00:00 end_tlv @evbhead:07:05:counts
++7	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:05:00:00:00 end_tlv @evbhead:07:05:counts
++8	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:05:00:00:00 end_tlv @evbhead:07:05:counts
++9	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:05:00:00:00 end_tlv @evbhead:07:05:counts
++15	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv
+diff --git a/test/qbg22/evb22/21-lldpad.conf b/test/qbg22/evb22/21-lldpad.conf
+new file mode 100644
+index 0000000..456da71
+--- /dev/null
++++ b/test/qbg22/evb22/21-lldpad.conf
+@@ -0,0 +1,55 @@
++#
++#  Implementation of EVB according to IEEE 802.1Qbg ratified standard
++#  (c) Copyright IBM Corp. 2014
++#
++#  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++#  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".
++#
++
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "0452540050244E";
++    };
++    tlvid00000002 : 
++    {
++      info = "0352540050244E";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = true;
++      evbmode = "station";
++      evbrrcap = false;
++      evbrrreq = true;
++      evbgpid = true;
++      ecpretries = 3;
++      ecprte = 8;
++      vdprwd = 8;
++      vdprka = 8;
++    };
++  };
++};
+diff --git a/test/qbg22/evb22/21.evb b/test/qbg22/evb22/21.evb
+new file mode 100644
+index 0000000..d68e299
+--- /dev/null
++++ b/test/qbg22/evb22/21.evb
+@@ -0,0 +1,62 @@
++/*
++ *  Implementation of EVB according to IEEE 802.1Qbg
++ *  (c) Copyright IBM Corp. 2014
++ *
++ *  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++ *
++ *  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".
++ *
++ */
++
++/*
++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set
++ * is needed for each transmission.
++ * The first column defines the run time of the test program  in seconds
++ * when the remaining data on this line will be sent. The rest of the line are
++ * data fields which define the TLVs.
++ * Line limit is 5KB, long lines can be split  with \\ as last character.
++ *
++ * The files are preprocessed with cpp before being read by the test program.
++ *
++ * The data fields per line are
++ * 1. time
++ * 2. destination MAC
++ * 3. source MAC (dash(-) replaced by the senders MAC address)
++ * 4. ethertype
++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are
++ *    chassis-id, port-id, ttl and end)
++ * 6. Optional. Several TLVs starting with @ which are expected results.
++ *    Its an error is it is missing in the reply or TLV differs.
++ */
++/*
++ * EVB negotiation - bridge offers support for reflective relay and station
++ *	requests it. Bridge denies group id bit, but station sets it.
++ */
++
++#include	"defines.evb"
++
++5	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:02:00:00:40:00 end_tlv @evbhead:02:0c:counts
++6	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:03:0c:00:00:00 end_tlv @evbhead:03:0d:counts
++7	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:03:0c:00:00:00 end_tlv @evbhead:03:0d:counts
++8	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:03:0c:00:00:00 end_tlv @evbhead:03:0d:counts
++9	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:03:0c:00:00:00 end_tlv @evbhead:03:0d:counts
++15	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv
+diff --git a/test/qbg22/evb22/22-lldpad.conf b/test/qbg22/evb22/22-lldpad.conf
+new file mode 100644
+index 0000000..456da71
+--- /dev/null
++++ b/test/qbg22/evb22/22-lldpad.conf
+@@ -0,0 +1,55 @@
++#
++#  Implementation of EVB according to IEEE 802.1Qbg ratified standard
++#  (c) Copyright IBM Corp. 2014
++#
++#  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++#  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".
++#
++
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "0452540050244E";
++    };
++    tlvid00000002 : 
++    {
++      info = "0352540050244E";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = true;
++      evbmode = "station";
++      evbrrcap = false;
++      evbrrreq = true;
++      evbgpid = true;
++      ecpretries = 3;
++      ecprte = 8;
++      vdprwd = 8;
++      vdprka = 8;
++    };
++  };
++};
+diff --git a/test/qbg22/evb22/22.evb b/test/qbg22/evb22/22.evb
+new file mode 100644
+index 0000000..628a7ea
+--- /dev/null
++++ b/test/qbg22/evb22/22.evb
+@@ -0,0 +1,62 @@
++/*
++ *  Implementation of EVB according to IEEE 802.1Qbg
++ *  (c) Copyright IBM Corp. 2014
++ *
++ *  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++ *
++ *  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".
++ *
++ */
++
++/*
++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set
++ * is needed for each transmission.
++ * The first column defines the run time of the test program  in seconds
++ * when the remaining data on this line will be sent. The rest of the line are
++ * data fields which define the TLVs.
++ * Line limit is 5KB, long lines can be split  with \\ as last character.
++ *
++ * The files are preprocessed with cpp before being read by the test program.
++ *
++ * The data fields per line are
++ * 1. time
++ * 2. destination MAC
++ * 3. source MAC (dash(-) replaced by the senders MAC address)
++ * 4. ethertype
++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are
++ *    chassis-id, port-id, ttl and end)
++ * 6. Optional. Several TLVs starting with @ which are expected results.
++ *    Its an error is it is missing in the reply or TLV differs.
++ */
++/*
++ * EVB negotiation - bridge offers support for reflective relay and station
++ *	requests it. Bridge and station set group id bit.
++ */
++
++#include	"defines.evb"
++
++5	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:06:00:00:40:00 end_tlv @evbhead:06:0c:counts
++6	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:0c:00:00:00 end_tlv @evbhead:07:0d:counts
++7	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:0d:00:00:00 end_tlv @evbhead:07:0d:counts
++8	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:0d:00:00:00 end_tlv @evbhead:07:0d:counts
++9	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:0d:00:00:00 end_tlv @evbhead:07:0d:counts
++15	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv
+diff --git a/test/qbg22/evb22/23-lldpad.conf b/test/qbg22/evb22/23-lldpad.conf
+new file mode 100644
+index 0000000..456da71
+--- /dev/null
++++ b/test/qbg22/evb22/23-lldpad.conf
+@@ -0,0 +1,55 @@
++#
++#  Implementation of EVB according to IEEE 802.1Qbg ratified standard
++#  (c) Copyright IBM Corp. 2014
++#
++#  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++#  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".
++#
++
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "0452540050244E";
++    };
++    tlvid00000002 : 
++    {
++      info = "0352540050244E";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = true;
++      evbmode = "station";
++      evbrrcap = false;
++      evbrrreq = true;
++      evbgpid = true;
++      ecpretries = 3;
++      ecprte = 8;
++      vdprwd = 8;
++      vdprka = 8;
++    };
++  };
++};
+diff --git a/test/qbg22/evb22/23.evb b/test/qbg22/evb22/23.evb
+new file mode 100644
+index 0000000..ebce9c9
+--- /dev/null
++++ b/test/qbg22/evb22/23.evb
+@@ -0,0 +1,72 @@
++/*
++ *  Implementation of EVB according to IEEE 802.1Qbg
++ *  (c) Copyright IBM Corp. 2014
++ *
++ *  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++ *
++ *  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".
++ *
++ */
++
++/*
++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set
++ * is needed for each transmission.
++ * The first column defines the run time of the test program  in seconds
++ * when the remaining data on this line will be sent. The rest of the line are
++ * data fields which define the TLVs.
++ * Line limit is 5KB, long lines can be split  with \\ as last character.
++ *
++ * The files are preprocessed with cpp before being read by the test program.
++ *
++ * The data fields per line are
++ * 1. time
++ * 2. destination MAC
++ * 3. source MAC (dash(-) replaced by the senders MAC address)
++ * 4. ethertype
++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are
++ *    chassis-id, port-id, ttl and end)
++ * 6. Optional. Several TLVs starting with @ which are expected results.
++ *    Its an error is it is missing in the reply or TLV differs.
++ */
++/*
++ * EVB negotiation - bridge offers support for reflective relay and station
++ *	requests it. Bridge and station set group id bit. Bridge turns off bgid
++ *	later.
++ */
++
++#include	"defines.evb"
++
++5	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:06:00:00:40:00 end_tlv @evbhead:06:0c:counts
++6	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:0c:00:00:00 end_tlv @evbhead:07:0d:counts
++7	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:0d:00:00:00 end_tlv @evbhead:07:0d:counts
++8	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:0d:00:00:00 end_tlv @evbhead:07:0d:counts
++9	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:0d:00:00:00 end_tlv @evbhead:07:0d:counts
++40	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:03:0d:00:00:00 end_tlv @evbhead:03:0d:counts
++41	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:03:0d:00:00:00 end_tlv @evbhead:03:0d:counts
++42	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:03:0d:00:00:00 end_tlv @evbhead:03:0d:counts
++43	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:03:0d:00:00:00 end_tlv @evbhead:03:0d:counts
++44	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:03:0d:00:00:00 end_tlv @evbhead:03:0d:counts
+diff --git a/test/qbg22/evb22/24-lldpad.conf b/test/qbg22/evb22/24-lldpad.conf
+new file mode 100644
+index 0000000..456da71
+--- /dev/null
++++ b/test/qbg22/evb22/24-lldpad.conf
+@@ -0,0 +1,55 @@
++#
++#  Implementation of EVB according to IEEE 802.1Qbg ratified standard
++#  (c) Copyright IBM Corp. 2014
++#
++#  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++#  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".
++#
++
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "0452540050244E";
++    };
++    tlvid00000002 : 
++    {
++      info = "0352540050244E";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = true;
++      evbmode = "station";
++      evbrrcap = false;
++      evbrrreq = true;
++      evbgpid = true;
++      ecpretries = 3;
++      ecprte = 8;
++      vdprwd = 8;
++      vdprka = 8;
++    };
++  };
++};
+diff --git a/test/qbg22/evb22/24.evb b/test/qbg22/evb22/24.evb
+new file mode 100644
+index 0000000..d79a2a9
+--- /dev/null
++++ b/test/qbg22/evb22/24.evb
+@@ -0,0 +1,73 @@
++/*
++ *  Implementation of EVB according to IEEE 802.1Qbg
++ *  (c) Copyright IBM Corp. 2014
++ *
++ *  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++ *
++ *  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".
++ *
++ */
++
++/*
++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set
++ * is needed for each transmission.
++ * The first column defines the run time of the test program  in seconds
++ * when the remaining data on this line will be sent. The rest of the line are
++ * data fields which define the TLVs.
++ * Line limit is 5KB, long lines can be split  with \\ as last character.
++ *
++ * The files are preprocessed with cpp before being read by the test program.
++ *
++ * The data fields per line are
++ * 1. time
++ * 2. destination MAC
++ * 3. source MAC (dash(-) replaced by the senders MAC address)
++ * 4. ethertype
++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are
++ *    chassis-id, port-id, ttl and end)
++ * 6. Optional. Several TLVs starting with @ which are expected results.
++ *    Its an error is it is missing in the reply or TLV differs.
++ */
++/*
++ * EVB negotiation - bridge offers support for reflective relay and station
++ *	requests it. Bridge and station set group id bit. Station turns off
++ *	sgid later.
++ */
++
++#include	"defines.evb"
++
++5	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:06:00:00:40:00 end_tlv @evbhead:06:0c:counts
++6	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:0c:00:40:00 end_tlv @evbhead:07:0d:counts
++7	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts
++8	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts
++9	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts
++51	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:05:00:40:00 end_tlv @evbhead:07:05:counts
++52	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:05:00:40:00 end_tlv @evbhead:07:05:counts
++53	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:05:00:40:00 end_tlv @evbhead:07:05:counts
++54	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:05:00:40:00 end_tlv @evbhead:07:05:counts
++55	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:05:00:40:00 end_tlv @evbhead:07:05:counts
++80	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv
+diff --git a/test/qbg22/evb22/24.sh b/test/qbg22/evb22/24.sh
+new file mode 100755
+index 0000000..f208a1d
+--- /dev/null
++++ b/test/qbg22/evb22/24.sh
+@@ -0,0 +1,33 @@
++#!/bin/bash
++#
++# Test case for LLDPAD EVB Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Configuration file for unknwon vsi data test cases
++#
++
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 16-Aug-2012
++#
++# Execute a single task on the machine running lldpad
++#
++
++# Wait 50 seconds change setting
++sleep 50;
++$1/lldptool -i veth0 -gncb -T -V evb -c evbgpid=no
+diff --git a/test/qbg22/evb22/25-lldpad.conf b/test/qbg22/evb22/25-lldpad.conf
+new file mode 100644
+index 0000000..cea1077
+--- /dev/null
++++ b/test/qbg22/evb22/25-lldpad.conf
+@@ -0,0 +1,55 @@
++#
++#  Implementation of EVB according to IEEE 802.1Qbg ratified standard
++#  (c) Copyright IBM Corp. 2014
++#
++#  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++#  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".
++#
++
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "0452540050244E";
++    };
++    tlvid00000002 : 
++    {
++      info = "0352540050244E";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = false;
++      evbmode = "station";
++      evbrrcap = false;
++      evbrrreq = true;
++      evbgpid = false;
++      ecpretries = 3;
++      ecprte = 8;
++      vdprwd = 8;
++      vdprka = 8;
++    };
++  };
++};
+diff --git a/test/qbg22/evb22/25.evb b/test/qbg22/evb22/25.evb
+new file mode 100644
+index 0000000..e78fd0b
+--- /dev/null
++++ b/test/qbg22/evb22/25.evb
+@@ -0,0 +1,72 @@
++/*
++ *  Implementation of EVB according to IEEE 802.1Qbg
++ *  (c) Copyright IBM Corp. 2014
++ *
++ *  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++ *
++ *  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".
++ *
++ */
++
++/*
++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set
++ * is needed for each transmission.
++ * The first column defines the run time of the test program  in seconds
++ * when the remaining data on this line will be sent. The rest of the line are
++ * data fields which define the TLVs.
++ * Line limit is 5KB, long lines can be split  with \\ as last character.
++ *
++ * The files are preprocessed with cpp before being read by the test program.
++ *
++ * The data fields per line are
++ * 1. time
++ * 2. destination MAC
++ * 3. source MAC (dash(-) replaced by the senders MAC address)
++ * 4. ethertype
++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are
++ *    chassis-id, port-id, ttl and end)
++ * 6. Optional. Several TLVs starting with @ which are expected results.
++ *    Its an error is it is missing in the reply or TLV differs.
++ */
++/*
++ * EVB negotiation - bridge offers support for reflective relay and station
++ *	requests it.
++ */
++
++#include	"defines.evb"
++
++5	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evb_brrr end_tlv \\
++		@02:07:04:e6:f1:20:5a:b0:e6\\
++		@04:07:03:e6:f1:20:5a:b0:e6\\
++		@06:02:00:78:00:00
++6	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:03:04:00:00:00 end_tlv \\
++		@02:07:04:e6:f1:20:5a:b0:e6\\
++		@04:07:03:e6:f1:20:5a:b0:e6\\
++		@06:02:00:78:00:00
++7	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:03:05:00:00:00 end_tlv \\
++		@02:07:04:e6:f1:20:5a:b0:e6\\
++		@04:07:03:e6:f1:20:5a:b0:e6\\
++		@06:02:00:78:00:00
++8	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:03:05:00:00:00 end_tlv \\
++		@02:07:04:e6:f1:20:5a:b0:e6\\
++		@04:07:03:e6:f1:20:5a:b0:e6\\
++		@06:02:00:78:00:00
++15	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv
+diff --git a/test/qbg22/evb22/26-lldpad.conf b/test/qbg22/evb22/26-lldpad.conf
+new file mode 100644
+index 0000000..ebe91e0
+--- /dev/null
++++ b/test/qbg22/evb22/26-lldpad.conf
+@@ -0,0 +1,55 @@
++#
++#  Implementation of EVB according to IEEE 802.1Qbg ratified standard
++#  (c) Copyright IBM Corp. 2014
++#
++#  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++#  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".
++#
++
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "0452540050244E";
++    };
++    tlvid00000002 : 
++    {
++      info = "0352540050244E";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = true;
++      evbmode = "station";
++      evbrrcap = false;
++      evbrrreq = true;
++      evbgpid = false;
++      ecpretries = 3;
++      ecprte = 8;
++      vdprwd = 8;
++      vdprka = 8;
++    };
++  };
++};
+diff --git a/test/qbg22/evb22/26.evb b/test/qbg22/evb22/26.evb
+new file mode 100644
+index 0000000..f3ff74d
+--- /dev/null
++++ b/test/qbg22/evb22/26.evb
+@@ -0,0 +1,83 @@
++/*
++ *  Implementation of EVB according to IEEE 802.1Qbg
++ *  (c) Copyright IBM Corp. 2014
++ *
++ *  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++ *
++ *  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".
++ *
++ */
++
++/*
++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set
++ * is needed for each transmission.
++ * The first column defines the run time of the test program  in seconds
++ * when the remaining data on this line will be sent. The rest of the line are
++ * data fields which define the TLVs.
++ * Line limit is 5KB, long lines can be split  with \\ as last character.
++ *
++ * The files are preprocessed with cpp before being read by the test program.
++ *
++ * The data fields per line are
++ * 1. time
++ * 2. destination MAC
++ * 3. source MAC (dash(-) replaced by the senders MAC address)
++ * 4. ethertype
++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are
++ *    chassis-id, port-id, ttl and end)
++ * 6. Optional. Several TLVs starting with @ which are expected results.
++ *    Its an error is it is missing in the reply or TLV differs.
++ */
++/*
++ * EVB negotiation - bridge offers support for reflective relay and station
++ *	requests it.
++ */
++
++#include	"defines.evb"
++
++5	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evb_brrr end_tlv @evbhead:02:04:counts
++6	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:03:04:00:00:00 end_tlv @evbhead:03:05:counts
++7	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:03:05:00:00:00 end_tlv @evbhead:03:05:counts
++8	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:03:05:00:00:00 end_tlv @evbhead:03:05:counts
++9	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:03:05:00:00:00 end_tlv @evbhead:03:05:counts
++10	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:03:05:00:00:00 end_tlv @evbhead:03:05:counts
++11	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:03:05:00:00:00 end_tlv @evbhead:03:05:counts
++41	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:03:05:00:00:00 end_tlv @evbhead:03:05:counts
++51	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:03:05:00:00:00 end_tlv \\
++		@02:07:04:e6:f1:20:5a:b0:e6\\
++		@04:07:03:e6:f1:20:5a:b0:e6\\
++		@06:02:00:78:00:00
++52	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:03:05:00:00:00 end_tlv \\
++		@02:07:04:e6:f1:20:5a:b0:e6\\
++		@04:07:03:e6:f1:20:5a:b0:e6\\
++		@06:02:00:78:00:00
++53	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:03:05:00:00:00 end_tlv \\
++		@02:07:04:e6:f1:20:5a:b0:e6\\
++		@04:07:03:e6:f1:20:5a:b0:e6\\
++		@06:02:00:78:00:00
++90	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv
+diff --git a/test/qbg22/evb22/26.sh b/test/qbg22/evb22/26.sh
+new file mode 100755
+index 0000000..10abfac
+--- /dev/null
++++ b/test/qbg22/evb22/26.sh
+@@ -0,0 +1,33 @@
++#!/bin/bash
++#
++# Test case for LLDPAD EVB Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Configuration file for unknwon vsi data test cases
++#
++
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 16-Aug-2012
++#
++# Execute a single task on the machine running lldpad
++#
++
++# Wait 50 seconds change setting
++sleep 50;
++$1/lldptool -i veth0 -gncb -T -V evb -c enableTx=no
+diff --git a/test/qbg22/evb22/3-lldpad.conf b/test/qbg22/evb22/3-lldpad.conf
+new file mode 100644
+index 0000000..ebe91e0
+--- /dev/null
++++ b/test/qbg22/evb22/3-lldpad.conf
+@@ -0,0 +1,55 @@
++#
++#  Implementation of EVB according to IEEE 802.1Qbg ratified standard
++#  (c) Copyright IBM Corp. 2014
++#
++#  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++#  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".
++#
++
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "0452540050244E";
++    };
++    tlvid00000002 : 
++    {
++      info = "0352540050244E";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = true;
++      evbmode = "station";
++      evbrrcap = false;
++      evbrrreq = true;
++      evbgpid = false;
++      ecpretries = 3;
++      ecprte = 8;
++      vdprwd = 8;
++      vdprka = 8;
++    };
++  };
++};
+diff --git a/test/qbg22/evb22/3.evb b/test/qbg22/evb22/3.evb
+new file mode 100644
+index 0000000..cd80fd0
+--- /dev/null
++++ b/test/qbg22/evb22/3.evb
+@@ -0,0 +1,60 @@
++/*
++ *  Implementation of EVB according to IEEE 802.1Qbg
++ *  (c) Copyright IBM Corp. 2014
++ *
++ *  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++ *
++ *  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".
++ *
++ */
++
++/*
++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set
++ * is needed for each transmission.
++ * The first column defines the run time of the test program  in seconds
++ * when the remaining data on this line will be sent. The rest of the line are
++ * data fields which define the TLVs.
++ * Line limit is 5KB, long lines can be split  with \\ as last character.
++ *
++ * The files are preprocessed with cpp before being read by the test program.
++ *
++ * The data fields per line are
++ * 1. time
++ * 2. destination MAC
++ * 3. source MAC (dash(-) replaced by the senders MAC address)
++ * 4. ethertype
++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are
++ *    chassis-id, port-id, ttl and end)
++ * 6. Optional. Several TLVs starting with @ which are expected results.
++ *    Its an error is it is missing in the reply or TLV differs.
++ */
++/*
++ * EVB negotiation - bridge does not support reflective relay but station
++ *	requests it.
++ */
++
++#include	"defines.evb"
++
++5	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evb_norr end_tlv @evb_strr_ack
++6	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evb_norr2 end_tlv @evb_strr_ack
++7	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evb_norr2 end_tlv @evb_strr_ack
++8	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evb_norr2 end_tlv @evb_strr_ack
++15	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv
+diff --git a/test/qbg22/evb22/30-lldpad.conf b/test/qbg22/evb22/30-lldpad.conf
+new file mode 100644
+index 0000000..0b1dcd8
+--- /dev/null
++++ b/test/qbg22/evb22/30-lldpad.conf
+@@ -0,0 +1,55 @@
++#
++#  Implementation of EVB according to IEEE 802.1Qbg ratified standard
++#  (c) Copyright IBM Corp. 2014
++#
++#  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++#  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".
++#
++
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "0452540050244E";
++    };
++    tlvid00000002 : 
++    {
++      info = "0352540050244E";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = true;
++      evbmode = "bridge";
++      evbrrcap = false;
++      evbrrreq = false;
++      evbgpid = false;
++      ecpretries = 5;
++      ecprte = 6;
++      vdprwd = 24;
++      vdprka = 24;
++    };
++  };
++};
+diff --git a/test/qbg22/evb22/30.evb b/test/qbg22/evb22/30.evb
+new file mode 100644
+index 0000000..49bbe29
+--- /dev/null
++++ b/test/qbg22/evb22/30.evb
+@@ -0,0 +1,61 @@
++/*
++ *  Implementation of EVB according to IEEE 802.1Qbg
++ *  (c) Copyright IBM Corp. 2014
++ *
++ *  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++ *
++ *  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".
++ *
++ */
++
++/*
++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set
++ * is needed for each transmission.
++ * The first column defines the run time of the test program  in seconds
++ * when the remaining data on this line will be sent. The rest of the line are
++ * data fields which define the TLVs.
++ * Line limit is 5KB, long lines can be split  with \\ as last character.
++ *
++ * The files are preprocessed with cpp before being read by the test program.
++ *
++ * The data fields per line are
++ * 1. time
++ * 2. destination MAC
++ * 3. source MAC (dash(-) replaced by the senders MAC address)
++ * 4. ethertype
++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are
++ *    chassis-id, port-id, ttl and end)
++ * 6. Optional. Several TLVs starting with @ which are expected results.
++ *    Its an error is it is missing in the reply or TLV differs.
++ */
++/*
++ * EVB negotiation - Runs a station. No reflective relay and sgid support.
++ */
++
++#include	"defines.evb"
++
++5	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:00:01:00:80:00 end_tlv @evbhead:00:01:stcounts
++6	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:00:00:00:00:00 end_tlv @evbhead:00:00:stcounts
++7	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:00:00:00:00:00 end_tlv @evbhead:00:00:stcounts
++8	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:00:00:00:00:00 end_tlv @evbhead:00:00:stcounts
++9	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:00:00:00:00:00 end_tlv @evbhead:00:00:stcounts
++15	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv
+diff --git a/test/qbg22/evb22/31-lldpad.conf b/test/qbg22/evb22/31-lldpad.conf
+new file mode 100644
+index 0000000..e2a7c42
+--- /dev/null
++++ b/test/qbg22/evb22/31-lldpad.conf
+@@ -0,0 +1,55 @@
++#
++#  Implementation of EVB according to IEEE 802.1Qbg ratified standard
++#  (c) Copyright IBM Corp. 2014
++#
++#  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++#  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".
++#
++
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "0452540050244E";
++    };
++    tlvid00000002 : 
++    {
++      info = "0352540050244E";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = true;
++      evbmode = "bridge";
++      evbrrcap = true;
++      evbrrreq = false;
++      evbgpid = false;
++      ecpretries = 5;
++      ecprte = 6;
++      vdprwd = 24;
++      vdprka = 24;
++    };
++  };
++};
+diff --git a/test/qbg22/evb22/31.evb b/test/qbg22/evb22/31.evb
+new file mode 100644
+index 0000000..4b6d8e6
+--- /dev/null
++++ b/test/qbg22/evb22/31.evb
+@@ -0,0 +1,62 @@
++/*
++ *  Implementation of EVB according to IEEE 802.1Qbg
++ *  (c) Copyright IBM Corp. 2014
++ *
++ *  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++ *
++ *  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".
++ *
++ */
++
++/*
++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set
++ * is needed for each transmission.
++ * The first column defines the run time of the test program  in seconds
++ * when the remaining data on this line will be sent. The rest of the line are
++ * data fields which define the TLVs.
++ * Line limit is 5KB, long lines can be split  with \\ as last character.
++ *
++ * The files are preprocessed with cpp before being read by the test program.
++ *
++ * The data fields per line are
++ * 1. time
++ * 2. destination MAC
++ * 3. source MAC (dash(-) replaced by the senders MAC address)
++ * 4. ethertype
++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are
++ *    chassis-id, port-id, ttl and end)
++ * 6. Optional. Several TLVs starting with @ which are expected results.
++ *    Its an error is it is missing in the reply or TLV differs.
++ */
++/*
++ * EVB negotiation - Runs a station. Bridge offers reflective relay,
++ *	no sgid support.
++ */
++
++#include	"defines.evb"
++
++5	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:00:01:00:80:00 end_tlv @evbhead:02:01:stcounts
++6	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:02:00:00:00:00 end_tlv @evbhead:02:00:stcounts
++7	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:02:00:00:00:00 end_tlv @evbhead:02:00:stcounts
++8	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:02:00:00:00:00 end_tlv @evbhead:02:00:stcounts
++9	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:02:00:00:00:00 end_tlv @evbhead:02:00:stcounts
++15	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv
+diff --git a/test/qbg22/evb22/32-lldpad.conf b/test/qbg22/evb22/32-lldpad.conf
+new file mode 100644
+index 0000000..78608e4
+--- /dev/null
++++ b/test/qbg22/evb22/32-lldpad.conf
+@@ -0,0 +1,55 @@
++#
++#  Implementation of EVB according to IEEE 802.1Qbg ratified standard
++#  (c) Copyright IBM Corp. 2014
++#
++#  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++#  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".
++#
++
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "0452540050244E";
++    };
++    tlvid00000002 : 
++    {
++      info = "0352540050244E";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = true;
++      evbmode = "bridge";
++      evbrrcap = true;
++      evbrrreq = false;
++      evbgpid = true;
++      ecpretries = 5;
++      ecprte = 6;
++      vdprwd = 24;
++      vdprka = 24;
++    };
++  };
++};
+diff --git a/test/qbg22/evb22/32.evb b/test/qbg22/evb22/32.evb
+new file mode 100644
+index 0000000..23127c4
+--- /dev/null
++++ b/test/qbg22/evb22/32.evb
+@@ -0,0 +1,62 @@
++/*
++ *  Implementation of EVB according to IEEE 802.1Qbg
++ *  (c) Copyright IBM Corp. 2014
++ *
++ *  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++ *
++ *  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".
++ *
++ */
++
++/*
++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set
++ * is needed for each transmission.
++ * The first column defines the run time of the test program  in seconds
++ * when the remaining data on this line will be sent. The rest of the line are
++ * data fields which define the TLVs.
++ * Line limit is 5KB, long lines can be split  with \\ as last character.
++ *
++ * The files are preprocessed with cpp before being read by the test program.
++ *
++ * The data fields per line are
++ * 1. time
++ * 2. destination MAC
++ * 3. source MAC (dash(-) replaced by the senders MAC address)
++ * 4. ethertype
++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are
++ *    chassis-id, port-id, ttl and end)
++ * 6. Optional. Several TLVs starting with @ which are expected results.
++ *    Its an error is it is missing in the reply or TLV differs.
++ */
++/*
++ * EVB negotiation - Runs a station. Bridge offers reflective relay and
++ *	sgid support.
++ */
++
++#include	"defines.evb"
++
++5	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:00:01:00:80:00 end_tlv @evbhead:06:01:stcounts
++6	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:06:00:00:00:00 end_tlv @evbhead:06:00:stcounts
++7	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:06:00:00:00:00 end_tlv @evbhead:06:00:stcounts
++8	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:06:00:00:00:00 end_tlv @evbhead:06:00:stcounts
++9	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:06:00:00:00:00 end_tlv @evbhead:06:00:stcounts
++15	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv
+diff --git a/test/qbg22/evb22/33-lldpad.conf b/test/qbg22/evb22/33-lldpad.conf
+new file mode 100644
+index 0000000..78608e4
+--- /dev/null
++++ b/test/qbg22/evb22/33-lldpad.conf
+@@ -0,0 +1,55 @@
++#
++#  Implementation of EVB according to IEEE 802.1Qbg ratified standard
++#  (c) Copyright IBM Corp. 2014
++#
++#  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++#  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".
++#
++
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "0452540050244E";
++    };
++    tlvid00000002 : 
++    {
++      info = "0352540050244E";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = true;
++      evbmode = "bridge";
++      evbrrcap = true;
++      evbrrreq = false;
++      evbgpid = true;
++      ecpretries = 5;
++      ecprte = 6;
++      vdprwd = 24;
++      vdprka = 24;
++    };
++  };
++};
+diff --git a/test/qbg22/evb22/33.evb b/test/qbg22/evb22/33.evb
+new file mode 100644
+index 0000000..65da9d2
+--- /dev/null
++++ b/test/qbg22/evb22/33.evb
+@@ -0,0 +1,62 @@
++/*
++ *  Implementation of EVB according to IEEE 802.1Qbg
++ *  (c) Copyright IBM Corp. 2014
++ *
++ *  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++ *
++ *  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".
++ *
++ */
++
++/*
++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set
++ * is needed for each transmission.
++ * The first column defines the run time of the test program  in seconds
++ * when the remaining data on this line will be sent. The rest of the line are
++ * data fields which define the TLVs.
++ * Line limit is 5KB, long lines can be split  with \\ as last character.
++ *
++ * The files are preprocessed with cpp before being read by the test program.
++ *
++ * The data fields per line are
++ * 1. time
++ * 2. destination MAC
++ * 3. source MAC (dash(-) replaced by the senders MAC address)
++ * 4. ethertype
++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are
++ *    chassis-id, port-id, ttl and end)
++ * 6. Optional. Several TLVs starting with @ which are expected results.
++ *    Its an error is it is missing in the reply or TLV differs.
++ */
++/*
++ * EVB negotiation - Runs a station. Bridge offers eflective relay and
++ *	sgid support. Station accepts both.
++ */
++
++#include	"defines.evb"
++
++5	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:00:0d:00:80:00 end_tlv @evbhead:07:0d:stcounts
++6	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:0e:00:00:00 end_tlv @evbhead:07:0e:stcounts
++7	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:0e:00:00:00 end_tlv @evbhead:07:0e:stcounts
++8	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:0e:00:00:00 end_tlv @evbhead:07:0e:stcounts
++9	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:0e:00:00:00 end_tlv @evbhead:07:0e:stcounts
++15	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv
+diff --git a/test/qbg22/evb22/4-lldpad.conf b/test/qbg22/evb22/4-lldpad.conf
+new file mode 100644
+index 0000000..ebe91e0
+--- /dev/null
++++ b/test/qbg22/evb22/4-lldpad.conf
+@@ -0,0 +1,55 @@
++#
++#  Implementation of EVB according to IEEE 802.1Qbg ratified standard
++#  (c) Copyright IBM Corp. 2014
++#
++#  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++#  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".
++#
++
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "0452540050244E";
++    };
++    tlvid00000002 : 
++    {
++      info = "0352540050244E";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = true;
++      evbmode = "station";
++      evbrrcap = false;
++      evbrrreq = true;
++      evbgpid = false;
++      ecpretries = 3;
++      ecprte = 8;
++      vdprwd = 8;
++      vdprka = 8;
++    };
++  };
++};
+diff --git a/test/qbg22/evb22/4.evb b/test/qbg22/evb22/4.evb
+new file mode 100644
+index 0000000..e64e5b5
+--- /dev/null
++++ b/test/qbg22/evb22/4.evb
+@@ -0,0 +1,60 @@
++/*
++ *  Implementation of EVB according to IEEE 802.1Qbg
++ *  (c) Copyright IBM Corp. 2014
++ *
++ *  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++ *
++ *  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".
++ *
++ */
++
++/*
++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set
++ * is needed for each transmission.
++ * The first column defines the run time of the test program  in seconds
++ * when the remaining data on this line will be sent. The rest of the line are
++ * data fields which define the TLVs.
++ * Line limit is 5KB, long lines can be split  with \\ as last character.
++ *
++ * The files are preprocessed with cpp before being read by the test program.
++ *
++ * The data fields per line are
++ * 1. time
++ * 2. destination MAC
++ * 3. source MAC (dash(-) replaced by the senders MAC address)
++ * 4. ethertype
++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are
++ *    chassis-id, port-id, ttl and end)
++ * 6. Optional. Several TLVs starting with @ which are expected results.
++ *    Its an error is it is missing in the reply or TLV differs.
++ */
++/*
++ * EVB negotiation - bridge offers support for reflective relay and station
++ *	requests it.
++ */
++
++#include	"defines.evb"
++
++5	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evb_brrr end_tlv @evbhead:02:04:counts
++6	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:03:04:00:00:00 end_tlv @evbhead:03:05:counts
++7	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:03:05:00:00:00 end_tlv @evbhead:03:05:counts
++8	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:03:05:00:00:00 end_tlv @evbhead:03:05:counts
++15	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv
+diff --git a/test/qbg22/evb22/41-lldpad.conf b/test/qbg22/evb22/41-lldpad.conf
+new file mode 100644
+index 0000000..ec9b520
+--- /dev/null
++++ b/test/qbg22/evb22/41-lldpad.conf
+@@ -0,0 +1,43 @@
++#
++#  Implementation of EVB according to IEEE 802.1Qbg ratified standard
++#  (c) Copyright IBM Corp. 2014
++#
++#  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++#  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".
++#
++
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "0452540050244E";
++    };
++    tlvid00000002 : 
++    {
++      info = "0352540050244E";
++    };
++    adminStatus = 3;
++  };
++};
+diff --git a/test/qbg22/evb22/41.evb b/test/qbg22/evb22/41.evb
+new file mode 100644
+index 0000000..ef941ce
+--- /dev/null
++++ b/test/qbg22/evb22/41.evb
+@@ -0,0 +1,57 @@
++/*
++ *  Implementation of EVB according to IEEE 802.1Qbg
++ *  (c) Copyright IBM Corp. 2014
++ *
++ *  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++ *
++ *  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".
++ *
++ */
++
++/*
++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set
++ * is needed for each transmission.
++ * The first column defines the run time of the test program  in seconds
++ * when the remaining data on this line will be sent. The rest of the line are
++ * data fields which define the TLVs.
++ * Line limit is 5KB, long lines can be split  with \\ as last character.
++ *
++ * The files are preprocessed with cpp before being read by the test program.
++ *
++ * The data fields per line are
++ * 1. time
++ * 2. destination MAC
++ * 3. source MAC (dash(-) replaced by the senders MAC address)
++ * 4. ethertype
++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are
++ *    chassis-id, port-id, ttl and end)
++ * 6. Optional. Several TLVs starting with @ which are expected results.
++ *    Its an error is it is missing in the reply or TLV differs.
++ */
++/*
++ * EVB negotiation - Do nothing, send data and expect no response.
++ */
++
++#include	"defines.evb"
++
++5	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120
++6	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120
++7	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120
++8	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120
++9	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120
++35	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120
++65	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120
+diff --git a/test/qbg22/evb22/41.sh b/test/qbg22/evb22/41.sh
+new file mode 100755
+index 0000000..03a1d00
+--- /dev/null
++++ b/test/qbg22/evb22/41.sh
+@@ -0,0 +1,58 @@
++#!/bin/bash
++#
++# Test case for LLDPAD EVB Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Configuration file for unknwon vsi data test cases
++#
++
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 16-Aug-2012
++#
++# Execute a single task on the machine running lldpad
++#
++
++# Wait some seconds and then change setting, define evb22.enableTx=no
++sleep 30;
++$1/lldptool -i veth0 -gncb -T -V evb -c enableTx=no
++rc=$?
++if [ $rc -ne 0 ]
++then
++	echo $rc "FAILURE:lldptool -i veth0 -gncb -T -V evb -c enabletx=no"
++	exit $rc
++fi
++
++sleep 20
++$1/lldptool -i veth0 -gncb -T -V evbcfg -c enableTx=no
++rc=$?
++if [ $rc -ne 0 ]
++then
++	echo $rc "FAILURE:lldptool -i veth0 -gncb -T -V evbcfg -c enabletx=no"
++	exit $rc
++fi
++
++sleep 10
++lines="$(fgrep 'enableTx = false;' /tmp/$(basename $0 .sh)-lldpad.conf | wc -l)"
++
++if [ "x$lines" != x2 ]
++then
++	rc=5
++	echo $rc "FAILURE:lldptool -V evbcfg/evb -c enabletx=no"
++fi
++exit $rc
+diff --git a/test/qbg22/evb22/42-lldpad.conf b/test/qbg22/evb22/42-lldpad.conf
+new file mode 100644
+index 0000000..ec9b520
+--- /dev/null
++++ b/test/qbg22/evb22/42-lldpad.conf
+@@ -0,0 +1,43 @@
++#
++#  Implementation of EVB according to IEEE 802.1Qbg ratified standard
++#  (c) Copyright IBM Corp. 2014
++#
++#  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++#  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".
++#
++
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "0452540050244E";
++    };
++    tlvid00000002 : 
++    {
++      info = "0352540050244E";
++    };
++    adminStatus = 3;
++  };
++};
+diff --git a/test/qbg22/evb22/42.evb b/test/qbg22/evb22/42.evb
+new file mode 100644
+index 0000000..ef941ce
+--- /dev/null
++++ b/test/qbg22/evb22/42.evb
+@@ -0,0 +1,57 @@
++/*
++ *  Implementation of EVB according to IEEE 802.1Qbg
++ *  (c) Copyright IBM Corp. 2014
++ *
++ *  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++ *
++ *  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".
++ *
++ */
++
++/*
++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set
++ * is needed for each transmission.
++ * The first column defines the run time of the test program  in seconds
++ * when the remaining data on this line will be sent. The rest of the line are
++ * data fields which define the TLVs.
++ * Line limit is 5KB, long lines can be split  with \\ as last character.
++ *
++ * The files are preprocessed with cpp before being read by the test program.
++ *
++ * The data fields per line are
++ * 1. time
++ * 2. destination MAC
++ * 3. source MAC (dash(-) replaced by the senders MAC address)
++ * 4. ethertype
++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are
++ *    chassis-id, port-id, ttl and end)
++ * 6. Optional. Several TLVs starting with @ which are expected results.
++ *    Its an error is it is missing in the reply or TLV differs.
++ */
++/*
++ * EVB negotiation - Do nothing, send data and expect no response.
++ */
++
++#include	"defines.evb"
++
++5	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120
++6	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120
++7	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120
++8	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120
++9	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120
++35	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120
++65	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120
+diff --git a/test/qbg22/evb22/42.sh b/test/qbg22/evb22/42.sh
+new file mode 100755
+index 0000000..dd9d179
+--- /dev/null
++++ b/test/qbg22/evb22/42.sh
+@@ -0,0 +1,65 @@
++#!/bin/bash
++#
++# Test case for LLDPAD EVB Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Configuration file for unknwon vsi data test cases
++#
++
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 16-Aug-2012
++#
++# Execute a single task on the machine running lldpad
++#
++
++# Wait some seconds and then change setting
++sleep 30;
++$1/lldptool -i veth0 -gncb -T -V evb -c enableTx=no
++rc=$?
++if [ $rc -ne 0 ]
++then
++	echo $rc "FAILURE:lldptool -i veth0 -gncb -T -V evb -c enabletx=no"
++	exit $rc
++fi
++lines="$(fgrep 'enableTx = false;' /tmp/$(basename $0 .sh)-lldpad.conf | wc -l)"
++if [ "x$lines" != x1 ]
++then
++	rc=4
++	echo $rc "FAILURE:lldptool -V evb -c enabletx=no"
++	exit $rc
++fi
++
++sleep 20
++$1/lldptool -i veth0 -gncb -T -V evbcfg -c enableTx=yes -c fmode=reflectiverelay -c capabilities="rte ecp vdp"
++rc=$?
++if [ $rc -ne 0 ]
++then
++	echo $rc "FAILURE:lldptool -i veth0 -gncb -T -V evbcfg -c enabletx=yes ..."
++	exit $rc
++fi
++
++lines="$(fgrep 'enableTx = true;' /tmp/$(basename $0 .sh)-lldpad.conf | wc -l)"
++if [ "x$lines" != x1 ]
++then
++	rc=5
++	echo $rc "FAILURE:lldptool -V evbcfg -c enabletx=yes ..."
++	echo lines $lines
++	exit $rc
++fi
++exit $rc
+diff --git a/test/qbg22/evb22/43-lldpad.conf b/test/qbg22/evb22/43-lldpad.conf
+new file mode 100644
+index 0000000..ec9b520
+--- /dev/null
++++ b/test/qbg22/evb22/43-lldpad.conf
+@@ -0,0 +1,43 @@
++#
++#  Implementation of EVB according to IEEE 802.1Qbg ratified standard
++#  (c) Copyright IBM Corp. 2014
++#
++#  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++#  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".
++#
++
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "0452540050244E";
++    };
++    tlvid00000002 : 
++    {
++      info = "0352540050244E";
++    };
++    adminStatus = 3;
++  };
++};
+diff --git a/test/qbg22/evb22/43.evb b/test/qbg22/evb22/43.evb
+new file mode 100644
+index 0000000..ef941ce
+--- /dev/null
++++ b/test/qbg22/evb22/43.evb
+@@ -0,0 +1,57 @@
++/*
++ *  Implementation of EVB according to IEEE 802.1Qbg
++ *  (c) Copyright IBM Corp. 2014
++ *
++ *  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++ *
++ *  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".
++ *
++ */
++
++/*
++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set
++ * is needed for each transmission.
++ * The first column defines the run time of the test program  in seconds
++ * when the remaining data on this line will be sent. The rest of the line are
++ * data fields which define the TLVs.
++ * Line limit is 5KB, long lines can be split  with \\ as last character.
++ *
++ * The files are preprocessed with cpp before being read by the test program.
++ *
++ * The data fields per line are
++ * 1. time
++ * 2. destination MAC
++ * 3. source MAC (dash(-) replaced by the senders MAC address)
++ * 4. ethertype
++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are
++ *    chassis-id, port-id, ttl and end)
++ * 6. Optional. Several TLVs starting with @ which are expected results.
++ *    Its an error is it is missing in the reply or TLV differs.
++ */
++/*
++ * EVB negotiation - Do nothing, send data and expect no response.
++ */
++
++#include	"defines.evb"
++
++5	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120
++6	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120
++7	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120
++8	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120
++9	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120
++35	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120
++65	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120
+diff --git a/test/qbg22/evb22/43.sh b/test/qbg22/evb22/43.sh
+new file mode 100755
+index 0000000..4961e59
+--- /dev/null
++++ b/test/qbg22/evb22/43.sh
+@@ -0,0 +1,64 @@
++#!/bin/bash
++#
++# Test case for LLDPAD EVB Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Configuration file for unknwon vsi data test cases
++#
++
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 16-Aug-2012
++#
++# Execute a single task on the machine running lldpad
++#
++
++# Wait some seconds and then change setting
++sleep 30;
++$1/lldptool -i veth0 -gncb -T -V evb -c enableTx=yes
++rc=$?
++if [ $rc -ne 0 ]
++then
++	echo $rc "FAILURE:lldptool -i veth0 -gncb -T -V evb -c enabletx=yes"
++	exit $rc
++fi
++lines="$(fgrep 'enableTx = true;' /tmp/$(basename $0 .sh)-lldpad.conf | wc -l)"
++if [ "x$lines" != x1 ]
++then
++	rc=4
++	echo $rc "FAILURE:lldptool -V evb -c enabletx=no"
++	exit $rc
++fi
++
++sleep 20
++$1/lldptool -i veth0 -gncb -T -V evbcfg -c enableTx=no -c fmode=reflectiverelay -c capabilities="rte ecp vdp"
++rc=$?
++if [ $rc -ne 0 ]
++then
++	echo $rc "FAILURE:lldptool -i veth0 -gncb -T -V evbcfg -c enabletx=no ..."
++	exit $rc
++fi
++
++lines="$(fgrep 'enableTx = false;' /tmp/$(basename $0 .sh)-lldpad.conf | wc -l)"
++if [ "x$lines" != x1 ]
++then
++	rc=5
++	echo $rc "FAILURE:lldptool -V evbcfg -c enabletx=no ..."
++	exit $rc
++fi
++exit $rc
+diff --git a/test/qbg22/evb22/44-lldpad.conf b/test/qbg22/evb22/44-lldpad.conf
+new file mode 100644
+index 0000000..ec9b520
+--- /dev/null
++++ b/test/qbg22/evb22/44-lldpad.conf
+@@ -0,0 +1,43 @@
++#
++#  Implementation of EVB according to IEEE 802.1Qbg ratified standard
++#  (c) Copyright IBM Corp. 2014
++#
++#  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++#  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".
++#
++
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "0452540050244E";
++    };
++    tlvid00000002 : 
++    {
++      info = "0352540050244E";
++    };
++    adminStatus = 3;
++  };
++};
+diff --git a/test/qbg22/evb22/44.evb b/test/qbg22/evb22/44.evb
+new file mode 100644
+index 0000000..d0b552e
+--- /dev/null
++++ b/test/qbg22/evb22/44.evb
+@@ -0,0 +1,59 @@
++/*
++ *  Implementation of EVB according to IEEE 802.1Qbg
++ *  (c) Copyright IBM Corp. 2014
++ *
++ *  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++ *
++ *  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".
++ *
++ */
++
++/*
++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set
++ * is needed for each transmission.
++ * The first column defines the run time of the test program  in seconds
++ * when the remaining data on this line will be sent. The rest of the line are
++ * data fields which define the TLVs.
++ * Line limit is 5KB, long lines can be split  with \\ as last character.
++ *
++ * The files are preprocessed with cpp before being read by the test program.
++ *
++ * The data fields per line are
++ * 1. time
++ * 2. destination MAC
++ * 3. source MAC (dash(-) replaced by the senders MAC address)
++ * 4. ethertype
++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are
++ *    chassis-id, port-id, ttl and end)
++ * 6. Optional. Several TLVs starting with @ which are expected results.
++ *    Its an error is it is missing in the reply or TLV differs.
++ */
++/*
++ * EVB negotiation - Do nothing, send data and expect no response.
++ */
++
++#include	"defines.evb"
++
++5	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120
++6	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120
++7	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120
++8	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120
++9	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120
++35	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120
++65	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120
++95	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120
++125	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120
+diff --git a/test/qbg22/evb22/44.sh b/test/qbg22/evb22/44.sh
+new file mode 100755
+index 0000000..351a478
+--- /dev/null
++++ b/test/qbg22/evb22/44.sh
+@@ -0,0 +1,60 @@
++#!/bin/bash
++#
++# Test case for LLDPAD EVB Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Configuration file for unknwon vsi data test cases
++#
++
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 16-Aug-2012
++#
++# Execute a single task on the machine running lldpad
++#
++
++# Wait some seconds and then change setting
++sleep 30;
++$1/lldptool -i veth0 -gncb -T -V evbcfg -c enableTx=yes -c fmode=reflectiverelay -c capabilities="rte ecp vdp"
++rc=$?
++if [ $rc -ne 0 ]
++then
++	echo $rc "FAILURE:lldptool -i veth0 -gncb -T -V evbcfg -c enabletx=yes ..."
++	exit $rc
++fi
++
++sleep 20
++# Command must not succeed
++$1/lldptool -i veth0 -gncb -T -V evb -c enableTx=yes >/dev/null
++rc=$?
++if [ $rc -ne 1 ]
++then
++	rc=4
++	echo $rc "FAILURE:lldptool -i veth0 -gncb -T -V evb -c enabletx=yes"
++	exit $rc
++fi
++rc=0
++
++sleep 30
++lines="$(fgrep 'enableTx = true;' /tmp/$(basename $0 .sh)-lldpad.conf | wc -l)"
++if [ "x$lines" != x1 ]
++then
++	rc=5
++	echo $rc "FAILURE:lldptool -V evbcfg/evb -c enabletx=yes"
++fi
++exit $rc
+diff --git a/test/qbg22/evb22/45-lldpad.conf b/test/qbg22/evb22/45-lldpad.conf
+new file mode 100644
+index 0000000..12b2304
+--- /dev/null
++++ b/test/qbg22/evb22/45-lldpad.conf
+@@ -0,0 +1,53 @@
++#
++#  Implementation of EVB according to IEEE 802.1Qbg ratified standard
++#  (c) Copyright IBM Corp. 2014
++#
++#  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++#  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".
++#
++
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "0452540050244E";
++    };
++    tlvid00000002 : 
++    {
++      info = "0352540050244E";
++    };
++    adminStatus = 3;
++    tlvid001b3f00 :
++    {
++      enableTx = true;
++      fmode = "reflectiverelay";
++      capabilities = "rte ecp vdp";
++    };
++    tlvid0080c20d : 
++    {
++      enableTx = true;
++    };
++  };
++};
+diff --git a/test/qbg22/evb22/45.evb b/test/qbg22/evb22/45.evb
+new file mode 100644
+index 0000000..bdcd955
+--- /dev/null
++++ b/test/qbg22/evb22/45.evb
+@@ -0,0 +1,56 @@
++/*
++ *  Implementation of EVB according to IEEE 802.1Qbg
++ *  (c) Copyright IBM Corp. 2014
++ *
++ *  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++ *
++ *  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".
++ *
++ */
++
++/*
++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set
++ * is needed for each transmission.
++ * The first column defines the run time of the test program  in seconds
++ * when the remaining data on this line will be sent. The rest of the line are
++ * data fields which define the TLVs.
++ * Line limit is 5KB, long lines can be split  with \\ as last character.
++ *
++ * The files are preprocessed with cpp before being read by the test program.
++ *
++ * The data fields per line are
++ * 1. time
++ * 2. destination MAC
++ * 3. source MAC (dash(-) replaced by the senders MAC address)
++ * 4. ethertype
++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are
++ *    chassis-id, port-id, ttl and end)
++ * 6. Optional. Several TLVs starting with @ which are expected results.
++ *    Its an error is it is missing in the reply or TLV differs.
++ */
++/*
++ * EVB negotiation - Do nothing, send data and expect no response.
++ */
++
++#include	"defines.evb"
++
++5	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120
++6	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120
++7	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120
++8	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120
++9	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120
++35	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120
+diff --git a/test/qbg22/evb22/45.sh b/test/qbg22/evb22/45.sh
+new file mode 100755
+index 0000000..a4dacf7
+--- /dev/null
++++ b/test/qbg22/evb22/45.sh
+@@ -0,0 +1,40 @@
++#!/bin/bash
++#
++# Test case for LLDPAD EVB Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Configuration file for unknwon vsi data test cases
++#
++
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 16-Aug-2012
++#
++# Execute a single task on the machine running lldpad
++#
++
++# Wait some seconds and then change setting
++sleep 30;
++rc=0
++hit="$(fgrep 'evb22_ifup:veth0 evb draft 0.2 protocol already enabled' /tmp/$(basename $0 .sh)-lldpad.conf.out )"
++if [ -z "$hit" ]
++then
++	rc=4
++	echo $rc "FAILURE:lldpad configuration file has evb and evb22 enabled"
++fi
++exit $rc
+diff --git a/test/qbg22/evb22/46-lldpad.conf b/test/qbg22/evb22/46-lldpad.conf
+new file mode 100644
+index 0000000..ec9b520
+--- /dev/null
++++ b/test/qbg22/evb22/46-lldpad.conf
+@@ -0,0 +1,43 @@
++#
++#  Implementation of EVB according to IEEE 802.1Qbg ratified standard
++#  (c) Copyright IBM Corp. 2014
++#
++#  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++#  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".
++#
++
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "0452540050244E";
++    };
++    tlvid00000002 : 
++    {
++      info = "0352540050244E";
++    };
++    adminStatus = 3;
++  };
++};
+diff --git a/test/qbg22/evb22/46.evb b/test/qbg22/evb22/46.evb
+new file mode 100644
+index 0000000..d0b552e
+--- /dev/null
++++ b/test/qbg22/evb22/46.evb
+@@ -0,0 +1,59 @@
++/*
++ *  Implementation of EVB according to IEEE 802.1Qbg
++ *  (c) Copyright IBM Corp. 2014
++ *
++ *  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++ *
++ *  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".
++ *
++ */
++
++/*
++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set
++ * is needed for each transmission.
++ * The first column defines the run time of the test program  in seconds
++ * when the remaining data on this line will be sent. The rest of the line are
++ * data fields which define the TLVs.
++ * Line limit is 5KB, long lines can be split  with \\ as last character.
++ *
++ * The files are preprocessed with cpp before being read by the test program.
++ *
++ * The data fields per line are
++ * 1. time
++ * 2. destination MAC
++ * 3. source MAC (dash(-) replaced by the senders MAC address)
++ * 4. ethertype
++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are
++ *    chassis-id, port-id, ttl and end)
++ * 6. Optional. Several TLVs starting with @ which are expected results.
++ *    Its an error is it is missing in the reply or TLV differs.
++ */
++/*
++ * EVB negotiation - Do nothing, send data and expect no response.
++ */
++
++#include	"defines.evb"
++
++5	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120
++6	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120
++7	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120
++8	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120
++9	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120
++35	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120
++65	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120
++95	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120
++125	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120
+diff --git a/test/qbg22/evb22/46.sh b/test/qbg22/evb22/46.sh
+new file mode 100755
+index 0000000..49142b4
+--- /dev/null
++++ b/test/qbg22/evb22/46.sh
+@@ -0,0 +1,60 @@
++#!/bin/bash
++#
++# Test case for LLDPAD EVB Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Configuration file for unknwon vsi data test cases
++#
++
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 16-Aug-2012
++#
++# Execute a single task on the machine running lldpad
++#
++
++# Wait some seconds and then change setting
++sleep 30;
++$1/lldptool -i veth0 -gncb -T -V evb -c enableTx=yes
++rc=$?
++if [ $rc -ne 0 ]
++then
++	echo $rc "FAILURE:lldptool -i veth0 -gncb -T -V evbcfg -c enabletx=yes ..."
++	exit $rc
++fi
++
++sleep 20
++# command must not succeed
++$1/lldptool -i veth0 -gncb -T -V evbcfg -c enableTx=yes -c fmode=reflectiverelay -c capabilities="rte ecp vdp" > /dev/null
++rc=$?
++if [ $rc -ne 1 ]
++then
++	rc=3
++	echo $rc "FAILURE:lldptool -i veth0 -gncb -T -V evb -c enabletx=yes"
++	exit $rc
++fi
++rc=0
++
++sleep 10
++lines="$(fgrep 'enableTx = true;' /tmp/$(basename $0 .sh)-lldpad.conf | wc -l)"
++if [ "x$lines" != x1 ]
++then
++	rc=5
++	echo $rc "FAILURE:lldptool -V evbcfg/evb -c enabletx=yes"
++fi
++exit $rc
+diff --git a/test/qbg22/evb22/5-lldpad.conf b/test/qbg22/evb22/5-lldpad.conf
+new file mode 100644
+index 0000000..ebe91e0
+--- /dev/null
++++ b/test/qbg22/evb22/5-lldpad.conf
+@@ -0,0 +1,55 @@
++#
++#  Implementation of EVB according to IEEE 802.1Qbg ratified standard
++#  (c) Copyright IBM Corp. 2014
++#
++#  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++#  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".
++#
++
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "0452540050244E";
++    };
++    tlvid00000002 : 
++    {
++      info = "0352540050244E";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = true;
++      evbmode = "station";
++      evbrrcap = false;
++      evbrrreq = true;
++      evbgpid = false;
++      ecpretries = 3;
++      ecprte = 8;
++      vdprwd = 8;
++      vdprka = 8;
++    };
++  };
++};
+diff --git a/test/qbg22/evb22/5.evb b/test/qbg22/evb22/5.evb
+new file mode 100644
+index 0000000..8367de0
+--- /dev/null
++++ b/test/qbg22/evb22/5.evb
+@@ -0,0 +1,75 @@
++/*
++ *  Implementation of EVB according to IEEE 802.1Qbg
++ *  (c) Copyright IBM Corp. 2014
++ *
++ *  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++ *
++ *  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".
++ *
++ */
++
++/*
++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set
++ * is needed for each transmission.
++ * The first column defines the run time of the test program  in seconds
++ * when the remaining data on this line will be sent. The rest of the line are
++ * data fields which define the TLVs.
++ * Line limit is 5KB, long lines can be split  with \\ as last character.
++ *
++ * The files are preprocessed with cpp before being read by the test program.
++ *
++ * The data fields per line are
++ * 1. time
++ * 2. destination MAC
++ * 3. source MAC (dash(-) replaced by the senders MAC address)
++ * 4. ethertype
++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are
++ *    chassis-id, port-id, ttl and end)
++ * 6. Optional. Several TLVs starting with @ which are expected results.
++ *    Its an error is it is missing in the reply or TLV differs.
++ */
++/*
++ * EVB negotiation
++ * - bridge offers support for reflective relay. 
++ * - station request it.
++ * - bridge withdraws reflective relay support some time later.
++ */
++
++#include	"defines.evb"
++
++5	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evb_brrr end_tlv @evbhead:02:04:counts
++6	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:03:04:00:40:00 end_tlv @evbhead:03:05:counts
++7	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:03:05:00:40:00 end_tlv @evbhead:03:05:counts
++8	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:03:05:00:40:00 end_tlv @evbhead:03:05:counts
++41	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:03:05:00:40:00 end_tlv @evbhead:03:05:counts
++60	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:00:06:00:40:00 end_tlv @evbhead:00:04:counts
++61	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:00:04:00:40:00 end_tlv @evbhead:00:04:counts
++62	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:00:04:00:40:00 end_tlv @evbhead:00:04:counts
++63	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:00:04:00:40:00 end_tlv @evbhead:00:04:counts
++64	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:00:04:00:40:00 end_tlv @evbhead:00:04:counts
++
++75	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv
+diff --git a/test/qbg22/evb22/6-lldpad.conf b/test/qbg22/evb22/6-lldpad.conf
+new file mode 100644
+index 0000000..ebe91e0
+--- /dev/null
++++ b/test/qbg22/evb22/6-lldpad.conf
+@@ -0,0 +1,55 @@
++#
++#  Implementation of EVB according to IEEE 802.1Qbg ratified standard
++#  (c) Copyright IBM Corp. 2014
++#
++#  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++#  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".
++#
++
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "0452540050244E";
++    };
++    tlvid00000002 : 
++    {
++      info = "0352540050244E";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = true;
++      evbmode = "station";
++      evbrrcap = false;
++      evbrrreq = true;
++      evbgpid = false;
++      ecpretries = 3;
++      ecprte = 8;
++      vdprwd = 8;
++      vdprka = 8;
++    };
++  };
++};
+diff --git a/test/qbg22/evb22/6.evb b/test/qbg22/evb22/6.evb
+new file mode 100644
+index 0000000..c01377c
+--- /dev/null
++++ b/test/qbg22/evb22/6.evb
+@@ -0,0 +1,75 @@
++/*
++ *  Implementation of EVB according to IEEE 802.1Qbg
++ *  (c) Copyright IBM Corp. 2014
++ *
++ *  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++ *
++ *  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".
++ *
++ */
++
++/*
++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set
++ * is needed for each transmission.
++ * The first column defines the run time of the test program  in seconds
++ * when the remaining data on this line will be sent. The rest of the line are
++ * data fields which define the TLVs.
++ * Line limit is 5KB, long lines can be split  with \\ as last character.
++ *
++ * The files are preprocessed with cpp before being read by the test program.
++ *
++ * The data fields per line are
++ * 1. time
++ * 2. destination MAC
++ * 3. source MAC (dash(-) replaced by the senders MAC address)
++ * 4. ethertype
++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are
++ *    chassis-id, port-id, ttl and end)
++ * 6. Optional. Several TLVs starting with @ which are expected results.
++ *    Its an error is it is missing in the reply or TLV differs.
++ */
++/*
++ * EVB negotiation
++ * - bridge offers support for reflective relay. 
++ * - station request it.
++ * - station withdraws reflective relay support some time later.
++ */
++
++#include	"defines.evb"
++
++5	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evb_brrr end_tlv @evbhead:02:04:counts
++6	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:03:04:00:40:00 end_tlv @evbhead:03:05:counts
++7	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:03:05:00:40:00 end_tlv @evbhead:03:05:counts
++8	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:03:05:00:40:00 end_tlv @evbhead:03:05:counts
++41	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:03:05:00:40:00 end_tlv @evbhead:03:05:counts
++51	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:02:00:00:40:00 end_tlv @evbhead:02:00:counts
++52	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:02:00:00:40:00 end_tlv @evbhead:02:00:counts
++53	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:02:00:00:40:00 end_tlv @evbhead:02:00:counts
++54	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:02:00:00:40:00 end_tlv @evbhead:02:00:counts
++55	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:02:00:00:40:00 end_tlv @evbhead:02:00:counts
++
++75	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv
+diff --git a/test/qbg22/evb22/6.sh b/test/qbg22/evb22/6.sh
+new file mode 100755
+index 0000000..557cc60
+--- /dev/null
++++ b/test/qbg22/evb22/6.sh
+@@ -0,0 +1,33 @@
++#!/bin/bash
++#
++# Test case for LLDPAD EVB Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Configuration file for unknwon vsi data test cases
++#
++
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 16-Aug-2012
++#
++# Execute a single task on the machine running lldpad
++#
++
++# Wait 50 seconds change setting
++sleep 50;
++$1/lldptool -i veth0 -gncb -T -V evb -c evbrrreq=no
+diff --git a/test/qbg22/evb22/7-lldpad.conf b/test/qbg22/evb22/7-lldpad.conf
+new file mode 100644
+index 0000000..ebe91e0
+--- /dev/null
++++ b/test/qbg22/evb22/7-lldpad.conf
+@@ -0,0 +1,55 @@
++#
++#  Implementation of EVB according to IEEE 802.1Qbg ratified standard
++#  (c) Copyright IBM Corp. 2014
++#
++#  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++#  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".
++#
++
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "0452540050244E";
++    };
++    tlvid00000002 : 
++    {
++      info = "0352540050244E";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = true;
++      evbmode = "station";
++      evbrrcap = false;
++      evbrrreq = true;
++      evbgpid = false;
++      ecpretries = 3;
++      ecprte = 8;
++      vdprwd = 8;
++      vdprka = 8;
++    };
++  };
++};
+diff --git a/test/qbg22/evb22/7.evb b/test/qbg22/evb22/7.evb
+new file mode 100644
+index 0000000..ea13107
+--- /dev/null
++++ b/test/qbg22/evb22/7.evb
+@@ -0,0 +1,60 @@
++/*
++ *  Implementation of EVB according to IEEE 802.1Qbg
++ *  (c) Copyright IBM Corp. 2014
++ *
++ *  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++ *
++ *  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".
++ *
++ */
++
++/*
++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set
++ * is needed for each transmission.
++ * The first column defines the run time of the test program  in seconds
++ * when the remaining data on this line will be sent. The rest of the line are
++ * data fields which define the TLVs.
++ * Line limit is 5KB, long lines can be split  with \\ as last character.
++ *
++ * The files are preprocessed with cpp before being read by the test program.
++ *
++ * The data fields per line are
++ * 1. time
++ * 2. destination MAC
++ * 3. source MAC (dash(-) replaced by the senders MAC address)
++ * 4. ethertype
++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are
++ *    chassis-id, port-id, ttl and end)
++ * 6. Optional. Several TLVs starting with @ which are expected results.
++ *    Its an error is it is missing in the reply or TLV differs.
++ */
++/*
++ * EVB negotiation - bridge does not support reflective relay but station
++ *	requests it. RTE value is higher than on station.
++ */
++
++#include	"defines.evb"
++
++5	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:00:00:1f:40:00 end_tlv @evbhead:00:04:7f:88:08
++6	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:00:00:1f:40:00 end_tlv @evbhead:00:04:7f:88:08
++7	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:00:00:1f:40:00 end_tlv @evbhead:00:04:7f:88:08
++8	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:00:00:1f:40:00 end_tlv @evbhead:00:04:7f:88:08
++15	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv
+diff --git a/test/qbg22/evb22/8-lldpad.conf b/test/qbg22/evb22/8-lldpad.conf
+new file mode 100644
+index 0000000..ebe91e0
+--- /dev/null
++++ b/test/qbg22/evb22/8-lldpad.conf
+@@ -0,0 +1,55 @@
++#
++#  Implementation of EVB according to IEEE 802.1Qbg ratified standard
++#  (c) Copyright IBM Corp. 2014
++#
++#  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++#  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".
++#
++
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "0452540050244E";
++    };
++    tlvid00000002 : 
++    {
++      info = "0352540050244E";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = true;
++      evbmode = "station";
++      evbrrcap = false;
++      evbrrreq = true;
++      evbgpid = false;
++      ecpretries = 3;
++      ecprte = 8;
++      vdprwd = 8;
++      vdprka = 8;
++    };
++  };
++};
+diff --git a/test/qbg22/evb22/8.evb b/test/qbg22/evb22/8.evb
+new file mode 100644
+index 0000000..26b10c7
+--- /dev/null
++++ b/test/qbg22/evb22/8.evb
+@@ -0,0 +1,60 @@
++/*
++ *  Implementation of EVB according to IEEE 802.1Qbg
++ *  (c) Copyright IBM Corp. 2014
++ *
++ *  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++ *
++ *  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".
++ *
++ */
++
++/*
++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set
++ * is needed for each transmission.
++ * The first column defines the run time of the test program  in seconds
++ * when the remaining data on this line will be sent. The rest of the line are
++ * data fields which define the TLVs.
++ * Line limit is 5KB, long lines can be split  with \\ as last character.
++ *
++ * The files are preprocessed with cpp before being read by the test program.
++ *
++ * The data fields per line are
++ * 1. time
++ * 2. destination MAC
++ * 3. source MAC (dash(-) replaced by the senders MAC address)
++ * 4. ethertype
++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are
++ *    chassis-id, port-id, ttl and end)
++ * 6. Optional. Several TLVs starting with @ which are expected results.
++ *    Its an error is it is missing in the reply or TLV differs.
++ */
++/*
++ * EVB negotiation - bridge does not support reflective relay but station
++ *	requests it. RTE value is lower than on station.
++ */
++
++#include	"defines.evb"
++
++5	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:00:00:00:40:00 end_tlv @evbhead:00:04:counts
++6	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:00:00:00:40:00 end_tlv @evbhead:00:04:counts
++7	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:00:00:00:40:00 end_tlv @evbhead:00:04:counts
++8	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:00:00:00:40:00 end_tlv @evbhead:00:04:counts
++15	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv
+diff --git a/test/qbg22/evb22/80-lldpad.conf b/test/qbg22/evb22/80-lldpad.conf
+new file mode 100644
+index 0000000..456da71
+--- /dev/null
++++ b/test/qbg22/evb22/80-lldpad.conf
+@@ -0,0 +1,55 @@
++#
++#  Implementation of EVB according to IEEE 802.1Qbg ratified standard
++#  (c) Copyright IBM Corp. 2014
++#
++#  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++#  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".
++#
++
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "0452540050244E";
++    };
++    tlvid00000002 : 
++    {
++      info = "0352540050244E";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = true;
++      evbmode = "station";
++      evbrrcap = false;
++      evbrrreq = true;
++      evbgpid = true;
++      ecpretries = 3;
++      ecprte = 8;
++      vdprwd = 8;
++      vdprka = 8;
++    };
++  };
++};
+diff --git a/test/qbg22/evb22/80.evb b/test/qbg22/evb22/80.evb
+new file mode 100644
+index 0000000..12924b9
+--- /dev/null
++++ b/test/qbg22/evb22/80.evb
+@@ -0,0 +1,72 @@
++/*
++ *  Implementation of EVB according to IEEE 802.1Qbg
++ *  (c) Copyright IBM Corp. 2014
++ *
++ *  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++ *
++ *  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".
++ *
++ */
++
++/*
++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set
++ * is needed for each transmission.
++ * The first column defines the run time of the test program  in seconds
++ * when the remaining data on this line will be sent. The rest of the line are
++ * data fields which define the TLVs.
++ * Line limit is 5KB, long lines can be split  with \\ as last character.
++ *
++ * The files are preprocessed with cpp before being read by the test program.
++ *
++ * The data fields per line are
++ * 1. time
++ * 2. destination MAC
++ * 3. source MAC (dash(-) replaced by the senders MAC address)
++ * 4. ethertype
++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are
++ *    chassis-id, port-id, ttl and end)
++ * 6. Optional. Several TLVs starting with @ which are expected results.
++ *    Its an error is it is missing in the reply or TLV differs.
++ */
++/*
++ * EVB negotiation - bridge offers support for reflective relay and station
++ *	requests it. Bridge and station set group id bit.
++ */
++
++#include	"defines.evb"
++
++5	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:06:00:00:40:00 end_tlv @evbhead:06:0c:counts
++6	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:0c:00:40:00 end_tlv @evbhead:07:0d:counts
++7	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts
++8	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts
++9	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts
++51	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:05:00:40:00 end_tlv @evbhead:07:0d:counts
++52	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:05:00:40:00 end_tlv @evbhead:07:0d:counts
++53	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:05:00:40:00 end_tlv @evbhead:07:0d:counts
++54	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:05:00:40:00 end_tlv @evbhead:07:0d:counts
++55	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:05:00:40:00 end_tlv @evbhead:07:0d:counts
++80	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv
+diff --git a/test/qbg22/evb22/80.sh b/test/qbg22/evb22/80.sh
+new file mode 100755
+index 0000000..fb8e3fa
+--- /dev/null
++++ b/test/qbg22/evb22/80.sh
+@@ -0,0 +1,47 @@
++#!/bin/bash
++#
++# Test case for LLDPAD EVB Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Configuration file for unknwon vsi data test cases
++#
++
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 16-Aug-2012
++#
++# Execute a single task on the machine running lldpad
++#
++
++# Wait 50 seconds before executing command
++sleep 50;
++
++# Replace newlines by blanks for easier comparison
++out=$($1/lldptool -i veth0 -gncb -t -V evb -c | tr '\n' ' ')
++rc=$?
++if [ "$rc" -eq 0 ]
++then
++	#echo out ":$out:"
++	if [ "$out" != "vdprka=8 vdprwd=8 ecprte=8 ecpretries=3 evbrrreq=yes evbrrcap=no evbgpid=yes evbmode=station enableTx=yes " ]
++	then
++		rc=99
++	fi
++fi
++# First field contains exit code of shell script, 0 for success anything else
++# for failure.
++echo $rc ":$out:"
+diff --git a/test/qbg22/evb22/81-lldpad.conf b/test/qbg22/evb22/81-lldpad.conf
+new file mode 100644
+index 0000000..456da71
+--- /dev/null
++++ b/test/qbg22/evb22/81-lldpad.conf
+@@ -0,0 +1,55 @@
++#
++#  Implementation of EVB according to IEEE 802.1Qbg ratified standard
++#  (c) Copyright IBM Corp. 2014
++#
++#  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++#  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".
++#
++
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "0452540050244E";
++    };
++    tlvid00000002 : 
++    {
++      info = "0352540050244E";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = true;
++      evbmode = "station";
++      evbrrcap = false;
++      evbrrreq = true;
++      evbgpid = true;
++      ecpretries = 3;
++      ecprte = 8;
++      vdprwd = 8;
++      vdprka = 8;
++    };
++  };
++};
+diff --git a/test/qbg22/evb22/81.evb b/test/qbg22/evb22/81.evb
+new file mode 100644
+index 0000000..3b88d6c
+--- /dev/null
++++ b/test/qbg22/evb22/81.evb
+@@ -0,0 +1,72 @@
++/*
++ *  Implementation of EVB according to IEEE 802.1Qbg
++ *  (c) Copyright IBM Corp. 2014
++ *
++ *  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++ *
++ *  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".
++ *
++ */
++
++/*
++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set
++ * is needed for each transmission.
++ * The first column defines the run time of the test program  in seconds
++ * when the remaining data on this line will be sent. The rest of the line are
++ * data fields which define the TLVs.
++ * Line limit is 5KB, long lines can be split  with \\ as last character.
++ *
++ * The files are preprocessed with cpp before being read by the test program.
++ *
++ * The data fields per line are
++ * 1. time
++ * 2. destination MAC
++ * 3. source MAC (dash(-) replaced by the senders MAC address)
++ * 4. ethertype
++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are
++ *    chassis-id, port-id, ttl and end)
++ * 6. Optional. Several TLVs starting with @ which are expected results.
++ *    Its an error is it is missing in the reply or TLV differs.
++ */
++/*
++ * EVB negotiation - bridge offers support for reflective relay and station
++ *	requests it. Bridge and station set group id bit.
++ */
++
++#include	"defines.evb"
++
++5	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:06:00:00:40:00 end_tlv @evbhead:06:0c:counts
++6	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:0c:00:40:00 end_tlv @evbhead:07:0d:counts
++7	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts
++8	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts
++9	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts
++51	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:05:00:40:00 end_tlv
++52	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:05:00:40:00 end_tlv
++53	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:05:00:40:00 end_tlv
++54	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:05:00:40:00 end_tlv
++55	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:05:00:40:00 end_tlv
++80	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv
+diff --git a/test/qbg22/evb22/81.sh b/test/qbg22/evb22/81.sh
+new file mode 100755
+index 0000000..03490ca
+--- /dev/null
++++ b/test/qbg22/evb22/81.sh
+@@ -0,0 +1,58 @@
++#!/bin/bash
++#
++# Test case for LLDPAD EVB Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Configuration file for unknwon vsi data test cases
++#
++
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 16-Aug-2012
++#
++# Execute a single task on the machine running lldpad
++#
++
++# Wait 50 seconds before executing command
++sleep 50;
++
++$1/lldptool -i veth0 -gncb -T -V evb -c enabletx=no 
++rc=$?
++if [ "$rc" -ne 0 ]
++then
++	let rc=98
++	echo $rc "FAILURE:lldptool -i veth0 -gncb -T -V evb -c enabletx=no"
++	exit $rc
++fi
++
++sleep 3
++
++out=$($1/lldptool -i veth0 -gncb -t -V evb -c enabletx)
++rc=$?
++if [ "$rc" -eq 0 ]
++then
++	# echo out ":$out:"
++	if [ "$out" != "enableTx=no" ]
++	then
++		rc=99
++	fi
++fi
++# First field contains exit code of shell script, 0 for success anything else
++# for failure.
++echo $rc ":$out:"
++exit $rc
+diff --git a/test/qbg22/evb22/82-lldpad.conf b/test/qbg22/evb22/82-lldpad.conf
+new file mode 100644
+index 0000000..456da71
+--- /dev/null
++++ b/test/qbg22/evb22/82-lldpad.conf
+@@ -0,0 +1,55 @@
++#
++#  Implementation of EVB according to IEEE 802.1Qbg ratified standard
++#  (c) Copyright IBM Corp. 2014
++#
++#  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++#  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".
++#
++
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "0452540050244E";
++    };
++    tlvid00000002 : 
++    {
++      info = "0352540050244E";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = true;
++      evbmode = "station";
++      evbrrcap = false;
++      evbrrreq = true;
++      evbgpid = true;
++      ecpretries = 3;
++      ecprte = 8;
++      vdprwd = 8;
++      vdprka = 8;
++    };
++  };
++};
+diff --git a/test/qbg22/evb22/82.evb b/test/qbg22/evb22/82.evb
+new file mode 100644
+index 0000000..3b88d6c
+--- /dev/null
++++ b/test/qbg22/evb22/82.evb
+@@ -0,0 +1,72 @@
++/*
++ *  Implementation of EVB according to IEEE 802.1Qbg
++ *  (c) Copyright IBM Corp. 2014
++ *
++ *  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++ *
++ *  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".
++ *
++ */
++
++/*
++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set
++ * is needed for each transmission.
++ * The first column defines the run time of the test program  in seconds
++ * when the remaining data on this line will be sent. The rest of the line are
++ * data fields which define the TLVs.
++ * Line limit is 5KB, long lines can be split  with \\ as last character.
++ *
++ * The files are preprocessed with cpp before being read by the test program.
++ *
++ * The data fields per line are
++ * 1. time
++ * 2. destination MAC
++ * 3. source MAC (dash(-) replaced by the senders MAC address)
++ * 4. ethertype
++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are
++ *    chassis-id, port-id, ttl and end)
++ * 6. Optional. Several TLVs starting with @ which are expected results.
++ *    Its an error is it is missing in the reply or TLV differs.
++ */
++/*
++ * EVB negotiation - bridge offers support for reflective relay and station
++ *	requests it. Bridge and station set group id bit.
++ */
++
++#include	"defines.evb"
++
++5	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:06:00:00:40:00 end_tlv @evbhead:06:0c:counts
++6	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:0c:00:40:00 end_tlv @evbhead:07:0d:counts
++7	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts
++8	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts
++9	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts
++51	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:05:00:40:00 end_tlv
++52	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:05:00:40:00 end_tlv
++53	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:05:00:40:00 end_tlv
++54	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:05:00:40:00 end_tlv
++55	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:05:00:40:00 end_tlv
++80	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv
+diff --git a/test/qbg22/evb22/82.sh b/test/qbg22/evb22/82.sh
+new file mode 100755
+index 0000000..4db9e0b
+--- /dev/null
++++ b/test/qbg22/evb22/82.sh
+@@ -0,0 +1,58 @@
++#!/bin/bash
++#
++# Test case for LLDPAD EVB Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Configuration file for unknwon vsi data test cases
++#
++
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 16-Aug-2012
++#
++# Execute a single task on the machine running lldpad
++#
++
++# Wait 50 seconds before executing command
++sleep 50;
++
++$1/lldptool -i veth0 -gncb -T -V evb -c evbmode=bridge
++rc=$?
++if [ "$rc" -ne 0 ]
++then
++	let rc=98
++	echo $rc "FAILURE:lldptool -i veth0 -gncb -T -V evb -c evbmode=bridge"
++	exit $rc
++fi
++
++sleep 3
++
++out=$($1/lldptool -i veth0 -gncb -t -V evb -c evbmode)
++rc=$?
++if [ "$rc" -eq 0 ]
++then
++	# echo out ":$out:"
++	if [ "$out" != "evbmode=bridge" ]
++	then
++		rc=99
++	fi
++fi
++# First field contains exit code of shell script, 0 for success anything else
++# for failure.
++echo $rc ":$out:"
++exit $rc
+diff --git a/test/qbg22/evb22/83-lldpad.conf b/test/qbg22/evb22/83-lldpad.conf
+new file mode 100644
+index 0000000..456da71
+--- /dev/null
++++ b/test/qbg22/evb22/83-lldpad.conf
+@@ -0,0 +1,55 @@
++#
++#  Implementation of EVB according to IEEE 802.1Qbg ratified standard
++#  (c) Copyright IBM Corp. 2014
++#
++#  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++#  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".
++#
++
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "0452540050244E";
++    };
++    tlvid00000002 : 
++    {
++      info = "0352540050244E";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = true;
++      evbmode = "station";
++      evbrrcap = false;
++      evbrrreq = true;
++      evbgpid = true;
++      ecpretries = 3;
++      ecprte = 8;
++      vdprwd = 8;
++      vdprka = 8;
++    };
++  };
++};
+diff --git a/test/qbg22/evb22/83.evb b/test/qbg22/evb22/83.evb
+new file mode 100644
+index 0000000..3b88d6c
+--- /dev/null
++++ b/test/qbg22/evb22/83.evb
+@@ -0,0 +1,72 @@
++/*
++ *  Implementation of EVB according to IEEE 802.1Qbg
++ *  (c) Copyright IBM Corp. 2014
++ *
++ *  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++ *
++ *  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".
++ *
++ */
++
++/*
++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set
++ * is needed for each transmission.
++ * The first column defines the run time of the test program  in seconds
++ * when the remaining data on this line will be sent. The rest of the line are
++ * data fields which define the TLVs.
++ * Line limit is 5KB, long lines can be split  with \\ as last character.
++ *
++ * The files are preprocessed with cpp before being read by the test program.
++ *
++ * The data fields per line are
++ * 1. time
++ * 2. destination MAC
++ * 3. source MAC (dash(-) replaced by the senders MAC address)
++ * 4. ethertype
++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are
++ *    chassis-id, port-id, ttl and end)
++ * 6. Optional. Several TLVs starting with @ which are expected results.
++ *    Its an error is it is missing in the reply or TLV differs.
++ */
++/*
++ * EVB negotiation - bridge offers support for reflective relay and station
++ *	requests it. Bridge and station set group id bit.
++ */
++
++#include	"defines.evb"
++
++5	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:06:00:00:40:00 end_tlv @evbhead:06:0c:counts
++6	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:0c:00:40:00 end_tlv @evbhead:07:0d:counts
++7	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts
++8	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts
++9	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts
++51	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:05:00:40:00 end_tlv
++52	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:05:00:40:00 end_tlv
++53	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:05:00:40:00 end_tlv
++54	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:05:00:40:00 end_tlv
++55	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:05:00:40:00 end_tlv
++80	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv
+diff --git a/test/qbg22/evb22/83.sh b/test/qbg22/evb22/83.sh
+new file mode 100755
+index 0000000..fbdce26
+--- /dev/null
++++ b/test/qbg22/evb22/83.sh
+@@ -0,0 +1,58 @@
++#!/bin/bash
++#
++# Test case for LLDPAD EVB Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Configuration file for unknwon vsi data test cases
++#
++
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 16-Aug-2012
++#
++# Execute a single task on the machine running lldpad
++#
++
++# Wait 50 seconds before executing command
++sleep 50;
++
++$1/lldptool -i veth0 -gncb -T -V evb -c evbrrreq=no
++rc=$?
++if [ "$rc" -ne 0 ]
++then
++	let rc=98
++	echo $rc "FAILURE:lldptool -i veth0 -gncb -T -V evb -c evbrrreq=no"
++	exit $rc
++fi
++
++sleep 3
++
++out=$($1/lldptool -i veth0 -gncb -t -V evb -c evbrrreq)
++rc=$?
++if [ "$rc" -eq 0 ]
++then
++	# echo out ":$out:"
++	if [ "$out" != "evbrrreq=no" ]
++	then
++		rc=99
++	fi
++fi
++# First field contains exit code of shell script, 0 for success anything else
++# for failure.
++echo $rc ":$out:"
++exit $rc
+diff --git a/test/qbg22/evb22/84-lldpad.conf b/test/qbg22/evb22/84-lldpad.conf
+new file mode 100644
+index 0000000..20ef072
+--- /dev/null
++++ b/test/qbg22/evb22/84-lldpad.conf
+@@ -0,0 +1,55 @@
++#
++#  Implementation of EVB according to IEEE 802.1Qbg ratified standard
++#  (c) Copyright IBM Corp. 2014
++#
++#  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++#  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".
++#
++
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "0452540050244E";
++    };
++    tlvid00000002 : 
++    {
++      info = "0352540050244E";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = true;
++      evbmode = "station";
++      evbrrcap = true;
++      evbrrreq = true;
++      evbgpid = true;
++      ecpretries = 3;
++      ecprte = 8;
++      vdprwd = 8;
++      vdprka = 8;
++    };
++  };
++};
+diff --git a/test/qbg22/evb22/84.evb b/test/qbg22/evb22/84.evb
+new file mode 100644
+index 0000000..3b88d6c
+--- /dev/null
++++ b/test/qbg22/evb22/84.evb
+@@ -0,0 +1,72 @@
++/*
++ *  Implementation of EVB according to IEEE 802.1Qbg
++ *  (c) Copyright IBM Corp. 2014
++ *
++ *  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++ *
++ *  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".
++ *
++ */
++
++/*
++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set
++ * is needed for each transmission.
++ * The first column defines the run time of the test program  in seconds
++ * when the remaining data on this line will be sent. The rest of the line are
++ * data fields which define the TLVs.
++ * Line limit is 5KB, long lines can be split  with \\ as last character.
++ *
++ * The files are preprocessed with cpp before being read by the test program.
++ *
++ * The data fields per line are
++ * 1. time
++ * 2. destination MAC
++ * 3. source MAC (dash(-) replaced by the senders MAC address)
++ * 4. ethertype
++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are
++ *    chassis-id, port-id, ttl and end)
++ * 6. Optional. Several TLVs starting with @ which are expected results.
++ *    Its an error is it is missing in the reply or TLV differs.
++ */
++/*
++ * EVB negotiation - bridge offers support for reflective relay and station
++ *	requests it. Bridge and station set group id bit.
++ */
++
++#include	"defines.evb"
++
++5	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:06:00:00:40:00 end_tlv @evbhead:06:0c:counts
++6	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:0c:00:40:00 end_tlv @evbhead:07:0d:counts
++7	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts
++8	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts
++9	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts
++51	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:05:00:40:00 end_tlv
++52	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:05:00:40:00 end_tlv
++53	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:05:00:40:00 end_tlv
++54	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:05:00:40:00 end_tlv
++55	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:05:00:40:00 end_tlv
++80	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv
+diff --git a/test/qbg22/evb22/84.sh b/test/qbg22/evb22/84.sh
+new file mode 100755
+index 0000000..092f35a
+--- /dev/null
++++ b/test/qbg22/evb22/84.sh
+@@ -0,0 +1,58 @@
++#!/bin/bash
++#
++# Test case for LLDPAD EVB Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Configuration file for unknwon vsi data test cases
++#
++
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 16-Aug-2012
++#
++# Execute a single task on the machine running lldpad
++#
++
++# Wait 50 seconds before executing command
++sleep 50;
++
++$1/lldptool -i veth0 -gncb -T -V evb -c evbrrcap=no
++rc=$?
++if [ "$rc" -ne 0 ]
++then
++	let rc=98
++	echo $rc "FAILURE:lldptool -i veth0 -gncb -T -V evb -c evbrrcap=no"
++	exit $rc
++fi
++
++sleep 3
++
++out=$($1/lldptool -i veth0 -gncb -t -V evb -c evbrrcap)
++rc=$?
++if [ "$rc" -eq 0 ]
++then
++	# echo out ":$out:"
++	if [ "$out" != "evbrrcap=no" ]
++	then
++		rc=99
++	fi
++fi
++# First field contains exit code of shell script, 0 for success anything else
++# for failure.
++echo $rc ":$out:"
++exit $rc
+diff --git a/test/qbg22/evb22/85-lldpad.conf b/test/qbg22/evb22/85-lldpad.conf
+new file mode 100644
+index 0000000..20ef072
+--- /dev/null
++++ b/test/qbg22/evb22/85-lldpad.conf
+@@ -0,0 +1,55 @@
++#
++#  Implementation of EVB according to IEEE 802.1Qbg ratified standard
++#  (c) Copyright IBM Corp. 2014
++#
++#  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++#  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".
++#
++
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "0452540050244E";
++    };
++    tlvid00000002 : 
++    {
++      info = "0352540050244E";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = true;
++      evbmode = "station";
++      evbrrcap = true;
++      evbrrreq = true;
++      evbgpid = true;
++      ecpretries = 3;
++      ecprte = 8;
++      vdprwd = 8;
++      vdprka = 8;
++    };
++  };
++};
+diff --git a/test/qbg22/evb22/85.evb b/test/qbg22/evb22/85.evb
+new file mode 100644
+index 0000000..3b88d6c
+--- /dev/null
++++ b/test/qbg22/evb22/85.evb
+@@ -0,0 +1,72 @@
++/*
++ *  Implementation of EVB according to IEEE 802.1Qbg
++ *  (c) Copyright IBM Corp. 2014
++ *
++ *  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++ *
++ *  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".
++ *
++ */
++
++/*
++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set
++ * is needed for each transmission.
++ * The first column defines the run time of the test program  in seconds
++ * when the remaining data on this line will be sent. The rest of the line are
++ * data fields which define the TLVs.
++ * Line limit is 5KB, long lines can be split  with \\ as last character.
++ *
++ * The files are preprocessed with cpp before being read by the test program.
++ *
++ * The data fields per line are
++ * 1. time
++ * 2. destination MAC
++ * 3. source MAC (dash(-) replaced by the senders MAC address)
++ * 4. ethertype
++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are
++ *    chassis-id, port-id, ttl and end)
++ * 6. Optional. Several TLVs starting with @ which are expected results.
++ *    Its an error is it is missing in the reply or TLV differs.
++ */
++/*
++ * EVB negotiation - bridge offers support for reflective relay and station
++ *	requests it. Bridge and station set group id bit.
++ */
++
++#include	"defines.evb"
++
++5	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:06:00:00:40:00 end_tlv @evbhead:06:0c:counts
++6	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:0c:00:40:00 end_tlv @evbhead:07:0d:counts
++7	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts
++8	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts
++9	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts
++51	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:05:00:40:00 end_tlv
++52	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:05:00:40:00 end_tlv
++53	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:05:00:40:00 end_tlv
++54	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:05:00:40:00 end_tlv
++55	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:05:00:40:00 end_tlv
++80	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv
+diff --git a/test/qbg22/evb22/85.sh b/test/qbg22/evb22/85.sh
+new file mode 100755
+index 0000000..597a3ff
+--- /dev/null
++++ b/test/qbg22/evb22/85.sh
+@@ -0,0 +1,58 @@
++#!/bin/bash
++#
++# Test case for LLDPAD EVB Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Configuration file for unknwon vsi data test cases
++#
++
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 16-Aug-2012
++#
++# Execute a single task on the machine running lldpad
++#
++
++# Wait 50 seconds before executing command
++sleep 50;
++
++$1/lldptool -i veth0 -gncb -T -V evb -c evbgpid=no
++rc=$?
++if [ "$rc" -ne 0 ]
++then
++	let rc=98
++	echo $rc "FAILURE:lldptool -i veth0 -gncb -T -V evb -c evbgpid=no"
++	exit $rc
++fi
++
++sleep 3
++
++out=$($1/lldptool -i veth0 -gncb -t -V evb -c evbgpid)
++rc=$?
++if [ "$rc" -eq 0 ]
++then
++	# echo out ":$out:"
++	if [ "$out" != "evbgpid=no" ]
++	then
++		rc=99
++	fi
++fi
++# First field contains exit code of shell script, 0 for success anything else
++# for failure.
++echo $rc ":$out:"
++exit $rc
+diff --git a/test/qbg22/evb22/86-lldpad.conf b/test/qbg22/evb22/86-lldpad.conf
+new file mode 100644
+index 0000000..20ef072
+--- /dev/null
++++ b/test/qbg22/evb22/86-lldpad.conf
+@@ -0,0 +1,55 @@
++#
++#  Implementation of EVB according to IEEE 802.1Qbg ratified standard
++#  (c) Copyright IBM Corp. 2014
++#
++#  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++#  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".
++#
++
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "0452540050244E";
++    };
++    tlvid00000002 : 
++    {
++      info = "0352540050244E";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = true;
++      evbmode = "station";
++      evbrrcap = true;
++      evbrrreq = true;
++      evbgpid = true;
++      ecpretries = 3;
++      ecprte = 8;
++      vdprwd = 8;
++      vdprka = 8;
++    };
++  };
++};
+diff --git a/test/qbg22/evb22/86.evb b/test/qbg22/evb22/86.evb
+new file mode 100644
+index 0000000..3b88d6c
+--- /dev/null
++++ b/test/qbg22/evb22/86.evb
+@@ -0,0 +1,72 @@
++/*
++ *  Implementation of EVB according to IEEE 802.1Qbg
++ *  (c) Copyright IBM Corp. 2014
++ *
++ *  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++ *
++ *  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".
++ *
++ */
++
++/*
++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set
++ * is needed for each transmission.
++ * The first column defines the run time of the test program  in seconds
++ * when the remaining data on this line will be sent. The rest of the line are
++ * data fields which define the TLVs.
++ * Line limit is 5KB, long lines can be split  with \\ as last character.
++ *
++ * The files are preprocessed with cpp before being read by the test program.
++ *
++ * The data fields per line are
++ * 1. time
++ * 2. destination MAC
++ * 3. source MAC (dash(-) replaced by the senders MAC address)
++ * 4. ethertype
++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are
++ *    chassis-id, port-id, ttl and end)
++ * 6. Optional. Several TLVs starting with @ which are expected results.
++ *    Its an error is it is missing in the reply or TLV differs.
++ */
++/*
++ * EVB negotiation - bridge offers support for reflective relay and station
++ *	requests it. Bridge and station set group id bit.
++ */
++
++#include	"defines.evb"
++
++5	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:06:00:00:40:00 end_tlv @evbhead:06:0c:counts
++6	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:0c:00:40:00 end_tlv @evbhead:07:0d:counts
++7	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts
++8	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts
++9	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts
++51	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:05:00:40:00 end_tlv
++52	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:05:00:40:00 end_tlv
++53	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:05:00:40:00 end_tlv
++54	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:05:00:40:00 end_tlv
++55	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:05:00:40:00 end_tlv
++80	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv
+diff --git a/test/qbg22/evb22/86.sh b/test/qbg22/evb22/86.sh
+new file mode 100755
+index 0000000..882220f
+--- /dev/null
++++ b/test/qbg22/evb22/86.sh
+@@ -0,0 +1,58 @@
++#!/bin/bash
++#
++# Test case for LLDPAD EVB Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Configuration file for unknwon vsi data test cases
++#
++
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 16-Aug-2012
++#
++# Execute a single task on the machine running lldpad
++#
++
++# Wait 50 seconds before executing command
++sleep 50;
++
++$1/lldptool -i veth0 -gncb -T -V evb -c ecpretries=7
++rc=$?
++if [ "$rc" -ne 0 ]
++then
++	let rc=98
++	echo $rc "FAILURE:lldptool -i veth0 -gncb -T -V evb -c ecpretries=7"
++	exit $rc
++fi
++
++sleep 3
++
++out=$($1/lldptool -i veth0 -gncb -t -V evb -c ecpretries)
++rc=$?
++if [ "$rc" -eq 0 ]
++then
++	# echo out ":$out:"
++	if [ "$out" != "ecpretries=7" ]
++	then
++		rc=99
++	fi
++fi
++# First field contains exit code of shell script, 0 for success anything else
++# for failure.
++echo $rc ":$out:"
++exit $rc
+diff --git a/test/qbg22/evb22/87-lldpad.conf b/test/qbg22/evb22/87-lldpad.conf
+new file mode 100644
+index 0000000..20ef072
+--- /dev/null
++++ b/test/qbg22/evb22/87-lldpad.conf
+@@ -0,0 +1,55 @@
++#
++#  Implementation of EVB according to IEEE 802.1Qbg ratified standard
++#  (c) Copyright IBM Corp. 2014
++#
++#  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++#  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".
++#
++
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "0452540050244E";
++    };
++    tlvid00000002 : 
++    {
++      info = "0352540050244E";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = true;
++      evbmode = "station";
++      evbrrcap = true;
++      evbrrreq = true;
++      evbgpid = true;
++      ecpretries = 3;
++      ecprte = 8;
++      vdprwd = 8;
++      vdprka = 8;
++    };
++  };
++};
+diff --git a/test/qbg22/evb22/87.evb b/test/qbg22/evb22/87.evb
+new file mode 100644
+index 0000000..3b88d6c
+--- /dev/null
++++ b/test/qbg22/evb22/87.evb
+@@ -0,0 +1,72 @@
++/*
++ *  Implementation of EVB according to IEEE 802.1Qbg
++ *  (c) Copyright IBM Corp. 2014
++ *
++ *  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++ *
++ *  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".
++ *
++ */
++
++/*
++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set
++ * is needed for each transmission.
++ * The first column defines the run time of the test program  in seconds
++ * when the remaining data on this line will be sent. The rest of the line are
++ * data fields which define the TLVs.
++ * Line limit is 5KB, long lines can be split  with \\ as last character.
++ *
++ * The files are preprocessed with cpp before being read by the test program.
++ *
++ * The data fields per line are
++ * 1. time
++ * 2. destination MAC
++ * 3. source MAC (dash(-) replaced by the senders MAC address)
++ * 4. ethertype
++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are
++ *    chassis-id, port-id, ttl and end)
++ * 6. Optional. Several TLVs starting with @ which are expected results.
++ *    Its an error is it is missing in the reply or TLV differs.
++ */
++/*
++ * EVB negotiation - bridge offers support for reflective relay and station
++ *	requests it. Bridge and station set group id bit.
++ */
++
++#include	"defines.evb"
++
++5	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:06:00:00:40:00 end_tlv @evbhead:06:0c:counts
++6	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:0c:00:40:00 end_tlv @evbhead:07:0d:counts
++7	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts
++8	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts
++9	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts
++51	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:05:00:40:00 end_tlv
++52	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:05:00:40:00 end_tlv
++53	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:05:00:40:00 end_tlv
++54	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:05:00:40:00 end_tlv
++55	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:05:00:40:00 end_tlv
++80	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv
+diff --git a/test/qbg22/evb22/87.sh b/test/qbg22/evb22/87.sh
+new file mode 100755
+index 0000000..17f7b96
+--- /dev/null
++++ b/test/qbg22/evb22/87.sh
+@@ -0,0 +1,58 @@
++#!/bin/bash
++#
++# Test case for LLDPAD EVB Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Configuration file for unknwon vsi data test cases
++#
++
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 16-Aug-2012
++#
++# Execute a single task on the machine running lldpad
++#
++
++# Wait 50 seconds before executing command
++sleep 50;
++
++$1/lldptool -i veth0 -gncb -T -V evb -c ecprte=31
++rc=$?
++if [ "$rc" -ne 0 ]
++then
++	let rc=98
++	echo $rc "FAILURE:lldptool -i veth0 -gncb -T -V evb -c ecprte=31"
++	exit $rc
++fi
++
++sleep 3
++
++out=$($1/lldptool -i veth0 -gncb -t -V evb -c ecprte)
++rc=$?
++if [ "$rc" -eq 0 ]
++then
++	# echo out ":$out:"
++	if [ "$out" != "ecprte=31" ]
++	then
++		rc=99
++	fi
++fi
++# First field contains exit code of shell script, 0 for success anything else
++# for failure.
++echo $rc ":$out:"
++exit $rc
+diff --git a/test/qbg22/evb22/88-lldpad.conf b/test/qbg22/evb22/88-lldpad.conf
+new file mode 100644
+index 0000000..20ef072
+--- /dev/null
++++ b/test/qbg22/evb22/88-lldpad.conf
+@@ -0,0 +1,55 @@
++#
++#  Implementation of EVB according to IEEE 802.1Qbg ratified standard
++#  (c) Copyright IBM Corp. 2014
++#
++#  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++#  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".
++#
++
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "0452540050244E";
++    };
++    tlvid00000002 : 
++    {
++      info = "0352540050244E";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = true;
++      evbmode = "station";
++      evbrrcap = true;
++      evbrrreq = true;
++      evbgpid = true;
++      ecpretries = 3;
++      ecprte = 8;
++      vdprwd = 8;
++      vdprka = 8;
++    };
++  };
++};
+diff --git a/test/qbg22/evb22/88.evb b/test/qbg22/evb22/88.evb
+new file mode 100644
+index 0000000..3b88d6c
+--- /dev/null
++++ b/test/qbg22/evb22/88.evb
+@@ -0,0 +1,72 @@
++/*
++ *  Implementation of EVB according to IEEE 802.1Qbg
++ *  (c) Copyright IBM Corp. 2014
++ *
++ *  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++ *
++ *  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".
++ *
++ */
++
++/*
++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set
++ * is needed for each transmission.
++ * The first column defines the run time of the test program  in seconds
++ * when the remaining data on this line will be sent. The rest of the line are
++ * data fields which define the TLVs.
++ * Line limit is 5KB, long lines can be split  with \\ as last character.
++ *
++ * The files are preprocessed with cpp before being read by the test program.
++ *
++ * The data fields per line are
++ * 1. time
++ * 2. destination MAC
++ * 3. source MAC (dash(-) replaced by the senders MAC address)
++ * 4. ethertype
++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are
++ *    chassis-id, port-id, ttl and end)
++ * 6. Optional. Several TLVs starting with @ which are expected results.
++ *    Its an error is it is missing in the reply or TLV differs.
++ */
++/*
++ * EVB negotiation - bridge offers support for reflective relay and station
++ *	requests it. Bridge and station set group id bit.
++ */
++
++#include	"defines.evb"
++
++5	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:06:00:00:40:00 end_tlv @evbhead:06:0c:counts
++6	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:0c:00:40:00 end_tlv @evbhead:07:0d:counts
++7	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts
++8	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts
++9	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts
++51	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:05:00:40:00 end_tlv
++52	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:05:00:40:00 end_tlv
++53	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:05:00:40:00 end_tlv
++54	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:05:00:40:00 end_tlv
++55	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:05:00:40:00 end_tlv
++80	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv
+diff --git a/test/qbg22/evb22/88.sh b/test/qbg22/evb22/88.sh
+new file mode 100755
+index 0000000..3474e77
+--- /dev/null
++++ b/test/qbg22/evb22/88.sh
+@@ -0,0 +1,58 @@
++#!/bin/bash
++#
++# Test case for LLDPAD EVB Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Configuration file for unknwon vsi data test cases
++#
++
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 16-Aug-2012
++#
++# Execute a single task on the machine running lldpad
++#
++
++# Wait 50 seconds before executing command
++sleep 50;
++
++$1/lldptool -i veth0 -gncb -T -V evb -c vdprwd=31
++rc=$?
++if [ "$rc" -ne 0 ]
++then
++	let rc=98
++	echo $rc "FAILURE:lldptool -i veth0 -gncb -T -V evb -c vdprwd=31"
++	exit $rc
++fi
++
++sleep 3
++
++out=$($1/lldptool -i veth0 -gncb -t -V evb -c vdprwd)
++rc=$?
++if [ "$rc" -eq 0 ]
++then
++	# echo out ":$out:"
++	if [ "$out" != "vdprwd=31" ]
++	then
++		rc=99
++	fi
++fi
++# First field contains exit code of shell script, 0 for success anything else
++# for failure.
++echo $rc ":$out:"
++exit $rc
+diff --git a/test/qbg22/evb22/89-lldpad.conf b/test/qbg22/evb22/89-lldpad.conf
+new file mode 100644
+index 0000000..20ef072
+--- /dev/null
++++ b/test/qbg22/evb22/89-lldpad.conf
+@@ -0,0 +1,55 @@
++#
++#  Implementation of EVB according to IEEE 802.1Qbg ratified standard
++#  (c) Copyright IBM Corp. 2014
++#
++#  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++#  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".
++#
++
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "0452540050244E";
++    };
++    tlvid00000002 : 
++    {
++      info = "0352540050244E";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = true;
++      evbmode = "station";
++      evbrrcap = true;
++      evbrrreq = true;
++      evbgpid = true;
++      ecpretries = 3;
++      ecprte = 8;
++      vdprwd = 8;
++      vdprka = 8;
++    };
++  };
++};
+diff --git a/test/qbg22/evb22/89.evb b/test/qbg22/evb22/89.evb
+new file mode 100644
+index 0000000..3b88d6c
+--- /dev/null
++++ b/test/qbg22/evb22/89.evb
+@@ -0,0 +1,72 @@
++/*
++ *  Implementation of EVB according to IEEE 802.1Qbg
++ *  (c) Copyright IBM Corp. 2014
++ *
++ *  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++ *
++ *  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".
++ *
++ */
++
++/*
++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set
++ * is needed for each transmission.
++ * The first column defines the run time of the test program  in seconds
++ * when the remaining data on this line will be sent. The rest of the line are
++ * data fields which define the TLVs.
++ * Line limit is 5KB, long lines can be split  with \\ as last character.
++ *
++ * The files are preprocessed with cpp before being read by the test program.
++ *
++ * The data fields per line are
++ * 1. time
++ * 2. destination MAC
++ * 3. source MAC (dash(-) replaced by the senders MAC address)
++ * 4. ethertype
++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are
++ *    chassis-id, port-id, ttl and end)
++ * 6. Optional. Several TLVs starting with @ which are expected results.
++ *    Its an error is it is missing in the reply or TLV differs.
++ */
++/*
++ * EVB negotiation - bridge offers support for reflective relay and station
++ *	requests it. Bridge and station set group id bit.
++ */
++
++#include	"defines.evb"
++
++5	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:06:00:00:40:00 end_tlv @evbhead:06:0c:counts
++6	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:0c:00:40:00 end_tlv @evbhead:07:0d:counts
++7	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts
++8	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts
++9	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts
++51	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:05:00:40:00 end_tlv
++52	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:05:00:40:00 end_tlv
++53	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:05:00:40:00 end_tlv
++54	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:05:00:40:00 end_tlv
++55	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:05:00:40:00 end_tlv
++80	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv
+diff --git a/test/qbg22/evb22/89.sh b/test/qbg22/evb22/89.sh
+new file mode 100755
+index 0000000..a10330e
+--- /dev/null
++++ b/test/qbg22/evb22/89.sh
+@@ -0,0 +1,58 @@
++#!/bin/bash
++#
++# Test case for LLDPAD EVB Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Configuration file for unknwon vsi data test cases
++#
++
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 16-Aug-2012
++#
++# Execute a single task on the machine running lldpad
++#
++
++# Wait 50 seconds before executing command
++sleep 50;
++
++$1/lldptool -i veth0 -gncb -T -V evb -c vdprka=31
++rc=$?
++if [ "$rc" -ne 0 ]
++then
++	let rc=98
++	echo $rc "FAILURE:lldptool -i veth0 -gncb -T -V evb -c vdprka=31"
++	exit $rc
++fi
++
++sleep 3
++
++out=$($1/lldptool -i veth0 -gncb -t -V evb -c vdprka)
++rc=$?
++if [ "$rc" -eq 0 ]
++then
++	# echo out ":$out:"
++	if [ "$out" != "vdprka=31" ]
++	then
++		rc=99
++	fi
++fi
++# First field contains exit code of shell script, 0 for success anything else
++# for failure.
++echo $rc ":$out:"
++exit $rc
+diff --git a/test/qbg22/evb22/9-lldpad.conf b/test/qbg22/evb22/9-lldpad.conf
+new file mode 100644
+index 0000000..ebe91e0
+--- /dev/null
++++ b/test/qbg22/evb22/9-lldpad.conf
+@@ -0,0 +1,55 @@
++#
++#  Implementation of EVB according to IEEE 802.1Qbg ratified standard
++#  (c) Copyright IBM Corp. 2014
++#
++#  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++#  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".
++#
++
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "0452540050244E";
++    };
++    tlvid00000002 : 
++    {
++      info = "0352540050244E";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = true;
++      evbmode = "station";
++      evbrrcap = false;
++      evbrrreq = true;
++      evbgpid = false;
++      ecpretries = 3;
++      ecprte = 8;
++      vdprwd = 8;
++      vdprka = 8;
++    };
++  };
++};
+diff --git a/test/qbg22/evb22/9.evb b/test/qbg22/evb22/9.evb
+new file mode 100644
+index 0000000..46ce2b6
+--- /dev/null
++++ b/test/qbg22/evb22/9.evb
+@@ -0,0 +1,60 @@
++/*
++ *  Implementation of EVB according to IEEE 802.1Qbg
++ *  (c) Copyright IBM Corp. 2014
++ *
++ *  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++ *
++ *  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".
++ *
++ */
++
++/*
++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set
++ * is needed for each transmission.
++ * The first column defines the run time of the test program  in seconds
++ * when the remaining data on this line will be sent. The rest of the line are
++ * data fields which define the TLVs.
++ * Line limit is 5KB, long lines can be split  with \\ as last character.
++ *
++ * The files are preprocessed with cpp before being read by the test program.
++ *
++ * The data fields per line are
++ * 1. time
++ * 2. destination MAC
++ * 3. source MAC (dash(-) replaced by the senders MAC address)
++ * 4. ethertype
++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are
++ *    chassis-id, port-id, ttl and end)
++ * 6. Optional. Several TLVs starting with @ which are expected results.
++ *    Its an error is it is missing in the reply or TLV differs.
++ */
++/*
++ * EVB negotiation - bridge does not support reflective relay but station
++ *	requests it. RKA value is higher than on station.
++ */
++
++#include	"defines.evb"
++
++5	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:00:00:00:04:1f end_tlv @evbhead:00:04:68:88:3f
++6	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:00:00:00:04:1f end_tlv @evbhead:00:04:68:88:3f
++7	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:00:00:00:04:1f end_tlv @evbhead:00:04:68:88:3f
++8	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:00:00:00:04:1f end_tlv @evbhead:00:04:68:88:3f
++15	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv
+diff --git a/test/qbg22/evb22/90-lldpad.conf b/test/qbg22/evb22/90-lldpad.conf
+new file mode 100644
+index 0000000..20ef072
+--- /dev/null
++++ b/test/qbg22/evb22/90-lldpad.conf
+@@ -0,0 +1,55 @@
++#
++#  Implementation of EVB according to IEEE 802.1Qbg ratified standard
++#  (c) Copyright IBM Corp. 2014
++#
++#  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++#  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".
++#
++
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "0452540050244E";
++    };
++    tlvid00000002 : 
++    {
++      info = "0352540050244E";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = true;
++      evbmode = "station";
++      evbrrcap = true;
++      evbrrreq = true;
++      evbgpid = true;
++      ecpretries = 3;
++      ecprte = 8;
++      vdprwd = 8;
++      vdprka = 8;
++    };
++  };
++};
+diff --git a/test/qbg22/evb22/90.evb b/test/qbg22/evb22/90.evb
+new file mode 100644
+index 0000000..3b88d6c
+--- /dev/null
++++ b/test/qbg22/evb22/90.evb
+@@ -0,0 +1,72 @@
++/*
++ *  Implementation of EVB according to IEEE 802.1Qbg
++ *  (c) Copyright IBM Corp. 2014
++ *
++ *  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++ *
++ *  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".
++ *
++ */
++
++/*
++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set
++ * is needed for each transmission.
++ * The first column defines the run time of the test program  in seconds
++ * when the remaining data on this line will be sent. The rest of the line are
++ * data fields which define the TLVs.
++ * Line limit is 5KB, long lines can be split  with \\ as last character.
++ *
++ * The files are preprocessed with cpp before being read by the test program.
++ *
++ * The data fields per line are
++ * 1. time
++ * 2. destination MAC
++ * 3. source MAC (dash(-) replaced by the senders MAC address)
++ * 4. ethertype
++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are
++ *    chassis-id, port-id, ttl and end)
++ * 6. Optional. Several TLVs starting with @ which are expected results.
++ *    Its an error is it is missing in the reply or TLV differs.
++ */
++/*
++ * EVB negotiation - bridge offers support for reflective relay and station
++ *	requests it. Bridge and station set group id bit.
++ */
++
++#include	"defines.evb"
++
++5	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:06:00:00:40:00 end_tlv @evbhead:06:0c:counts
++6	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:0c:00:40:00 end_tlv @evbhead:07:0d:counts
++7	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts
++8	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts
++9	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:0d:00:40:00 end_tlv @evbhead:07:0d:counts
++51	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:05:00:40:00 end_tlv
++52	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:05:00:40:00 end_tlv
++53	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:05:00:40:00 end_tlv
++54	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:05:00:40:00 end_tlv
++55	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evbhead:07:05:00:40:00 end_tlv
++80	lldpad_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv
+diff --git a/test/qbg22/evb22/90.sh b/test/qbg22/evb22/90.sh
+new file mode 100755
+index 0000000..1492d3b
+--- /dev/null
++++ b/test/qbg22/evb22/90.sh
+@@ -0,0 +1,47 @@
++#!/bin/bash
++#
++# Test case for LLDPAD EVB Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Configuration file for unknwon vsi data test cases
++#
++
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 16-Aug-2012
++#
++# Execute a single task on the machine running lldpad
++#
++
++# Wait 50 seconds before executing command
++sleep 50;
++
++out=$($1/lldptool -i veth0 -gncb -t -V evb | tr -d '\t\n')
++rc=$?
++if [ "$rc" -eq 0 ]
++then
++	# echo out ":$out:"
++	if [ "$out" != "EVB Configuration TLVbridge:bgid,rrcap,rrctr(0x7)station:sgid,rrreq,rrstat(0xd)retries:3 rte:8mode:station r/l:0 rwd:8r/l:0 rka:8" ]
++	then
++		rc=99
++	fi
++fi
++# First field contains exit code of shell script, 0 for success anything else
++# for failure.
++echo $rc ":$out:"
++exit $rc
+diff --git a/test/qbg22/evb22/README b/test/qbg22/evb22/README
+new file mode 100644
+index 0000000..f9814b4
+--- /dev/null
++++ b/test/qbg22/evb22/README
+@@ -0,0 +1,142 @@
++#
++#  Implementation of EVB according to IEEE 802.1Qbg ratified standard
++#  (c) Copyright IBM Corp. 2014
++#
++#  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++#  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".
++#
++
++
++Test cases for IEEE802.1Qbg ratified standard EVB module. 
++To test this setup:
++- on bridge_ns 'qbg22sim -v -v -v -d 30 veth2' to display any messages.
++- on 'qbg22sim -v -v -v -d 20 veth0 brtest.evb' to send 5 messages.
++On netns2 name space messages with EVB TLV should be displayed.
++
++Files
++=====
++There are 3 shell scripts which are executed on f18a
++allevb.sh:	Runs all test cases with file names [1-9]*.evb. Uses
++		runevb.sh to execute one test case.
++		On success the exit code is zero, on failure none zero.
++		A none zero exit code termintes the evball.sh immediately.
++runevb.sh	Runs one test case. 
++		Return 0 on success and none zero otherwise.
++		Uses ssh for remote communication between virtual machines
++		and predefined pathes/IP addresses.
++24.sh		<Test case number>.sh contain shell scripts to be executed
++		on the remote virtual machine. Usually done to change some
++		lldpad configuration settings during execution of lldpad.
++
++Tests
++=====
++The following test cases are executed. Each test case has a number.
++All test cases need a lldpad.conf configuration file and an qbg22sim input
++file:
++- The qbg22sim input files have the extension .evb.
++- The lldpad configuration file has the extension -lldpad.conf
++
++The purpose is to trigger an EVB DU exchange between qbg22sim and llpdad.
++The exchanged data can be inspected automaticly with little inteligence
++(see qbg22sim.1) or manually.
++
++Test	Description
++1	Neither station nor bridge support refective-relay.
++2	Station denies reflective-relay but bridge offers it.
++3	Station request reflective-relay but bridge does not support it.
++4	Station request reflective-relay and bridge supports it.
++5	Station request reflective-relay and bridge supports it. After some
++	time bridge turns off reflective relay support.
++6	Station request reflective-relay and bridge supports it. After some
++	time station does not request reflective relay support anymore.
++7	Use different RTE value. Local value is higher.
++8	Use different RTE value. Local value is lower.
++9	Use different RKA value. Local value is higher.
++10	Use different RKA value. Local value is lower.
++11	Use different RWD value. Local value is lower.
++12	Use different RWD value. Local value is higher.
++13	Use different retry value. Local value is higher.
++14	Use different retry value. Local value is lower.
++20	Station request reflective-relay and bridge supports it. Bridge sets
++	group id support, but station denies this.
++21	Station request reflective-relay and bridge supports it. Station sets
++	group id support, but bridge denies this.
++22	Station request reflective-relay and bridge supports it. Bridge sets
++	group id support, station sets group id support.
++23	Station request reflective-relay and bridge supports it. Bridge sets
++	group id support, station sets group id support. Bridge turns it off.
++24	Station request reflective-relay and bridge supports it. Bridge sets
++	group id support, station sets group id support. Station turns it off.
++25	Station request reflective-relay and bridge supports it. EVB TLV
++	transmission turned off.
++26	Station request reflective-relay and bridge supports it. EVB TLV
++	changed after 30 seconds via lldptool on station side
++30	Lldpad runs as bridge no reflective relay support.
++31	Lldpad runs as bridge with reflective relay support.
++32	Lldpad runs as bridge with reflective relay support and bgid support.
++33	Lldpad runs as bridge with reflective relay support and bgid support.
++		Station runs with reflective relay and sgid support
++41	Check for creation of evb.enableTx=off and evb22.enableTx=off
++42	Check for creation of evb.enableTx=on and evb22.enableTx=off
++43	Check for creation of evb.enableTx=off and evb22.enableTx=on
++44	Check for creation of evb.enableTx=on and evb22.enableTx=on
++45	Check for evb.enableTx=on and evb22.enableTx=on in config file
++46	Check for creation of evb22.enableTx=on and evb.enableTx=on
++80	Check for lldptool command using evb22 protocol display evb22 (-c only)
++90	Check for lldptool command using evb22 protocol display evb22
++81-89	Check for lldptool command using evb22 protocol turn off various parms
++
++Remarks:
++On some tests the warning "expect_reply reply to message sent (xx sec) missing
++may appear or not. This is randon, sometime all tests run without any warning
++at all, sometimes several tests display this warning.
++The warning can be ignored. The warning is displayed be the qbg22sim program
++only when an expected reply has not been received in time (1 second).
++The reason is:
++1. qbg22sim sends out and LLDP message
++2. lldpad receives the message and updates its MIB
++3. lldpad waits about 900ms until it sends out its updated LLDP TLS
++4. Mostly qbg22sim gets the reply from lldpad before it sends the next EVB TLV
++   one second later. In vary rare cases the TLVs are received after the timer
++   in qbg22sim expired and the next message is sent. When the next message is
++   sent and no reply received, the warning is issue.
++5. This is no problem at all. The LLDP standard says the messages are exchanged
++   in 1 second intervals without any handshaking at all. Each party simply
++   transmit its current status.
++
++Test Execution
++==============
++Directory structure:
++The following directory structure is assumed:
++/home/richter/dcn/qbg/mywork/open-lldp	--> lldpad
++/home/richter/dcn/qbg/mywork/open-lldp	--> qbg22sim
++/home/richter/dcn/qbg/mywork/nstest/qbg22/evb22	--> EVB protocol test cases
++
++To allow flexibility the path to execute the executables can be specified.
++Set the PATH variable properly.
++
++Select the qbg22sim simulation program by adding a symbolic link
++directory
++1. cd /home/richter/dcn/qbg/mywork/test/qbg22/evb22
++2. Create a symbolic link to the qbg22sim program
++   to use. Something like 'ln -s ../../../open-lldp-new/qbg22sim'
++3. Add the environment variable LLDPAD_DIR=abc to select an different lldpad
++   executable. For example the invocation 
++   LLDPAD_DIR=open-lldp-new evball.sh
++   selects the file /home/richter/dcn/qbg/mywork/open-lldp-new/lldpad
++   for execution.
+diff --git a/test/qbg22/evb22/allevb.sh b/test/qbg22/evb22/allevb.sh
+new file mode 100755
+index 0000000..62b3fb2
+--- /dev/null
++++ b/test/qbg22/evb22/allevb.sh
+@@ -0,0 +1,64 @@
++#!/bin/bash
++#
++# Test case for LLDPAD EVB Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Configuration file for unknwon vsi data test cases
++#
++
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 16-Aug-2012
++#
++# Execute the complete evb test suite.
++#
++
++runcommand()
++{
++	# echo parameter $@
++	cmd=$1
++	file=$2
++
++	echo "start testcase $number"
++	$cmd $file $@ 2>&1
++	rc="$?"
++	if [ "$rc" -ne 0 ]
++	then
++		echo -en "\\033[1;31m"	# Failures in red
++		echo "ERROR $file exit with $rc"
++		echo -en "\\033[0;39m"
++		exit 2
++	fi
++	echo -en "\\033[1;32m"	# Success in green
++	echo "OK testcase $file"
++	echo -en "\\033[0;39m"
++	return 0
++}
++
++if ! which runevb.sh 2>/dev/null
++then
++	export PATH=$PATH:$PWD
++fi
++
++echo "Start testsuite at $(date)"
++for i in $(ls [1-9]*.evb|sort -n)
++do
++	runcommand runevb.sh $i
++done
++echo "Stop testsuite at $(date)"
++exit 0
+diff --git a/test/qbg22/evb22/brtest.evb b/test/qbg22/evb22/brtest.evb
+new file mode 100644
+index 0000000..8871830
+--- /dev/null
++++ b/test/qbg22/evb22/brtest.evb
+@@ -0,0 +1,69 @@
++/*
++ *  Implementation of EVB according to IEEE 802.1Qbg
++ *  (c) Copyright IBM Corp. 2014
++ *
++ *  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++ *
++ *  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".
++ *
++ */
++
++/*
++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set
++ * is needed for each transmission.
++ * The first column defines the run time of the test program  in seconds
++ * when the remaining data on this line will be sent. The rest of the line are
++ * data fields which define the TLVs.
++ * Line limit is 5KB, long lines can be split  with \\ as last character.
++ *
++ * The files are preprocessed with cpp before being read by the test program.
++ *
++ * The data fields per line are
++ * 1. time
++ * 2. destination MAC
++ * 3. source MAC (dash(-) replaced by the senders MAC address)
++ * 4. ethertype
++ * 5. Severval TLVs according to standard 802.3ad (Mandatory TLV are
++ *    chassis-id, port-id, ttl and end)
++ * 6. Optional. Several TLVs starting with @ which are expected results.
++ *    Its an error is it is missing in the reply or TLV differs.
++ */
++/*
++ * EVB negotiation - test virtual bridge forwards mac multicast to 
++ * 	nearest customer bridge (01:80:c2:00:00:00).
++ */
++
++#define	dst_mac		01:80:c2:00:00:00
++#define	lldp_type	88:cc
++#define chassis_tlv	02:07:06:64:75:6d:6d:79:00
++#define	port_tlv	04:05:05:65:74:68:30
++#define	ttl_tlv120	06:02:00:78
++#define	ttl_tlv0	06:02:00:00
++#define	end_tlv		00:00
++
++#define	evbhead		fe:09:00:80:c2:0d
++#define	evb_norr	evbhead:00:00:00:40:00
++
++5	dst_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evb_norr end_tlv
++6	dst_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evb_norr end_tlv
++7	dst_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evb_norr end_tlv
++8	dst_mac - lldp_type chassis_tlv port_tlv ttl_tlv120 \\
++		evb_norr end_tlv
++15	dst_mac - lldp_type chassis_tlv port_tlv ttl_tlv0 end_tlv
+diff --git a/test/qbg22/evb22/defines.evb b/test/qbg22/evb22/defines.evb
+new file mode 100644
+index 0000000..7e01a75
+--- /dev/null
++++ b/test/qbg22/evb22/defines.evb
+@@ -0,0 +1,53 @@
++/*
++ *  Implementation of EVB according to IEEE 802.1Qbg
++ *  (c) Copyright IBM Corp. 2014
++ *
++ *  Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++ *
++ *  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".
++ *
++ */
++
++/*
++ * EVB Protocol test data. Define a complete LLDP DU in hex. One complete set
++ * is needed for each transmission.
++ */
++/*
++ * Very common defines
++ */
++
++#define	lldpad_mac	01:80:c2:00:00:00
++#define	lldp_type	88:cc
++#define chassis_tlv	02:07:06:64:75:6d:6d:79:00
++#define	port_tlv	04:05:05:65:74:68:30
++#define	ttl_tlv120	06:02:00:78
++#define	ttl_tlv0	06:02:00:00
++#define	end_tlv		00:00
++
++#define	evbhead		fe:09:00:80:c2:0d
++#define	counts		68:88:08
++#define	stcounts	a6:58:18
++
++/* No Reflective Relay on bridge */
++#define	evb_norr	evbhead:00:00:00:40:00
++#define	evb_norr_ack	evbhead:00:00:counts
++/* Bridge offers reflective-relay */
++#define	evb_brrr	evbhead:02:00:00:40:00
++#define	evb_brrr_ack	evbhead:02:00:counts
++/* Station request reflective relay */
++#define	evb_norr2	evbhead:00:04:00:40:00
++#define	evb_strr_ack	evbhead:00:04:counts
+diff --git a/test/qbg22/evb22/runevb.sh b/test/qbg22/evb22/runevb.sh
+new file mode 100755
+index 0000000..c4cc88c
+--- /dev/null
++++ b/test/qbg22/evb22/runevb.sh
+@@ -0,0 +1,152 @@
++#!/bin/bash
++#
++# Execute test case for LLDPAD testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 16-Aug-2012
++#
++# Execute a single  test. Parameter is the name of the test file
++#
++
++# Check if lldpad is up and running. Return pid or 0 if not running.
++# Note that lldpad may be started without creating a PID file. If no PID file
++# exists, use the lldptool to query the PID of lldpad.
++function lldpad_up()
++{
++	if [ ! -r /var/run/lldpad.pid ]
++	then
++		pidfile=$(../../../lldptool -p 2>/dev/null)
++		if [ "$?" -ne 0 ]
++		then
++			return 0
++		fi
++	else
++		pidfile="$(cat /var/run/lldpad.pid)"
++	fi
++	if [ -z "$pidfile" ]
++	then
++		return 0
++	else
++		ps -p $pidfile -o pid --no-header > /dev/null
++		if [ $? -ne 0 ]
++		then
++			return 0
++		fi
++	fi
++	echo "LLDPAD running pid $pidfile"
++	return $pidfile
++}
++
++function lldpad_down()
++{
++	if [ ! -r /var/run/lldpad.pid ]
++	then
++		pidfile=$(../../../lldptool -p 2>/dev/null)
++		if [ "$?" -ne 0 ]
++		then
++			return 1
++		fi
++	else
++		pidfile="$(cat /var/run/lldpad.pid)"
++	fi
++	if [ -z "$pidfile" ]
++	then
++		return 1
++	fi
++	kill -s SIGTERM $pidfile
++	sleep 1
++	ps -p $pidfile -o pid --no-header > /dev/null
++	if [ $? -ne 1 ]
++	then
++		kill -s SIGKILL $pidfile
++	fi
++	return 0
++}
++
++# Use the correct lldpad configuration file and start lldpad.
++# Parameter 1: path to lldpad to use
++# Parameter 2: name of configuration file
++function lldpad_start()
++{
++	if lldpad_up
++	then
++		rm -f /var/lib/lldpad/lldpad.conf ./lldpad.conf
++		cp $2 /tmp/$2
++		$1/lldpad -V7 -f /tmp/$2 >/tmp/$2.out 2>&1 &
++		sleep 1
++		if lldpad_up
++		then
++			echo "$0:lldpad not started or terminated unexpectedly"
++			exit 1
++		fi
++	else
++		exit 1
++	fi
++	return 0
++}
++
++if ! which runevb.sh 1>/dev/null 2>/dev/null
++then
++	export PATH=$PATH:$PWD
++fi
++
++# Extract type of test case from last 3 characters of invocation
++type=$(basename $0)
++type=".${type:3:3}"
++
++testfile=$1
++no=$(basename $testfile $type)
++
++# Start lldpad using this name space
++if ! lldpad_start ../../.. $no-lldpad.conf
++then
++	echo "$0:can not start lldpad"
++	exit 1
++fi
++
++# Check for shell script to run in parallel
++if [ -r "./$no.sh" -a -x "./$no.sh" ]
++then
++	./$no.sh ../../.. > /tmp/$no.sh.out &
++fi
++
++# get the duration from the last entry in the test file.
++duration=$(cpp $testfile | cut -f1 -d' ' | sed '/^$/d' | tail -1)
++let duration=duration+5
++
++# run the test with output save to /tmp/testfile.out
++ip netns exec bridge_ns ../../../qbg22sim -v -v -v -T 5000000 -d $duration veth2 $testfile > /tmp/$testfile.out
++rc=$?
++
++# Stop lldpad
++if ! lldpad_down
++then
++	echo "$0:can not stop lldpad"
++	exit 1
++fi
++
++# Check for output file script to test result of test case
++if [ -r "/tmp/$no.sh.out" ]
++then
++	rc=$(cut -f1 -d' ' "/tmp/$no.sh.out")
++fi
++
++exit $rc
+diff --git a/test/qbg22/vdp22/100-lldpad.conf b/test/qbg22/vdp22/100-lldpad.conf
+new file mode 100644
+index 0000000..9c76b9c
+--- /dev/null
++++ b/test/qbg22/vdp22/100-lldpad.conf
+@@ -0,0 +1,55 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013
++#
++# LLDPAD station rule configuration file
++#
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = false;
++      evbmode = "station";
++      evbrrreq = true;
++      evbgpid = false;
++      ecpretries = 3;
++      ecprte = 14;
++      vdprwd = 20;
++      vdprka = 20;
++    };
++  };
++};
+diff --git a/test/qbg22/vdp22/100.nlc b/test/qbg22/vdp22/100.nlc
+new file mode 100755
+index 0000000..5d746ba
+--- /dev/null
++++ b/test/qbg22/vdp22/100.nlc
+@@ -0,0 +1,37 @@
++#!/bin/bash
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2013
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++
++# 
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014
++#
++# Execute a simple assoc/de-assoc test. Station has no EVB TLV disabled
++# Expect failure
++#
++
++sleep 30	# Must: Wait some time for lldpad to start up and initialize
++outfile=$(basename $0)
++dirfile=$(dirname $0)
++cd $dirfile
++
++../../../vdptest -v -v -v -F vm.cfg -i veth0 -a vm1,e=-93 -s,w=10
++rc=$?
++exit $rc
+diff --git a/test/qbg22/vdp22/100.vdp b/test/qbg22/vdp22/100.vdp
+new file mode 100644
+index 0000000..fa3efbd
+--- /dev/null
++++ b/test/qbg22/vdp22/100.vdp
+@@ -0,0 +1,43 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013
++# lldpad bridge mode configuration file
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth2 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    @include "brevb_default.res"
++  };
++};
+diff --git a/test/qbg22/vdp22/101-lldpad.conf b/test/qbg22/vdp22/101-lldpad.conf
+new file mode 100644
+index 0000000..ff35cc7
+--- /dev/null
++++ b/test/qbg22/vdp22/101-lldpad.conf
+@@ -0,0 +1,56 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013
++#
++# LLDPAD station rule configuration file
++#
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = true;
++      evbmode = "bridge";
++      evbrrcap = true;
++      evbrrreq = true;
++      evbgpid = false;
++      ecpretries = 3;
++      ecprte = 14;
++      vdprwd = 20;
++      vdprka = 20;
++    };
++  };
++};
+diff --git a/test/qbg22/vdp22/101.nlc b/test/qbg22/vdp22/101.nlc
+new file mode 100755
+index 0000000..b63c8a5
+--- /dev/null
++++ b/test/qbg22/vdp22/101.nlc
+@@ -0,0 +1,36 @@
++#!/bin/bash
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2013
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++
++# 
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014
++#
++# Execute a simple assoc and expect error because lldpad runs in bridge role.
++#
++
++sleep 30	# Must: Wait some time for lldpad to start up and initialize
++outfile=$(basename $0)
++dirfile=$(dirname $0)
++cd $dirfile
++
++../../../vdptest -v -v -v -F vm.cfg -i veth0 -a vm1,e=-95 -s,w=5
++rc=$?
++exit $rc
+diff --git a/test/qbg22/vdp22/101.vdp b/test/qbg22/vdp22/101.vdp
+new file mode 100644
+index 0000000..9ae4eaa
+--- /dev/null
++++ b/test/qbg22/vdp22/101.vdp
+@@ -0,0 +1,57 @@
++#!/bin/bash
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++
++# 
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013
++# lldpad bridge mode configuration file
++#
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth2 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = true;
++      evbmode = "station";
++      evbrrreq = true;
++      evbgpid = false;
++      ecpretries = 3;
++      ecprte = 14;
++      vdprwd = 20;
++      vdprka = 20;
++    };
++  };
++};
+diff --git a/test/qbg22/vdp22/102-lldpad.conf b/test/qbg22/vdp22/102-lldpad.conf
+new file mode 100644
+index 0000000..2ea4e18
+--- /dev/null
++++ b/test/qbg22/vdp22/102-lldpad.conf
+@@ -0,0 +1,56 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013
++#
++# LLDPAD station rule configuration file
++#
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = true;
++      evbmode = "station";
++      evbrrcap = false;
++      evbrrreq = false;
++      evbgpid = false;
++      ecpretries = 3;
++      ecprte = 14;
++      vdprwd = 20;
++      vdprka = 20;
++    };
++  };
++};
+diff --git a/test/qbg22/vdp22/102.nlc b/test/qbg22/vdp22/102.nlc
+new file mode 100755
+index 0000000..8dd7558
+--- /dev/null
++++ b/test/qbg22/vdp22/102.nlc
+@@ -0,0 +1,36 @@
++#!/bin/bash
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2013
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++
++# 
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014
++#
++# Execute a simple assoc/de-assoc test. Station has no RR capabililty requested.
++#
++
++sleep 30	# Must: Wait some time for lldpad to start up and initialize
++outfile=$(basename $0)
++dirfile=$(dirname $0)
++cd $dirfile
++
++../../../vdptest -v -v -v -F vm.cfg -i veth0 -a vm1 -s,w=30 -d vm1 -s,w=10
++rc=$?
++exit $rc
+diff --git a/test/qbg22/vdp22/102.vdp b/test/qbg22/vdp22/102.vdp
+new file mode 100644
+index 0000000..1f56138
+--- /dev/null
++++ b/test/qbg22/vdp22/102.vdp
+@@ -0,0 +1,47 @@
++#!/bin/bash
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++
++# 
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013
++# lldpad bridge mode configuration file
++#
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth2 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    @include "brevb_default.res"
++  }
++};
+diff --git a/test/qbg22/vdp22/103-lldpad.conf b/test/qbg22/vdp22/103-lldpad.conf
+new file mode 100644
+index 0000000..fdbb132
+--- /dev/null
++++ b/test/qbg22/vdp22/103-lldpad.conf
+@@ -0,0 +1,56 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013
++#
++# LLDPAD station rule configuration file
++#
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = true;
++      evbmode = "station";
++      evbrrcap = false;
++      evbrrreq = true;
++      evbgpid = false;
++      ecpretries = 3;
++      ecprte = 14;
++      vdprwd = 20;
++      vdprka = 20;
++    };
++  };
++};
+diff --git a/test/qbg22/vdp22/103.nlc b/test/qbg22/vdp22/103.nlc
+new file mode 100755
+index 0000000..69fbdbc
+--- /dev/null
++++ b/test/qbg22/vdp22/103.nlc
+@@ -0,0 +1,35 @@
++#!/bin/bash
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2013
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++
++# 
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014
++#
++# Execute a simple assoc/de-assoc test.
++#
++
++# Must: Wait some time for lldpad to start up and initialize
++outfile=$(basename $0)
++dirfile=$(dirname $0)
++cd $dirfile
++
++../../../vdptest -v -v -v -F vm.cfg -i veth0 -s,w=30 -a vm1,w=20 -s,w=60 -d vm1 -s,w=10
++exit $?
+diff --git a/test/qbg22/vdp22/103.vdp b/test/qbg22/vdp22/103.vdp
+new file mode 100644
+index 0000000..5b1f36a
+--- /dev/null
++++ b/test/qbg22/vdp22/103.vdp
+@@ -0,0 +1,47 @@
++#!/bin/bash
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++
++# 
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013
++# lldpad bridge mode configuration file
++#
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth2 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    @include "brevb_default.res"
++  };
++};
+diff --git a/test/qbg22/vdp22/104-lldpad.conf b/test/qbg22/vdp22/104-lldpad.conf
+new file mode 100644
+index 0000000..fdbb132
+--- /dev/null
++++ b/test/qbg22/vdp22/104-lldpad.conf
+@@ -0,0 +1,56 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013
++#
++# LLDPAD station rule configuration file
++#
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = true;
++      evbmode = "station";
++      evbrrcap = false;
++      evbrrreq = true;
++      evbgpid = false;
++      ecpretries = 3;
++      ecprte = 14;
++      vdprwd = 20;
++      vdprka = 20;
++    };
++  };
++};
+diff --git a/test/qbg22/vdp22/104.nlc b/test/qbg22/vdp22/104.nlc
+new file mode 100755
+index 0000000..ea3c17c
+--- /dev/null
++++ b/test/qbg22/vdp22/104.nlc
+@@ -0,0 +1,36 @@
++#!/bin/bash
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2013
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++
++# 
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014
++#
++# Execute two simple assoc/de-assoc test.
++#
++
++sleep 30	# Must: Wait some time for lldpad to start up and initialize
++outfile=$(basename $0)
++dirfile=$(dirname $0)
++cd $dirfile
++
++../../../vdptest -v -v -v -F vm.cfg -i veth0 -a vm1 -s,w=5 -a vm2 -s,w=60 -d vm1 -d vm2
++rc=$?
++exit $rc
+diff --git a/test/qbg22/vdp22/104.vdp b/test/qbg22/vdp22/104.vdp
+new file mode 100644
+index 0000000..5de5046
+--- /dev/null
++++ b/test/qbg22/vdp22/104.vdp
+@@ -0,0 +1,45 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# 
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013
++# lldpad bridge mode configuration file
++#
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth2 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    @include "brevb_default.res"
++  };
++};
+diff --git a/test/qbg22/vdp22/105-lldpad.conf b/test/qbg22/vdp22/105-lldpad.conf
+new file mode 100644
+index 0000000..fdbb132
+--- /dev/null
++++ b/test/qbg22/vdp22/105-lldpad.conf
+@@ -0,0 +1,56 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013
++#
++# LLDPAD station rule configuration file
++#
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = true;
++      evbmode = "station";
++      evbrrcap = false;
++      evbrrreq = true;
++      evbgpid = false;
++      ecpretries = 3;
++      ecprte = 14;
++      vdprwd = 20;
++      vdprka = 20;
++    };
++  };
++};
+diff --git a/test/qbg22/vdp22/105.nlc b/test/qbg22/vdp22/105.nlc
+new file mode 100755
+index 0000000..4ee9d30
+--- /dev/null
++++ b/test/qbg22/vdp22/105.nlc
+@@ -0,0 +1,36 @@
++#!/bin/bash
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2013
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++
++# 
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014
++#
++# Execute a simple pre-assoc/de-assoc test.
++#
++
++sleep 30	# Must: Wait some time for lldpad to start up and initialize
++outfile=$(basename $0)
++dirfile=$(dirname $0)
++cd $dirfile
++
++../../../vdptest -v -v -v -F vm.cfg -i veth0 -p vm1 -s,w=45 -d vm1
++rc=$?
++exit $rc
+diff --git a/test/qbg22/vdp22/105.vdp b/test/qbg22/vdp22/105.vdp
+new file mode 100644
+index 0000000..fa3efbd
+--- /dev/null
++++ b/test/qbg22/vdp22/105.vdp
+@@ -0,0 +1,43 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013
++# lldpad bridge mode configuration file
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth2 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    @include "brevb_default.res"
++  };
++};
+diff --git a/test/qbg22/vdp22/106-lldpad.conf b/test/qbg22/vdp22/106-lldpad.conf
+new file mode 100644
+index 0000000..fdbb132
+--- /dev/null
++++ b/test/qbg22/vdp22/106-lldpad.conf
+@@ -0,0 +1,56 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013
++#
++# LLDPAD station rule configuration file
++#
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = true;
++      evbmode = "station";
++      evbrrcap = false;
++      evbrrreq = true;
++      evbgpid = false;
++      ecpretries = 3;
++      ecprte = 14;
++      vdprwd = 20;
++      vdprka = 20;
++    };
++  };
++};
+diff --git a/test/qbg22/vdp22/106.nlc b/test/qbg22/vdp22/106.nlc
+new file mode 100755
+index 0000000..833051a
+--- /dev/null
++++ b/test/qbg22/vdp22/106.nlc
+@@ -0,0 +1,36 @@
++#!/bin/bash
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2013
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++
++# 
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014
++#
++# Execute two pre-assoc/de-assoc test.
++#
++
++sleep 30	# Must: Wait some time for lldpad to start up and initialize
++outfile=$(basename $0)
++dirfile=$(dirname $0)
++cd $dirfile
++
++../../../vdptest -v -v -v -F vm.cfg -i veth0 -p vm1 -s,w=5 -p vm2 -s,w=60 -d vm1 -d vm2
++rc=$?
++exit $rc
+diff --git a/test/qbg22/vdp22/106.vdp b/test/qbg22/vdp22/106.vdp
+new file mode 100644
+index 0000000..fa3efbd
+--- /dev/null
++++ b/test/qbg22/vdp22/106.vdp
+@@ -0,0 +1,43 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013
++# lldpad bridge mode configuration file
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth2 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    @include "brevb_default.res"
++  };
++};
+diff --git a/test/qbg22/vdp22/107-lldpad.conf b/test/qbg22/vdp22/107-lldpad.conf
+new file mode 100644
+index 0000000..fdbb132
+--- /dev/null
++++ b/test/qbg22/vdp22/107-lldpad.conf
+@@ -0,0 +1,56 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013
++#
++# LLDPAD station rule configuration file
++#
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = true;
++      evbmode = "station";
++      evbrrcap = false;
++      evbrrreq = true;
++      evbgpid = false;
++      ecpretries = 3;
++      ecprte = 14;
++      vdprwd = 20;
++      vdprka = 20;
++    };
++  };
++};
+diff --git a/test/qbg22/vdp22/107.nlc b/test/qbg22/vdp22/107.nlc
+new file mode 100755
+index 0000000..99d80a0
+--- /dev/null
++++ b/test/qbg22/vdp22/107.nlc
+@@ -0,0 +1,36 @@
++#!/bin/bash
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2013
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++
++# 
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014
++#
++# Execute a simple pre-assoc-rr/de-assoc test.
++#
++
++sleep 30	# Must: Wait some time for lldpad to start up and initialize
++outfile=$(basename $0)
++dirfile=$(dirname $0)
++cd $dirfile
++
++../../../vdptest -v -v -v -F vm.cfg -i veth0 -r vm1 -s,w=45 -d vm1
++rc=$?
++exit $rc
+diff --git a/test/qbg22/vdp22/107.vdp b/test/qbg22/vdp22/107.vdp
+new file mode 100644
+index 0000000..fa3efbd
+--- /dev/null
++++ b/test/qbg22/vdp22/107.vdp
+@@ -0,0 +1,43 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013
++# lldpad bridge mode configuration file
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth2 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    @include "brevb_default.res"
++  };
++};
+diff --git a/test/qbg22/vdp22/108-lldpad.conf b/test/qbg22/vdp22/108-lldpad.conf
+new file mode 100644
+index 0000000..fdbb132
+--- /dev/null
++++ b/test/qbg22/vdp22/108-lldpad.conf
+@@ -0,0 +1,56 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013
++#
++# LLDPAD station rule configuration file
++#
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = true;
++      evbmode = "station";
++      evbrrcap = false;
++      evbrrreq = true;
++      evbgpid = false;
++      ecpretries = 3;
++      ecprte = 14;
++      vdprwd = 20;
++      vdprka = 20;
++    };
++  };
++};
+diff --git a/test/qbg22/vdp22/108.nlc b/test/qbg22/vdp22/108.nlc
+new file mode 100755
+index 0000000..8381135
+--- /dev/null
++++ b/test/qbg22/vdp22/108.nlc
+@@ -0,0 +1,36 @@
++#!/bin/bash
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2013
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++
++# 
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014
++#
++# Execute a simple assoc/pre-assoc test. Expect error.
++#
++
++sleep 30	# Must: Wait some time for lldpad to start up and initialize
++outfile=$(basename $0)
++dirfile=$(dirname $0)
++cd $dirfile
++
++../../../vdptest -v -v -v -F vm.cfg -i veth0 -a vm1 -s,w=45 -p vm1,e=-22
++rc=$?
++exit $rc
+diff --git a/test/qbg22/vdp22/108.vdp b/test/qbg22/vdp22/108.vdp
+new file mode 100644
+index 0000000..fa3efbd
+--- /dev/null
++++ b/test/qbg22/vdp22/108.vdp
+@@ -0,0 +1,43 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013
++# lldpad bridge mode configuration file
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth2 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    @include "brevb_default.res"
++  };
++};
+diff --git a/test/qbg22/vdp22/110-lldpad.conf b/test/qbg22/vdp22/110-lldpad.conf
+new file mode 100644
+index 0000000..fdbb132
+--- /dev/null
++++ b/test/qbg22/vdp22/110-lldpad.conf
+@@ -0,0 +1,56 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013
++#
++# LLDPAD station rule configuration file
++#
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = true;
++      evbmode = "station";
++      evbrrcap = false;
++      evbrrreq = true;
++      evbgpid = false;
++      ecpretries = 3;
++      ecprte = 14;
++      vdprwd = 20;
++      vdprka = 20;
++    };
++  };
++};
+diff --git a/test/qbg22/vdp22/110.nlc b/test/qbg22/vdp22/110.nlc
+new file mode 100755
+index 0000000..7878340
+--- /dev/null
++++ b/test/qbg22/vdp22/110.nlc
+@@ -0,0 +1,36 @@
++#!/bin/bash
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2013
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++
++# 
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014
++#
++# Execute a simple pre-assoc/pre-assoc-rr/assoc/de-assoc test.
++#
++
++sleep 30	# Must: Wait some time for lldpad to start up and initialize
++outfile=$(basename $0)
++dirfile=$(dirname $0)
++cd $dirfile
++
++../../../vdptest -v -v -v -F vm.cfg -i veth0 -p vm1 -s,w=30 -r vm1 -s,w=30 -a vm1 -s,w=30 -d vm1 -s,w=10
++rc=$?
++exit $rc
+diff --git a/test/qbg22/vdp22/110.vdp b/test/qbg22/vdp22/110.vdp
+new file mode 100644
+index 0000000..fa3efbd
+--- /dev/null
++++ b/test/qbg22/vdp22/110.vdp
+@@ -0,0 +1,43 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013
++# lldpad bridge mode configuration file
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth2 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    @include "brevb_default.res"
++  };
++};
+diff --git a/test/qbg22/vdp22/111-lldpad.conf b/test/qbg22/vdp22/111-lldpad.conf
+new file mode 100644
+index 0000000..fdbb132
+--- /dev/null
++++ b/test/qbg22/vdp22/111-lldpad.conf
+@@ -0,0 +1,56 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013
++#
++# LLDPAD station rule configuration file
++#
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = true;
++      evbmode = "station";
++      evbrrcap = false;
++      evbrrreq = true;
++      evbgpid = false;
++      ecpretries = 3;
++      ecprte = 14;
++      vdprwd = 20;
++      vdprka = 20;
++    };
++  };
++};
+diff --git a/test/qbg22/vdp22/111.nlc b/test/qbg22/vdp22/111.nlc
+new file mode 100755
+index 0000000..4f15b28
+--- /dev/null
++++ b/test/qbg22/vdp22/111.nlc
+@@ -0,0 +1,36 @@
++#!/bin/bash
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2013
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++
++# 
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014
++#
++# Execute a simple pre-assoc/pre-assoc/de-assoc test.
++#
++
++sleep 30	# Must: Wait some time for lldpad to start up and initialize
++outfile=$(basename $0)
++dirfile=$(dirname $0)
++cd $dirfile
++
++../../../vdptest -v -v -v -F vm.cfg -i veth0 -p vm1 -s,w=30 -p vm1 -s,w=30 -d vm1 -s,w=10
++rc=$?
++exit $rc
+diff --git a/test/qbg22/vdp22/111.vdp b/test/qbg22/vdp22/111.vdp
+new file mode 100644
+index 0000000..fa3efbd
+--- /dev/null
++++ b/test/qbg22/vdp22/111.vdp
+@@ -0,0 +1,43 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013
++# lldpad bridge mode configuration file
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth2 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    @include "brevb_default.res"
++  };
++};
+diff --git a/test/qbg22/vdp22/112-lldpad.conf b/test/qbg22/vdp22/112-lldpad.conf
+new file mode 100644
+index 0000000..fdbb132
+--- /dev/null
++++ b/test/qbg22/vdp22/112-lldpad.conf
+@@ -0,0 +1,56 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013
++#
++# LLDPAD station rule configuration file
++#
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = true;
++      evbmode = "station";
++      evbrrcap = false;
++      evbrrreq = true;
++      evbgpid = false;
++      ecpretries = 3;
++      ecprte = 14;
++      vdprwd = 20;
++      vdprka = 20;
++    };
++  };
++};
+diff --git a/test/qbg22/vdp22/112.nlc b/test/qbg22/vdp22/112.nlc
+new file mode 100755
+index 0000000..6b14209
+--- /dev/null
++++ b/test/qbg22/vdp22/112.nlc
+@@ -0,0 +1,36 @@
++#!/bin/bash
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2013
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++
++# 
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014
++#
++# Execute a simple pre-assoc-rr/pre-assoc-rr/de-assoc test.
++#
++
++sleep 30	# Must: Wait some time for lldpad to start up and initialize
++outfile=$(basename $0)
++dirfile=$(dirname $0)
++cd $dirfile
++
++../../../vdptest -v -v -v -F vm.cfg -i veth0 -r vm1 -s,w=30 -r vm1 -s,w=30 -d vm1 -s,w=10
++rc=$?
++exit $rc
+diff --git a/test/qbg22/vdp22/112.vdp b/test/qbg22/vdp22/112.vdp
+new file mode 100644
+index 0000000..fa3efbd
+--- /dev/null
++++ b/test/qbg22/vdp22/112.vdp
+@@ -0,0 +1,43 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013
++# lldpad bridge mode configuration file
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth2 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    @include "brevb_default.res"
++  };
++};
+diff --git a/test/qbg22/vdp22/113-lldpad.conf b/test/qbg22/vdp22/113-lldpad.conf
+new file mode 100644
+index 0000000..fdbb132
+--- /dev/null
++++ b/test/qbg22/vdp22/113-lldpad.conf
+@@ -0,0 +1,56 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013
++#
++# LLDPAD station rule configuration file
++#
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = true;
++      evbmode = "station";
++      evbrrcap = false;
++      evbrrreq = true;
++      evbgpid = false;
++      ecpretries = 3;
++      ecprte = 14;
++      vdprwd = 20;
++      vdprka = 20;
++    };
++  };
++};
+diff --git a/test/qbg22/vdp22/113.nlc b/test/qbg22/vdp22/113.nlc
+new file mode 100755
+index 0000000..bd53ba6
+--- /dev/null
++++ b/test/qbg22/vdp22/113.nlc
+@@ -0,0 +1,36 @@
++#!/bin/bash
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2013
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++
++# 
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014
++#
++# Execute a simple assoc/assoc/de-assoc test.
++#
++
++sleep 30	# Must: Wait some time for lldpad to start up and initialize
++outfile=$(basename $0)
++dirfile=$(dirname $0)
++cd $dirfile
++
++../../../vdptest -v -v -v -F vm.cfg -i veth0 -a vm1 -s,w=36 -a vm1 -s,w=37 -d vm1 -s,w=10
++rc=$?
++exit $rc
+diff --git a/test/qbg22/vdp22/113.vdp b/test/qbg22/vdp22/113.vdp
+new file mode 100644
+index 0000000..fa3efbd
+--- /dev/null
++++ b/test/qbg22/vdp22/113.vdp
+@@ -0,0 +1,43 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013
++# lldpad bridge mode configuration file
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth2 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    @include "brevb_default.res"
++  };
++};
+diff --git a/test/qbg22/vdp22/114-lldpad.conf b/test/qbg22/vdp22/114-lldpad.conf
+new file mode 100644
+index 0000000..fdbb132
+--- /dev/null
++++ b/test/qbg22/vdp22/114-lldpad.conf
+@@ -0,0 +1,56 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013
++#
++# LLDPAD station rule configuration file
++#
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = true;
++      evbmode = "station";
++      evbrrcap = false;
++      evbrrreq = true;
++      evbgpid = false;
++      ecpretries = 3;
++      ecprte = 14;
++      vdprwd = 20;
++      vdprka = 20;
++    };
++  };
++};
+diff --git a/test/qbg22/vdp22/114.nlc b/test/qbg22/vdp22/114.nlc
+new file mode 100755
+index 0000000..97ba73a
+--- /dev/null
++++ b/test/qbg22/vdp22/114.nlc
+@@ -0,0 +1,36 @@
++#!/bin/bash
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2013
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++
++# 
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014
++#
++# Execute a simple de-assoc test.
++#
++
++sleep 30	# Must: Wait some time for lldpad to start up and initialize
++outfile=$(basename $0)
++dirfile=$(dirname $0)
++cd $dirfile
++
++../../../vdptest -v -v -v -F vm.cfg -i veth0 -d vm1,e=-22
++rc=$?
++exit $rc
+diff --git a/test/qbg22/vdp22/114.vdp b/test/qbg22/vdp22/114.vdp
+new file mode 100644
+index 0000000..fa3efbd
+--- /dev/null
++++ b/test/qbg22/vdp22/114.vdp
+@@ -0,0 +1,43 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013
++# lldpad bridge mode configuration file
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth2 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    @include "brevb_default.res"
++  };
++};
+diff --git a/test/qbg22/vdp22/115-lldpad.conf b/test/qbg22/vdp22/115-lldpad.conf
+new file mode 100644
+index 0000000..fdbb132
+--- /dev/null
++++ b/test/qbg22/vdp22/115-lldpad.conf
+@@ -0,0 +1,56 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013
++#
++# LLDPAD station rule configuration file
++#
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = true;
++      evbmode = "station";
++      evbrrcap = false;
++      evbrrreq = true;
++      evbgpid = false;
++      ecpretries = 3;
++      ecprte = 14;
++      vdprwd = 20;
++      vdprka = 20;
++    };
++  };
++};
+diff --git a/test/qbg22/vdp22/115.nlc b/test/qbg22/vdp22/115.nlc
+new file mode 100755
+index 0000000..58af2db
+--- /dev/null
++++ b/test/qbg22/vdp22/115.nlc
+@@ -0,0 +1,36 @@
++#!/bin/bash
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2013
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++
++# 
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014
++#
++# Execute a simple assoc with error returned
++#
++
++sleep 30	# Must: Wait some time for lldpad to start up and initialize
++outfile=$(basename $0)
++dirfile=$(dirname $0)
++cd $dirfile
++
++../../../vdptest -v -v -v -F vm.cfg -i veth0 -a vm201,e=2 -s,w=5
++rc=$?
++exit $rc
+diff --git a/test/qbg22/vdp22/115.vdp b/test/qbg22/vdp22/115.vdp
+new file mode 100644
+index 0000000..fa3efbd
+--- /dev/null
++++ b/test/qbg22/vdp22/115.vdp
+@@ -0,0 +1,43 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013
++# lldpad bridge mode configuration file
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth2 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    @include "brevb_default.res"
++  };
++};
+diff --git a/test/qbg22/vdp22/116-lldpad.conf b/test/qbg22/vdp22/116-lldpad.conf
+new file mode 100644
+index 0000000..fdbb132
+--- /dev/null
++++ b/test/qbg22/vdp22/116-lldpad.conf
+@@ -0,0 +1,56 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013
++#
++# LLDPAD station rule configuration file
++#
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = true;
++      evbmode = "station";
++      evbrrcap = false;
++      evbrrreq = true;
++      evbgpid = false;
++      ecpretries = 3;
++      ecprte = 14;
++      vdprwd = 20;
++      vdprka = 20;
++    };
++  };
++};
+diff --git a/test/qbg22/vdp22/116.nlc b/test/qbg22/vdp22/116.nlc
+new file mode 100755
+index 0000000..da6448a
+--- /dev/null
++++ b/test/qbg22/vdp22/116.nlc
+@@ -0,0 +1,37 @@
++#!/bin/bash
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2013
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++
++# 
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014
++#
++# Execute a simple pre-assoc with error returned after 1. keep alive message.
++# Expect de-assoc response after first KA message
++#
++
++sleep 30	# Must: Wait some time for lldpad to start up and initialize
++outfile=$(basename $0)
++dirfile=$(dirname $0)
++cd $dirfile
++
++../../../vdptest -v -v -v -F vm.cfg -Cnew=vmxxx,name=vm201,typeidver=2 -i veth0 -a vmxxx -g,e=1,w=60 -s,w=20
++rc=$?
++exit $rc
+diff --git a/test/qbg22/vdp22/116.vdp b/test/qbg22/vdp22/116.vdp
+new file mode 100644
+index 0000000..1f56138
+--- /dev/null
++++ b/test/qbg22/vdp22/116.vdp
+@@ -0,0 +1,47 @@
++#!/bin/bash
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++
++# 
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013
++# lldpad bridge mode configuration file
++#
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth2 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    @include "brevb_default.res"
++  }
++};
+diff --git a/test/qbg22/vdp22/117-lldpad.conf b/test/qbg22/vdp22/117-lldpad.conf
+new file mode 100644
+index 0000000..fdbb132
+--- /dev/null
++++ b/test/qbg22/vdp22/117-lldpad.conf
+@@ -0,0 +1,56 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013
++#
++# LLDPAD station rule configuration file
++#
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = true;
++      evbmode = "station";
++      evbrrcap = false;
++      evbrrreq = true;
++      evbgpid = false;
++      ecpretries = 3;
++      ecprte = 14;
++      vdprwd = 20;
++      vdprka = 20;
++    };
++  };
++};
+diff --git a/test/qbg22/vdp22/117.nlc b/test/qbg22/vdp22/117.nlc
+new file mode 100755
+index 0000000..89864df
+--- /dev/null
++++ b/test/qbg22/vdp22/117.nlc
+@@ -0,0 +1,37 @@
++#!/bin/bash
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2013
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++
++# 
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014
++#
++# Execute a simple assoc with unsolicited de-assoc message from switch
++# Expect unsolicited message from lldpad.
++#
++
++sleep 30	# Must: Wait some time for lldpad to start up and initialize
++outfile=$(basename $0)
++dirfile=$(dirname $0)
++cd $dirfile
++
++../../../vdptest -v -v -v -F vm.cfg -i veth0 -a vm200 -g,e=1,w=90 -s,w=20
++rc=$?
++exit $rc
+diff --git a/test/qbg22/vdp22/117.vdp b/test/qbg22/vdp22/117.vdp
+new file mode 100644
+index 0000000..fa3efbd
+--- /dev/null
++++ b/test/qbg22/vdp22/117.vdp
+@@ -0,0 +1,43 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013
++# lldpad bridge mode configuration file
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth2 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    @include "brevb_default.res"
++  };
++};
+diff --git a/test/qbg22/vdp22/118-lldpad.conf b/test/qbg22/vdp22/118-lldpad.conf
+new file mode 100644
+index 0000000..fdbb132
+--- /dev/null
++++ b/test/qbg22/vdp22/118-lldpad.conf
+@@ -0,0 +1,56 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013
++#
++# LLDPAD station rule configuration file
++#
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = true;
++      evbmode = "station";
++      evbrrcap = false;
++      evbrrreq = true;
++      evbgpid = false;
++      ecpretries = 3;
++      ecprte = 14;
++      vdprwd = 20;
++      vdprka = 20;
++    };
++  };
++};
+diff --git a/test/qbg22/vdp22/118.nlc b/test/qbg22/vdp22/118.nlc
+new file mode 100755
+index 0000000..32083a6
+--- /dev/null
++++ b/test/qbg22/vdp22/118.nlc
+@@ -0,0 +1,36 @@
++#!/bin/bash
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2013
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++
++# 
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014
++#
++# Execute a simple pre-assoc with error returned
++#
++
++sleep 30	# Must: Wait some time for lldpad to start up and initialize
++outfile=$(basename $0)
++dirfile=$(dirname $0)
++cd $dirfile
++
++../../../vdptest -v -v -v -F vm.cfg -i veth0 -p vm201,e=2 -s,w=5
++rc=$?
++exit $rc
+diff --git a/test/qbg22/vdp22/118.vdp b/test/qbg22/vdp22/118.vdp
+new file mode 100644
+index 0000000..171d0a0
+--- /dev/null
++++ b/test/qbg22/vdp22/118.vdp
+@@ -0,0 +1,44 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# 
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013
++# lldpad bridge mode configuration file
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth2 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    @include "brevb_default.res"
++  };
++};
+diff --git a/test/qbg22/vdp22/119-lldpad.conf b/test/qbg22/vdp22/119-lldpad.conf
+new file mode 100644
+index 0000000..fdbb132
+--- /dev/null
++++ b/test/qbg22/vdp22/119-lldpad.conf
+@@ -0,0 +1,56 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013
++#
++# LLDPAD station rule configuration file
++#
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = true;
++      evbmode = "station";
++      evbrrcap = false;
++      evbrrreq = true;
++      evbgpid = false;
++      ecpretries = 3;
++      ecprte = 14;
++      vdprwd = 20;
++      vdprka = 20;
++    };
++  };
++};
+diff --git a/test/qbg22/vdp22/119.nlc b/test/qbg22/vdp22/119.nlc
+new file mode 100755
+index 0000000..b46ff6b
+--- /dev/null
++++ b/test/qbg22/vdp22/119.nlc
+@@ -0,0 +1,37 @@
++#!/bin/bash
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2013
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++
++# 
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014
++#
++# Execute a simple pre-assoc-rr with error returned after 1. keep alive message.
++# Expect unsolicited message from lldpad.
++#
++
++sleep 30	# Must: Wait some time for lldpad to start up and initialize
++outfile=$(basename $0)
++dirfile=$(dirname $0)
++cd $dirfile
++
++../../../vdptest -v -v -v -F vm.cfg -Cnew=vm999,name=vm201,typeidver=2 -i veth0 -r vm999 -g,e=1,w=60 -s,w=20
++rc=$?
++exit $rc
+diff --git a/test/qbg22/vdp22/119.vdp b/test/qbg22/vdp22/119.vdp
+new file mode 100644
+index 0000000..48d5499
+--- /dev/null
++++ b/test/qbg22/vdp22/119.vdp
+@@ -0,0 +1,46 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++
++# 
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013
++# lldpad bridge mode configuration file
++#
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth2 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    @include "brevb_default.res"
++  };
++};
+diff --git a/test/qbg22/vdp22/120-lldpad.conf b/test/qbg22/vdp22/120-lldpad.conf
+new file mode 100644
+index 0000000..fdbb132
+--- /dev/null
++++ b/test/qbg22/vdp22/120-lldpad.conf
+@@ -0,0 +1,56 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013
++#
++# LLDPAD station rule configuration file
++#
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = true;
++      evbmode = "station";
++      evbrrcap = false;
++      evbrrreq = true;
++      evbgpid = false;
++      ecpretries = 3;
++      ecprte = 14;
++      vdprwd = 20;
++      vdprka = 20;
++    };
++  };
++};
+diff --git a/test/qbg22/vdp22/120.nlc b/test/qbg22/vdp22/120.nlc
+new file mode 100755
+index 0000000..ea8d2cb
+--- /dev/null
++++ b/test/qbg22/vdp22/120.nlc
+@@ -0,0 +1,37 @@
++#!/bin/bash
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2013
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++
++# 
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014
++#
++# Execute a simple pre-assoc with unsolicited de-assoc message from switch
++# Expect unsolicited message from lldpad.
++#
++
++sleep 30	# Must: Wait some time for lldpad to start up and initialize
++outfile=$(basename $0)
++dirfile=$(dirname $0)
++cd $dirfile
++
++../../../vdptest -v -v -v -F vm.cfg -i veth0 -p vm200 -g,e=1,w=90 -s,w=20
++rc=$?
++exit $rc
+diff --git a/test/qbg22/vdp22/120.vdp b/test/qbg22/vdp22/120.vdp
+new file mode 100644
+index 0000000..fa3efbd
+--- /dev/null
++++ b/test/qbg22/vdp22/120.vdp
+@@ -0,0 +1,43 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013
++# lldpad bridge mode configuration file
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth2 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    @include "brevb_default.res"
++  };
++};
+diff --git a/test/qbg22/vdp22/121-lldpad.conf b/test/qbg22/vdp22/121-lldpad.conf
+new file mode 100644
+index 0000000..fdbb132
+--- /dev/null
++++ b/test/qbg22/vdp22/121-lldpad.conf
+@@ -0,0 +1,56 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013
++#
++# LLDPAD station rule configuration file
++#
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = true;
++      evbmode = "station";
++      evbrrcap = false;
++      evbrrreq = true;
++      evbgpid = false;
++      ecpretries = 3;
++      ecprte = 14;
++      vdprwd = 20;
++      vdprka = 20;
++    };
++  };
++};
+diff --git a/test/qbg22/vdp22/121.nlc b/test/qbg22/vdp22/121.nlc
+new file mode 100755
+index 0000000..761dec4
+--- /dev/null
++++ b/test/qbg22/vdp22/121.nlc
+@@ -0,0 +1,36 @@
++#!/bin/bash
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2013
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++
++# 
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014
++#
++# Execute a simple assoc with keep-error returned after 1. keep alive message.
++#
++
++sleep 30	# Must: Wait some time for lldpad to start up and initialize
++outfile=$(basename $0)
++dirfile=$(dirname $0)
++cd $dirfile
++
++../../../vdptest -v -v -v -F vm.cfg -i veth0 -a vm202 -g,e=1,w=60 -s,w=20
++rc=$?
++exit $rc
+diff --git a/test/qbg22/vdp22/121.vdp b/test/qbg22/vdp22/121.vdp
+new file mode 100644
+index 0000000..48d5499
+--- /dev/null
++++ b/test/qbg22/vdp22/121.vdp
+@@ -0,0 +1,46 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++
++# 
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013
++# lldpad bridge mode configuration file
++#
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth2 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    @include "brevb_default.res"
++  };
++};
+diff --git a/test/qbg22/vdp22/122-lldpad.conf b/test/qbg22/vdp22/122-lldpad.conf
+new file mode 100644
+index 0000000..fdbb132
+--- /dev/null
++++ b/test/qbg22/vdp22/122-lldpad.conf
+@@ -0,0 +1,56 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013
++#
++# LLDPAD station rule configuration file
++#
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = true;
++      evbmode = "station";
++      evbrrcap = false;
++      evbrrreq = true;
++      evbgpid = false;
++      ecpretries = 3;
++      ecprte = 14;
++      vdprwd = 20;
++      vdprka = 20;
++    };
++  };
++};
+diff --git a/test/qbg22/vdp22/122.nlc b/test/qbg22/vdp22/122.nlc
+new file mode 100755
+index 0000000..c2fc425
+--- /dev/null
++++ b/test/qbg22/vdp22/122.nlc
+@@ -0,0 +1,36 @@
++#!/bin/bash
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2013
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++
++# 
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014
++#
++# Execute a simple pre-assoc with hard-error returned from switch
++#
++
++sleep 30	# Must: Wait some time for lldpad to start up and initialize
++outfile=$(basename $0)
++dirfile=$(dirname $0)
++cd $dirfile
++
++../../../vdptest -v -v -v -F vm.cfg -i veth0 -Cnew=vmxxx,name=vm201,typeid=203 -p vmxxx,e=18 -s,w=5
++rc=$?
++exit $rc
+diff --git a/test/qbg22/vdp22/122.vdp b/test/qbg22/vdp22/122.vdp
+new file mode 100644
+index 0000000..48d5499
+--- /dev/null
++++ b/test/qbg22/vdp22/122.vdp
+@@ -0,0 +1,46 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++
++# 
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013
++# lldpad bridge mode configuration file
++#
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth2 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    @include "brevb_default.res"
++  };
++};
+diff --git a/test/qbg22/vdp22/123-lldpad.conf b/test/qbg22/vdp22/123-lldpad.conf
+new file mode 100644
+index 0000000..7e61fbc
+--- /dev/null
++++ b/test/qbg22/vdp22/123-lldpad.conf
+@@ -0,0 +1,56 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013
++#
++# LLDPAD station rule configuration file
++#
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    tlvid0080c20d : 
++    {
++      enableTx = true;
++      evbmode = "station";
++      evbrrcap = false;
++      evbrrreq = true;
++      evbgpid = false;
++      ecpretries = 3;
++      ecprte = 14;
++      vdprwd = 15;
++      vdprka = 20;
++    };
++  };
++};
+diff --git a/test/qbg22/vdp22/123.nlc b/test/qbg22/vdp22/123.nlc
+new file mode 100755
+index 0000000..006a1b6
+--- /dev/null
++++ b/test/qbg22/vdp22/123.nlc
+@@ -0,0 +1,37 @@
++#!/bin/bash
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2013
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++
++# 
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014
++#
++# Execute a simple assoc test and expect resource wait delay timeout
++# from bridge.
++#
++
++sleep 30	# Must: Wait some time for lldpad to start up and initialize
++outfile=$(basename $0)
++dirfile=$(dirname $0)
++cd $dirfile
++
++../../../vdptest -v -v -v -F vm.cfg -i veth0 -a vm199,w=15000,d=12000 -s,w=30
++rc=$?
++exit $rc
+diff --git a/test/qbg22/vdp22/123.vdp b/test/qbg22/vdp22/123.vdp
+new file mode 100644
+index 0000000..fa3efbd
+--- /dev/null
++++ b/test/qbg22/vdp22/123.vdp
+@@ -0,0 +1,43 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013
++# lldpad bridge mode configuration file
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth2 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    @include "brevb_default.res"
++  };
++};
+diff --git a/test/qbg22/vdp22/200-lldpad.conf b/test/qbg22/vdp22/200-lldpad.conf
+new file mode 100644
+index 0000000..d22aa2b
+--- /dev/null
++++ b/test/qbg22/vdp22/200-lldpad.conf
+@@ -0,0 +1,46 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013
++#
++# LLDPAD station rule configuration file
++#
++
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    @include "stevb_default.res"
++  };
++};
+diff --git a/test/qbg22/vdp22/200.nlc b/test/qbg22/vdp22/200.nlc
+new file mode 100755
+index 0000000..88e3112
+--- /dev/null
++++ b/test/qbg22/vdp22/200.nlc
+@@ -0,0 +1,35 @@
++#!/bin/bash
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2013
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++
++# 
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014
++#
++# Execute a simple assoc/de-assoc test. Use command line interface
++#
++
++# Must: Wait some time for lldpad to start up and initialize
++outfile=$(basename $0)
++dirfile=$(dirname $0)
++cd $dirfile
++
++../../../vdptest -v -v -v -F vm2.cfg -i veth0 -s,w=30 -a vm2_1 -s,w=30 -d vm2_1 -s,w=10
++exit $?
+diff --git a/test/qbg22/vdp22/200.vdp b/test/qbg22/vdp22/200.vdp
+new file mode 100644
+index 0000000..171d0a0
+--- /dev/null
++++ b/test/qbg22/vdp22/200.vdp
+@@ -0,0 +1,44 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# 
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013
++# lldpad bridge mode configuration file
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth2 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    @include "brevb_default.res"
++  };
++};
+diff --git a/test/qbg22/vdp22/201-lldpad.conf b/test/qbg22/vdp22/201-lldpad.conf
+new file mode 100644
+index 0000000..d22aa2b
+--- /dev/null
++++ b/test/qbg22/vdp22/201-lldpad.conf
+@@ -0,0 +1,46 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013
++#
++# LLDPAD station rule configuration file
++#
++
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    @include "stevb_default.res"
++  };
++};
+diff --git a/test/qbg22/vdp22/201.nlc b/test/qbg22/vdp22/201.nlc
+new file mode 100755
+index 0000000..2791190
+--- /dev/null
++++ b/test/qbg22/vdp22/201.nlc
+@@ -0,0 +1,36 @@
++#!/bin/bash
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2013
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++
++# 
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014
++#
++# Execute a simple assoc with group id support requested and not supportted by
++# bridge and station.
++#
++
++outfile=$(basename $0)
++dirfile=$(dirname $0)
++cd $dirfile
++
++# Must: Wait some time for lldpad to start up and initialize
++../../../vdptest -v -v -v -F vm2.cfg -Cnew=vm2_xxx,name=vm2_1,map=13-52:bb:cc:dd:ee:ff-222 -i veth0 -s,w=30 -a vm2_xxx,e=1 -s,w=30
++exit $?
+diff --git a/test/qbg22/vdp22/201.vdp b/test/qbg22/vdp22/201.vdp
+new file mode 100644
+index 0000000..fa3efbd
+--- /dev/null
++++ b/test/qbg22/vdp22/201.vdp
+@@ -0,0 +1,43 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013
++# lldpad bridge mode configuration file
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth2 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    @include "brevb_default.res"
++  };
++};
+diff --git a/test/qbg22/vdp22/202-lldpad.conf b/test/qbg22/vdp22/202-lldpad.conf
+new file mode 100644
+index 0000000..d22aa2b
+--- /dev/null
++++ b/test/qbg22/vdp22/202-lldpad.conf
+@@ -0,0 +1,46 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013
++#
++# LLDPAD station rule configuration file
++#
++
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    @include "stevb_default.res"
++  };
++};
+diff --git a/test/qbg22/vdp22/202.nlc b/test/qbg22/vdp22/202.nlc
+new file mode 100755
+index 0000000..9cd3a90
+--- /dev/null
++++ b/test/qbg22/vdp22/202.nlc
+@@ -0,0 +1,37 @@
++#!/bin/bash
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2013
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++
++# 
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014
++#
++# Execute a simple assoc without group id support in bridge and station.
++# Assign VID by bridge and report back to caller.
++# Caller then de-assoc with wrong vid.
++#
++
++outfile=$(basename $0)
++dirfile=$(dirname $0)
++cd $dirfile
++
++# Must: Wait some time for lldpad to start up and initialize
++../../../vdptest -v -v -v -F vm2.cfg -Cnew=vm2_xxx,name=vm2_205,map=0/205 -i veth0 -s,w=30 -a vm2_xxx -s,w=30 -d vm2_xxx,e=1 -s,w=10
++exit $?
+diff --git a/test/qbg22/vdp22/202.vdp b/test/qbg22/vdp22/202.vdp
+new file mode 100644
+index 0000000..fa3efbd
+--- /dev/null
++++ b/test/qbg22/vdp22/202.vdp
+@@ -0,0 +1,43 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013
++# lldpad bridge mode configuration file
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth2 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    @include "brevb_default.res"
++  };
++};
+diff --git a/test/qbg22/vdp22/203-lldpad.conf b/test/qbg22/vdp22/203-lldpad.conf
+new file mode 100644
+index 0000000..d22aa2b
+--- /dev/null
++++ b/test/qbg22/vdp22/203-lldpad.conf
+@@ -0,0 +1,46 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013
++#
++# LLDPAD station rule configuration file
++#
++
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    @include "stevb_default.res"
++  };
++};
+diff --git a/test/qbg22/vdp22/203.nlc b/test/qbg22/vdp22/203.nlc
+new file mode 100755
+index 0000000..6afe8f8
+--- /dev/null
++++ b/test/qbg22/vdp22/203.nlc
+@@ -0,0 +1,37 @@
++#!/bin/bash
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2013
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++
++# 
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014
++#
++# Execute a simple assoc without group id support in bridge and station.
++# Assign VID by bridge and report back to caller, caller de-assoc with correct
++# filter.
++#
++
++outfile=$(basename $0)
++dirfile=$(dirname $0)
++cd $dirfile
++
++# Must: Wait some time for lldpad to start up and initialize
++../../../vdptest -n -v -v -v -F vm2.cfg -Cnew=vm2_xxx,name=vm2_205,map=0/205 -i veth0 -s,w=30 -a vm2_xxx -s,w=30 -Cnew=vm2_yyy,name=vm2_205,map=205 -d vm2_yyy -s,w=10
++exit $?
+diff --git a/test/qbg22/vdp22/203.vdp b/test/qbg22/vdp22/203.vdp
+new file mode 100644
+index 0000000..fa3efbd
+--- /dev/null
++++ b/test/qbg22/vdp22/203.vdp
+@@ -0,0 +1,43 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013
++# lldpad bridge mode configuration file
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth2 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    @include "brevb_default.res"
++  };
++};
+diff --git a/test/qbg22/vdp22/204-lldpad.conf b/test/qbg22/vdp22/204-lldpad.conf
+new file mode 100644
+index 0000000..d22aa2b
+--- /dev/null
++++ b/test/qbg22/vdp22/204-lldpad.conf
+@@ -0,0 +1,46 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013
++#
++# LLDPAD station rule configuration file
++#
++
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    @include "stevb_default.res"
++  };
++};
+diff --git a/test/qbg22/vdp22/204.nlc b/test/qbg22/vdp22/204.nlc
+new file mode 100755
+index 0000000..2e515ba
+--- /dev/null
++++ b/test/qbg22/vdp22/204.nlc
+@@ -0,0 +1,37 @@
++#!/bin/bash
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2013
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++
++# 
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014
++#
++# Execute a simple assoc without group id support in bridge and station.
++# Assign QoS by bridge and report back to caller, caller de-assoc with incorrect
++# QoS.
++#
++
++outfile=$(basename $0)
++dirfile=$(dirname $0)
++cd $dirfile
++
++# Must: Wait some time for lldpad to start up and initialize
++../../../vdptest -v -v -v -F vm2.cfg -Cnew=vm2_xx1,name=vm2_206,map=2/61442 -i veth0 -s,w=30 -a vm2_xx1 -s,w=30 -Cnew=vm2_xx2,name=vm2_206,map=2 -d vm2_xx2,e=1 -s,w=10
++exit $?
+diff --git a/test/qbg22/vdp22/204.vdp b/test/qbg22/vdp22/204.vdp
+new file mode 100644
+index 0000000..fa3efbd
+--- /dev/null
++++ b/test/qbg22/vdp22/204.vdp
+@@ -0,0 +1,43 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013
++# lldpad bridge mode configuration file
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth2 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    @include "brevb_default.res"
++  };
++};
+diff --git a/test/qbg22/vdp22/205-lldpad.conf b/test/qbg22/vdp22/205-lldpad.conf
+new file mode 100644
+index 0000000..d22aa2b
+--- /dev/null
++++ b/test/qbg22/vdp22/205-lldpad.conf
+@@ -0,0 +1,46 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013
++#
++# LLDPAD station rule configuration file
++#
++
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    @include "stevb_default.res"
++  };
++};
+diff --git a/test/qbg22/vdp22/205.nlc b/test/qbg22/vdp22/205.nlc
+new file mode 100755
+index 0000000..084ef12
+--- /dev/null
++++ b/test/qbg22/vdp22/205.nlc
+@@ -0,0 +1,37 @@
++#!/bin/bash
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2013
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++
++# 
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014
++#
++# Execute a simple assoc without group id support in bridge and station.
++# Assign QoS by bridge and report back to caller, caller de-assoc with correct
++# QoS.
++#
++
++outfile=$(basename $0)
++dirfile=$(dirname $0)
++cd $dirfile
++
++# Must: Wait some time for lldpad to start up and initialize
++../../../vdptest -v -v -v -F vm2.cfg -Cnew=vm2_xx1,name=vm2_206,map=2/61442 -i veth0 -s,w=30 -a vm2_xx1 -s,w=30 -Cnew=vm2_xx2,name=vm2_206,map=61442 -d vm2_xx2 -s,w=10
++exit $?
+diff --git a/test/qbg22/vdp22/205.vdp b/test/qbg22/vdp22/205.vdp
+new file mode 100644
+index 0000000..171d0a0
+--- /dev/null
++++ b/test/qbg22/vdp22/205.vdp
+@@ -0,0 +1,44 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# 
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013
++# lldpad bridge mode configuration file
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth2 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    @include "brevb_default.res"
++  };
++};
+diff --git a/test/qbg22/vdp22/206-lldpad.conf b/test/qbg22/vdp22/206-lldpad.conf
+new file mode 100644
+index 0000000..d22aa2b
+--- /dev/null
++++ b/test/qbg22/vdp22/206-lldpad.conf
+@@ -0,0 +1,46 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013
++#
++# LLDPAD station rule configuration file
++#
++
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    @include "stevb_default.res"
++  };
++};
+diff --git a/test/qbg22/vdp22/206.nlc b/test/qbg22/vdp22/206.nlc
+new file mode 100755
+index 0000000..0704a25
+--- /dev/null
++++ b/test/qbg22/vdp22/206.nlc
+@@ -0,0 +1,35 @@
++#!/bin/bash
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2013
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++
++# 
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014
++#
++# Execute a simple assoc without group id support in bridge and station.
++# Provoke invalid Filter data response from bridge
++#
++
++outfile=$(basename $0)
++dirfile=$(dirname $0)
++cd $dirfile
++
++../../../vdptest -v -v -v -F vm2.cfg -Cnew=vm2_xx1,name=vm2_206,map=2/61440,typeidver=0x15 -i veth0 -s,w=30 -a vm2_xx1,e=5 -s,w=10
++exit $?
+diff --git a/test/qbg22/vdp22/206.vdp b/test/qbg22/vdp22/206.vdp
+new file mode 100644
+index 0000000..fa3efbd
+--- /dev/null
++++ b/test/qbg22/vdp22/206.vdp
+@@ -0,0 +1,43 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013
++# lldpad bridge mode configuration file
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth2 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    @include "brevb_default.res"
++  };
++};
+diff --git a/test/qbg22/vdp22/207-lldpad.conf b/test/qbg22/vdp22/207-lldpad.conf
+new file mode 100644
+index 0000000..d22aa2b
+--- /dev/null
++++ b/test/qbg22/vdp22/207-lldpad.conf
+@@ -0,0 +1,46 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013
++#
++# LLDPAD station rule configuration file
++#
++
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    @include "stevb_default.res"
++  };
++};
+diff --git a/test/qbg22/vdp22/207.nlc b/test/qbg22/vdp22/207.nlc
+new file mode 100755
+index 0000000..99a6800
+--- /dev/null
++++ b/test/qbg22/vdp22/207.nlc
+@@ -0,0 +1,36 @@
++#!/bin/bash
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2013
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++
++# 
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014
++#
++# Execute a simple assoc without group id support in bridge and station.
++# Assign QoS by bridge and report back to caller, caller does not expected
++# changed QoS.
++#
++
++outfile=$(basename $0)
++dirfile=$(dirname $0)
++cd $dirfile
++
++../../../vdptest -v -v -v -F vm2.cfg -Cnew=vm2_xx1,name=vm2_206,map=2,e=250 -i veth0 -s,w=30 -a vm2_xx1 -s,w=10
++exit $?
+diff --git a/test/qbg22/vdp22/207.vdp b/test/qbg22/vdp22/207.vdp
+new file mode 100644
+index 0000000..fa3efbd
+--- /dev/null
++++ b/test/qbg22/vdp22/207.vdp
+@@ -0,0 +1,43 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013
++# lldpad bridge mode configuration file
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth2 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    @include "brevb_default.res"
++  };
++};
+diff --git a/test/qbg22/vdp22/208-lldpad.conf b/test/qbg22/vdp22/208-lldpad.conf
+new file mode 100644
+index 0000000..d22aa2b
+--- /dev/null
++++ b/test/qbg22/vdp22/208-lldpad.conf
+@@ -0,0 +1,46 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013
++#
++# LLDPAD station rule configuration file
++#
++
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    @include "stevb_default.res"
++  };
++};
+diff --git a/test/qbg22/vdp22/208.nlc b/test/qbg22/vdp22/208.nlc
+new file mode 100755
+index 0000000..e7d953f
+--- /dev/null
++++ b/test/qbg22/vdp22/208.nlc
+@@ -0,0 +1,36 @@
++#!/bin/bash
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2013
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++
++# 
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014
++#
++# Execute a simple assoc without group id support in bridge and station.
++# Send VLAN/QoS to bridge and report back to caller.
++#
++
++# Must: Wait some time for lldpad to start up and initialize
++outfile=$(basename $0)
++dirfile=$(dirname $0)
++cd $dirfile
++
++../../../vdptest -v -v -v -F vm2.cfg -Cnew=vm2_xx1,name=vm2_1,map=0x8002 -i veth0 -s,w=30 -a vm2_xx1 -s,w=30 -d vm2_xx1 -s,w=10
++exit $?
+diff --git a/test/qbg22/vdp22/208.vdp b/test/qbg22/vdp22/208.vdp
+new file mode 100644
+index 0000000..fa3efbd
+--- /dev/null
++++ b/test/qbg22/vdp22/208.vdp
+@@ -0,0 +1,43 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013
++# lldpad bridge mode configuration file
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth2 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    @include "brevb_default.res"
++  };
++};
+diff --git a/test/qbg22/vdp22/209-lldpad.conf b/test/qbg22/vdp22/209-lldpad.conf
+new file mode 100644
+index 0000000..d22aa2b
+--- /dev/null
++++ b/test/qbg22/vdp22/209-lldpad.conf
+@@ -0,0 +1,46 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013
++#
++# LLDPAD station rule configuration file
++#
++
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    @include "stevb_default.res"
++  };
++};
+diff --git a/test/qbg22/vdp22/209.nlc b/test/qbg22/vdp22/209.nlc
+new file mode 100755
+index 0000000..41ddb21
+--- /dev/null
++++ b/test/qbg22/vdp22/209.nlc
+@@ -0,0 +1,36 @@
++#!/bin/bash
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2013
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++
++# 
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014
++#
++# Execute a simple assoc without group id support in bridge and station.
++# Send VLAN/QoS to bridge and report back to caller.
++#
++
++# Must: Wait some time for lldpad to start up and initialize
++outfile=$(basename $0)
++dirfile=$(dirname $0)
++cd $dirfile
++
++../../../vdptest -v -v -v -F vm2.cfg -Cnew=vm2_xx1,name=vm2_206,map=0x8002 -i veth0 -s,w=30 -a vm2_xx1,e=5 -s,w=10
++exit $?
+diff --git a/test/qbg22/vdp22/209.vdp b/test/qbg22/vdp22/209.vdp
+new file mode 100644
+index 0000000..fa3efbd
+--- /dev/null
++++ b/test/qbg22/vdp22/209.vdp
+@@ -0,0 +1,43 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013
++# lldpad bridge mode configuration file
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth2 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    @include "brevb_default.res"
++  };
++};
+diff --git a/test/qbg22/vdp22/210-lldpad.conf b/test/qbg22/vdp22/210-lldpad.conf
+new file mode 100644
+index 0000000..d22aa2b
+--- /dev/null
++++ b/test/qbg22/vdp22/210-lldpad.conf
+@@ -0,0 +1,46 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013
++#
++# LLDPAD station rule configuration file
++#
++
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    @include "stevb_default.res"
++  };
++};
+diff --git a/test/qbg22/vdp22/210.nlc b/test/qbg22/vdp22/210.nlc
+new file mode 100755
+index 0000000..7b6a457
+--- /dev/null
++++ b/test/qbg22/vdp22/210.nlc
+@@ -0,0 +1,37 @@
++#!/bin/bash
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2013
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++
++# 
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014
++#
++# Execute a simple assoc without group id support in bridge and station.
++# Send many VIDs (one VID is zero) and expect error as VID 0 must be the only
++# VID in the list.
++#
++
++# Must: Wait some time for lldpad to start up and initialize
++outfile=$(basename $0)
++dirfile=$(dirname $0)
++cd $dirfile
++
++../../../vdptest -v -v -v -F vm2.cfg -Cnew=vm2_xxx,name=vm2_205a -i veth0 -s,w=30 -a vm2_xxx,e=1 -s,w=30 -d vm2_xxx,e=1 -s,w=10
++exit $?
+diff --git a/test/qbg22/vdp22/210.vdp b/test/qbg22/vdp22/210.vdp
+new file mode 100644
+index 0000000..171d0a0
+--- /dev/null
++++ b/test/qbg22/vdp22/210.vdp
+@@ -0,0 +1,44 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# 
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013
++# lldpad bridge mode configuration file
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth2 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    @include "brevb_default.res"
++  };
++};
+diff --git a/test/qbg22/vdp22/211-lldpad.conf b/test/qbg22/vdp22/211-lldpad.conf
+new file mode 100644
+index 0000000..d22aa2b
+--- /dev/null
++++ b/test/qbg22/vdp22/211-lldpad.conf
+@@ -0,0 +1,46 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013
++#
++# LLDPAD station rule configuration file
++#
++
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    @include "stevb_default.res"
++  };
++};
+diff --git a/test/qbg22/vdp22/211.nlc b/test/qbg22/vdp22/211.nlc
+new file mode 100755
+index 0000000..ac978bf
+--- /dev/null
++++ b/test/qbg22/vdp22/211.nlc
+@@ -0,0 +1,36 @@
++#!/bin/bash
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2013
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++
++# 
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014
++#
++# Execute a simple assoc without group id support in bridge and station.
++# Send many VIDs and expect QoS for VID indexed 3 changed
++#
++
++# Must: Wait some time for lldpad to start up and initialize
++outfile=$(basename $0)
++dirfile=$(dirname $0)
++cd $dirfile
++
++../../../vdptest -v -v -v -F vm2.cfg -i veth0 -s,w=30 -a vm2_206b -s,w=30 -Cnew=vm2_xxx,name=vm2_206b,map=10,map=11,map=12,map=0xd00d,map=14,map=15 -d vm2_xxx -s,w=10
++exit $?
+diff --git a/test/qbg22/vdp22/211.vdp b/test/qbg22/vdp22/211.vdp
+new file mode 100644
+index 0000000..fa3efbd
+--- /dev/null
++++ b/test/qbg22/vdp22/211.vdp
+@@ -0,0 +1,43 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013
++# lldpad bridge mode configuration file
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth2 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    @include "brevb_default.res"
++  };
++};
+diff --git a/test/qbg22/vdp22/212-lldpad.conf b/test/qbg22/vdp22/212-lldpad.conf
+new file mode 100644
+index 0000000..d22aa2b
+--- /dev/null
++++ b/test/qbg22/vdp22/212-lldpad.conf
+@@ -0,0 +1,46 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013
++#
++# LLDPAD station rule configuration file
++#
++
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    @include "stevb_default.res"
++  };
++};
+diff --git a/test/qbg22/vdp22/212.nlc b/test/qbg22/vdp22/212.nlc
+new file mode 100755
+index 0000000..91d856c
+--- /dev/null
++++ b/test/qbg22/vdp22/212.nlc
+@@ -0,0 +1,36 @@
++#!/bin/bash
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2013
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++
++# 
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014
++#
++# Execute a simple assoc without group id support in bridge and station.
++# Send many VIDs (filter format VID/MAC) and expect VID 0 replaced.
++#
++
++# Must: Wait some time for lldpad to start up and initialize
++outfile=$(basename $0)
++dirfile=$(dirname $0)
++cd $dirfile
++
++../../../vdptest -v -v -v -F vm2.cfg -i veth0 -s,w=30 -a vm2_208 -s,w=30 -Cnew=vm2_xxx,name=vm2_208,map=10-aa:bb:00:00:00:10,map=20-aa:bb:00:00:00:11,map=0xb0d0-aa:bb:00:00:00:22 -d vm2_xxx,e=1 -s,w=10
++exit $?
+diff --git a/test/qbg22/vdp22/212.vdp b/test/qbg22/vdp22/212.vdp
+new file mode 100644
+index 0000000..fa3efbd
+--- /dev/null
++++ b/test/qbg22/vdp22/212.vdp
+@@ -0,0 +1,43 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013
++# lldpad bridge mode configuration file
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth2 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    @include "brevb_default.res"
++  };
++};
+diff --git a/test/qbg22/vdp22/213-lldpad.conf b/test/qbg22/vdp22/213-lldpad.conf
+new file mode 100644
+index 0000000..d22aa2b
+--- /dev/null
++++ b/test/qbg22/vdp22/213-lldpad.conf
+@@ -0,0 +1,46 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013
++#
++# LLDPAD station rule configuration file
++#
++
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    @include "stevb_default.res"
++  };
++};
+diff --git a/test/qbg22/vdp22/213.nlc b/test/qbg22/vdp22/213.nlc
+new file mode 100755
+index 0000000..cd011d5
+--- /dev/null
++++ b/test/qbg22/vdp22/213.nlc
+@@ -0,0 +1,36 @@
++#!/bin/bash
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2013
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++
++# 
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014
++#
++# Execute a simple assoc without group id support in bridge and station.
++# Send many VIDs (filter format VID/MAC) and expect VID 0 replaced.
++#
++
++# Must: Wait some time for lldpad to start up and initialize
++outfile=$(basename $0)
++dirfile=$(dirname $0)
++cd $dirfile
++
++../../../vdptest -v -v -v -F vm2.cfg -i veth0 -s,w=30 -a vm2_208 -s,w=30 -Cnew=vm2_xxx,name=vm2_208,map=10-aa:bb:00:00:00:10,map=0xb0d0-aa:bb:00:00:00:11,map=0xb0d0-aa:bb:00:00:00:22 -d vm2_xxx -s,w=10
++exit $?
+diff --git a/test/qbg22/vdp22/213.vdp b/test/qbg22/vdp22/213.vdp
+new file mode 100644
+index 0000000..fa3efbd
+--- /dev/null
++++ b/test/qbg22/vdp22/213.vdp
+@@ -0,0 +1,43 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013
++# lldpad bridge mode configuration file
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth2 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    @include "brevb_default.res"
++  };
++};
+diff --git a/test/qbg22/vdp22/220-lldpad.conf b/test/qbg22/vdp22/220-lldpad.conf
+new file mode 100644
+index 0000000..c75f7f2
+--- /dev/null
++++ b/test/qbg22/vdp22/220-lldpad.conf
+@@ -0,0 +1,46 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013
++#
++# LLDPAD station rule configuration file
++#
++
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    @include "stevb_groupid.res"
++  };
++};
+diff --git a/test/qbg22/vdp22/220.nlc b/test/qbg22/vdp22/220.nlc
+new file mode 100755
+index 0000000..a7a83fe
+--- /dev/null
++++ b/test/qbg22/vdp22/220.nlc
+@@ -0,0 +1,36 @@
++#!/bin/bash
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2013
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++
++# 
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014
++#
++# Execute a simple assoc with group id support on bridge and station.
++# Send 1 VIDs (filter format VID/MAC/GPID) and expect no VID replacement.
++#
++
++sleep 30	# Must: Wait some time for lldpad to start up and initialize
++outfile=$(basename $0)
++dirfile=$(dirname $0)
++cd $dirfile
++
++../../../vdptest -v -v -v -F vm2.cfg -i veth0 -Cnew=vm2_xx1,name=vm2_1,map=13-52:bb:cc:dd:ee:ff-1024 -s,w=30 -a vm2_xx1 -s,w=30 -d vm2_xx1 -s,w=10
++exit $?
+diff --git a/test/qbg22/vdp22/220.vdp b/test/qbg22/vdp22/220.vdp
+new file mode 100644
+index 0000000..0f29fa0
+--- /dev/null
++++ b/test/qbg22/vdp22/220.vdp
+@@ -0,0 +1,43 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013
++# lldpad bridge mode configuration file
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth2 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    @include "brevb_groupid.res"
++  };
++};
+diff --git a/test/qbg22/vdp22/221-lldpad.conf b/test/qbg22/vdp22/221-lldpad.conf
+new file mode 100644
+index 0000000..c75f7f2
+--- /dev/null
++++ b/test/qbg22/vdp22/221-lldpad.conf
+@@ -0,0 +1,46 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013
++#
++# LLDPAD station rule configuration file
++#
++
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    @include "stevb_groupid.res"
++  };
++};
+diff --git a/test/qbg22/vdp22/221.nlc b/test/qbg22/vdp22/221.nlc
+new file mode 100755
+index 0000000..1b85957
+--- /dev/null
++++ b/test/qbg22/vdp22/221.nlc
+@@ -0,0 +1,36 @@
++#!/bin/bash
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2013
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++
++# 
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014
++#
++# Execute a simple assoc with group id support on bridge and station.
++# Send 1 VIDs (filter format VID/MAC/GPID) and expect VID replaced.
++#
++
++# Must: Wait some time for lldpad to start up and initialize
++outfile=$(basename $0)
++dirfile=$(dirname $0)
++cd $dirfile
++
++../../../vdptest -v -v -v -F vm2.cfg -i veth0 -Cnew=vm2_xx1,name=vm2_207,map=0/1014-aa:bb:cc:00:00:ff-1014 -s,w=30 -a vm2_xx1 -s,w=30 -Cnew=vm2_xx2,name=vm2_207,map=1014-aa:bb:cc:00:00:ff-1014 -d vm2_xx2 -s,w=10
++exit $?
+diff --git a/test/qbg22/vdp22/221.vdp b/test/qbg22/vdp22/221.vdp
+new file mode 100644
+index 0000000..0f29fa0
+--- /dev/null
++++ b/test/qbg22/vdp22/221.vdp
+@@ -0,0 +1,43 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013
++# lldpad bridge mode configuration file
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth2 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    @include "brevb_groupid.res"
++  };
++};
+diff --git a/test/qbg22/vdp22/222-lldpad.conf b/test/qbg22/vdp22/222-lldpad.conf
+new file mode 100644
+index 0000000..c75f7f2
+--- /dev/null
++++ b/test/qbg22/vdp22/222-lldpad.conf
+@@ -0,0 +1,46 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013
++#
++# LLDPAD station rule configuration file
++#
++
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    @include "stevb_groupid.res"
++  };
++};
+diff --git a/test/qbg22/vdp22/222.nlc b/test/qbg22/vdp22/222.nlc
+new file mode 100755
+index 0000000..cc1fbd9
+--- /dev/null
++++ b/test/qbg22/vdp22/222.nlc
+@@ -0,0 +1,36 @@
++#!/bin/bash
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2013
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++
++# 
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014
++#
++# Execute a simple assoc with group id support on bridge and station.
++# Send many VIDs (filter format VID/MAC/GPID) and expect no VID replacement.
++#
++
++# Must: Wait some time for lldpad to start up and initialize
++outfile=$(basename $0)
++dirfile=$(dirname $0)
++cd $dirfile
++
++../../../vdptest -v -v -v -F vm2.cfg -i veth0 -Cnew=vm2_xx1,name=vm2_1,map=13-52:bb:cc:dd:ee:ff-1024,map=14-52:bb:cc:dd:ee:10-1025,map=15-52:bb:cc:dd:ee:00-1025 -s,w=30 -a vm2_xx1 -s,w=30 -d vm2_xx1 -s,w=10
++exit $?
+diff --git a/test/qbg22/vdp22/222.vdp b/test/qbg22/vdp22/222.vdp
+new file mode 100644
+index 0000000..0f29fa0
+--- /dev/null
++++ b/test/qbg22/vdp22/222.vdp
+@@ -0,0 +1,43 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013
++# lldpad bridge mode configuration file
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth2 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    @include "brevb_groupid.res"
++  };
++};
+diff --git a/test/qbg22/vdp22/223-lldpad.conf b/test/qbg22/vdp22/223-lldpad.conf
+new file mode 100644
+index 0000000..c75f7f2
+--- /dev/null
++++ b/test/qbg22/vdp22/223-lldpad.conf
+@@ -0,0 +1,46 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013
++#
++# LLDPAD station rule configuration file
++#
++
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    @include "stevb_groupid.res"
++  };
++};
+diff --git a/test/qbg22/vdp22/223.nlc b/test/qbg22/vdp22/223.nlc
+new file mode 100755
+index 0000000..587b08a
+--- /dev/null
++++ b/test/qbg22/vdp22/223.nlc
+@@ -0,0 +1,36 @@
++#!/bin/bash
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2013
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++
++# 
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014
++#
++# Execute a simple assoc with group id support on bridge and station.
++# Send many VIDs (filter format VID/MAC//GPID) and expect VID 0 replaced.
++#
++
++# Must: Wait some time for lldpad to start up and initialize
++outfile=$(basename $0)
++dirfile=$(dirname $0)
++cd $dirfile
++
++../../../vdptest -v -v -v -F vm2.cfg -i veth0 -Cnew=vm2_xx1,name=vm2_208,typeidver=0,map=0/1014-aa:bb:cc:00:00:ff-1014,map=0/1024-aa:bb:cc:00:00:dd-1024,map=1024-aa:bb:cc:00:00:aa-1024 -s,w=30 -a vm2_xx1 -s,w=30 -Cnew=vm2_xx2,name=vm2_208,typeidver=0,map=1014-aa:bb:cc:00:00:ff-1014,map=1024-aa:bb:cc:00:00:dd-1024,map=1024-aa:bb:cc:00:00:aa-1024 -d vm2_xx2 -s,w=10
++exit $?
+diff --git a/test/qbg22/vdp22/223.vdp b/test/qbg22/vdp22/223.vdp
+new file mode 100644
+index 0000000..0f29fa0
+--- /dev/null
++++ b/test/qbg22/vdp22/223.vdp
+@@ -0,0 +1,43 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013
++# lldpad bridge mode configuration file
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth2 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    @include "brevb_groupid.res"
++  };
++};
+diff --git a/test/qbg22/vdp22/224-lldpad.conf b/test/qbg22/vdp22/224-lldpad.conf
+new file mode 100644
+index 0000000..c75f7f2
+--- /dev/null
++++ b/test/qbg22/vdp22/224-lldpad.conf
+@@ -0,0 +1,46 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013
++#
++# LLDPAD station rule configuration file
++#
++
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    @include "stevb_groupid.res"
++  };
++};
+diff --git a/test/qbg22/vdp22/224.nlc b/test/qbg22/vdp22/224.nlc
+new file mode 100755
+index 0000000..864cb76
+--- /dev/null
++++ b/test/qbg22/vdp22/224.nlc
+@@ -0,0 +1,36 @@
++#!/bin/bash
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2013
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++
++# 
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014
++#
++# Execute a simple assoc with group id support on bridge and station.
++# Send many VIDs (filter format VID/MAC/GPID) and expect QoS (fid 1) set.
++#
++
++sleep 30	# Must: Wait some time for lldpad to start up and initialize
++outfile=$(basename $0)
++dirfile=$(dirname $0)
++cd $dirfile
++
++../../../vdptest -v -v -v -F vm2.cfg -i veth0 -Cnew=vm2_xx1,name=vm2_206,typeidver=0x11,map=1014-aa:bb:cc:00:00:ff-1014,map=1024/0x9400-aa:bb:cc:00:00:dd-1024,map=1024-aa:bb:cc:00:00:aa-1024 -s,w=30 -a vm2_xx1 -s,w=30 -Cnew=vm2_xx2,name=vm2_206,typeidver=0x11,map=1014-aa:bb:cc:00:00:ff-1014,map=0x9400-aa:bb:cc:00:00:dd-1024,map=1024-aa:bb:cc:00:00:aa-1024 -d vm2_xx2 -s,w=10
++exit $?
+diff --git a/test/qbg22/vdp22/224.vdp b/test/qbg22/vdp22/224.vdp
+new file mode 100644
+index 0000000..0f29fa0
+--- /dev/null
++++ b/test/qbg22/vdp22/224.vdp
+@@ -0,0 +1,43 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013
++# lldpad bridge mode configuration file
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth2 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    @include "brevb_groupid.res"
++  };
++};
+diff --git a/test/qbg22/vdp22/225-lldpad.conf b/test/qbg22/vdp22/225-lldpad.conf
+new file mode 100644
+index 0000000..c75f7f2
+--- /dev/null
++++ b/test/qbg22/vdp22/225-lldpad.conf
+@@ -0,0 +1,46 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013
++#
++# LLDPAD station rule configuration file
++#
++
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    @include "stevb_groupid.res"
++  };
++};
+diff --git a/test/qbg22/vdp22/225.nlc b/test/qbg22/vdp22/225.nlc
+new file mode 100755
+index 0000000..ffc209e
+--- /dev/null
++++ b/test/qbg22/vdp22/225.nlc
+@@ -0,0 +1,37 @@
++#!/bin/bash
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2013
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++
++# 
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014
++#
++# Execute a simple assoc with group id support on bridge and station.
++# Send many VIDs (filter format VID/MAC/GPID) and expect VID 0 replaced and
++# QoS set.
++#
++
++# Must: Wait some time for lldpad to start up and initialize
++outfile=$(basename $0)
++dirfile=$(dirname $0)
++cd $dirfile
++
++../../../vdptest -v -v -v -F vm2.cfg -i veth0 -Cnew=vm2_xx1,name=vm2_208,map=0/0xb3f6-aa:bb:cc:00:00:ff-0x3f6,map=0/0xb400-aa:bb:cc:00:00:dd-0x400 -s,w=30 -a vm2_xx1 -s,w=30 -Cnew=vm2_xx2,name=vm2_208,map=0xb3f6-aa:bb:cc:00:00:ff-0x3f6,map=0xb400-aa:bb:cc:00:00:dd-0x400 -d vm2_xx2 -s,w=10
++exit $?
+diff --git a/test/qbg22/vdp22/225.vdp b/test/qbg22/vdp22/225.vdp
+new file mode 100644
+index 0000000..0f29fa0
+--- /dev/null
++++ b/test/qbg22/vdp22/225.vdp
+@@ -0,0 +1,43 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013
++# lldpad bridge mode configuration file
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth2 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    @include "brevb_groupid.res"
++  };
++};
+diff --git a/test/qbg22/vdp22/240-lldpad.conf b/test/qbg22/vdp22/240-lldpad.conf
+new file mode 100644
+index 0000000..d22aa2b
+--- /dev/null
++++ b/test/qbg22/vdp22/240-lldpad.conf
+@@ -0,0 +1,46 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013
++#
++# LLDPAD station rule configuration file
++#
++
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    @include "stevb_default.res"
++  };
++};
+diff --git a/test/qbg22/vdp22/240.nlc b/test/qbg22/vdp22/240.nlc
+new file mode 100755
+index 0000000..2a0de5a
+--- /dev/null
++++ b/test/qbg22/vdp22/240.nlc
+@@ -0,0 +1,43 @@
++#!/bin/bash
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2013
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++
++# 
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014
++#
++# Execute a simple assoc without group id support in bridge and station.
++# Check for hint bit support
++#
++
++# Must: Wait some time for lldpad to start up and initialize
++outfile=$(basename $0)
++dirfile=$(dirname $0)
++testcase=$(basename $outfile .nlc)
++cd $dirfile
++
++../../../vdptest -v -v -v -F vm2.cfg -i veth0 -s,w=30 -a vm2_1 -s,w=30 -d vm2_1 -s,w=10
++rc=$?
++if [ "$rc" -ne 0 ]
++then
++	exit $rc
++fi
++fgrep -q '06 21 10 00 00 01 00 05 a1 41 28 57' /tmp/$testcase-lldpad.conf.out
++exit $?
+diff --git a/test/qbg22/vdp22/240.vdp b/test/qbg22/vdp22/240.vdp
+new file mode 100644
+index 0000000..fa3efbd
+--- /dev/null
++++ b/test/qbg22/vdp22/240.vdp
+@@ -0,0 +1,43 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013
++# lldpad bridge mode configuration file
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth2 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    @include "brevb_default.res"
++  };
++};
+diff --git a/test/qbg22/vdp22/241-lldpad.conf b/test/qbg22/vdp22/241-lldpad.conf
+new file mode 100644
+index 0000000..d22aa2b
+--- /dev/null
++++ b/test/qbg22/vdp22/241-lldpad.conf
+@@ -0,0 +1,46 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013
++#
++# LLDPAD station rule configuration file
++#
++
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth0 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    @include "stevb_default.res"
++  };
++};
+diff --git a/test/qbg22/vdp22/241.nlc b/test/qbg22/vdp22/241.nlc
+new file mode 100755
+index 0000000..b508e8a
+--- /dev/null
++++ b/test/qbg22/vdp22/241.nlc
+@@ -0,0 +1,43 @@
++#!/bin/bash
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2013
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++
++# 
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2014
++#
++# Execute a simple assoc without group id support in bridge and station.
++# Check for hint bit support
++#
++
++# Must: Wait some time for lldpad to start up and initialize
++outfile=$(basename $0)
++dirfile=$(dirname $0)
++testcase=$(basename $outfile .nlc)
++cd $dirfile
++
++../../../vdptest -v -v -v -F vm2.cfg -i veth0 -Cnew=vm2_xx1,name=vm2_1,hints=from  -s,w=30 -a vm2_xx1 -s,w=30 -d vm2_xx1 -s,w=10
++rc=$?
++if [ "$rc" -ne 0 ]
++then
++	exit $rc
++fi
++fgrep -q '06 21 20 00 00 01 00 05 a1 41 28 57' /tmp/$testcase-lldpad.conf.out
++exit $?
+diff --git a/test/qbg22/vdp22/241.vdp b/test/qbg22/vdp22/241.vdp
+new file mode 100644
+index 0000000..fa3efbd
+--- /dev/null
++++ b/test/qbg22/vdp22/241.vdp
+@@ -0,0 +1,43 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2014
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2013
++# lldpad bridge mode configuration file
++dcbx : 
++{
++  version = "1.0";
++  dcbx_version = 2;
++};
++nearest_customer_bridge : 
++{
++  veth2 : 
++  {
++    tlvid00000001 : 
++    {
++      info = "04C68829509676";
++    };
++    tlvid00000002 : 
++    {
++      info = "03C68829509676";
++    };
++    adminStatus = 3;
++    @include "brevb_default.res"
++  };
++};
+diff --git a/test/qbg22/vdp22/README b/test/qbg22/vdp22/README
+new file mode 100644
+index 0000000..f58df8a
+--- /dev/null
++++ b/test/qbg22/vdp22/README
+@@ -0,0 +1,148 @@
++
++(c) Copyright IBM Corp. 2012, 2013
++
++Thomas Richter, IBM Research and Development, Germany, Mar 2013
++
++Test cases for IEEE802.1Qbg ratified standard VDP module.
++
++14-Jun-2013
++===========
++Some test cases run the lldpad program in station mode and in bridge mode
++This is achieved via namespaces for network and IPC. Additionally the
++lldpad in bridge mode does not create a pid run time file /var/run/lldpad.pid.
++Use the network name space bridge_ns and then create an unnamed IPC namespace
++and execute lldpad in bridge mode.
++
++Files
++=====
++ns_unshare	Executes a command and with prior set of namespaces. Used to 
++		set up an unnamed IPC namespace so 2 shared memory segments can
++		coexist for both lldpads (station and bridge role).
++runvdp.sh	Runs one test case.
++		Return 0 on success and none zero otherwise. Uses qbg22sim as
++		bridge simulator. Test case result is determined by the
++		qbg22sim program.
++vm.cfg		Configuration file for vdptest
++vm2.cfg		Configuration file for vdptest using netlink format 2
++
++Tests
++=====
++The following test cases are executed. Each test case has a number.
++All test cases need a lldpad.conf configuration file, a VDP test input
++file and a netlink command file to send request to lldpad:
++- The VDP test input files have the extension .vdp. The test case number
++  is the base file name. This can be a qbg22sim input file or an lldpad
++  bridge-role configuration file.
++- The lldpad configuration file has the extension -lldpad.conf
++- The netlink command file has the extension .nlc
++
++The purpose is to trigger an VDP DU exchange between qbg22sim and llpdad.
++The exchanged data can be inspected automaticly with little inteligence
++(see qbg22sim.1) or manually.
++
++All test case with numbers 1 to 99 use lldpad as station role and numbers
++higher then 100 use lldpad as station and bridge role.
++
++Test cases with number 200 and higher use netlink message format 2 to
++communicate between vdptest and llpdad.
++
++Test cases with number 300 and higher use lldptool to trigger VDP22 protocol.
++
++A (M) indication manual checking via lldpad trace output file inspection.
++
++Test	Description
++
++100	Run assoc test with EVB22 disabled
++101	Check if netlink message is ignored in bridge role.
++102	Run assoc test with RR disabled
++103	Run a simple assoc and de-assoc test
++104	Run two simple assoc and de-assoc test
++105	Run a simple pre-assoc and de-assoc test
++106	Run two simple pre-assoc and de-assoc test
++107	Run a simple pre-assoc-rr and de-assoc test
++108	Run assoc --> pre-assoc test
++110	Run pre-assoc --> pre-assoc-rr --> assoc --> de-assoc test
++111	Run pre-assoc --> pre-assoc -- de-assoc test
++112	Run pre-assoc-rr --> pre-assoc-rr -- de-assoc test
++113	Run assoc --> assoc -- de-assoc test
++114	Run de-assoc test
++
++115	Run assoc test with error response from switch
++116	Run pre-assoc test with error response in first keep alive from switch
++117	Run assoc test with de-assoc response in unsolicited message from switch
++118	Run pre-assoc test with error response from switch
++119	Run pre-assoc-rr test with error response in first keep alive from
++	switch
++120	Run pre-assoc test with de-assoc response in unsolicited message from
++	switch
++121	Run assoc test with keep-error response in first keep alive from switch
++122	Run pre-assoc test with hard-error response from switch switch
++123	Run assoc test with resource wait delay timeout on bridge.
++124	Run assoc test with keep alive timeout on bridge.
++
++200	Run assoc/de-assoc test with long manager-id
++201	Run assoc/de-assoc test with gpid and group support turned off
++202	Run assoc/de-assoc test with vlan 0 replacement (fif 1)
++	de-assoc fails due to wrong filter
++203	Run assoc/de-assoc test with vlan 0 replacement (fif 1)
++	de-assoc succeeds due to correct filter
++204	Run assoc/de-assoc test with qos 0 replacement (fif 1)
++	de-assoc fails due to incorrect filter
++205	Run assoc/de-assoc test with qos 0 replacement (fif 1)
++	de-assoc succeeds due to correct filter
++206	Run assoc/de-assoc test with qos 0 replacement (fif 1)
++	fails due to wrong filter index
++207	Run assoc/de-assoc test with qos 0 replacement (fif 1)
++	fails due to unexpected QoS returned
++208	Run assoc/de-assoc test with vlan/qos requested by caller (fif 1)
++209	Run assoc/de-assoc test with vlan/qos requested by caller but not 
++	confirmed by swtich (fif 1)
++210	Run assoc/de-assoc with multiple VID and one VID set to zero (fif 1)
++	fails because only one VID entry allowed, which is 0.
++211	Run assoc/de-assoc with multiple VIDs and expect QoS changed
++	for entry 4 (fif 1)
++212	Run assoc/de-assoc with multiple MAC/VIDs and expect all VLAN ID 0
++	changed (fif 2). De-assoc fails because of wrong filter.
++213	Run assoc/de-assoc with multiple MAC/VIDs and expect all VLAN ID 0
++	changed (fif 2). De-assoc succeeds.
++
++Tests with group identifer support
++220	Run assoc/de-assoc test with 1 filter entry (fif 4)
++221	Run assoc/de-assoc test with 1 vlan 0 replacement (fif 4)
++222	Run assoc/de-assoc test with several filter entries (fif 4)
++223	Run assoc/de-assoc test with several vlan 0 replacement (fif 4)
++224	Run assoc/de-assoc test with QoS replacement (fif 4)
++225	Run assoc/de-assoc test with several vlan 0 and QoS replacement (fif 4)
++
++Test with hint bits
++240	Run assoc/de-assoc test with suspend hints
++241	Run assoc/de-assoc test with migrate hints
++
++TODO
++Test case with multiple filter entries. Combiniation of filter data.
++Run assoc(1) and assoc(2) with deassoc(1,2)
++
++Run ethernet interface up/down tests while VSI actives
++Add filter info data to an existing VSI
++
++
++Remarks:
++
++Test Execution
++==============
++Directory structure:
++
++The following directory structure is assumed:
++/home/richter/dcn/qbg/mywork/open-lldp	--> lldpad to test on target f18b
++/home/richter/dcn/qbg/mywork/test/qbg22/evb22	--> EVB protocol test cases
++/home/richter/dcn/qbg/mywork/test/qbg22/ecp22	--> ECP protocol test cases
++/home/richter/dcn/qbg/mywork/test/qbg22/vdp22	--> VDP protocol test cases
++
++On local machine f18a:
++Select the evttest program by adding the path relative to test directory
++1. cd /home/richter/dcn/qbg/mywork/test/qbg22/vdp22
++2. Use a symbolic link such as ./qbg22sim --> ../../../xxx/qbg22sim.
++3. Add the environment variable LLDPAD_DIR=abc to select an different lldpad
++   executable. For example the invocation 
++   LLDPAD_DIR=new vdprun.sh 1.vdp
++   selects the file /home/richter/dcn/qbg/mywork/new/lldpad for execution.
+diff --git a/test/qbg22/vdp22/allvdp.sh b/test/qbg22/vdp22/allvdp.sh
+new file mode 100755
+index 0000000..0012618
+--- /dev/null
++++ b/test/qbg22/vdp22/allvdp.sh
+@@ -0,0 +1,66 @@
++#!/bin/bash
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2013
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 16-Aug-2013
++#
++# Execute the complete vdp test suite.
++#
++
++runcommand()
++{
++	# echo parameter $@
++	cmd=$1
++	file=$2
++
++	echo "start testcase $number"
++	$cmd $file 2>&1
++	rc="$?"
++	if [ "$rc" -ne 0 ]
++	then
++		echo -en "\\033[1;31m"	# Failures in red
++		echo "ERROR $file exit with $rc"
++		echo -en "\\033[0;39m"
++		exit 2
++	fi
++	echo -en "\\033[1;32m"	# Success in green
++	echo "OK testcase $file"
++	echo -en "\\033[0;39m"
++	return 0
++}
++
++# Extract type of test case from the first 3 characters of invocation file
++type=$(basename $0)
++type="${type:3:3}"
++
++if ! which run$type.sh 2>/dev/null
++then
++	export PATH=$PATH:.
++fi
++
++echo "Start testsuite at $(date)"
++for i in $(ls [1-9]*.$type|sort -n)
++do
++	runcommand run$type.sh $i
++done
++echo "Stop testsuite at $(date)"
++exit 0
+diff --git a/test/qbg22/vdp22/brevb_default.res b/test/qbg22/vdp22/brevb_default.res
+new file mode 100644
+index 0000000..c626be1
+--- /dev/null
++++ b/test/qbg22/vdp22/brevb_default.res
+@@ -0,0 +1,36 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2013
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013
++#
++# LLDPAD bridge mode default resource file
++#
++tlvid0080c20d : 
++{
++	enableTx = true;
++	evbmode = "bridge";
++	evbrrcap = true;
++	evbrrreq = true;
++	evbgpid = false;
++	ecpretries = 3;
++	ecprte = 14;
++	vdprwd = 20;
++	vdprka = 20;
++};
+diff --git a/test/qbg22/vdp22/brevb_groupid.res b/test/qbg22/vdp22/brevb_groupid.res
+new file mode 100644
+index 0000000..3651381
+--- /dev/null
++++ b/test/qbg22/vdp22/brevb_groupid.res
+@@ -0,0 +1,36 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2013
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013
++#
++# LLDPAD bridge mode default resource file
++#
++tlvid0080c20d : 
++{
++	enableTx = true;
++	evbmode = "bridge";
++	evbrrcap = true;
++	evbrrreq = true;
++	evbgpid = true;
++	ecpretries = 3;
++	ecprte = 14;
++	vdprwd = 20;
++	vdprka = 20;
++};
+diff --git a/test/qbg22/vdp22/ns_unshare.c b/test/qbg22/vdp22/ns_unshare.c
+new file mode 100644
+index 0000000..cbc322a
+--- /dev/null
++++ b/test/qbg22/vdp22/ns_unshare.c
+@@ -0,0 +1,54 @@
++#define _GNU_SOURCE
++#include <sched.h>
++#include <unistd.h>
++#include <stdlib.h>
++#include <stdio.h>
++
++/* A simple error-handling function: print an error message based
++   on the value in 'errno' and terminate the calling process */
++
++#define errExit(msg)    do { perror(msg); exit(EXIT_FAILURE); \
++                        } while (0)
++
++static void
++usage(char *pname)
++{
++    fprintf(stderr, "Usage: %s [options] program [arg...]\n", pname);
++    fprintf(stderr, "Options can be:\n");
++    fprintf(stderr, "    -i   unshare IPC namespace\n");
++    fprintf(stderr, "    -m   unshare mount namespace\n");
++    fprintf(stderr, "    -n   unshare network namespace\n");
++    fprintf(stderr, "    -p   unshare PID namespace\n");
++    fprintf(stderr, "    -u   unshare UTS namespace\n");
++    fprintf(stderr, "    -U   unshare user namespace\n");
++    exit(EXIT_FAILURE);
++}
++
++int
++main(int argc, char *argv[])
++{
++    int flags, opt;
++
++    flags = 0;
++
++    while ((opt = getopt(argc, argv, "imnpuU")) != -1) {
++        switch (opt) {
++        case 'i': flags |= CLONE_NEWIPC;        break;
++        case 'm': flags |= CLONE_NEWNS;         break;
++        case 'n': flags |= CLONE_NEWNET;        break;
++        case 'p': flags |= CLONE_NEWPID;        break;
++        case 'u': flags |= CLONE_NEWUTS;        break;
++        case 'U': flags |= CLONE_NEWUSER;       break;
++        default:  usage(argv[0]);
++        }
++    }
++
++    if (optind >= argc)
++        usage(argv[0]);
++
++    if (unshare(flags) == -1)
++        errExit("unshare");
++
++    execvp(argv[optind], &argv[optind]);  
++    errExit("execvp");
++}
+diff --git a/test/qbg22/vdp22/runvdp.sh b/test/qbg22/vdp22/runvdp.sh
+new file mode 100755
+index 0000000..538c956
+--- /dev/null
++++ b/test/qbg22/vdp22/runvdp.sh
+@@ -0,0 +1,186 @@
++#!/bin/bash
++#
++# Execute test case for LLDPAD testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2013
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 16-Aug-2012
++#
++# Execute a single test. Parameter is the name of the test file.
++# Run 2 lldpad instances in parallel using 2 network name spaces
++#
++
++# Check if lldpad (bridge role) is up and running. Do not use the pid file.
++# Return 0 is not running and 1 if running (pid returned as string)
++function lldpad_brpid()
++{
++	PID_lldpbr=$(ps -ef | fgrep lldpad | fgrep -- .vdp | awk '{ print $2 }')
++	if [ -z "$PID_lldpbr" ]
++	then
++		return 0
++	fi
++	return 1
++}
++
++# Check if lldpad is up and running. Return pid or 0 if not running.
++function lldpad_pid()
++{
++	PID_lldp=$(ps -ef | fgrep lldpad | fgrep -- .conf | awk '{ print $2 }')
++	if [ -z "$PID_lldp" ]
++	then
++		return 0
++	fi
++	return 1
++}
++
++function lldpad_stop()
++{
++	if [ "$1" -eq 0 ]
++	then
++		echo "$0:lldpad $2 terminated unexpectedly"
++		return 1
++	fi
++	kill -s SIGTERM $1
++	sleep 1
++	ps -p $1 -o pid --no-header > /dev/null
++	if [ $? -ne 1 ]
++	then
++		kill -s SIGKILL $1
++	fi
++	return 0
++}
++
++function cp_include()
++{
++	for i in $(fgrep @include $1 | awk '{ print $2 }' | sed 's-"--gp')
++	do
++		cp $i /tmp
++	done
++}
++
++# Use the correct lldpad configuration file and start lldpad.
++# Parameter 1: path to lldpad to use
++# Parameter 2: name of configuration file
++function lldpad_start()
++{
++	if lldpad_pid
++	then
++		rm -f /var/lib/lldpad/lldpad.conf ./lldpad.conf
++		cp $2 /tmp/$2
++		$1/lldpad -V7 -f /tmp/$2 >/tmp/$2.out 2>&1 &
++		sleep 1
++		if lldpad_pid
++		then
++			echo "$0:lldpad not started or terminated unexpectedly"
++			exit 1
++		else
++			echo "LLDPAD running pid $PID_lldp"
++		fi
++	else
++		exit 1
++	fi
++	return 0
++}
++
++# Start lldpad in bridge role
++# Testfile is an lldpad configuration file with bridge settings.
++# Run lldpad without creating the /var/run/lldpad.pid file
++function lldpad_brstart()
++{
++	if lldpad_brpid
++	then
++		cp $2 /tmp/$2
++		cp_include $2
++		cmd="./ns_unshare -i -- ../../../lldpad -p -V7 -f /tmp/$2"
++		ip netns exec bridge_ns $cmd > /tmp/$2.out 2>&1 &
++		sleep 1
++		if lldpad_brpid
++		then
++			echo "$0:lldpad bridge role not started or terminated unexpectedly"
++			return 1
++		else
++			echo "LLDPAD bridge role running pid $PID_lldpbr"
++		fi
++	else
++		return 1
++	fi
++	return 0
++}
++
++if ! ip netns list | fgrep -qi bridge_ns
++then
++	echo "$0:bridge_ns network name space missing"
++	exit 1
++fi
++
++if ! which runvdp.sh 1>/dev/null 2>/dev/null
++then
++	export PATH=$PATH:$PWD
++fi
++
++# Extract type of test case from last 3 characters of invocation
++type=$(basename $0)
++type=".${type:3:3}"
++
++testfile=$1
++no=$(basename $testfile $type)
++
++# Find out if test case file is a lldpad configuration file to run lldpad
++# in bridge mode
++if ! egrep -qi tlvid0080c20d $testfile && egrep -qi 'evbmode[ \t]*=[ \t]*"?bridge"?' $testfile
++then 
++	echo "$0:use qbg22sim as bridge simulator"
++	exit 1
++fi
++
++# Start lldpad using this name space
++if ! lldpad_start ../../.. $no-lldpad.conf
++then
++	echo "$0:can not start lldpad"
++	exit 1
++fi
++
++# Start lldpad bridge role
++if ! lldpad_brstart ../../.. $no.vdp
++then
++	echo "$0:can not start lldpad in bridge role"
++	# Stop lldpad
++	lldpad_stop $PID_lldp "station role"
++	exit 1
++fi
++
++# Check for shell script to run in parallel
++if [ -r "./$no.sh" -a -x "./$no.sh" ]
++then
++	./$no.sh ../../.. &
++fi
++
++# Start vdptest test program
++if [ -r "$no.nlc" ]
++then
++	./$no.nlc >/tmp/$no.nlc.out 2>&1
++	rc=$?
++fi
++
++# Stop lldpad
++lldpad_stop $PID_lldpbr "bridge role"
++lldpad_stop $PID_lldp "station role"
++
++exit $rc
+diff --git a/test/qbg22/vdp22/stevb_default.res b/test/qbg22/vdp22/stevb_default.res
+new file mode 100644
+index 0000000..2dbf8f8
+--- /dev/null
++++ b/test/qbg22/vdp22/stevb_default.res
+@@ -0,0 +1,36 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2013
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013
++#
++# LLDPAD station mode default resource file
++#
++tlvid0080c20d : 
++{
++	enableTx = true;
++	evbmode = "station";
++	evbrrcap = true;
++	evbrrreq = true;
++	evbgpid = false;
++	ecpretries = 3;
++	ecprte = 14;
++	vdprwd = 20;
++	vdprka = 20;
++};
+diff --git a/test/qbg22/vdp22/stevb_groupid.res b/test/qbg22/vdp22/stevb_groupid.res
+new file mode 100644
+index 0000000..f83e241
+--- /dev/null
++++ b/test/qbg22/vdp22/stevb_groupid.res
+@@ -0,0 +1,36 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2013
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 11-Jul-2013
++#
++# LLDPAD station mode default resource file
++#
++tlvid0080c20d : 
++{
++	enableTx = true;
++	evbmode = "station";
++	evbrrcap = true;
++	evbrrreq = true;
++	evbgpid = true;
++	ecpretries = 3;
++	ecprte = 14;
++	vdprwd = 20;
++	vdprka = 20;
++};
+diff --git a/test/qbg22/vdp22/vm.cfg b/test/qbg22/vdp22/vm.cfg
+new file mode 100644
+index 0000000..cf5c21e
+--- /dev/null
++++ b/test/qbg22/vdp22/vm.cfg
+@@ -0,0 +1,56 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2012
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 20-Apr-2012
++#
++# Configuration file for vsi data test cases
++#
++
++name=vm1,mgrid=1,typeid=1,typeidver=1,\
++     uuid=a1412857-60f7-4ce1-e95a-2164943f53aa,\
++     map=2-52:54:00:8e:aa:11
++name=vm3,mgrid=1,typeid=1,typeidver=1,\
++     uuid=a1412857-60f7-4ce1-e95a-2164943f53aa,\
++     map=2-52:54:00:8e:aa:1a
++name=vm2,mgrid=1,typeid=1,typeidver=1,\
++     uuid=a1412857-60f7-4ce1-e95a-2164943f53dd,\
++     map=2-52:54:00:8e:aa:22
++name=vm1u3,mgrid=1,typeid=1,typeidver=1,\
++     uuid=a1412857-60f7-4ce1-e95a-2164943f53aa,\
++     map=2-52:54:00:8e:aa:11, \
++     map=2-52:54:00:8e:aa:1a
++
++# Used type ID 199 and check for bridge resource wait delay timeout
++name=vm199,mgrid=1,typeid=199,typeidver=1,\
++     uuid=a1412857-60f7-4ce1-e95a-2164943f53aa,\
++     map=3-52:54:00:8e:aa:33
++# Used type ID 200 and check for bridge unsolicited deassoc message
++name=vm200,mgrid=1,typeid=200,typeidver=3,\
++     uuid=a1412857-60f7-4ce1-e95a-2164943f53aa,\
++     map=3-52:54:00:8e:aa:33
++# Used type ID 201 and check if bridge return error response
++name=vm201,mgrid=1,typeid=201,typeidver=1,\
++     uuid=a1412857-60f7-4ce1-e95a-2164943f53aa,\
++     map=4-52:54:00:8e:aa:44
++# Used type ID 202 and check if bridge return keep-error response
++name=vm202,mgrid=1,typeid=202,typeidver=3,\
++     uuid=a1412857-60f7-4ce1-e95a-2164943f53aa,\
++     map=202-52:54:00:8e:aa:44
+diff --git a/test/qbg22/vdp22/vm2.cfg b/test/qbg22/vdp22/vm2.cfg
+new file mode 100644
+index 0000000..c27a08b
+--- /dev/null
++++ b/test/qbg22/vdp22/vm2.cfg
+@@ -0,0 +1,58 @@
++#
++# Test case for LLDPAD VDP Testing according to IEEE 802.1Qbg
++#
++# Copyright (c) International Business Machines Corp., 2012
++#
++# Author(s): Thomas Richter <tmricht at linux.vnet.ibm.com>
++#
++# 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.
++#
++#
++# Thomas Richter, IBM Research & Development, Boeblingen, Germany, 21-Sep-2013
++#
++# Configuration file for vsi data test cases. Use new netlink message format 2
++# supporting features from the vdptest program:
++# - new group notation in the filter information: vlan-mac-group
++# - vlan id zero
++# - new long mgrid
++# - hint flags for VM migration support.
++
++# Test new message format, filter info format 2
++name=vm2_1,2mgrid=blabla,typeid=1,typeidver=0,hints=to,\
++     uuid=a1412857-60f7-4ce1-e95a-2164943f53aa,\
++     map=13-52:bb:cc:dd:ee:ff
++# Test VLAN 0 return. Bridge returns typeid as vlan.
++name=vm2_205,2mgrid=vlantest,typeid=205,typeidver=0,\
++     uuid=00000000-1111-2222-3333-aabbccddeeff,\
++     map=14
++name=vm2_205a,2mgrid=vlantesta,typeid=205,typeidver=0,\
++     uuid=00000000-1111-2222-3333-aabbccddeeff,\
++     map=3,map=0/205,map=2,map=32
++name=vm2_208,2mgrid=vlantestb,typeid=208,typeidver=0x13,\
++     uuid=00000000-1111-2222-3333-aabbccddeeff,\
++     map=10-aa:bb:00:00:00:10,map=0/0xb0d0-aa:bb:00:00:00:11,\
++     map=0/0xb0d0-aa:bb:00:00:00:22
++# Test QoS return. Bridge returns typeidver as qos (lower 3 bits).
++# Typeidver upper nibble used as index in fid array.
++name=vm2_206,2mgrid=qostest,typeid=206,typeidver=7,\
++     uuid=00000000-1111-2222-3333-aabbccddeeff,\
++     map=14
++name=vm2_206b,2mgrid=qostest,typeid=206,typeidver=0x35,\
++     uuid=00000000-1111-2222-3333-aabbccddeeff,\
++     map=10,map=11,map=12,map=13/0xd00d,map=14,map=15
++# Test VLAN assigned by bridge using group-id.
++# Typeidver upper nibble used as index in fid array.
++name=vm2_207,2mgrid=groupidtest,typeid=207,typeidver=0,\
++     uuid=00000000-1111-2222-3333-aabbccddeeff,\
++     map=2
+diff --git a/test/qbg22/veth-setup.sh b/test/qbg22/veth-setup.sh
+new file mode 100755
+index 0000000..be94fa1
+--- /dev/null
++++ b/test/qbg22/veth-setup.sh
+@@ -0,0 +1,45 @@
++#!/bin/bash
++#
++# Thomas Richter, DCN Linux Technology Center, IBM Research, Germany 29-Apr-2013
++#
++# Setup a lldpad test environment with 2 virtual ethernet device in 2 different
++# network name spaces.
++# lldpad runs in default name space and the qbg22sim runs in the newly created
++# bridge_ns name space. veth0 is in the default net name space where as
++# interface veth2 is in the bridge_ns name space
++#
++
++# Check if the name space already exists. Also check if the interface veth0
++# has been defined.
++if ip netns list | fgrep -qi bridge_ns
++then
++	if ip link | fgrep -qi veth0
++	then
++		if ip netns exec bridge_ns ip link | fgrep -qi veth2
++		then
++			exit 0		# veth0 and veth2 exists
++		else
++			echo interface veth2 missing
++			ip netns del bridge_ns
++		fi
++	else
++		ip netns del bridge_ns
++	fi
++fi
++
++# create veth pair(veth0, veth2)
++# with this mac address on veth0 e6:f1:20:5a:b0:e6 for evb testing
++ip link add veth0 address e6:f1:20:5a:b0:e6 type veth peer name veth2
++ip link set veth0 up
++ip addr add 50.0.0.1/24 dev veth0
++
++# create a new network namespace bridge_ns, bring up veth0 and assign an ip addr
++ip netns add bridge_ns
++
++# move veth2 to bridge_ns
++ip link set veth2 netns bridge_ns
++ip netns exec bridge_ns ip link set veth2 up
++ip netns exec bridge_ns ip addr add 50.0.0.2/24 dev veth2
++
++# exec bash in bridge_ns
++# ip netns exec bridge_ns bash
+diff --git a/test/qbg22sim.c b/test/qbg22sim.c
+index eeafd7e..9ca227b 100644
+--- a/test/qbg22sim.c
++++ b/test/qbg22sim.c
+@@ -59,7 +59,7 @@
+ #define	MYDEBUG		0
+ #define	DIM(x)		(sizeof(x)/sizeof(x[0]))
+ #define ETH_P_LLDP	0x88cc
+-#define ETH_P_ECP	0x8890
++#define ETH_P_ECP	0x8940
+ #define MACSTR		"%02x:%02x:%02x:%02x:%02x:%02x"
+ #define MAC2STR(a)	(a)[0] & 0xff, (a)[1] & 0xff, (a)[2] & 0xff, \
+ 			(a)[3] & 0xff, (a)[4] & 0xff, (a)[5] & 0xff
+@@ -70,7 +70,7 @@
+ 
+ static char *progname;
+ static unsigned char eth_p_lldp[2] = { 0x88, 0xcc };
+-static unsigned char eth_p_ecp[2] = { 0x88, 0x90 };
++static unsigned char eth_p_ecp[2] = { ETH_P_ECP >> 8, ETH_P_ECP & 0xff };
+ 
+ static int verbose;
+ static char *tokens[1024];	/* Used to parse command line params */
+@@ -118,7 +118,7 @@ struct lldp {			/* LLDP DUs */
+ unsigned long runtime;		/* Program run time in seconds */
+ static struct lldp *lldphead;	/* List of commands */
+ static struct lldp *er_ecp;	/* Expected replies ECP protocol */
+-static struct lldp *er_evb;	/* Expected replies ECP protocol */
++static struct lldp *er_evb;	/* Expected replies EVB protocol */
+ 
+ struct ecphdr {			/* ECP header received */
+ 	unsigned char version;	/* Version number */
+@@ -534,7 +534,10 @@ static int addone(void)
+ 		exit(3);
+ 	p->opr = valid_cmd();
+ 	if (p->opr) {
+-		p->ether = validate("88:90", 0);
++		char ecp_str[8];
++
++		sprintf(ecp_str, "%02x:%02x", eth_p_ecp[0], eth_p_ecp[1]);
++		p->ether = validate(ecp_str, 0);
+ 		goto out;
+ 	}
+ 	p->dst = validate(tokens[1], 0);
+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,17 +466,13 @@ 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"
++Define a profile and show its definition.
++.sp 1
+ .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
+-.EE
+-.sp 1
+ Copies the entry named
+ .I thomas2
+ and assigns its contents to the name
+@@ -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..8a423fb 100644
+--- a/test/vdptest.c
++++ b/test/vdptest.c
+@@ -29,7 +29,27 @@
+  * - associate a VSI
+  * - disassociate a VSI
+  * - receive a netlink message from lldpad when
+- *   - the switch de-associates the VSI profile (switch data base cleaned)
++ *    - the switch de-associates the VSI profile (switch data base cleaned)
++ *
++ * Note:
++ * libvirtd is currently the only production code user of lldpad netlink
++ * interface. It uses
++ * - no qos: always set to 0.
++ * - only one mac/macvlan pair.
++ * - netlink message format 1 (no qos/vlanid change on switch side, no group
++ *   id support at all)
++ *
++ * Netlink message format 1 is the default and does not
++ * - expect vlanid etc back from switch
++ * - use the vsi.maclist.qos member at all.
++ *
++ * Netlink message format 2 is selected when
++ * - group id is entered in the map keyword
++ * - 2mgrid is selected as keyword to specified long manager identifier
++ * - replacement vlan identifier is specified in the map keyword
++ * - hints keyword is specified.
++ * This format handles a reply from the switch and compares returned vlan/qos
++ * values.
+  */
+ 
+ #include <stdint.h>
+@@ -40,7 +60,10 @@
+ #include <errno.h>
+ #include <ctype.h>
+ #include <stdarg.h>
++#include <time.h>
++#include <stdbool.h>
+ 
++#include <sys/time.h>
+ #include <sys/socket.h>
+ #include <sys/ioctl.h>
+ 
+@@ -48,15 +71,17 @@
+ #include <linux/netlink.h>
+ #include <linux/rtnetlink.h>
+ 
++#include <net/if.h>
+ #include <netlink/msg.h>
+ 
+ #include "clif.h"
+ #include "clif_msgs.h"
++#include "include/qbg22.h"
++#include "qbg_vdp22def.h"
++#include "qbg_vdpnl.h"
+ 
+-#define	UUIDLEN			16
+-#define	DIM(x)			(sizeof(x)/sizeof(x[0]))
+-#define	COPY_OP			"new="
+-#define	KEYLEN			16
++#define	COPY_OP		"new="
++#define	KEYLEN		16
+ #define CMD_ASSOC	'a'	/* Association */
+ #define CMD_DEASSOC	'd'	/* DE-Association */
+ #define CMD_PREASSOC	'p'	/* pre-Association */
+@@ -67,23 +92,710 @@
+ #define CMD_EXTERN	'E'	/* External command */
+ #define CMD_SETDF	'X'	/* Change defaults */
+ 
++#define	BAD_FILTER	250	/* VLAN error in filter data */
++
++#define	DIM(x)			(sizeof(x)/sizeof(x[0]))
++
++/*
++ * New version, implemented as library function and header file in lldpad-devel
++ * package.
++ *
++ * Netlink message for QBG 2.2 ratified standard
++ */
++
++enum {					/* 802.1Qbg VDP ratified standard */
++	IFLA_PORT_VSI_TYPE22 = IFLA_PORT_MAX,
++	IFLA_PORT_VSI_FILTER,
++	__IFLA_PORT_MAX_NEW
++};
++
++#undef	IFLA_PORT_MAX
++#define IFLA_PORT_MAX (__IFLA_PORT_MAX_NEW - 1)
++
++/*
++ * Filter information data. Valid fields are determined by the
++ * filter information format type member named  'vsi_filter_fmt'. The
++ * number of the entries available is stored in the member named
++ * 'vsi_filter_num', see below.
++ */
++struct ifla_port_vsi_filter {
++	__u32 gpid;			/* Group Identifier*/
++	__u16 vlanid;			/* Vlan id and QoS */
++	__u8 mac[6];			/* MAC address */
++};
++
++struct ifla_port_vsi22 {		/* 802.1 Qbg Ratified standard */
++	__u8 vsi_mgrid[PORT_UUID_MAX];	/* Manager identifier */
++	__u8 vsi_uuid[PORT_UUID_MAX];	/* VSI identifier */
++	__u8 vsi_uuidfmt;		/* Format of UUID string */
++	__u8 vsi_type_id[3];		/* Type identifier */
++	__u8 vsi_type_version;		/* Type version identifier */
++	__u8 vsi_hints;			/* Hint bits */
++	__u8 vsi_filter_fmt;		/* Filter information format */
++	__u16 vsi_filter_num;		/* # of filter data entries */
++};
++
++/*
++ * Helper functions to construct a netlink message.
++ * The functions assume the nlmsghdr.nlmsg_len is set correctly.
++ */
++static void mynla_nest_end(struct nlmsghdr *nlh, struct nlattr *start)
++{
++	start->nla_type |= NLA_F_NESTED;
++	start->nla_len = (void *)nlh + nlh->nlmsg_len - (void *)start;
++}
++
++static struct nlattr *mynla_nest_start(struct nlmsghdr *nlh, int type)
++{
++	struct nlattr *ap = (struct nlattr *)((void *)nlh + nlh->nlmsg_len);
++
++	ap->nla_type = type;
++	nlh->nlmsg_len += NLA_HDRLEN;
++	return ap;
++}
++
++static void mynla_put(struct nlmsghdr *nlh, int type, size_t len, void *data)
++{
++	struct nlattr *ap = (struct nlattr *)((void *)nlh + nlh->nlmsg_len);
++
++	ap->nla_type = type;
++	ap->nla_len = NLA_HDRLEN + len;
++	memcpy(ap + 1, data, len);
++	nlh->nlmsg_len += NLA_HDRLEN + NLA_ALIGN(len);
++}
++
++static void mynla_put_u8(struct nlmsghdr *nlh, int type, __u8 data)
++{
++	mynla_put(nlh, type, sizeof data, &data);
++}
++
++static void mynla_put_u32(struct nlmsghdr *nlh, int type, __u32 data)
++{
++	mynla_put(nlh, type, sizeof data, &data);
++}
++
++static void *mynla_data(const struct nlattr *nla)
++{
++	return (char *)nla + NLA_HDRLEN;
++}
++
++static void mynla_get(const struct nlattr *nla, size_t len, void *data)
++{
++	memcpy(data, mynla_data(nla), len);
++}
++
++static __u32 mynla_get_u32(const struct nlattr *nla)
++{
++	return *(__u32 *)mynla_data(nla);
++}
++
++static __u16 mynla_get_u16(const struct nlattr *nla)
++{
++	return *(__u16 *)mynla_data(nla);
++}
++
++static int mynla_payload(const struct nlattr *nla)
++{
++	return nla->nla_len - NLA_HDRLEN;
++}
++
++static int mynla_type(const struct nlattr *nla)
++{
++	return nla->nla_type & ~NLA_F_NESTED;
++}
++
++static int mynla_ok(const struct nlattr *nla, int rest)
++{
++	return rest >= (int) sizeof(*nla) &&
++	       nla->nla_len >= sizeof(*nla) && nla->nla_len <= rest;
++}
++
++static 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;
++}
++
++static 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.
++ */
++static 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;
++}
++
++
++/*
++ * Return needed buffer space in bytes to construct netlink message setlink
++ * request. Return the maximum size needed.
++ * In netlink message format 1 only one MAC/VLAN pair is supported.
++ * In netlink message format 2 many MAC/VLAN/group pairs are supported.
++ */
++static size_t nlvsi_getsize(struct vdpnl_vsi *vsip)
++{
++	return NLMSG_SPACE(sizeof(struct ifinfomsg))	/* Header */
++		+ mynla_total_size(IFNAMSIZ + 1)	/* IFLA_IFNAME */
++		+ mynla_total_size(sizeof(struct nlattr)) /* IFLA_VF_PORTS */
++		+ mynla_total_size(4)		/* VF_PORTS */
++		+ mynla_total_size(4)		/* VF_PORT */
++		+ mynla_total_size(1)		/* PORT_VDP_REQUEST */
++		+ mynla_total_size(2)		/* PORT_VDP_RESPONSE */
++		+ mynla_total_size(PORT_UUID_MAX)	/* INSTANCE UUID */
++		+ mynla_total_size(sizeof(struct ifla_port_vsi))
++						/* VSI_TYPE */
++		+ mynla_total_size(sizeof(struct nlattr))
++						/* IFLA_VFINFO_LIST */
++		+ mynla_total_size(sizeof(struct nlattr))
++						/* IFLA_VF_INFO */
++		+ mynla_total_size(sizeof(struct ifla_vf_mac))
++						/* IFLA_VF_MAC */
++		+ mynla_total_size(sizeof(struct ifla_vf_vlan ))
++						/* IFLA_VF_VLAN */
++		+ mynla_total_size(sizeof(struct ifla_port_vsi22))
++		+ mynla_total_size(vsip->macsz
++					* sizeof(struct ifla_port_vsi_filter));
++}
++
++/*
++ * Test input and return false on error.
++ */
++static int nlvsi_isgood(struct vdpnl_vsi *vsip)
++{
++	if (!vsip->macsz)
++		return 0;
++	switch (vsip->filter_fmt) {
++	case VDP22_FFMT_MACVID:
++	case VDP22_FFMT_VID:
++	case VDP22_FFMT_GROUPMACVID:
++	case VDP22_FFMT_GROUPVID:
++		break;
++	default:
++		return 0;
++	}
++
++	/*
++	 * Adjust for different request numbering.
++	 * Draft 0.2 starts from 0 and ratified standard starts from 1.
++	 * Sequence is PREASSOC, PREASSOC_RR, ASSOC, DEASSOC
++	 *
++	 * Expect "offical" draft 0.2 numbering defined in
++	 * /usr/include/linux/if_link.h
++	 */
++	switch (vsip->request + 1) {
++	case VDP22_PREASSOC:
++	case VDP22_PREASSOC_WITH_RR:
++	case VDP22_ASSOC:
++	case VDP22_DEASSOC:
++		break;
++	default:
++		return 0;
++	}
++
++	switch (vsip->vsi_idfmt) {
++	case VDP22_ID_IP4:
++	case VDP22_ID_IP6:
++	case VDP22_ID_MAC:
++	case VDP22_ID_LOCAL:
++	case VDP22_ID_UUID:
++		break;
++	default:
++		return 0;
++	}
++
++	if (vsip->hints && (vsip->hints != VDP22_MIGTO
++	    && vsip->hints != VDP22_MIGFROM))
++		return 0;
++
++	if (vsip->vsi_typeid >= (1 << 24))	/* 3 byte type identifier */
++		return 0;
++	return 1;
++}
++
++/*
++ * Build netlink message 1 format.
++ */
++static void nlf1(struct vdpnl_vsi *vsip, struct nlmsghdr *nlh)
++{
++	struct nlattr *port, *ports;
++	struct ifla_port_vsi myvsi;
++	int i;
++
++	ports = mynla_nest_start(nlh, IFLA_VF_PORTS);
++	port = mynla_nest_start(nlh, IFLA_VF_PORT);
++	mynla_put_u8(nlh, IFLA_PORT_REQUEST, vsip->request);
++	memset(&myvsi, 0, sizeof(myvsi));
++	myvsi.vsi_mgr_id = vsip->vsi_mgrid;
++	myvsi.vsi_type_id[2] = (vsip->vsi_typeid >> 16) & 0xff;
++	myvsi.vsi_type_id[1] = (vsip->vsi_typeid >> 8) & 0xff;
++	myvsi.vsi_type_id[0] = vsip->vsi_typeid & 0xff;
++	myvsi.vsi_type_version = vsip->vsi_typeversion;
++	mynla_put(nlh, IFLA_PORT_VSI_TYPE, sizeof(myvsi), &myvsi);
++	mynla_put(nlh, IFLA_PORT_INSTANCE_UUID, PORT_UUID_MAX, vsip->vsi_uuid);
++	mynla_nest_end(nlh, port);
++	mynla_nest_end(nlh, ports);
++
++	ports = mynla_nest_start(nlh, IFLA_VFINFO_LIST);
++	for (i = 0; i < vsip->macsz; ++i) {
++		port = mynla_nest_start(nlh, IFLA_VF_INFO);
++		if (vsip->filter_fmt == VDP22_FFMT_MACVID) {
++			struct ifla_vf_mac vf_mac = {
++				.vf = PORT_SELF_VF
++			};
++
++			memcpy(vf_mac.mac, vsip->maclist[i].mac, ETH_ALEN);
++			mynla_put(nlh, IFLA_VF_MAC, sizeof(vf_mac), &vf_mac);
++		}
++		if (vsip->filter_fmt) {
++			struct ifla_vf_vlan vf_vlan = {
++				.vf = PORT_SELF_VF,
++				.vlan = vsip->maclist[i].vlan & 0xfff,
++				.qos = (vsip->maclist[i].vlan >> 12) & 7
++			};
++
++			mynla_put(nlh, IFLA_VF_VLAN, sizeof(vf_vlan), &vf_vlan);
++		}
++		mynla_nest_end(nlh, port);
++	}
++	mynla_nest_end(nlh, ports);
++}
++
++/*
++ * Build netlink message 2 format.
++ */
++static void nlf2(struct vdpnl_vsi *vsip, struct nlmsghdr *nlh)
++{
++	struct ifla_port_vsi22 myvsi;
++	struct ifla_port_vsi_filter fdata[vsip->macsz];
++	struct nlattr *port, *ports;
++	int i;
++
++	memset(&myvsi, 0, sizeof(myvsi));
++	memset(fdata, 0, sizeof(fdata));
++	ports = mynla_nest_start(nlh, IFLA_VF_PORTS);
++	port = mynla_nest_start(nlh, IFLA_VF_PORT);
++	mynla_put_u32(nlh, IFLA_PORT_VF, vsip->vf);
++	mynla_put_u8(nlh, IFLA_PORT_REQUEST, vsip->request);
++	mynla_put(nlh, IFLA_PORT_INSTANCE_UUID, PORT_UUID_MAX, vsip->vsi_uuid);
++	myvsi.vsi_type_id[2] = (vsip->vsi_typeid >> 16) & 0xff;
++	myvsi.vsi_type_id[1] = (vsip->vsi_typeid >> 8) & 0xff;
++	myvsi.vsi_type_id[0] = vsip->vsi_typeid & 0xff;
++	myvsi.vsi_type_version = vsip->vsi_typeversion;
++	myvsi.vsi_uuidfmt = vsip->vsi_idfmt;
++	memcpy(myvsi.vsi_mgrid, vsip->vsi_mgrid2, sizeof(myvsi.vsi_mgrid));
++	myvsi.vsi_hints = vsip->hints;
++	myvsi.vsi_filter_fmt = vsip->filter_fmt;
++	myvsi.vsi_filter_num = vsip->macsz;
++	mynla_put(nlh, IFLA_PORT_VSI_TYPE22, sizeof(myvsi), &myvsi);
++	for (i = 0; i < vsip->macsz; ++i) {
++		struct ifla_port_vsi_filter *ep = &fdata[i];
++
++		ep->vlanid = vsip->maclist[i].vlan;
++		if (vsip->filter_fmt == VDP22_FFMT_MACVID
++		    || vsip->filter_fmt == VDP22_FFMT_GROUPMACVID)
++			memcpy(ep->mac, vsip->maclist[i].mac, sizeof(ep->mac));
++		if (vsip->filter_fmt == VDP22_FFMT_GROUPVID
++		    || vsip->filter_fmt == VDP22_FFMT_GROUPMACVID)
++			ep->gpid = vsip->maclist[i].gpid;
++	}
++	mynla_put(nlh, IFLA_PORT_VSI_FILTER, sizeof(fdata), fdata);
++	mynla_nest_end(nlh, port);
++	mynla_nest_end(nlh, ports);
++}
++
++/*
++ * Construct the netlink request message for the VSI profile.
++ * Return number of bytes occupied in buffer or errno on error.
++ */
++static int vdpnl_request_build(struct vdpnl_vsi *vsip, unsigned char *buf,
++			       size_t len)
++{
++	struct nlmsghdr *nlh = (struct nlmsghdr *)buf;
++	struct ifinfomsg ifinfo;
++
++	if (!nlvsi_isgood(vsip))
++		return -EINVAL;
++	if (nlvsi_getsize(vsip) > len)
++		return -ENOMEM;
++	memset(buf, 0, len);
++	memset(&ifinfo, 0, sizeof(ifinfo));
++	nlh->nlmsg_type = RTM_SETLINK;
++	nlh->nlmsg_pid = getpid();
++	nlh->nlmsg_seq = vsip->req_seq;
++	nlh->nlmsg_flags = NLM_F_REQUEST;
++	nlh->nlmsg_len = NLMSG_SPACE(sizeof ifinfo);
++	ifinfo.ifi_index = vsip->ifindex;
++	ifinfo.ifi_family = AF_UNSPEC;
++	memcpy(NLMSG_DATA(nlh), &ifinfo, sizeof(ifinfo));
++	mynla_put(nlh, IFLA_IFNAME, 1 + strlen(vsip->ifname), vsip->ifname);
++	if (vsip->nl_version == vdpnl_nlf2)
++		nlf2(vsip, nlh);
++	else
++		nlf1(vsip, nlh);
++	return nlh->nlmsg_len;
++}
++
++/*
++ * Read the contents of the IFLA_PORT_VSI_FILTER netlink attribute.
++ * It is an array of struct ifla_port_vsi_filter entries.
++ * Return 0 on success and errno on failure.
++ *
++ * Code to parse netlink message format 2.
++ */
++static void parse_filter_data(struct vdpnl_vsi *vsip, struct nlattr *tb)
++{
++	int i = 0;
++	struct ifla_port_vsi_filter elem[vsip->macsz];
++
++	mynla_get(tb, sizeof(elem), elem);
++	for (i = 0; i < vsip->macsz; ++i) {
++		struct vdpnl_mac *macp = &vsip->maclist[i];
++		struct ifla_port_vsi_filter *ep = &elem[i];
++
++		macp->vlan = ep->vlanid;
++		macp->gpid = ep->gpid;
++		memcpy(macp->mac, ep->mac, sizeof(macp->mac));
++	}
++}
++
++/*
++ * Read the contents of the IFLA_PORT_VSI_FILTER netlink attribute.
++ * Return 0 on success and errno on failure.
++ *
++ * Code to parse netlink message format 2.
++ */
++static int parse_vsi_type22(struct vdpnl_vsi *vsip, struct nlattr *tb,
++			    struct nlattr *tc)
++{
++	struct ifla_port_vsi22 myvsi;
++
++	mynla_get(tb, sizeof(myvsi), &myvsi);
++	vsip->filter_fmt = myvsi.vsi_filter_fmt;
++	if (vsip->macsz >= myvsi.vsi_filter_num) {
++		vsip->macsz = myvsi.vsi_filter_num;
++		parse_filter_data(vsip, tc);
++		return 0;
++	}
++	return -E2BIG;
++}
++
++/*
++ * Parse the IFLA_VF_PORT block of the netlink message.
++ * Return 1 when uuid found and 0 when not found and errno else.
++ * Set length of filter pair on return.
++ *
++ * Code to parse netlink message format 1.
++ */
++static int scan_vf_port(struct vdpnl_vsi *vsi, struct nlattr *tb)
++{
++	struct nlattr *vf[IFLA_PORT_MAX + 1];
++	int found = 0, rc;
++
++	memset(vf, 0, sizeof(vf));
++	rc = mynla_parse(vf, DIM(vf), mynla_data(tb), mynla_payload(tb));
++	if (rc)
++		return -EINVAL;
++	if (vf[IFLA_PORT_INSTANCE_UUID]) {
++		if (!memcmp(mynla_data(vf[IFLA_PORT_INSTANCE_UUID]),
++			    vsi->vsi_uuid, sizeof(vsi->vsi_uuid))
++		     && vf[IFLA_PORT_RESPONSE]) {
++			found = 1;
++			vsi->response = mynla_get_u16(vf[IFLA_PORT_RESPONSE]);
++		}
++	} else
++		return -EINVAL;
++	if (found && vf[IFLA_PORT_VSI_TYPE22] && vf[IFLA_PORT_VSI_FILTER])
++		rc = parse_vsi_type22(vsi, vf[IFLA_PORT_VSI_TYPE22],
++				      vf[IFLA_PORT_VSI_FILTER]);
++	else
++		vsi->macsz = 0;
++	return found;
++}
++
++/*
++ * Parse the IFLA_VF_PORTS block of the netlink message. Expect many
++ * IFLA_VF_PORT attribute and search the one we are looking for.
++ * Return zero on success and errno else.
++ *
++ * Code to parse netlink message format 1.
++ */
++static int scan_vf_ports(struct vdpnl_vsi *vsi, struct nlattr *tb)
++{
++	struct nlattr *pos;
++	int rest, rc = 0;
++
++	for (rest = mynla_payload(tb), pos = mynla_data(tb);
++		mynla_ok(pos, rest) && rc == 0; pos = mynla_next(pos, &rest)) {
++		if (mynla_type(pos) == IFLA_VF_PORT)
++			rc = scan_vf_port(vsi, pos);
++		else
++			rc = -EINVAL;
++	}
++	return rc;
++}
++
++/*
++ * Scan the GETLINK reply and parse the response for the UUID.
++ *
++ * Return
++ * < 0 on error
++ * 0 wanted UUID not in reply
++ * 1 found
++ */
++static int vdpnl_getreply_parse(struct vdpnl_vsi *p, unsigned char *buf,
++		size_t len)
++{
++	struct nlmsghdr *nlh = (struct nlmsghdr *)buf;
++	struct nlattr *tb[IFLA_MAX + 1];
++	int rc;
++
++	if (len < nlh->nlmsg_len)
++		return -ENOMEM;
++	memset(tb, 0, sizeof(tb));
++	rc = mynla_parse(tb, DIM(tb),
++			 (struct nlattr *)IFLA_RTA(NLMSG_DATA(nlh)),
++			 IFLA_PAYLOAD(nlh));
++	if (rc || !tb[IFLA_VF_PORTS])
++		return -EINVAL;
++	return scan_vf_ports(p, tb[IFLA_VF_PORTS]);
++}
++
++/*
++ * Parse a received netlink request message and check for errors.
++ * When a netlink error message is received, return it in the 3rd
++ * parameter.
++ *
++ * Return
++ * <0 on parse error.
++ * 1 when a netlink error response is received.
++ * 0 when no netlink error response
++ */
++static int vdpnl_getreply_error(unsigned char *buf, size_t len, int *error)
++{
++	struct nlmsghdr *nlh = (struct nlmsghdr *)buf;
++
++	if (len < nlh->nlmsg_len)
++		return -ENOMEM;
++	if (nlh->nlmsg_type == NLMSG_ERROR) {
++		struct nlmsgerr *err = NLMSG_DATA(nlh);
++
++		if (error)
++			*error = err->error;
++		return 1;
++	}
++	return 0;
++}
++
+ /*
+- * Set the define MYDEBUG to any value for detailed debugging
++ * Parse the IFLA_VF_PORT block of an unsolicited netlink message triggered
++ * after a dis-associated from switch.
++ * Set length of filter pair on return.
++ *
++ * Code to parse netlink message format 1.
+  */
++static int trigger_vf_port(struct vdpnl_vsi *vsi, struct nlattr *tb)
++{
++	struct nlattr *vf[IFLA_PORT_MAX + 1];
++	int rc;
++	struct ifla_port_vsi portvsi;
+ 
++	memset(vf, 0, sizeof(vf));
++	rc = mynla_parse(vf, DIM(vf), mynla_data(tb), mynla_payload(tb));
++	if (rc)
++		return -EINVAL;
++	if (vf[IFLA_PORT_INSTANCE_UUID])
++		mynla_get(vf[IFLA_PORT_INSTANCE_UUID], sizeof(vsi->vsi_uuid),
++			  vsi->vsi_uuid);
++	else
++		return -EINVAL;
++	if (vf[IFLA_PORT_REQUEST])
++		vsi->response = mynla_get_u16(vf[IFLA_PORT_REQUEST]);
++	else
++		return -EINVAL;
++	if (vf[IFLA_PORT_VF])
++		vsi->vf = mynla_get_u32(vf[IFLA_PORT_VF]);
++	else
++		return -EINVAL;
++	if (vf[IFLA_PORT_VSI_TYPE]) {
++		mynla_get(vf[IFLA_PORT_VSI_TYPE], sizeof portvsi, &portvsi);
++		vsi->vsi_mgrid = portvsi.vsi_mgr_id;
++		vsi->vsi_typeversion = portvsi.vsi_type_version;
++		vsi->vsi_typeid = portvsi.vsi_type_id[0] << 16
++				  | portvsi.vsi_type_id[1] << 8
++				  | portvsi.vsi_type_id[2] << 8;
++	} else
++		return -EINVAL;
++	vsi->macsz = 0;		/* No returned filter data */
++	return 0;
++}
++
++/*
++ * Parse the IFLA_VF_PORTS block of the netlink message. Expect many
++ * IFLA_VF_PORT attribute and search the one we are looking for.
++ * Return zero on success and errno else.
++ *
++ * Code to parse netlink message format 1.
++ */
++static int trigger_vf_ports(struct vdpnl_vsi *vsi, struct nlattr *tb)
++{
++	struct nlattr *pos;
++	int rest, rc = 0;
++
++	for (rest = mynla_payload(tb), pos = mynla_data(tb);
++		mynla_ok(pos, rest) && rc == 0; pos = mynla_next(pos, &rest)) {
++		if (mynla_type(pos) == IFLA_VF_PORT)
++			rc = trigger_vf_port(vsi, pos);
++		else
++			rc = -EINVAL;
++	}
++	return rc;
++}
++
++/*
++ * Parse the IFLA_VF_INFO block.
++ */
++static int trigger_vf_info(struct vdpnl_mac *p, struct nlattr *tb)
++{
++	struct nlattr *vf[IFLA_VF_MAX + 1];
++	struct ifla_vf_mac ifla_vf_mac;
++	struct ifla_vf_vlan ifla_vf_vlan;
++	int rc;
++
++	memset(vf, 0, sizeof(vf));
++	memset(&ifla_vf_mac, 0, sizeof(ifla_vf_mac));
++	memset(&ifla_vf_vlan, 0, sizeof(ifla_vf_vlan));
++	rc = mynla_parse(vf, DIM(vf), mynla_data(tb), mynla_payload(tb));
++	if (rc)
++		return -EINVAL;
++	if (vf[IFLA_VF_MAC]) {
++		mynla_get(vf[IFLA_VF_MAC], sizeof ifla_vf_mac, &ifla_vf_mac);
++		memcpy(p->mac, ifla_vf_mac.mac, sizeof(p->mac));
++	} else
++		return -EINVAL;
++	if (vf[IFLA_VF_VLAN]) {
++		mynla_get(vf[IFLA_VF_VLAN], sizeof ifla_vf_vlan, &ifla_vf_vlan);
++		p->vlan = ifla_vf_vlan.vlan & 0xfff;
++		p->qos = ifla_vf_vlan.qos & 0xf;
++	} else
++		return -EINVAL;
++	return 0;
++}
++
++/*
++ * Parse the IFLA_VFINFO_LIST block which contains blocks of VF_INFO blocks.
++ */
++static int trigger_vfinfo_list(struct vdpnl_vsi *p, struct nlattr *tb)
++{
++	struct nlattr *pos;
++	int i = 0, rest, rc = 0;
++
++	if (p->macsz)		/* This must be netlink format 2 */
++		return -EINVAL;
++	for (rest = mynla_payload(tb), pos = mynla_data(tb);
++		mynla_ok(pos, rest); pos = mynla_next(pos, &rest)) {
++		++p->macsz;
++	}
++	if (!p->macsz)		/* No VLAN/MAC pair */
++		return -EINVAL;
++	p->maclist = calloc(p->macsz, sizeof(*p->maclist));
++	if (!p->maclist) {
++		p->macsz = 0;
++		return -ENOMEM;
++	}
++	for (rest = mynla_payload(tb), pos = mynla_data(tb);
++			mynla_ok(pos, rest) && rc == 0;
++					++i, pos = mynla_next(pos, &rest)) {
++		if (mynla_type(pos) == IFLA_VF_INFO)
++			rc = trigger_vf_info(&p->maclist[i], pos);
++		else
++			rc = -EINVAL;
++	}
++	if (rc) {
++		free(p->maclist);
++		p->maclist = NULL;
++		p->macsz = 0;
++	}
++	return rc;
++}
++
++/*
++ * Scan an unsolicited message from lldpad and parse the response for the UUID.
++ *
++ * Return
++ * < 0 on error
++ * 0 success
++ */
++static int vdpnl_trigger_parse(struct vdpnl_vsi *p, unsigned char *buf,
++				size_t len)
++{
++	struct nlmsghdr *nlh = (struct nlmsghdr *)buf;
++	struct nlattr *tb[IFLA_MAX + 1];
++	int rc;
++
++	if (len < nlh->nlmsg_len)
++		return -ENOMEM;
++	memset(tb, 0, sizeof(tb));
++	rc = mynla_parse(tb, DIM(tb),
++			 (struct nlattr *)IFLA_RTA(NLMSG_DATA(nlh)),
++			 IFLA_PAYLOAD(nlh));
++	if (rc || !tb[IFLA_VF_PORTS] || !tb[IFLA_IFNAME]
++	    || !tb[IFLA_VFINFO_LIST])
++		return -EINVAL;
++	mynla_get(tb[IFLA_IFNAME], sizeof(p->ifname), p->ifname);
++	return trigger_vf_ports(p, tb[IFLA_VF_PORTS])
++		| trigger_vfinfo_list(p, tb[IFLA_VFINFO_LIST]);
++}
++
++
++/*
++ * Code for construction vdp protocol messages.
++ */
+ enum {
+ 	f_map,
+ 	f_mgrid,
+ 	f_typeid,
+ 	f_typeidver,
+-	f_uuid
++	f_uuid,
++	f_hints,
++	f_2mgrid
++};
++
++enum {
++	fid_clr = 0,			/* Returned filter check */
++	fid_ok = 1,			/* Filter changed ok */
++	fid_mod = 2			/* Filter modified unexpectedly */
+ };
+ 
+ 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 */
++	unsigned char flags;		/* Tested? */
+ };
+ 
++#define	CMDTABSZ	32		/* Table size for VSI commands */
+ static struct vdpdata {
+ 	char key[KEYLEN];	/* Profile name */
+ 	unsigned char modified;	/* Field altered */
+@@ -91,9 +803,20 @@ static struct vdpdata {
+ 	unsigned char mgrid;	/* Manager ID */
+ 	unsigned char typeidver;	/* Type ID version */
+ 	unsigned int typeid;	/* Type ID */
+-	unsigned char uuid[UUIDLEN];	/* Instance ID */
++	unsigned char uuid[PORT_UUID_MAX];	/* Instance ID */
++	unsigned char mgrid2[PORT_UUID_MAX];	/* Manager ID VDP22 */
+ 	struct macvlan addr[10];	/* Pairs of MAC/VLAN */
+-} vsidata[32];
++	unsigned char fif;	/* Filter info format */
++	unsigned char hints;	/* Migrate to/from hits */
++	unsigned char nlmsg_v;	/* Version of netlink message to use */
++} vsidata[CMDTABSZ];
++
++struct vdpback {			/* Reply data from lldpad */
++	unsigned char uuid[PORT_UUID_MAX];	/* Instance ID */
++	unsigned short resp;		/* Response */
++	unsigned char pairs;		/* # of returned VLAN */
++	struct macvlan addr[10];	/* Pairs of MAC/VLAN */
++};
+ 
+ static struct command {		/* Command structure */
+ 	char key[KEYLEN];	/* Name of profile to use */
+@@ -104,8 +827,9 @@ static struct command {		/* Command structure */
+ 	unsigned char no_err;	/* # of expected errors */
+ 	int errors[4];		/* Expected errors */
+ 	int rc;			/* Encountered error */
++	int sys_rc;		/* System error on send/receive of messages */
+ 	char *text;		/* Text to display */
+-} cmds[32], defaults = {	/* Default values in structure */
++} cmds[CMDTABSZ], defaults = {	/* Default values in structure */
+ 	.waittime = 1,
+ 	.repeats = 1,
+ 	.delay = 1000
+@@ -119,24 +843,6 @@ static int ifindex;		/* Index of ifname */
+ static char *ifname;		/* Interface to operate on */
+ static pid_t lldpad;		/* LLDPAD process identifier */
+ static int my_sock;		/* Netlink socket for lldpad talk */
+-static char mybuf[1024];	/* Buffer for netlink message decode */
+-
+-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_RESPONSE] = {
+-		.type = NLA_U16
+-	}
+-};
+ 
+ static void uuid2buf(const unsigned char *p, char *buf)
+ {
+@@ -146,167 +852,94 @@ static void uuid2buf(const unsigned char *p, char *buf)
+ 		p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]);
+ }
+ 
+-static int addit(char *format, ...)
++#if 0
++static void showmac(struct vdpnl_vsi *p)
+ {
+-	size_t left = strlen(mybuf);
+-	int c;
+-	va_list ap;
++	int i;
++	struct vdpnl_mac *macp = p->maclist;
+ 
+-	va_start(ap, format);
+-	c = vsnprintf(mybuf + left, sizeof mybuf - left, format, ap);
+-	va_end(ap);
+-	return (c < 0 || ((unsigned)c >= sizeof mybuf - left)) ? -1 : 0;
++	for (i = 0; i < p->macsz; ++i, ++macp)
++		printf("\tvlan:%hd qos:%d\n", macp->vlan, macp->qos);
+ }
++#endif
+ 
+-static int showerror(struct nlmsghdr *nlh)
++static int test_new(unsigned short new, unsigned short me)
+ {
+-	struct nlmsgerr *err = NLMSG_DATA(nlh);
++	unsigned short new_vlan = (new & 0xfff);
++	unsigned char new_qos = (new >> 12) & 0xf;
++	unsigned short vlan = (me & 0xfff);
++	unsigned char qos = (me >> 12) & 0xf;
+ 
+-	if (verbose)
+-		printf("%s setlink response:%d\n", progname, err->error);
+-	return err->error;
++	return (vlan == new_vlan && qos == new_qos);
+ }
+ 
+-static void parse_vfinfolist(struct nlattr *vfinfolist)
++static void expect_fid(struct vdpdata *vdp)
+ {
+-	struct nlattr *le1, *vf[IFLA_VF_MAX + 1];
+-	int rem;
+-
+-	addit("\tfound IFLA_VFINFO_LIST!\n");
+-	nla_for_each_nested(le1, vfinfolist, rem) {
+-		if (nla_type(le1) != IFLA_VF_INFO) {
+-			fprintf(stderr, "%s nested parsing of"
+-			    "IFLA_VFINFO_LIST failed\n", progname);
+-			return;
+-		}
+-		if (nla_parse_nested(vf, IFLA_VF_MAX, le1, ifla_vf_policy)) {
+-			fprintf(stderr, "%s nested parsing of "
+-			    "IFLA_VF_INFO failed\n", progname);
+-			return;
+-		}
+-
+-		if (vf[IFLA_VF_MAC]) {
+-			struct ifla_vf_mac *mac = RTA_DATA(vf[IFLA_VF_MAC]);
+-			unsigned char *m = mac->mac;
+-
+-			addit("\tIFLA_VF_MAC=%02x:%02x:%02x:"
+-			    " %02x:%02x:%02x\n",
+-			    m[0], m[1], m[2], m[3], m[4], m[5]);
+-		}
+-
+-		if (vf[IFLA_VF_VLAN]) {
+-			struct ifla_vf_vlan *vlan = RTA_DATA(vf[IFLA_VF_VLAN]);
++	int i;
++	struct macvlan *mac = vdp->addr;
++
++	printf(" expected");
++	for (i = 0; i < vdp->pairs; ++i, ++mac)
++		if( mac->flags == fid_clr)
++			printf(" [%hu,%hu]",
++				(mac->newvid ?: mac->vlanid) & 0xfff,
++				(mac->newvid ?: mac->vlanid) >> 12 & 0xf);
++}
+ 
+-			addit("\tIFLA_VF_VLAN=%d\n", vlan->vlan);
++static int test_fid(struct vdpnl_mac *new, struct vdpdata *vdp)
++{
++	int i;
++	struct macvlan *mac = vdp->addr;
++
++	for (i = 0; i < vdp->pairs; ++i, ++mac) {
++		if (mac->flags == fid_clr) {
++			if (test_new(new->vlan, mac->newvid ?: mac->vlanid)) {
++				mac->flags = fid_ok;
++				return 0;
++			}
+ 		}
+ 	}
++	return BAD_FILTER;
+ }
+ 
+-static void show_nlas(struct nlattr **tb, int max)
++static int compare_fid(struct vdpnl_vsi *back, struct vdpdata *vdp)
+ {
+-	int rem;
+-
+-	for (rem = 0; rem < max; ++rem) {
+-		if (tb[rem])
+-			printf("nlattr %02d type:%d len:%d\n", rem,
+-			    tb[rem]->nla_type, tb[rem]->nla_len);
++	int rc = 0, i;
++
++	for (i = 0; i < vdp->pairs; ++i)
++		vdp->addr[i].flags = fid_clr;
++	/*
++	 * Check each returned filter data. Should be in the list of newvid.
++	 */
++	for (i = 0; rc == 0 && i < back->macsz; ++i) {
++		rc |= test_fid(&back->maclist[i], vdp);
++		if (verbose >= 3) {
++			printf("%s fid:%d vlan:%hu qos:%hu",
++				progname, i, back->maclist[i].vlan & 0xfff,
++				(back->maclist[i].vlan >> 12) & 0xf);
++			if (rc)
++				expect_fid(vdp);
++			else
++				printf(" match ok");
++			printf("\n");
++		}
+ 	}
++	return rc;
+ }
+ 
+-static void showmsg(struct nlmsghdr *nlh, int *status)
++static int compare_vsi(struct vdpnl_vsi *p, struct vdpdata *vdp)
+ {
+-	struct nlattr *tb[IFLA_MAX + 1], *tb3[IFLA_PORT_MAX + 1];
+-	struct ifinfomsg ifinfo;
+-	char *ifname;
+-	int rem;
++	int rc = 0;
+ 
+-	if (status)
+-		*status = -1;
+-	if (nlh->nlmsg_type == NLMSG_ERROR) {
+-		if (status)
+-			*status = showerror(nlh);
+-		return;
+-	}
+-	memset(mybuf, 0, sizeof mybuf);
+-	addit("\tnlh.nl_pid:%d nlh_type:%d nlh_seq:%#x nlh_len:%#x\n",
+-	    nlh->nlmsg_pid, nlh->nlmsg_type, nlh->nlmsg_seq, nlh->nlmsg_len);
+-	memcpy(&ifinfo, NLMSG_DATA(nlh), sizeof ifinfo);
+-	addit("\tifinfo.family:%#x type:%#x index:%d flags:%#x change:%#x\n",
+-	    ifinfo.ifi_family, ifinfo.ifi_type, ifinfo.ifi_index,
+-	    ifinfo.ifi_flags, ifinfo.ifi_change);
+-	if (nlmsg_parse(nlh, sizeof ifinfo,
+-		(struct nlattr **)&tb, IFLA_MAX, NULL)) {
+-		fprintf(stderr, "%s error parsing request...\n", progname);
+-		return;
+-	}
+-	if (verbose >= 3)
+-		show_nlas(tb, IFLA_MAX);
+-	if (tb[IFLA_IFNAME]) {
+-		ifname = (char *)RTA_DATA(tb[IFLA_IFNAME]);
+-		addit("\tIFLA_IFNAME=%s\n", ifname);
+-	}
+-	if (tb[IFLA_OPERSTATE]) {
+-		rem = *(unsigned short *)RTA_DATA(tb[IFLA_OPERSTATE]);
+-		addit("\tIFLA_OPERSTATE=%d\n", rem);
+-	}
+-	if (tb[IFLA_VFINFO_LIST])
+-		parse_vfinfolist(tb[IFLA_VFINFO_LIST]);
+-	if (tb[IFLA_VF_PORTS]) {
+-		struct nlattr *tb_vf_ports;
+-
+-		addit("\tfound IFLA_VF_PORTS\n");
+-		nla_for_each_nested(tb_vf_ports, tb[IFLA_VF_PORTS], rem) {
+-
+-			if (nla_type(tb_vf_ports) != IFLA_VF_PORT) {
+-				fprintf(stderr, "%s not a IFLA_VF_PORT, "
+-				    " skipping\n", progname);
+-				continue;
+-			}
+-			if (nla_parse_nested(tb3, IFLA_PORT_MAX, tb_vf_ports,
+-				ifla_port_policy)) {
+-				fprintf(stderr, "%s nested parsing on level 2"
+-				    " failed\n", progname);
+-			}
+-			if (tb3[IFLA_PORT_VF])
+-				addit("\tIFLA_PORT_VF=%d\n",
+-				    *(uint32_t *) RTA_DATA(tb3[IFLA_PORT_VF]));
+-			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];
+-				addit("\tIFLA_PORT_VSI_TYPE=mgr_id:%d "
+-				    " type_id:%d typeid_version:%d\n",
+-				    pvsi->vsi_mgr_id, tid,
+-				    pvsi->vsi_type_version);
+-			}
+-			if (tb3[IFLA_PORT_INSTANCE_UUID]) {
+-				char uuidbuf[64];
+-				unsigned char *uuid;
++	if (verbose >= 2) {
++		char uuidbuf[64];
+ 
+-				uuid = (unsigned char *)
+-				    RTA_DATA(tb3[IFLA_PORT_INSTANCE_UUID]);
+-				uuid2buf(uuid, uuidbuf);
+-				addit("\tIFLA_PORT_INSTANCE_UUID=%s\n",
+-				    uuidbuf);
+-			}
+-			if (tb3[IFLA_PORT_REQUEST])
+-				addit("\tIFLA_PORT_REQUEST=%d\n", *(uint8_t *)
+-				    RTA_DATA(tb3[IFLA_PORT_REQUEST]));
+-			if (tb3[IFLA_PORT_RESPONSE]) {
+-				addit("\tIFLA_PORT_RESPONSE=%d\n", *(uint16_t *)
+-				    RTA_DATA(tb3[IFLA_PORT_RESPONSE]));
+-				*status = *(int *)
+-				    RTA_DATA(tb3[IFLA_PORT_RESPONSE]);
+-			}
+-		}
++		uuid2buf(p->vsi_uuid, uuidbuf);
++		printf("%s uuid:%s response:%d no_vlanid:%hd\n", progname,
++			uuidbuf, p->response, p->macsz);
+ 	}
+-	if (verbose >= 2)
+-		printf("%s", mybuf);
++	rc = compare_fid(p, vdp);
++	return rc;
+ }
+ 
+ /*
+@@ -314,35 +947,38 @@ static void showmsg(struct nlmsghdr *nlh, int *status)
+  *
+  * Return number of bytes received. 0 means timeout and -1 on error.
+  */
+-static int waitmsg(struct command *cp, int *status)
++static int lldp_waitmsg(int waittime, unsigned char *msgbuf, size_t msgbuf_len)
+ {
+-	struct msghdr msg;
++	struct timeval tv1, tv2, tv_res;
+ 	struct sockaddr_nl dest_addr;
+-	struct iovec iov;
+-	unsigned char msgbuf[1024];
+-	struct nlmsghdr *nlh = (struct nlmsghdr *)msgbuf;
++	struct iovec iov = {
++		.iov_base = msgbuf,
++		.iov_len = msgbuf_len
++	};
++	struct msghdr msg = {
++		.msg_name = &dest_addr,
++		.msg_namelen = sizeof(dest_addr),
++		.msg_iov = &iov,
++		.msg_iovlen = 1,
++		.msg_controllen = 0,
++		.msg_control = 0
++	};
+ 	int n, result = 0;
+ 	fd_set readfds;
+ 
+ 	struct timeval tv = {
+-		.tv_sec = cp->waittime
++		.tv_sec = waittime
+ 	};
+ 
+-	memset(&msgbuf, 0, sizeof msgbuf);
+-	memset(&dest_addr, 0, sizeof dest_addr);
+-	iov.iov_base = (void *)nlh;
+-	iov.iov_len = sizeof msgbuf;
+-	msg.msg_name = (void *)&dest_addr;
+-	msg.msg_namelen = sizeof(dest_addr);
+-	msg.msg_iov = &iov;
+-	msg.msg_iovlen = 1;
+-
+ 	if (verbose)
+ 		printf("%s Waiting %d seconds for message...\n", progname,
+-		    cp->waittime);
++		    waittime);
+ 	FD_ZERO(&readfds);
+ 	FD_SET(my_sock, &readfds);
++	gettimeofday(&tv1, NULL);
+ 	n = select(my_sock + 1, &readfds, NULL, NULL, &tv);
++	gettimeofday(&tv2, NULL);
++	timersub(&tv2, &tv1, &tv_res);
+ 	if (n <= 0) {
+ 		if (n < 0)
+ 			fprintf(stderr, "%s error netlink socket:%s\n",
+@@ -353,88 +989,119 @@ static int waitmsg(struct command *cp, int *status)
+ 				    progname);
+ 		return n;
+ 	}
++	memset(msgbuf, 0, msgbuf_len);
++	memset(&dest_addr, 0, sizeof(dest_addr));
+ 	result = recvmsg(my_sock, &msg, MSG_DONTWAIT);
+ 	if (result < 0)
+-		fprintf(stderr, "%s receive error:%s\n",
+-		    progname, strerror(errno));
+-	else {
+-		if (verbose)
+-			printf("%s received %d bytes from %d\n",
+-			    progname, result, dest_addr.nl_pid);
+-		showmsg(nlh, status);
+-	}
++		fprintf(stderr, "%s receive error:%s wait:%ld:%06ld\n\n",
++			progname, strerror(errno), tv_res.tv_sec,
++			tv_res.tv_usec);
++	else if (verbose)
++		printf("%s received %d bytes from %d wait:%ld:%06ld\n",
++			progname, result, dest_addr.nl_pid, tv_res.tv_sec,
++			tv_res.tv_usec);
+ 	return result;
+ }
+ 
+-static int lldp_wait(struct command *cp)
+-{
+-	int rc = 0;
+-	unsigned int cnt;
+-
+-	for (cnt = 0; cnt < cp->repeats && rc >= 0; ++cnt)
+-		if ((rc = waitmsg(cp, 0))) {
+-			cp->rc = 1;
+-			break;
+-		}
+-	return rc;
+-}
+-
+ /*
+- * Construct the GETLINK message to lldpad.
++ * Find out which vdp this unsolicited message was sent for.
+  */
+-static int mk_nlas(char *buf)
++static struct vdpdata *finduuid(unsigned char *uuid)
+ {
+-	int total;
+-	struct nlattr *nlap;
+-	char *cp;
+-	struct ifinfomsg *to = (struct ifinfomsg *)buf;
++	unsigned int i;
+ 
+-	to->ifi_index = ifindex;
+-	to->ifi_family = AF_UNSPEC;
+-	total = NLMSG_ALIGN(sizeof *to);
+-	nlap = (struct nlattr *)(buf + NLMSG_ALIGN(sizeof *to));
+-	nlap->nla_type = IFLA_IFNAME;
+-	nlap->nla_len = NLA_HDRLEN + NLA_ALIGN(1 + strlen(ifname));
+-	total += nlap->nla_len;
+-	cp = (char *)nlap + NLA_HDRLEN;
+-	strcpy(cp, ifname);
+-	return total;
++	for (i = 0; i < DIM(vsidata); ++i)
++		if (!memcmp(vsidata[i].uuid, uuid, sizeof(vsidata[i].uuid)))
++			return &vsidata[i];
++	return 0;
++}
++
++static int trigger_test(struct vdpnl_vsi *p)
++{
++	char uuid[64];
++	int rc = -1;
++
++	uuid2buf(p->vsi_uuid, uuid);
++	if (finduuid(p->vsi_uuid)) {
++		if (p->response == PORT_REQUEST_DISASSOCIATE)
++			rc = 1;
++	}
++	if (p->maclist)
++		free(p->maclist);
++	if (verbose >= 2)
++		printf("%s switch dis-assoc %s rc:%d\n", progname, uuid, rc);
++	return rc;
++}
++
++int vdpnl_trigger_parse(struct vdpnl_vsi *, unsigned char *, size_t);
++
++static void lldp_wait(struct command *cp)
++{
++	int rc = 0;
++	unsigned int cnt;
++	unsigned char rcvbuf[2 * 1024];
++	struct vdpnl_vsi p;
++
++	for (cnt = 0; cnt < cp->repeats && rc >= 0; ++cnt) {
++		cp->sys_rc = cp->rc = 0;
++		rc = lldp_waitmsg(cp->waittime, rcvbuf, sizeof(rcvbuf));
++		if (rc < 0) {
++			cp->sys_rc = rc;
++			break;
++		}
++		if (rc > 0) {	/* Check for de-assoc message */
++			memset(&p, 0, sizeof(p));
++			rc = vdpnl_trigger_parse(&p, rcvbuf, sizeof(rcvbuf));
++			if (rc < 0)
++				cp->sys_rc = rc;
++			else
++				cp->rc = trigger_test(&p);
++			break;
++		}
++	}
+ }
+ 
+ /*
+  * Send a GETLINK message to lldpad to query the status of the operation.
+  */
+-static int getlink(void)
++static int lldp_getlink(void)
+ {
+-	struct sockaddr_nl d_nladdr;
+-	struct msghdr msg;
+-	char buffer[256];
+-	struct nlmsghdr *nlh = (struct nlmsghdr *)buffer;
+-	struct iovec iov;
++	char msgbuf[256];
++	struct iovec iov = {
++		.iov_base = msgbuf,
++		.iov_len = sizeof(msgbuf),
++	};
++	struct sockaddr_nl dest_addr;
++	struct msghdr msg = {
++		.msg_name = &dest_addr,
++		.msg_namelen = sizeof(dest_addr),
++		.msg_iov = &iov,
++		.msg_iovlen = 1,
++		.msg_controllen = 0,
++		.msg_control = 0
++	};
++	struct nlmsghdr *nlh = (struct nlmsghdr *)msgbuf;
++	struct ifinfomsg ifinfo;
+ 	int rc;
+ 
+-	memset(buffer, 0, sizeof buffer);
+-	/* Destination address */
+-	memset(&d_nladdr, 0, sizeof d_nladdr);
+-	d_nladdr.nl_family = PF_NETLINK;
+-	d_nladdr.nl_pid = lldpad;
++	memset(msgbuf, 0, sizeof(msgbuf));
++	ifinfo.ifi_index = ifindex;
++	ifinfo.ifi_family = AF_UNSPEC;
+ 
+ 	/* Fill the netlink message header */
+-	nlh->nlmsg_len = NLMSG_HDRLEN + mk_nlas((char *)NLMSG_DATA(nlh));
+ 	nlh->nlmsg_pid = getpid();
+ 	nlh->nlmsg_flags = NLM_F_REQUEST;
+ 	nlh->nlmsg_type = RTM_GETLINK;
++	nlh->nlmsg_len = NLMSG_SPACE(sizeof(ifinfo));
++	memcpy(NLMSG_DATA(nlh), &ifinfo, sizeof(ifinfo));
++	mynla_put(nlh, IFLA_IFNAME, 1 + strlen(ifname), ifname);
++	iov.iov_len =  nlh->nlmsg_len;
+ 
+-	/* Iov structure */
+-	iov.iov_base = (void *)nlh;
+-	iov.iov_len = nlh->nlmsg_len;
++	/* Destination address */
++	memset(&dest_addr, 0, sizeof(dest_addr));
++	dest_addr.nl_family = PF_NETLINK;
++	dest_addr.nl_pid = lldpad;
+ 
+-	/* Msg */
+-	memset(&msg, 0, sizeof msg);
+-	msg.msg_name = (void *)&d_nladdr;
+-	msg.msg_namelen = sizeof d_nladdr;
+-	msg.msg_iov = &iov;
+-	msg.msg_iovlen = 1;
+ 	if ((rc = sendmsg(my_sock, &msg, 0)) == -1)
+ 		perror(progname);
+ 	if (verbose)
+@@ -445,195 +1112,219 @@ static int getlink(void)
+ /*
+  * Send a RTM_GETLINK message and retrieve the status of the pending
+  * command.
++ *
++ * Return
++ * <0 send/receive error
++ * 0  send/receive ok, but returned netlink message contains netlink error
++ * 1  send/receive ok, returned netlink message contains parsed response
++ * 2  send/receive ok, but no message returned at all
+  */
+-static int lldp_ack(struct command *cp)
++int vdpnl_getreply_error(unsigned char *, size_t, int *);
++int vdpnl_getreply_parse(struct vdpnl_vsi *, unsigned char *, size_t);
++
++static int lldp_recv(struct command *cp, struct vdpnl_vsi *p)
+ {
+-	int bytes;
+-	int status;
+-
+-	bytes = getlink();
+-	if (bytes <= 0)
+-		return bytes;
+-	bytes = waitmsg(cp, &status);
+-	if (bytes <= 0)
+-		return bytes;
+-	cp->rc = status;
++	unsigned int cnt;
++	int rc, rc2, bytes;
++	unsigned char rcvbuf[2 * 1024];
++
++	for (bytes = 0, cnt = 0; cnt < cp->repeats && bytes == 0; ++cnt) {
++		usleep(cp->delay * 1000);
++		cp->sys_rc = lldp_getlink();
++		if (cp->sys_rc < 0)
++			return cp->sys_rc;
++		cp->rc = cp->sys_rc = 0;
++		bytes = lldp_waitmsg(cp->waittime, rcvbuf, sizeof(rcvbuf));
++		if (bytes < 0)			/* Error */
++			return cp->sys_rc = bytes;
++		if (bytes > 0) {			/* Got reply */
++			rc2 = vdpnl_getreply_error(rcvbuf, sizeof(rcvbuf), &rc);
++			if (rc2 < 0) {		/* Parsing failed */
++				if (verbose)
++					printf("%s getlink errmsg parse "
++						"error:%d\n", progname, rc2);
++				return cp->sys_rc = cp->rc = rc2;
++			} else if (rc2 == 1) {	/* Error reply */
++				if (verbose)
++					printf("%s getlink error response:%d\n",
++						progname, rc);
++				cp->rc = rc;
++				return 0;
++			}
++			/* Normal reply, parsed ok */
++			rc2 = vdpnl_getreply_parse(p, rcvbuf, sizeof(rcvbuf));
++			if (rc2 < 0) {		/* Parsing failed */
++				if (verbose)
++					printf("%s getlink parse error rc:%d\n",
++						progname, rc2);
++				return cp->sys_rc = cp->rc = rc2;
++			} else if (rc2 == 1) {	/* Found reply */
++				cp->rc = p->response;
++				return 1;
++			} else if (rc2 == 0) {
++				/* Reply without UUID/RESPONSE attribute */
++				if (verbose >= 2)
++					printf("%s getlink parse UUID/RESPONSE"
++						" missing\n", progname);
++				cp->rc = -1;
++			}
++		}
++	}
++	return 2;
++}
++
++static int check_sendack(struct nlmsghdr *nlh, int *ack)
++{
++	struct nlmsgerr *err = NLMSG_DATA(nlh);
++
++	if (nlh->nlmsg_type != NLMSG_ERROR)
++		return -1;
+ 	if (verbose)
+-		printf("%s lldp_ack status:%d\n", progname, cp->rc);
+-	return bytes;
+-}
+-
+-static int addvfs(struct nl_msg *nl_msg, struct vdpdata *vdp, unsigned char cmd)
+-{
+-	struct nlattr *vfports, *vfport;
+-	struct ifla_port_vsi vsi;
+-	unsigned char op;
+-
+-	switch (cmd) {
+-	case CMD_ASSOC:
+-		op = PORT_REQUEST_ASSOCIATE;
+-		break;
+-	case CMD_DEASSOC:
+-		op = PORT_REQUEST_DISASSOCIATE;
+-		break;
+-	case CMD_PREASSOC:
+-		op = PORT_REQUEST_PREASSOCIATE;
+-		break;
+-	case CMD_RRPREASSOC:
+-		op = PORT_REQUEST_PREASSOCIATE_RR;
+-		break;
+-	}
+-
+-	vsi.vsi_mgr_id = vdp->mgrid;
+-	vsi.vsi_type_version = vdp->typeidver;
+-	vsi.vsi_type_id[2] = vdp->typeid >> 16;
+-	vsi.vsi_type_id[1] = vdp->typeid >> 8;
+-	vsi.vsi_type_id[0] = vdp->typeid;
+-
+-	if (!(vfports = nla_nest_start(nl_msg, IFLA_VF_PORTS)))
+-		return -ENOMEM;
+-	if (!(vfport = nla_nest_start(nl_msg, IFLA_VF_PORT)))
+-		return -ENOMEM;
+-	if (nla_put(nl_msg, IFLA_PORT_VSI_TYPE, sizeof vsi, &vsi) < 0)
+-		return -ENOMEM;
+-	if (nla_put(nl_msg, IFLA_PORT_INSTANCE_UUID, UUIDLEN, vdp->uuid) < 0)
+-		return -ENOMEM;
+-	if (nla_put(nl_msg, IFLA_PORT_REQUEST, sizeof op, &op) < 0)
+-		return -ENOMEM;
+-	nla_nest_end(nl_msg, vfport);
+-	nla_nest_end(nl_msg, vfports);
++		printf("%s setlink response:%d\n", progname, err->error);
++	*ack = err->error;
+ 	return 0;
+ }
+ 
+-static int addmacs(struct nl_msg *nl_msg, struct vdpdata *vdp)
+-{
+-	int i;
+-	struct nlattr *vfinfolist, *vfinfo;
+-
+-	if (vdp->pairs == 0)
+-		return 0;
+-	if (!(vfinfolist = nla_nest_start(nl_msg, IFLA_VFINFO_LIST)))
+-		return -ENOMEM;
+-	for (i = 0; i < vdp->pairs; ++i) {
+-		if (!(vfinfo = nla_nest_start(nl_msg, IFLA_VF_INFO)))
+-			return -ENOMEM;
+-
+-		if (vdp->addr[i].mac) {
+-			struct ifla_vf_mac ifla_vf_mac;
+-
+-			ifla_vf_mac.vf = PORT_SELF_VF;
+-			memcpy(ifla_vf_mac.mac, vdp->addr[i].mac, ETH_ALEN);
+-			if (nla_put(nl_msg, IFLA_VF_MAC, sizeof ifla_vf_mac,
+-				&ifla_vf_mac) < 0)
+-				return -ENOMEM;
+-		}
+-
+-		if (vdp->addr[i].vlanid) {
+-			struct ifla_vf_vlan ifla_vf_vlan = {
+-				.vf = PORT_SELF_VF,
+-				.vlan = vdp->addr[i].vlanid,
+-				.qos = 0,
+-			};
+-
+-			if (nla_put(nl_msg, IFLA_VF_VLAN, sizeof ifla_vf_vlan,
+-				&ifla_vf_vlan) < 0)
+-				return -ENOMEM;
+-		}
+-		nla_nest_end(nl_msg, vfinfo);
+-	}
+-	nla_nest_end(nl_msg, vfinfolist);
+-	return 0;
+-}
+-
+-/*
+- * Build the netlink message, return total length of message
+- */
+-static int buildmsg(unsigned char *buf, size_t len, unsigned char cmd,
+-    struct vdpdata *vdp)
+-{
+-	struct nlmsghdr *nlh;
+-	struct nl_msg *nl_msg;
+-	struct ifinfomsg ifinfo;
+-
+-	nl_msg = nlmsg_alloc();
+-	if (!nl_msg)
+-		goto err_exit;
+-	ifinfo.ifi_index = ifindex;
+-	ifinfo.ifi_family = AF_UNSPEC;
+-	if (nlmsg_append(nl_msg, &ifinfo, sizeof ifinfo, NLMSG_ALIGNTO) < 0)
+-		goto err_exit;
+-	if (addmacs(nl_msg, vdp))
+-		goto err_exit;
+-	if (addvfs(nl_msg, vdp, cmd))
+-		goto err_exit;
+-	/*
+-	 * Fill the netlink message header
+-	 */
+-	nlh = nlmsg_hdr(nl_msg);
+-	nlh->nlmsg_type = RTM_SETLINK;
+-	nlh->nlmsg_pid = getpid();
+-	nlh->nlmsg_flags = NLM_F_REQUEST;
+-	if (len < nlh->nlmsg_len)
+-		goto err_exit;
+-	memcpy(buf, nlh, nlh->nlmsg_len);
+-	nlmsg_free(nl_msg);
+-	return 0;
+-
+-err_exit:
+-	if (nl_msg)
+-		nlmsg_free(nl_msg);
+-	fprintf(stderr, "%s: can not build netlink message\n", progname);
+-	return -ENOMEM;
+-}
+-
+ /*
+  * Send a netlink message to lldpad. Its a SETLINK message to trigger an
+  * action. LLDPAD responds with an error netlink message indicating if the
+  * profile was accepted.
+  * LLDPAD sends negative numbers as error indicators.
+  */
+-static int lldp_send(struct command *cp, struct vdpdata *vdp)
++static int lldp_send(struct vdpnl_vsi *vsi, int waittime, int *ack)
+ {
+-	unsigned char sndbuf[1024];
+-	struct iovec iov;
+-	struct msghdr msg;
+-	struct sockaddr_nl d_nladdr;
+-	struct nlmsghdr *nlh = (struct nlmsghdr *)sndbuf;
+-	int rc, vsiok = 0;
++	unsigned char msgbuf[2 * 1024];
++	struct iovec iov = {
++		.iov_base = msgbuf,
++		.iov_len = sizeof(msgbuf),
++	};
++	struct sockaddr_nl dest_addr = {
++		.nl_family = AF_NETLINK,
++		.nl_groups = 0,
++		.nl_pid = lldpad		/* Target PID */
++	};
++	struct msghdr msg = {
++		.msg_name = &dest_addr,
++		.msg_namelen = sizeof(dest_addr),
++		.msg_iov = &iov,
++		.msg_iovlen = 1,
++		.msg_controllen = 0,
++		.msg_control = 0
++	};
++	struct nlmsghdr *nlh = (struct nlmsghdr *)msgbuf;
++	int rc;
+ 
+-	memset(&d_nladdr, 0, sizeof d_nladdr);
+-	d_nladdr.nl_family = AF_NETLINK;
+-	d_nladdr.nl_pid = lldpad;	/* Target PID */
++	memset(msgbuf, 0, sizeof msgbuf);
++	rc = vdpnl_request_build(vsi, msgbuf, sizeof(msgbuf));
++	if (rc < 0) {
++		fprintf(stderr, "%s: can not build netlink msg (ver %d): %d\n",
++			progname, vsi->nl_version, rc);
++		return rc;
++	}
+ 
+-	memset(sndbuf, 0, sizeof sndbuf);
+-	rc = buildmsg(sndbuf, sizeof sndbuf, cp->cmd, vdp);
+-	if (rc)
+-		return -ENOMEM;
+-	iov.iov_base = (void *)nlh;
+-	iov.iov_len = nlh->nlmsg_len;
+-
+-	/* Msg */
+-	memset(&msg, 0, sizeof msg);
+-	msg.msg_name = (void *)&d_nladdr;
+-	msg.msg_namelen = sizeof d_nladdr;
+-	msg.msg_iov = &iov;
+-	msg.msg_iovlen = 1;
++	iov.iov_len = nlh->nlmsg_len;		/* Set  msg length */
+ 	rc = sendmsg(my_sock, &msg, 0);
+-	if (rc < 0)
++	if (rc < 0){
+ 		perror(progname);
+-	else {
+-		if (verbose)
+-			printf("%s send message to %d --> rc:%d\n", progname,
+-			    lldpad, rc);
+-		rc = waitmsg(cp, &vsiok);
+-		if (rc > 0)
+-			rc = vsiok;
+-		else if (rc == 0)	/* Time out */
+-			rc = -1;
++		return rc;
+ 	}
++	if (verbose)
++		printf("%s send message to %d --> rc:%d\n", progname, lldpad,
++			rc);
++	rc = lldp_waitmsg(waittime, msgbuf, sizeof(msgbuf));
++	if (rc > 0)
++		 rc = check_sendack(nlh, ack);
++	else if (rc == 0)	/* Time out */
++		rc = -1;
+ 	return rc;
+ }
+ 
++static unsigned char cvt_request(unsigned char cmd)
++{
++	switch (cmd) {
++	case CMD_ASSOC:
++		return PORT_REQUEST_ASSOCIATE;
++	case CMD_DEASSOC:
++		return PORT_REQUEST_DISASSOCIATE;
++	case CMD_PREASSOC:
++		return PORT_REQUEST_PREASSOCIATE;
++	case CMD_RRPREASSOC:
++		return PORT_REQUEST_PREASSOCIATE_RR;
++	}
++	return PORT_REQUEST_PREASSOCIATE;
++}
++
++/*
++ * Convert vdp to vsi structure.
++ */
++static void vdp2vsi(struct vdpnl_vsi *p, unsigned char cmd, struct vdpdata *vdp)
++{
++	int i;
++	static unsigned long nlseq;
++	struct vdpnl_mac *mac = p->maclist;
++
++	strncpy(p->ifname, ifname, sizeof(p->ifname) - 1);
++	p->ifindex = ifindex;
++	p->vf = PORT_SELF_VF;
++	p->nl_version = vdp->nlmsg_v;
++	p->request = cvt_request(cmd);
++	p->req_seq = ++nlseq;
++	p->vsi_typeversion = vdp->typeidver;
++	p->vsi_typeid = vdp->typeid;
++	p->vsi_mgrid = vdp->mgrid;
++	p->hints = vdp->hints;
++	p->vsi_idfmt = VDP22_ID_UUID;
++	memcpy(p->vsi_uuid, vdp->uuid, sizeof(p->vsi_uuid));
++	memcpy(p->vsi_mgrid2, vdp->mgrid2, sizeof(p->vsi_mgrid2));
++	p->filter_fmt = vdp->fif;
++	for (i = 0; i < p->macsz; ++ i, ++mac) {
++		mac->vlan = vdp->addr[i].vlanid;
++		mac->gpid = vdp->addr[i].gpid;
++		memcpy(mac->mac, vdp->addr[i].mac, sizeof(mac->mac));
++	}
++}
++
++static void clear_vsi(struct vdpnl_vsi *vsi, struct vdpnl_mac *macp, size_t sz)
++{
++	memset(vsi, 0, sizeof(*vsi));
++	memset(macp, 0, sizeof(*macp) * sz);
++	vsi->macsz = sz;
++	vsi->maclist = macp;
++}
++
++/*
++ * Convey a message to lldpad.
++ *
++ * Return
++ * 1 for response from lldpad GETLINK command
++ * 0 for error response as sendack from lldpad (in cp->rc)
++ * -1 for system error (in cp->sys_rc)
++ */
++static void cmd_lldp(struct command *cp, struct vdpdata *vdp)
++{
++	int lldpad_cmdack;
++	struct vdpnl_mac mac[vdp->pairs];
++	struct vdpnl_vsi vsi;
++
++	/* Send command */
++	clear_vsi(&vsi, mac, vdp->pairs);
++	vdp2vsi(&vsi, cp->cmd, vdp);
++	cp->rc = 0;
++	cp->sys_rc = lldp_send(&vsi, cp->waittime, &lldpad_cmdack);
++	if (cp->sys_rc < 0)
++		return;
++	cp->rc = lldpad_cmdack;
++	if (cp->rc)
++		return;
++	/* Receive reply */
++	clear_vsi(&vsi, mac, vdp->pairs);
++	memcpy(vsi.vsi_uuid, vdp->uuid, sizeof(vsi.vsi_uuid));
++	if (lldp_recv(cp, &vsi) == 1) {
++		if (vsi.macsz)
++			cp->rc = compare_vsi(&vsi, vdp);
++	}
++}
++
+ /*
+  * Open netlink socket to talk to lldpad daemon.
+  */
+@@ -689,13 +1380,14 @@ static void lldpad_pid(void)
+ static unsigned long getnumber(char *key, char *word, char stopchar, int *ec)
+ {
+ 	char *endp;
+-	unsigned long no = strtoul(word, &endp, 0);
++	unsigned long no;
+ 
+ 	if (word == 0 || *word == '\0') {
+ 		fprintf(stderr, "key %s has missing number\n", key);
+ 		*ec = 1;
+ 		return 0;
+ 	}
++	no = strtoul(word, &endp, 0);
+ #ifdef MYDEBUG
+ 	printf("%s:stopchar:%c endp:%c\n", __func__, stopchar, *endp);
+ #endif
+@@ -759,37 +1451,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;
++		}
+ 	}
+-	vlan = getnumber("map", value, '-', &ec);
++	memset(x, 0, sizeof(x));
++	slash = strchr(value, '/');
++	if (slash) {		/* Expect replacement vid incl. changed QoS */
++		*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 %#lx too high\n",
++				progname, newvlan);
++			return -1;
++		}
++		profile->nlmsg_v = vdpnl_nlf2;
++	}
++	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 = VDP22_FFMT_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 = VDP22_FFMT_MACVID;
+ 	}
+-	/* 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 = vdpnl_nlf2;
+ 	}
+ #ifdef MYDEBUG
+ 	for (i = 0; i < ETH_ALEN; ++i)
+@@ -797,18 +1530,34 @@ 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, profile->fif);
++		return -1;
++	}
++	profile->fif = fif;
+ 	for (ec = 0; ec < profile->pairs; ++ec) {
+-		for (i = 0; i < ETH_ALEN; ++i)
+-			if (profile->addr[ec].mac[i] != x[i])
+-				break;
+-		if (i == ETH_ALEN) {
+-			fprintf(stderr, "%s duplicate mac address %s\n",
+-			    progname, value);
++		if (DIM(profile->addr) == i) {
++			fprintf(stderr, "%s too many filter addresses\n",
++			    progname);
+ 			return -1;
+ 		}
++		if (profile->fif == VDP22_FFMT_MACVID
++		    || profile->fif == VDP22_FFMT_GROUPMACVID)  {
++			for (i = 0; i < ETH_ALEN; ++i)
++				if (profile->addr[ec].mac[i] != x[i])
++					break;
++			if (i == ETH_ALEN) {
++				fprintf(stderr, "%s duplicate mac address %s\n",
++				    progname, value);
++			return -1;
++			}
++		}
+ 	}
+ 	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;
+@@ -818,7 +1567,7 @@ static int check_map(char *value, struct vdpdata *profile)
+ static int check_uuid(char *value, struct vdpdata *profile)
+ {
+ 	unsigned int rc;
+-	unsigned int p[UUIDLEN];
++	unsigned int p[PORT_UUID_MAX];
+ 
+ 	rc = sscanf(value, "%02x%02x%02x%02x-%02x%02x-%02x%02x-"
+ 		"%02x%02x-%02x%02x%02x%02x%02x%02x",
+@@ -828,11 +1577,11 @@ static int check_uuid(char *value, struct vdpdata *profile)
+ 	int i;
+ 
+ 	printf("cc=%d\n", rc);
+-	for (i = 0; i < UUIDLEN; ++i)
++	for (i = 0; i < PORT_UUID_MAX; ++i)
+ 		printf("p[%d]=%#x ", i, p[i]);
+ 	puts("");
+ #endif
+-	if (rc != UUIDLEN) {
++	if (rc != PORT_UUID_MAX) {
+ 		fprintf(stderr, "%s invalid uuid %s\n", progname, value);
+ 		return -1;
+ 	}
+@@ -858,7 +1607,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 +1629,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 +1641,17 @@ static int check_mgrid(char *value, struct vdpdata *profile)
+ 	unsigned long no;
+ 	int ec;
+ 
++	if (profile->nlmsg_v == vdpnl_nlf2) {
++		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 = vdpnl_nlf1;
+ 			profile->mgrid = no;
+ 			profile->modified |= 1 << f_mgrid;
++			memset(profile->mgrid2, 0, sizeof(profile->mgrid2));
+ 		} else {
+ 			ec = -1;
+ 			fprintf(stderr, "%s: invalid mgrid %ld\n", progname,
+@@ -908,6 +1664,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 == vdpnl_nlf1) {
++		fprintf(stderr, "%s: mgrid and 2mgrid specified\n", progname);
++		return -1;
++	}
++	memcpy(profile->mgrid2, value, sizeof(profile->mgrid2) - 1);
++	profile->mgrid2[sizeof(profile->mgrid2) - 1] = '\0';
++	profile->mgrid = 0;
++	profile->modified |= 1 << f_mgrid;
++	profile->nlmsg_v = vdpnl_nlf2;
++	return 0;
++}
++
++static int check_hints(char *value, struct vdpdata *profile)
++{
++	int rc = 0;
++
++	if(!strcmp(value, "to")) {
++		profile->hints = VDP22_MIGTO;
++		profile->modified |= 1 << f_hints;
++		profile->nlmsg_v = vdpnl_nlf2;
++	} else if(!strcmp(value, "from")) {
++		profile->hints = VDP22_MIGFROM;
++		profile->modified |= 1 << f_hints;
++		profile->nlmsg_v = vdpnl_nlf2;
++	} else if(!strcmp(value, "none")) {
++		profile->hints = 0;
++		profile->modified |= 1 << f_hints;
++		profile->nlmsg_v = vdpnl_nlf2;
++	} 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 +1750,9 @@ static char *keytable[] = {
+ 	"typeidver",
+ 	"typeid",
+ 	"uuid",
+-	"name"
++	"name",
++	"2mgrid",
++	"hints"
+ };
+ 
+ static int findkeyword(char *word)
+@@ -995,6 +1791,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 +1836,22 @@ 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;
++		printf("\t%hu", found->addr[i].vlanid);
++		if (found->addr[i].newvid)
++			printf("/%hu", found->addr[i].newvid);
++		if (found->fif == VDP22_FFMT_MACVID ||
++		    found->fif == VDP22_FFMT_GROUPMACVID) {
++			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(" %02x:%02x:%02x:%02x:%02x:%02x",
++				xp[0], xp[1], xp[2], xp[3], xp[4], xp[5]);
++		}
++		if (found->fif == VDP22_FFMT_GROUPVID ||
++		    found->fif == VDP22_FFMT_GROUPMACVID)
++			printf(" %ld", found->addr[i].gpid);
++		printf("\n");
+ 	}
+ }
+ 
+@@ -1049,8 +1859,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 == VDP22_MIGTO ? "to" : "from");
++	printf("\n");
+ 	uuid2buf(found->uuid, uuid);
+ 	printf("\tuuid:%s\n", uuid);
+ 	if (found->pairs)
+@@ -1063,17 +1881,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, sizeof(change->mgrid2));
++	}
+ 	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 +1918,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,20 +1982,34 @@ 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)
++static int 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);
+ 		memset(vdp->key, 0, sizeof vdp->key);
++		return -1;
+ 	}
++	if (vdp->nlmsg_v != vdpnl_nlf2 && vdp->nlmsg_v != vdpnl_nlf1) {
++		fprintf(stderr, "%s key %s has wrong netlink msg format\n",
++		    progname, vdp->key);
++		memset(vdp->key, 0, sizeof vdp->key);
++		return -1;
++	}
++	return 0;
+ }
+ 
+ static int make_profiles(char *profile, char *newkey)
+@@ -1199,16 +2037,22 @@ static int make_profiles(char *profile, char *newkey)
+ 			    progname, nextone.key);
+ 			return -1;
+ 		}
++		if (!strcmp(newkey, found->key) || findkey(newkey)) {
++			fprintf(stderr, "%s target key %s already exits\n",
++				progname, newkey);
++			return -1;
++		}
+ 		if (!(vdp = nextfree())) {
+ 			fprintf(stderr, "%s too many profiles\n", progname);
+ 			return -1;
+ 		}
+ 		*vdp = *found;
+ 		strncpy(vdp->key, newkey, sizeof vdp->key);
++		if (!nextone.nlmsg_v)		/* Test for netlink format */
++			nextone.nlmsg_v = vdp->nlmsg_v;
+ 		change_profile(vdp, &nextone);
+ 	}
+-	isvalid_profile(vdp);
+-	return 0;
++	return isvalid_profile(vdp);
+ }
+ 
+ static int del_profiles(char *name)
+@@ -1233,7 +2077,7 @@ static int copy_profiles(char *profile)
+ 		fprintf(stderr, "%s missing key new=name\n", progname);
+ 		return -1;
+ 	}
+-	newkey = profile + 4;
++	newkey = profile + strlen(COPY_OP);
+ 	newprofile = strchr(newkey, ',');
+ 	if (!newprofile) {
+ 		fprintf(stderr, "%s invalid copy command\n", progname);
+@@ -1500,6 +2344,11 @@ static int cmd_checkrc(struct command *cmdp)
+ {
+ 	int i;
+ 
++	if (cmdp->sys_rc) {
++		printf("FAILURE sys_rc:%d ", cmdp->sys_rc);
++		show_command(cmdp, 1);
++		return -1;
++	}
+ 	for (i = 0; i < cmdp->no_err; ++i)
+ 		if (cmdp->rc == cmdp->errors[i]) {
+ 			if (verbose)
+@@ -1542,40 +2391,282 @@ static void cmd_sleep(struct command *cmdp)
+ 			cmdp->rc |= sleep(cmdp->waittime);
+ }
+ 
+-static int rc_ok(struct command *cmdp)
++/*
++ * Code to use the command line interface via clif_xxx functions.
++ */
++static int tool_use;
++static struct clif *tool_conn;
++
++static void tool_open()
++{
++	tool_conn = clif_open();
++	if (!tool_conn) {
++		fprintf(stderr, "%s can not open connection to LLDPAD\n",
++			progname);
++		exit(5);
++	}
++	if (clif_attach(tool_conn, "80c4")) {
++		fprintf(stderr, "%s can not attach to LLDPAD\n",
++			progname);
++		clif_close(tool_conn);
++		tool_conn = NULL;
++		exit(5);
++	}
++}
++
++static void tool_close(void)
++{
++	if (tool_conn) {
++		clif_detach(tool_conn);
++		clif_close(tool_conn);
++		tool_conn = NULL;
++	}
++}
++
++/*
++ * Convert VSI command mode to string.
++ */
++static unsigned int request2tlvid(unsigned char cmd)
++{
++	switch (cmd) {
++	case CMD_ASSOC:
++		return VDP22_ASSOC;
++	case CMD_DEASSOC:
++		return VDP22_DEASSOC;
++	case CMD_PREASSOC:
++		return VDP22_PREASSOC;
++	case CMD_RRPREASSOC:
++		return VDP22_PREASSOC_WITH_RR;
++	}
++	return 0;
++}
++
++static const char *request2str(unsigned char cmd)
++{
++	switch (cmd) {
++	case CMD_ASSOC:
++		return "assoc";
++	case CMD_DEASSOC:
++		return "deassoc";
++	case CMD_PREASSOC:
++		return "preassoc";
++	case CMD_RRPREASSOC:
++		return "preassoc-rr";
++	}
++	return "unknown";
++}
++
++/*
++ * Convert hint bits to string.
++ */
++static const char *hints2str(unsigned char hint)
++{
++	switch (hint) {
++	case VDP22_MIGTO:
++		return "to";
++	case VDP22_MIGFROM:
++		return "from";
++	default:
++		return "none";
++	}
++}
++
++/*
++ * Create a command string understood by vdp22 module to forward it to
++ * the vdp22 module.
++ */
++static size_t vdp2str(char *cmd, size_t cmd_len, char oper, struct vdpdata *vdp)
+ {
+ 	int i;
++	size_t len;
++	char uuidbuf[64], mgrid[64];
+ 
+-	for (i = 0; i < cmdp->no_err; ++i)
+-		if (cmdp->rc == cmdp->errors[i])
+-			return 1;
++	uuid2buf(vdp->uuid, uuidbuf);
++	if (vdp->nlmsg_v == vdpnl_nlf1)
++		sprintf(mgrid, "%d", vdp->mgrid);
++	else
++		strcpy(mgrid, (char *)vdp->mgrid2);
++	snprintf(cmd, cmd_len, "%s,%s,%d,%d,%s,%s",
++			request2str(oper), mgrid, vdp->typeid,
++			vdp->typeidver, uuidbuf, hints2str(vdp->hints));
++
++	/* Add Filter information data */
++	for (i = 0; i < vdp->pairs; ++i) {
++		len = strlen(cmd);
++		snprintf(cmd + len, cmd_len - len, ",%d",
++			 vdp->addr[i].vlanid);
++		if (vdp->fif == VDP22_FFMT_MACVID ||
++		    vdp->fif == VDP22_FFMT_GROUPMACVID) {
++			len = strlen(cmd);
++			snprintf(cmd + len, cmd_len - len,
++				 "-%02x:%02x:%02x:%02x:%02x:%02x",
++				 vdp->addr[i].mac[0], vdp->addr[i].mac[1],
++				 vdp->addr[i].mac[2], vdp->addr[i].mac[3],
++				 vdp->addr[i].mac[4], vdp->addr[i].mac[5]);
++		}
++		if (vdp->fif == VDP22_FFMT_GROUPVID ||
++		    vdp->fif == VDP22_FFMT_GROUPMACVID) {
++			len = strlen(cmd);
++			snprintf(cmd + len, cmd_len - len, "-%ld",
++					vdp->addr[i].gpid);
++		}
++	}
++	return strlen(cmd);
++}
++
++/*
++ * Convert ascii string to vdp. Return command.
++ */
++static char *str2vdp(char *ok, struct vdpdata *p, int *response)
++{
++	int i, ec;
++	char *token, *cmd = NULL;
++
++	for (i = 0, token = strtok(ok, ","); token;
++					++i, token = strtok(NULL, ",")) {
++		if (i == 0)
++			cmd = token;
++		if (i == 1) {
++			char *myend;
++			unsigned long x = strtol(token, &myend, 10);
++
++			if (*myend || x > 255)
++				strcpy((char *)p->mgrid2, token);
++			else
++				p->mgrid = x;
++		}
++		if (i == 2) {
++			p->typeid = getnumber("typeid", token, '\0', &ec);
++			if (ec)
++				return NULL;
++		}
++		if (i == 3) {
++			p->typeidver = getnumber("typeidver", token, '\0', &ec);
++			if (ec)
++				return NULL;
++		}
++		if (i == 4 && check_uuid(token, p))
++			return NULL;
++		/* Hints field contains response */
++		if (i == 5) {
++			char *myend;
++			unsigned long x = strtol(token, &myend, 10);
++
++			if (*myend)
++				return NULL;
++			*response = x;
++		}
++		if (i >= 6 && check_map(token, p))
++			return NULL;
++	}
++	p->modified = 0;
++	return cmd;
++}
++
++/*
++ * Test data of association.
++ */
++static int check_vsi(struct vdpdata *p, struct vdpdata *back)
++{
++	int i;
++
++	if (p->mgrid && p->mgrid != back->mgrid) {
++		if (verbose >= 2)
++			printf("invalid mgrid identifer %d (expected %d)\n",
++					 back->mgrid, p->mgrid);
++		return -EINVAL;
++	}
++	if (p->pairs != back->pairs) {
++		if (verbose >= 2)
++			printf("invalid fid pairs %d (expected %d)\n",
++					 back->pairs, p->pairs);
++		return -ENFILE;
++	}
++	for (i = 0; i < p->pairs; ++i) {
++		if (p->addr[i].newvid) {
++			if (p->addr[i].newvid != back->addr[i].vlanid) {
++				if (verbose >= 2) {
++					printf("invalid vlanid[%d]:%#hx "
++					       "(expected %#hx)\n",
++					       i, back->addr[i].vlanid,
++					       p->addr[i].newvid);
++					return -EMFILE;
++				}
++			}
++		} else if (p->addr[i].vlanid) {
++			if (p->addr[i].vlanid != back->addr[i].vlanid) {
++				if (verbose >= 2) {
++					printf("unexpected vlanid[%d]:%#hx "
++						"(expected %#hx)\n",
++						i, back->addr[i].vlanid,
++						p->addr[i].vlanid);
++					return -ENOTTY;
++				}
++			}
++		} else {
++			printf("invalid vlanid input[%d]:%#hx "
++					"(expected %#hx)\n",
++					i, back->addr[i].vlanid,
++					p->addr[i].newvid);
++			return -ETXTBSY;
++		}
++	}
+ 	return 0;
+ }
+ 
++static void tool_lldp(struct command *cmdp, struct vdpdata *vdp)
++{
++	char cmd[MAX_CLIF_MSGBUF], ok[MAX_CLIF_MSGBUF];
++	size_t ok_len = sizeof(ok);
++	struct vdpdata back;
++
++	memset(&back, 0, sizeof(back));
++	cmdp->sys_rc = cmdp->rc = 0;
++	vdp2str(cmd, sizeof(cmd), cmdp->cmd, vdp);
++	cmdp->rc = clif_vsiwait(tool_conn, ifname, request2tlvid(cmdp->cmd),
++				cmd, ok, &ok_len, cmdp->waittime);
++	if (!cmdp->rc) {
++		char *cmd = str2vdp(ok, &back, &cmdp->rc);
++		if (!cmd)
++			cmdp->rc = -EINVAL;
++		if (!strcmp(cmd, request2str(cmdp->cmd)) && !cmdp->rc)
++			cmdp->rc = check_vsi(vdp, &back);
++	}
++}
++
++/*
++ * Return 0 with command executed as expected.
++ * Maybe with expected error.
++ */
+ static void cmd_profile(struct command *cmdp)
+ {
+ 	struct vdpdata *vdp = findkey(cmdp->key);
+-	int got_ack = 0;
+-	unsigned int i;
+ 
+ 	if (!vdp) {
+ 		cmdp->rc = ENFILE;
+ 		return;
+ 	}
+-	if ((cmdp->rc = lldp_send(cmdp, vdp)) >= 0)
+-		for (i = 0; got_ack == 0 && i < cmdp->repeats; ++i) {
+-			usleep(cmdp->delay * 1000);
+-			got_ack = lldp_ack(cmdp);
+-			if (got_ack < 0) {	/* Error */
+-				cmdp->rc = -1;
+-				break;
+-			} else if (got_ack > 0) {	/* Got ack */
+-				if (rc_ok(cmdp))
+-					break;
+-				else
+-					got_ack = 0;
+-			}
+-		}
++	if (vdp->nlmsg_v == vdpnl_nlf2 || tool_use)
++		tool_lldp(cmdp, vdp);
++	else
++		cmd_lldp(cmdp, vdp);
++}
++
++/*
++ * Wait for unsolicited messsage from lldpad vdp22 module.
++ */
++static void tool_wait(struct command *cmdp)
++{
++	char ok[MAX_CLIF_MSGBUF];
++	size_t ok_len = sizeof(ok);
++
++	cmdp->sys_rc = cmdp->rc = 0;
++	cmdp->rc = clif_vsievt(tool_conn, ok, &ok_len, cmdp->waittime);
++	if (cmdp->rc == -EAGAIN)	/* No message received */
++		cmdp->rc = 0;
++	else if (cmdp->rc == 0 && !strncmp(ok, "deassoc", strlen("deassoc")))
++		/* Data received and dessaoc command */
++		cmdp->rc = 1;
+ }
+ 
+ static int runcmds()
+@@ -1604,7 +2695,10 @@ static int runcmds()
+ 			cmd_echo(&cmds[i]);
+ 			break;
+ 		case CMD_GETMSG:
+-			lldp_wait(&cmds[i]);
++			if (tool_use)
++				tool_wait(&cmds[i]);
++			else
++				lldp_wait(&cmds[i]);
+ 			break;
+ 		}
+ 		rc = cmd_checkrc(&cmds[i]);
+@@ -1614,6 +2708,29 @@ static int runcmds()
+ 	return rc;
+ }
+ 
++/*
++ * Check for VSI draft 0.2 and draft 2.2 input format on one command line.
++ */
++static void inputformats(void)
++{
++	int f1 = 0, f2 = 0;
++	unsigned int i;
++
++	for (i = 0; i < DIM(cmds) && i < cmdidx; ++i) {
++		if (vsidata[i].nlmsg_v == vdpnl_nlf1)
++			++f1;
++		if (vsidata[i].nlmsg_v == vdpnl_nlf2)
++			++f2;
++	}
++	if (f1 && f2) {
++		fprintf(stderr, "%s mixed input format of VSI draft 0.2"
++				" and draft 2.2 not supported\n", progname);
++		exit(1);
++	}
++	if (!f1)		/* Draft 2,2 with clif only */
++		tool_use = 1;
++}
++
+ #include <net/if.h>
+ 
+ int main(int argc, char **argv)
+@@ -1624,7 +2741,7 @@ int main(int argc, char **argv)
+ 	char *slash, mybuf[32];
+ 
+ 	progname = (slash = strrchr(argv[0], '/')) ? slash + 1 : argv[0];
+-	while ((ch = getopt(argc, argv, ":A:C:D:F:S::a:d:e:E:g:p:r:s::i:v"))
++	while ((ch = getopt(argc, argv, ":A:C:D:F:S::a:d:e:E:g:p:r:s::i:vn"))
+ 	    != EOF)
+ 		switch (ch) {
+ 		case '?':
+@@ -1635,6 +2752,9 @@ int main(int argc, char **argv)
+ 			fprintf(stderr, "%s missing option argument for -%c\n",
+ 			    progname, optopt);
+ 			exit(1);
++		case 'n':
++			tool_use = 1;
++			break;
+ 		case 'F':
+ 			read_profiles(optarg);
+ 			break;
+@@ -1663,8 +2783,8 @@ int main(int argc, char **argv)
+ 			break;
+ 		case CMD_SLEEP:
+ 			if (!optarg) {
+-				optarg = mybuf,
+-				    strncpy(mybuf, "w=1", sizeof mybuf);
++				optarg = mybuf;
++				strncpy(mybuf, "w=1", sizeof mybuf);
+ 			}
+ 			parse_cmd(ch, optarg);
+ 			break;
+@@ -1683,6 +2803,7 @@ int main(int argc, char **argv)
+ 	for (; optind < argc; ++optind)
+ 		printf("%d %s\n", optind, argv[optind]);
+ #endif
++	inputformats();
+ 	if (!needif)
+ 		exit(0);
+ 	if (!ifname) {
+@@ -1690,14 +2811,27 @@ int main(int argc, char **argv)
+ 		    progname);
+ 		exit(2);
+ 	}
+-	lldpad_pid();
+-	if ((my_sock = open_socket(NETLINK_ROUTE)) < 0)
+-		exit(4);
+-	if (verbose >= 2)
++	if (tool_use)
++		tool_open();
++	else {
++		lldpad_pid();
++		if ((my_sock = open_socket(NETLINK_ROUTE)) < 0)
++			exit(4);
++	}
++	if (verbose >= 2) {
++		printf("\nTests to run:\n");
+ 		show_commands(0);
++	}
++	if (verbose >= 2)
++		printf("\nExecution:\n");
+ 	rc = runcmds();
+-	close(my_sock);
+-	if (verbose >= 2)
++	if (tool_use)
++		tool_close();
++	else
++		close(my_sock);
++	if (verbose >= 2) {
++		printf("\nSummary:\n");
+ 		show_commands(1);
++	}
+ 	return rc;
+ }
+diff --git a/tlv_dcbx.c b/tlv_dcbx.c
+index 14eab58..bae9b51 100644
+--- a/tlv_dcbx.c
++++ b/tlv_dcbx.c
+@@ -107,7 +107,7 @@ struct unpacked_tlv *bld_dcbx1_tlv(struct dcbx_tlvs *dcbx)
+ 	struct unpacked_tlv *tlv = create_tlv();
+ 	struct  packed_tlv *ptlv =  NULL;
+ 	u8 oui[DCB_OUI_LEN] = INIT_DCB_OUI;
+-	u8 subtype = dcbx_subtype1;
++	u8 subtype = DCBX_SUBTYPE1;
+ 	u32 offset = 0;
+ 
+ 	if (!tlv)
+@@ -211,7 +211,7 @@ struct unpacked_tlv *bld_dcbx2_tlv(struct dcbx_tlvs *dcbx)
+ 	struct unpacked_tlv *tlv = create_tlv();
+ 	struct packed_tlv *ptlv =  NULL;
+ 	u8 oui[DCB_OUI_LEN] = INIT_DCB_OUI;
+-	u8 subtype = dcbx_subtype2;
++	u8 subtype = DCBX_SUBTYPE2;
+ 	u32 offset = 0;
+ 
+ 	if (!tlv)
+@@ -448,14 +448,14 @@ struct unpacked_tlv *bld_dcbx2_pg_tlv(struct dcbx_tlvs *dcbx, bool *success)
+ 
+ 		for (j=0,k=0 ; k < MAX_BANDWIDTH_GROUPS; j++, k=k+2) {
+ 			tmpbyte = 0;
+-			if (pg_cfg.tx.up[k].strict_priority == dcb_link)
++			if (pg_cfg.tx.up[k].strict_priority == DCB_LINK)
+ 				tmpbyte = 0xf;
+ 			else
+ 				tmpbyte = pg_cfg.tx.up[k].pgid & 0xf;
+ 
+ 			tmpbyte <<= 4;
+ 
+-			if (pg_cfg.tx.up[k+1].strict_priority == dcb_link)
++			if (pg_cfg.tx.up[k+1].strict_priority == DCB_LINK)
+ 				tmpbyte |= 0xf;
+ 			else
+ 				tmpbyte |= (pg_cfg.tx.up[k+1].pgid & 0xf);
+@@ -873,7 +873,7 @@ bool unpack_dcbx1_tlvs(struct port *port, struct lldp_agent *agent,
+ 			break;
+ 		case DCB_PRIORITY_GROUPS_TLV:
+ 			/* store if subtype 2 is not present */
+-			if (agent->rx.dcbx_st == dcbx_subtype1) {
++			if (agent->rx.dcbx_st == DCBX_SUBTYPE1) {
+ 				if (tlvs->manifest->dcbx_pg == NULL) {
+ 					tlvs->dcbdu |= RCVD_DCBX_TLV_PG;
+ 					tlvs->manifest->dcbx_pg = dcbtlv;
+@@ -888,7 +888,7 @@ bool unpack_dcbx1_tlvs(struct port *port, struct lldp_agent *agent,
+ 			break;
+ 		case DCB_PRIORITY_FLOW_CONTROL_TLV:
+ 			/* store if subtype 2 is not present */
+-			if (agent->rx.dcbx_st == dcbx_subtype1) {
++			if (agent->rx.dcbx_st == DCBX_SUBTYPE1) {
+ 				if (tlvs->manifest->dcbx_pfc == NULL) {
+ 					tlvs->dcbdu |= RCVD_DCBX_TLV_PFC;
+ 					tlvs->manifest->dcbx_pfc = dcbtlv;
+@@ -903,7 +903,7 @@ bool unpack_dcbx1_tlvs(struct port *port, struct lldp_agent *agent,
+ 			break;
+ 		case DCB_APPLICATION_TLV:
+ 			/* store if subtype 2 is not present */
+-			if ((agent->rx.dcbx_st == dcbx_subtype1) &&
++			if ((agent->rx.dcbx_st == DCBX_SUBTYPE1) &&
+ 				(dcbtlv->info[DCBX_HDR_SUB_TYPE_OFFSET]
+ 					== APP_FCOE_STYPE)) {
+ 				if (tlvs->manifest->dcbx_app == NULL) {
+@@ -1213,7 +1213,7 @@ bool process_dcbx_pg_tlv(struct port *port, struct lldp_agent *agent)
+ 	if (agent == NULL)
+ 		return false;
+ 
+-	if (agent->rx.dcbx_st == dcbx_subtype2) {
++	if (agent->rx.dcbx_st == DCBX_SUBTYPE2) {
+ 		if (tlvs->manifest->dcbx_pg->length != DCBX2_PG_LEN) {
+ 			LLDPAD_DBG("process_dcbx2_pg_tlv: ERROR - len\n");
+ 			return(false);
+@@ -1258,7 +1258,7 @@ bool process_dcbx_pg_tlv(struct port *port, struct lldp_agent *agent)
+ 		peer_pg.protocol.Error_Flag |= DUP_DCBX_TLV_PG;
+ 	}
+ 
+-	if (agent->rx.dcbx_st == dcbx_subtype2) {
++	if (agent->rx.dcbx_st == DCBX_SUBTYPE2) {
+ 		memset(used, false, sizeof(used));
+ 		for (j=0,k=0 ; k < MAX_BANDWIDTH_GROUPS; j++, k=k+2) {
+ 			u8 tmpbyte = tlvs->manifest->dcbx_pg->info
+@@ -1268,14 +1268,14 @@ bool process_dcbx_pg_tlv(struct port *port, struct lldp_agent *agent)
+ 			peer_pg.tx.up[k].pgid = (tmpbyte >> 4) & 0xf;
+ 			peer_pg.rx.up[k].pgid = (tmpbyte >> 4) & 0xf;
+ 			if (peer_pg.tx.up[k+1].pgid == LINK_STRICT_PGID) {
+-				peer_pg.tx.up[k+1].strict_priority = dcb_link;
+-				peer_pg.rx.up[k+1].strict_priority = dcb_link;
++				peer_pg.tx.up[k+1].strict_priority = DCB_LINK;
++				peer_pg.rx.up[k+1].strict_priority = DCB_LINK;
+ 			} else {
+ 				used[peer_pg.tx.up[k+1].pgid] = true;
+ 			}
+ 			if (peer_pg.tx.up[k].pgid == LINK_STRICT_PGID) {
+-				peer_pg.tx.up[k].strict_priority = dcb_link;
+-				peer_pg.rx.up[k].strict_priority = dcb_link;
++				peer_pg.tx.up[k].strict_priority = DCB_LINK;
++				peer_pg.rx.up[k].strict_priority = DCB_LINK;
+ 			} else {
+ 				used[peer_pg.tx.up[k].pgid] = true;
+ 			}
+@@ -1360,7 +1360,7 @@ bool process_dcbx_pfc_tlv(struct port *port, struct lldp_agent *agent)
+ 	if (agent == NULL)
+ 		return false;
+ 
+-	if (agent->rx.dcbx_st == dcbx_subtype2) {
++	if (agent->rx.dcbx_st == DCBX_SUBTYPE2) {
+ 		if (tlvs->manifest->dcbx_pfc->length != DCBX2_PFC_LEN) {
+ 			LLDPAD_DBG("process_dcbx2_pfc_tlv: ERROR - len\n");
+ 			return(false);
+@@ -1410,7 +1410,7 @@ bool process_dcbx_pfc_tlv(struct port *port, struct lldp_agent *agent)
+ 		temp = tlvs->manifest->dcbx_pfc->info[DCBX_PFC_MAP_OFFSET];
+ 		peer_pfc.admin[i] = (pfc_type)((temp >> i) & BIT0);
+ 	}
+-	if (agent->rx.dcbx_st == dcbx_subtype2) {
++	if (agent->rx.dcbx_st == DCBX_SUBTYPE2) {
+ 		peer_pfc.num_tcs = tlvs->manifest->dcbx_pfc->info
+ 				[DCBX2_PFC__NUM_TC_OFFSET];
+ 	}
+@@ -1437,7 +1437,7 @@ bool process_dcbx_app_tlv(struct port *port, struct lldp_agent *agent)
+ 		return false;
+ 
+ 	len = tlvs->manifest->dcbx_app->length;
+-	if (agent->rx.dcbx_st == dcbx_subtype2) {
++	if (agent->rx.dcbx_st == DCBX_SUBTYPE2) {
+ 		if (len < DCBX2_APP_LEN) {
+ 			LLDPAD_DBG("process_dcbx2_app_tlv: ERROR - len\n");
+ 			return(false);
+@@ -1481,7 +1481,7 @@ bool process_dcbx_app_tlv(struct port *port, struct lldp_agent *agent)
+ 		peer_app.protocol.Error_Flag |= DUP_DCBX_TLV_APP;
+ 	}
+ 
+-	if (agent->rx.dcbx_st == dcbx_subtype2) {
++	if (agent->rx.dcbx_st == DCBX_SUBTYPE2) {
+ 		/* processs upper layer protocol IDs until we 
+ 		 * match Selector Field, FCoE or FIP ID and OUI */
+ 		len -= DCBX2_APP_DATA_OFFSET;
+@@ -1550,7 +1550,7 @@ bool process_dcbx_app_tlv(struct port *port, struct lldp_agent *agent)
+ 			put_peer_app(port->ifname, APP_ISCSI_STYPE, &peer_app);
+ 		if (!fip)
+ 			put_peer_app(port->ifname, APP_FIP_STYPE, &peer_app);
+-	} else if (agent->rx.dcbx_st == dcbx_subtype1) {
++	} else if (agent->rx.dcbx_st == DCBX_SUBTYPE1) {
+ 		sub_type = pBuf[DCBX_HDR_SUB_TYPE_OFFSET];
+ 		len = tlvs->manifest->dcbx_app->length -
+ 			sizeof(struct  dcbx_tlv_header);
diff --git a/lldpad.spec b/lldpad.spec
index c4161f3..4c424b5 100644
--- a/lldpad.spec
+++ b/lldpad.spec
@@ -1,18 +1,19 @@
 %global _default_patch_fuzz 2
 
 # https://fedoraproject.org/wiki/Packaging:Guidelines#Compiler_flags
-%define _hardened_build 1
+%global _hardened_build 1
+
+%global checkout 48a5f38
 
 Name:               lldpad
 Version:            0.9.46
-Release:            7%{?dist}
+Release:            8.git%{checkout}%{?dist}
 Summary:            Intel LLDP Agent
 Group:              System Environment/Daemons
 License:            GPLv2
 URL:                http://open-lldp.org/
 Source0:            %{name}-%{version}.tar.gz
-Patch0:             lldpad-0.9.46-subdir-objects.patch
-Patch1:             lldpad-0.9.46-libnl3.patch
+Patch0:             %{name}-%{version}-123-g48a5f38.patch
 
 BuildRequires:      automake autoconf libtool
 BuildRequires:      flex >= 2.5.33
@@ -45,7 +46,6 @@ that use %{name}.
 %prep
 %setup -q
 %patch0 -p1
-%patch1 -p1
 
 %build
 ./bootstrap.sh
@@ -56,23 +56,19 @@ make %{?_smp_mflags}
 
 %install
 make install DESTDIR=%{buildroot}
-rm -f %{buildroot}%{_mandir}/man8/dcbd.8
-mkdir -p %{buildroot}%{_unitdir}
-install -m644 %{name}.service %{buildroot}%{_unitdir}
-rm -rf %{buildroot}/etc/init.d
 mkdir -p %{buildroot}%{_sharedstatedir}/%{name}
 rm -f %{buildroot}%{_libdir}/liblldp_clif.la
 
 %post
 /sbin/ldconfig
-%systemd_post %{name}.service
+%systemd_post %{name}.service %{name}.socket
 
 %preun
-%systemd_preun %{name}.service
+%systemd_preun %{name}.service %{name}.socket
 
 %postun
 /sbin/ldconfig
-%systemd_postun_with_restart %{name}.service
+%systemd_postun_with_restart %{name}.service %{name}.socket
 
 %files
 %doc COPYING README ChangeLog
@@ -80,6 +76,7 @@ rm -f %{buildroot}%{_libdir}/liblldp_clif.la
 %{_libdir}/liblldp_clif.so.*
 %dir %{_sharedstatedir}/%{name}
 %{_unitdir}/%{name}.service
+%{_unitdir}/%{name}.socket
 %dir %{_sysconfdir}/bash_completion.d/
 %{_sysconfdir}/bash_completion.d/*
 %{_mandir}/man8/*
@@ -90,6 +87,9 @@ rm -f %{buildroot}%{_libdir}/liblldp_clif.la
 %{_libdir}/liblldp_clif.so
 
 %changelog
+* Thu Oct 23 2014 Chris Leech <cleech at redhat.com> - 0.9.46-8.git48a5f38
+- sync to upstream v0.9.46-123-g48a5f38
+
 * Sun Aug 17 2014 Fedora Release Engineering <rel-eng at lists.fedoraproject.org> - 0.9.46-7
 - Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild
 


More information about the scm-commits mailing list