Blame SOURCES/open-lldp-v1.0.1-2-VDP-vdptool-first-version.patch

89f6b3
From 3b559d8d0b52e6a254dc3f59833de4308e18711e Mon Sep 17 00:00:00 2001
89f6b3
From: Thomas Richter <tmricht@linux.vnet.ibm.com>
89f6b3
Date: Wed, 21 Jan 2015 03:36:26 +0000
89f6b3
Subject: [PATCH] VDP: vdptool first version
89f6b3
89f6b3
This is the first version of a vdp command line interface
89f6b3
tool to send and retrieve data to the vdp22 module.
89f6b3
This tool follows similar concept as the lldptool.
89f6b3
The command line options are similar and some intended
89f6b3
functionality (such as -n to retrieve neighbor inforamtion,
89f6b3
that is tlv data send by bridges) is not yet implemented.
89f6b3
89f6b3
Signed-off-by: Thomas Richter <tmricht@linux.vnet.ibm.com>
89f6b3
Signed-off-by: John Fastabend <john.r.fastabend@intel.com>
89f6b3
---
89f6b3
 .gitignore               |    1 +
89f6b3
 Makefile.am              |    8 +-
89f6b3
 docs/vdptool.8           |  280 +++++++++++
89f6b3
 include/qbg_vdp22_clif.h |    2 +
89f6b3
 qbg/vdp22_clif.c         |  141 ++++++
89f6b3
 vdptool.c                | 1149 ++++++++++++++++++++++++++++++++++++++++++++++
89f6b3
 6 files changed, 1579 insertions(+), 2 deletions(-)
89f6b3
 create mode 100644 docs/vdptool.8
89f6b3
 create mode 100644 qbg/vdp22_clif.c
89f6b3
 create mode 100644 vdptool.c
89f6b3
89f6b3
diff --git a/.gitignore b/.gitignore
89f6b3
index c2ac5d7..e2230d9 100644
89f6b3
--- a/.gitignore
89f6b3
+++ b/.gitignore
89f6b3
@@ -31,6 +31,7 @@ missing
89f6b3
 dcbtool
89f6b3
 lldpad
89f6b3
 lldptool
89f6b3
+vdptool
89f6b3
 nltest
89f6b3
 vdptest
89f6b3
 qbg22sim
89f6b3
diff --git a/Makefile.am b/Makefile.am
89f6b3
index 4889d32..fc4f8d6 100644
89f6b3
--- a/Makefile.am
89f6b3
+++ b/Makefile.am
89f6b3
@@ -1,5 +1,5 @@
89f6b3
 # target programs to be installed in ${sbindir}
89f6b3
-sbin_PROGRAMS = lldpad dcbtool lldptool
89f6b3
+sbin_PROGRAMS = lldpad dcbtool lldptool vdptool
89f6b3
 
89f6b3
 # package nltest and vdptest, but do not install it anywhere
89f6b3
 if BUILD_DEBUG
89f6b3
@@ -41,7 +41,7 @@ include/parse_cli.h include/version.h include/lldptool_cli.h include/list.h \
89f6b3
 include/lldp_mand_clif.h include/lldp_basman_clif.h include/lldp_med_clif.h \
89f6b3
 include/lldp_8023_clif.h include/lldp_dcbx_clif.h include/lldp_evb_clif.h \
89f6b3
 include/lldp_evb22_clif.h include/qbg_vdp_clif.h include/qbg_vdpnl.h \
89f6b3
-include/lldp_8021qaz_clif.h \
89f6b3
+include/qbg_vdp22_clif.h include/lldp_8021qaz_clif.h \
89f6b3
 include/lldp_orgspec_clif.h include/lldp_cisco_clif.h \
89f6b3
 include/lldptool.h include/lldp_rtnl.h include/dcbtool.h include/lldp_dcbx_cfg.h
89f6b3
 
89f6b3
@@ -76,6 +76,10 @@ liblldp_clif_la_LDFLAGS = -version-info 1:0:0
89f6b3
 liblldp_clif_includedir = ${srcdir}/include
89f6b3
 liblldp_clif_la_SOURCES = clif.c
89f6b3
 
89f6b3
+vdptool_SOURCES = vdptool.c lldp_util.c qbg/vdp22_clif.c
89f6b3
+vdptool_LDADD = ${srcdir}/liblldp_clif.la
89f6b3
+vdptool_LDFLAGS = -llldp_clif $(LIBNL_LIBS)
89f6b3
+
89f6b3
 dcbtool_SOURCES = dcbtool.c dcbtool_cmds.c parse_cli.l \
89f6b3
 weak_readline.c $(lldpad_include_HEADERS) $(noinst_HEADERS)
89f6b3
 dcbtool_LDADD = ${srcdir}/liblldp_clif.la
89f6b3
diff --git a/docs/vdptool.8 b/docs/vdptool.8
89f6b3
new file mode 100644
89f6b3
index 0000000..5110bb9
89f6b3
--- /dev/null
89f6b3
+++ b/docs/vdptool.8
89f6b3
@@ -0,0 +1,280 @@
89f6b3
+.\" LICENSE
89f6b3
+.\"
89f6b3
+.\" This software program is released under the terms of a license agreement
89f6b3
+.\" between you ('Licensee') and Intel.  Do not use or load this software or
89f6b3
+.\" any associated materials (collectively, the 'Software') until you have
89f6b3
+.\" carefully read the full terms and conditions of the LICENSE located in this
89f6b3
+.\" software package.  By loading or using the Software, you agree to the
89f6b3
+.\" terms of this Agreement. If you do not agree with the terms of this
89f6b3
+.\" Agreement, do not install or use the Software.
89f6b3
+.\"
89f6b3
+.\" * Other names and brands may be claimed as the property of others.
89f6b3
+.\"
89f6b3
+.TH vdptool 8 "April 2014" "open-lldp" "Linux"
89f6b3
+.SH NAME
89f6b3
+vdptool \- manage the VSI associations and status of lldpad
89f6b3
+.SH SYNOPSIS
89f6b3
+.B vdptool <command> [options] [argument]
89f6b3
+.br
89f6b3
+.SH DESCRIPTION
89f6b3
+.B vdptool
89f6b3
+is used to query and configure the VSI associations in
89f6b3
+.B lldpad.
89f6b3
+Only the ratified stardard version of the VDP protocol
89f6b3
+(also refered to as vdp22) is supported.
89f6b3
+It connects to the client interface of
89f6b3
+.B lldpad
89f6b3
+to perform these operations.
89f6b3
+.B vdptool
89f6b3
+will operate in interactive mode if it is executed without a \fIcommand\fR.
89f6b3
+In interactive mode,
89f6b3
+.B vdptool
89f6b3
+will also function as an event listener to print out events
89f6b3
+as they are received asynchronously from
89f6b3
+.BR lldpad "(still to be done)."
89f6b3
+It will use libreadline for interactive input when available
89f6b3
+(still to be done).
89f6b3
+.SH OPTIONS
89f6b3
+.TP
89f6b3
+.B \-i [ifname]
89f6b3
+specifies the network interface to which the command applies.  Most
89f6b3
+.B vdptool
89f6b3
+commands require specifying a network interface.
89f6b3
+.TP
89f6b3
+.B -V [tlvid]
89f6b3
+specifies the VDP tlv identifier to be set or queried.
89f6b3
+.br
89f6b3
+The tlvid is an integer value used to identify specific
89f6b3
+VDP TLVs.  The tlvid value is the type value for types not equal
89f6b3
+to 127 (the organizationally specific type).
89f6b3
+For organizationally specific
89f6b3
+TLVs, the tlvid is the value represented by the 3 byte OUI and 1 byte
89f6b3
+subtype - where the subtype is the lowest order byte of the tlvid.
89f6b3
+.br
89f6b3
+The tlvid can be entered as a numerical value (e.g. 10 or 0xa), or for
89f6b3
+supported TLVs, as a keyword (such as assoc, deassoc, preassoc,
89f6b3
+preassoc-rr, etc).
89f6b3
+Review the
89f6b3
+.B vdptool
89f6b3
+help output to see the list of supported TLV keywords.
89f6b3
+.sp 1
89f6b3
+Use option -c to specify the parameters and its values to be set or queried.
89f6b3
+.TP
89f6b3
+.B \-n
89f6b3
+"neighbor" option for commands which can use it (e.g. get-tlv).
89f6b3
+Use this flag to retrieve the last VDP22 data returned from the
89f6b3
+bridge.
89f6b3
+(not yet supported).
89f6b3
+.TP
89f6b3
+.B \-c <argument list>
89f6b3
+Specifies additional parameters for TLV queries and associations commands.
89f6b3
+The argument list varies, depending on the command option
89f6b3
+.B (-T)
89f6b3
+or 
89f6b3
+.BR (-t) .
89f6b3
+To establish a VSI association use the command option 
89f6b3
+.B (-T)
89f6b3
+and specify additional information as arguments in the form
89f6b3
+of key=value. See the 
89f6b3
+.I "VSI Parameter"
89f6b3
+subsection and
89f6b3
+.I Example
89f6b3
+section below.
89f6b3
+To query a VSI specific association use the command option 
89f6b3
+.B (-t)
89f6b3
+and specify the value of the
89f6b3
+VSI Instance Identifier (keywork uuid followed be the VSI
89f6b3
+UUID value)
89f6b3
+of the VSI association as configuration parameter.
89f6b3
+.TP
89f6b3
+.B \-r
89f6b3
+show raw client interface messages
89f6b3
+.TP
89f6b3
+.B \-R
89f6b3
+show only raw Client interface messages
89f6b3
+.SS VSI Parameter
89f6b3
+Each VDP22 TLVs contains a command mode, manager identifier,
89f6b3
+type identifier, type identifier version, VSI instance identifier,
89f6b3
+migiration hints and filter information.
89f6b3
+The fields are explained next:
89f6b3
+.TP
89f6b3
+.B "mode (Command Mode):"
89f6b3
+The command mode determines the type 
89f6b3
+of the VSI association to be established.
89f6b3
+It is an ascii string can be one of:
89f6b3
+.RS
89f6b3
+.IP assoc:
89f6b3
+Create an VSI association.
89f6b3
+.IP preassoc:
89f6b3
+Create an VSI preassociation. The association
89f6b3
+is only announced to the switch.
89f6b3
+.IP preassoc-rr:
89f6b3
+Create an VSI preassociation. The association
89f6b3
+is only announced to the switch and the 
89f6b3
+switch should reserve the resources.
89f6b3
+.IP deassoc:
89f6b3
+Delete an VSI association.
89f6b3
+.RE
89f6b3
+Other strings are not recognized and return an error.
89f6b3
+.TP
89f6b3
+.B "mgrid2 (Manager identifier):"
89f6b3
+The manager identifier is a string of up to 16
89f6b3
+alphanumeric characters.
89f6b3
+It can also be an UUID according to RFC 4122
89f6b3
+with optional dashes in between.
89f6b3
+.TP
89f6b3
+.B "typeid (Type Identifier):"
89f6b3
+The type identifier is a number in the range
89f6b3
+of 0 to 2^24 - 1.
89f6b3
+.TP
89f6b3
+.B "typeidver (Type Identifier Version):"
89f6b3
+The type identifer version is a number
89f6b3
+in the range of 0 to 255.
89f6b3
+.TP
89f6b3
+.B "uuid (VSI Instance Identifier):"
89f6b3
+The VSI instance identifier is
89f6b3
+an UUID according to RFC 4122
89f6b3
+with optional dashes in between.
89f6b3
+.TP
89f6b3
+.B "hints (Migration Hints):"
89f6b3
+The migiration hints is a string aiding in 
89f6b3
+migration of virtual machines:
89f6b3
+.RS
89f6b3
+.IP none:
89f6b3
+No hints available.
89f6b3
+.IP from:
89f6b3
+The virtual machine is migrating away.
89f6b3
+.IP to:
89f6b3
+The virtual machine is migrating to.
89f6b3
+.RE
89f6b3
+.TP
89f6b3
+.B "fid (Filter Information Data):"
89f6b3
+The filter information data can be supplied in four
89f6b3
+different formats identified by numbers in parathesis.
89f6b3
+Multiple filter information fields can be supplied,
89f6b3
+but all have to be of the same format.
89f6b3
+.RS
89f6b3
+.IP "vlan (1)"
89f6b3
+A vlan number only, also known as filter information format 1.
89f6b3
+The vlan identifier is a number in the range of 1 to 2^16 - 1.
89f6b3
+The high order 4 bits are used as quality of service bits.
89f6b3
+The vlan identifier can be zero, a vlan identifier is then
89f6b3
+selected by the switch. Refer to IEEE 802.1 Qbg ratified
89f6b3
+standard for details.
89f6b3
+.IP "vlan-mac (2)"
89f6b3
+A vlan number and MAC address delimited by a slash ('-'),
89f6b3
+also known as filter information format 2.
89f6b3
+The MAC address is specified in the format xx:xx:xx:xx:xx:xx.
89f6b3
+The colons are mandatory.
89f6b3
+For vlan details see (1).
89f6b3
+.IP "vlan-mac-group (4)"
89f6b3
+A vlan number, MAC address and group identifier, 
89f6b3
+each delimited by a slash ('-'),
89f6b3
+also known as filter information format 4.
89f6b3
+The group identifier is a 32 bit number.
89f6b3
+For vlan and MAC address details see (1) and (2).
89f6b3
+.IP "vlan--group (3)"
89f6b3
+A vlan number and group identifier, 
89f6b3
+delimited by two slashes ('--'),
89f6b3
+also known as filter information format 3.
89f6b3
+For vlan and group details see (1) and (4).
89f6b3
+.RE
89f6b3
+.SH COMMANDS
89f6b3
+.TP
89f6b3
+.B license
89f6b3
+show license information
89f6b3
+.TP
89f6b3
+.B \-h, help
89f6b3
+show usage information
89f6b3
+.TP
89f6b3
+.B \-v, version
89f6b3
+show version information
89f6b3
+.TP
89f6b3
+.B \-t, get-tlv
89f6b3
+get TLV information for the specified interface
89f6b3
+.TP
89f6b3
+.B \-T, set-tlv
89f6b3
+set TLV information for the specified interface
89f6b3
+.TP
89f6b3
+.B \-p, ping
89f6b3
+display the process identifier of the running lldpad process
89f6b3
+.TP
89f6b3
+.B \-q, quit
89f6b3
+exit from interactive mode
89f6b3
+.PP
89f6b3
+.SH NOTES
89f6b3
+This tool is in its early design and development phase.
89f6b3
+It it buggy, incomplete and most of the ideas have not even
89f6b3
+been thought of....
89f6b3
+It reflects the current state of development when
89f6b3
+I had been given another work assignment.
89f6b3
+I append it so some else can continue to work on this.
89f6b3
+.SH EXAMPLES
89f6b3
+.TP
89f6b3
+Display process identifier of lldpad
89f6b3
+.br
89f6b3
+vdptool -p
89f6b3
+.TP
89f6b3
+Create a VSI association on interface eth2
89f6b3
+.br
89f6b3
+.nf
89f6b3
+Supported today: One config parameter and comma separated list
89f6b3
+vdptool -i eth2 -T -V assoc -c vsi=assoc,blabla,5, \\
89f6b3
+	1122,4,none,2-52:00:00:11:22:33-200
89f6b3
+
89f6b3
+Planned for the future:
89f6b3
+vdptool -i eth2 -T -V assoc -c mgrid2=blabla -c typeid=5 \\
89f6b3
+	-c uuid=1122 -c typeidver=4 -c hints=none -c fid=2-52:00:00:11:22:33-200
89f6b3
+.fi
89f6b3
+.TP
89f6b3
+Query all VSI association on interface eth2
89f6b3
+.br
89f6b3
+vdptool -i eth2 -t -V assoc
89f6b3
+.SH SEE ALSO
89f6b3
+.BR lldptool-dcbx (8),
89f6b3
+.BR lldptool-ets (8),
89f6b3
+.BR lldptool-pfc (8),
89f6b3
+.BR lldptool-app (8),
89f6b3
+.BR lldptool-med (8),
89f6b3
+.BR lldptool-vdp (8),
89f6b3
+.BR lldptool-evb (8),
89f6b3
+.BR lldptool-evb22 (8),
89f6b3
+.BR dcbtool (8),
89f6b3
+.BR lldpad (8)
89f6b3
+.br
89f6b3
+.SH COPYRIGHT
89f6b3
+vdptool - VSI configuration utility
89f6b3
+.br
89f6b3
+.IP Copyright(c)
89f6b3
+(c) 2014 IBM Corporation.
89f6b3
+.BR
89f6b3
+Portions of vdptool are based on:
89f6b3
+.IP open-lldp-0.96
89f6b3
+.IP "lldptool - LLDP agent configuration utility"
89f6b3
+.IP Copyright(c)
89f6b3
+2007-2012 Intel Corporation.
89f6b3
+.BR
89f6b3
+Portions of lldptool are based on:
89f6b3
+.IP hostapd-0.5.7
89f6b3
+.IP Copyright
89f6b3
+(c) 2004-2008, Jouni Malinen <j@w1.fi>
89f6b3
+
89f6b3
+.SH LICENSE
89f6b3
+This program is free software; you can redistribute it and/or modify it
89f6b3
+under the terms and conditions of the GNU General Public License,
89f6b3
+version 2, as published by the Free Software Foundation.
89f6b3
+.LP
89f6b3
+This program is distributed in the hope it will be useful, but WITHOUT
89f6b3
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
89f6b3
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
89f6b3
+more details.
89f6b3
+.LP
89f6b3
+You should have received a copy of the GNU General Public License along with
89f6b3
+this program; if not, write to the Free Software Foundation, Inc.,
89f6b3
+51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
89f6b3
+.LP
89f6b3
+The full GNU General Public License is included in this distribution in
89f6b3
+the file called "COPYING".
89f6b3
+.SH SUPPORT
89f6b3
+Contact Information:
89f6b3
+open-lldp Mailing List <lldp-devel@open-lldp.org>
89f6b3
diff --git a/include/qbg_vdp22_clif.h b/include/qbg_vdp22_clif.h
89f6b3
index 20330b8..008022a 100644
89f6b3
--- a/include/qbg_vdp22_clif.h
89f6b3
+++ b/include/qbg_vdp22_clif.h
89f6b3
@@ -52,4 +52,6 @@ typedef enum {
89f6b3
 	op_delete = 0x20,
89f6b3
 	op_key = 0x40
89f6b3
 } vdp22_op;
89f6b3
+
89f6b3
+struct lldp_module *vdp22_cli_register(void);
89f6b3
 #endif
89f6b3
diff --git a/qbg/vdp22_clif.c b/qbg/vdp22_clif.c
89f6b3
new file mode 100644
89f6b3
index 0000000..649305d
89f6b3
--- /dev/null
89f6b3
+++ b/qbg/vdp22_clif.c
89f6b3
@@ -0,0 +1,141 @@
89f6b3
+/*******************************************************************************
89f6b3
+
89f6b3
+  Implementation of VDP 22 (ratified standard) according to IEEE 802.1Qbg
89f6b3
+  (c) Copyright IBM Corp. 2014
89f6b3
+
89f6b3
+  Author(s): Thomas Richter <tmricht@linux.vnet.ibm.com>
89f6b3
+
89f6b3
+  This program is free software; you can redistribute it and/or modify it
89f6b3
+  under the terms and conditions of the GNU General Public License,
89f6b3
+  version 2, as published by the Free Software Foundation.
89f6b3
+
89f6b3
+  This program is distributed in the hope it will be useful, but WITHOUT
89f6b3
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
89f6b3
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
89f6b3
+  more details.
89f6b3
+
89f6b3
+  You should have received a copy of the GNU General Public License along with
89f6b3
+  this program; if not, write to the Free Software Foundation, Inc.,
89f6b3
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
89f6b3
+
89f6b3
+  The full GNU General Public License is included in this distribution in
89f6b3
+  the file called "COPYING".
89f6b3
+
89f6b3
+*******************************************************************************/
89f6b3
+
89f6b3
+#include <stdio.h>
89f6b3
+#include <stdlib.h>
89f6b3
+#include <syslog.h>
89f6b3
+#include <sys/un.h>
89f6b3
+
89f6b3
+#include "lldp_mod.h"
89f6b3
+#include "clif_msgs.h"
89f6b3
+#include "lldp.h"
89f6b3
+#include "qbg22.h"
89f6b3
+#include "qbg_vdp22def.h"
89f6b3
+#include "qbg_vdpnl.h"
89f6b3
+#include "qbg_vdp22_cmds.h"
89f6b3
+#include "qbg_vdp22_clif.h"
89f6b3
+#include "qbg_vdp22def.h"
89f6b3
+
89f6b3
+static struct type_name_info vdp22_tlv_names[] = {
89f6b3
+	{
89f6b3
+		.name = "VDP VSI Association",
89f6b3
+		.key = "assoc",
89f6b3
+		.type = VDP22_ASSOC
89f6b3
+	},
89f6b3
+	{
89f6b3
+		.name = "VDP VSI Deassociation",
89f6b3
+		.key = "deassoc",
89f6b3
+		.type = VDP22_DEASSOC
89f6b3
+	},
89f6b3
+	{
89f6b3
+		.name = "VDP VSI Preassociation",
89f6b3
+		.key = "preassoc",
89f6b3
+		.type = VDP22_PREASSOC
89f6b3
+	},
89f6b3
+	{
89f6b3
+		.name = "VDP VSI Preassociation with resource reservation",
89f6b3
+		.key = "preassoc-rr",
89f6b3
+		.type = VDP22_PREASSOC_WITH_RR
89f6b3
+	},
89f6b3
+	{
89f6b3
+		.type = INVALID_TLVID
89f6b3
+	}
89f6b3
+};
89f6b3
+
89f6b3
+static int vdp22_print_help(void)
89f6b3
+{
89f6b3
+	struct type_name_info *tn = &vdp22_tlv_names[0];
89f6b3
+
89f6b3
+	while (tn->type != INVALID_TLVID) {
89f6b3
+		if (tn->key && strlen(tn->key) && tn->name) {
89f6b3
+			printf("   %s", tn->key);
89f6b3
+			if (strlen(tn->key) + 3 < 8)
89f6b3
+				printf("\t");
89f6b3
+			printf("\t: %s\n", tn->name);
89f6b3
+		}
89f6b3
+		tn++;
89f6b3
+	}
89f6b3
+	return 0;
89f6b3
+}
89f6b3
+
89f6b3
+static u32 vdp22_lookup_tlv_name(char *tlvid_str)
89f6b3
+{
89f6b3
+	struct type_name_info *tn = &vdp22_tlv_names[0];
89f6b3
+
89f6b3
+	while (tn->type != INVALID_TLVID) {
89f6b3
+		if (!strcasecmp(tn->key, tlvid_str))
89f6b3
+			return tn->type;
89f6b3
+		tn++;
89f6b3
+	}
89f6b3
+	return INVALID_TLVID;
89f6b3
+}
89f6b3
+
89f6b3
+static void vdp22_cli_unregister(struct lldp_module *mod)
89f6b3
+{
89f6b3
+	free(mod);
89f6b3
+}
89f6b3
+
89f6b3
+/* return 1: if it printed the TLV
89f6b3
+ *	  0: if it did not
89f6b3
+ */
89f6b3
+static int vdp22_print_tlv(u32 tlvid, u16 len, char *info)
89f6b3
+{
89f6b3
+	struct type_name_info *tn = &vdp22_tlv_names[0];
89f6b3
+
89f6b3
+	while (tn->type != INVALID_TLVID) {
89f6b3
+		if (tlvid == tn->type) {
89f6b3
+			printf("%s\n", tn->name);
89f6b3
+			if (tn->print_info) {
89f6b3
+				printf("\t");
89f6b3
+				tn->print_info(len - 4, info);
89f6b3
+			}
89f6b3
+			return 1;
89f6b3
+		}
89f6b3
+		tn++;
89f6b3
+	}
89f6b3
+	return 0;
89f6b3
+}
89f6b3
+
89f6b3
+static const struct lldp_mod_ops vdp22_ops_clif = {
89f6b3
+	.lldp_mod_register	= vdp22_cli_register,
89f6b3
+	.lldp_mod_unregister	= vdp22_cli_unregister,
89f6b3
+	.print_tlv		= vdp22_print_tlv,
89f6b3
+	.lookup_tlv_name	= vdp22_lookup_tlv_name,
89f6b3
+	.print_help		= vdp22_print_help,
89f6b3
+};
89f6b3
+
89f6b3
+struct lldp_module *vdp22_cli_register(void)
89f6b3
+{
89f6b3
+	struct lldp_module *mod;
89f6b3
+
89f6b3
+	mod = malloc(sizeof(*mod));
89f6b3
+	if (!mod) {
89f6b3
+		fprintf(stderr, "failed to malloc module data\n");
89f6b3
+		return NULL;
89f6b3
+	}
89f6b3
+	mod->id = LLDP_MOD_VDP22;
89f6b3
+	mod->ops = &vdp22_ops_clif;
89f6b3
+	return mod;
89f6b3
+}
89f6b3
diff --git a/vdptool.c b/vdptool.c
89f6b3
new file mode 100644
89f6b3
index 0000000..e7d384a
89f6b3
--- /dev/null
89f6b3
+++ b/vdptool.c
89f6b3
@@ -0,0 +1,1149 @@
89f6b3
+/*******************************************************************************
89f6b3
+
89f6b3
+  LLDP Agent Daemon (LLDPAD) Software
89f6b3
+  Copyright(c) IBM Corp. 2014
89f6b3
+
89f6b3
+  Substantially modified from:
89f6b3
+  hostapd-0.5.7
89f6b3
+  Copyright (c) 2002-2007, Jouni Malinen <jkmaline@cc.hut.fi> and
89f6b3
+  contributors
89f6b3
+
89f6b3
+  This program is free software; you can redistribute it and/or modify it
89f6b3
+  under the terms and conditions of the GNU General Public License,
89f6b3
+  version 2, as published by the Free Software Foundation.
89f6b3
+
89f6b3
+  This program is distributed in the hope it will be useful, but WITHOUT
89f6b3
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
89f6b3
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
89f6b3
+  more details.
89f6b3
+
89f6b3
+  You should have received a copy of the GNU General Public License along with
89f6b3
+  this program; if not, write to the Free Software Foundation, Inc.,
89f6b3
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
89f6b3
+
89f6b3
+  The full GNU General Public License is included in this distribution in
89f6b3
+  the file called "COPYING".
89f6b3
+
89f6b3
+  Contact Information:
89f6b3
+  open-lldp Mailing List <lldp-devel@open-lldp.org>
89f6b3
+
89f6b3
+*******************************************************************************/
89f6b3
+
89f6b3
+/*
89f6b3
+ * Thomas Richter, IBM LTC Boeblingen, Germany, Feb 2014
89f6b3
+ *
89f6b3
+ * Command line interface tool to connect to vdp module of lldpad to
89f6b3
+ * set and query VSI profile settings.
89f6b3
+ */
89f6b3
+
89f6b3
+#include <stdlib.h>
89f6b3
+#include <stdio.h>
89f6b3
+#include <unistd.h>
89f6b3
+#include <signal.h>
89f6b3
+#include <ctype.h>
89f6b3
+#include <errno.h>
89f6b3
+#include <getopt.h>
89f6b3
+
89f6b3
+#include <sys/queue.h>
89f6b3
+
89f6b3
+#include "version.h"
89f6b3
+#include "clif.h"
89f6b3
+#include "clif_msgs.h"
89f6b3
+#include "lldp_mod.h"
89f6b3
+
89f6b3
+#include "qbg22.h"
89f6b3
+#include "qbg_vdp22_clif.h"
89f6b3
+
89f6b3
+static char *print_status(cmd_status status)
89f6b3
+{
89f6b3
+	char *str;
89f6b3
+
89f6b3
+	switch (status) {
89f6b3
+	case cmd_success:
89f6b3
+		str = "Successful";
89f6b3
+		break;
89f6b3
+	case cmd_failed:
89f6b3
+		str = "Failed";
89f6b3
+		break;
89f6b3
+	case cmd_device_not_found:
89f6b3
+		str = "Device not found or inactive";
89f6b3
+		break;
89f6b3
+	case cmd_agent_not_found:
89f6b3
+		str = "Agent instance for device not found";
89f6b3
+		break;
89f6b3
+	case cmd_invalid:
89f6b3
+		str = "Invalid command";
89f6b3
+		break;
89f6b3
+	case cmd_bad_params:
89f6b3
+		str = "Invalid parameters";
89f6b3
+		break;
89f6b3
+	case cmd_peer_not_present:
89f6b3
+		str = "Peer feature not present";
89f6b3
+		break;
89f6b3
+	case cmd_ctrl_vers_not_compatible:
89f6b3
+		str = "Version not compatible";
89f6b3
+		break;
89f6b3
+	case cmd_not_capable:
89f6b3
+		str = "Device not capable";
89f6b3
+		break;
89f6b3
+	case cmd_not_applicable:
89f6b3
+		str = "Command not applicable";
89f6b3
+		break;
89f6b3
+	case cmd_no_access:
89f6b3
+		str = "Access denied";
89f6b3
+		break;
89f6b3
+	case cmd_agent_not_supported:
89f6b3
+		str = "TLV does not support agent type";
89f6b3
+		break;
89f6b3
+	default:
89f6b3
+		str = "Unknown status";
89f6b3
+		break;
89f6b3
+	}
89f6b3
+	return str;
89f6b3
+}
89f6b3
+
89f6b3
+static void get_arg_value(char *str, char **arg, char **argval)
89f6b3
+{
89f6b3
+	unsigned int i;
89f6b3
+
89f6b3
+	for (i = 0; i < strlen(str); i++)
89f6b3
+		if (!isprint(str[i]))
89f6b3
+			return;
89f6b3
+
89f6b3
+	for (i = 0; i < strlen(str); i++)
89f6b3
+		if (str[i] == '=')
89f6b3
+			break;
89f6b3
+
89f6b3
+	if (i < strlen(str)) {
89f6b3
+		str[i] = '\0';
89f6b3
+		*argval = &str[i+1];
89f6b3
+	}
89f6b3
+	*arg = str;
89f6b3
+}
89f6b3
+
89f6b3
+static int render_cmd(struct cmd *cmd, int argc, char **args, char **argvals)
89f6b3
+{
89f6b3
+	int len;
89f6b3
+	int i;
89f6b3
+
89f6b3
+	len = sizeof(cmd->obuf);
89f6b3
+
89f6b3
+	/* all command messages begin this way */
89f6b3
+	snprintf(cmd->obuf, len, "%c%08x%c%1x%02x%08x%02x%s%02x%08x",
89f6b3
+		MOD_CMD, cmd->module_id, CMD_REQUEST, CLIF_MSG_VERSION,
89f6b3
+		cmd->cmd, cmd->ops, (unsigned int) strlen(cmd->ifname),
89f6b3
+		cmd->ifname, cmd->type, cmd->tlvid);
89f6b3
+#if PADDU
89f6b3
+	if (cmd->cmd == cmd_settlv) {
89f6b3
+		size_t len2 = 0;
89f6b3
+		/*
89f6b3
+		 * Get total length and append it plus any args and argvals
89f6b3
+		 * to the command message
89f6b3
+		 */
89f6b3
+		for (i = 0; i < argc; i++) {
89f6b3
+			if (args[i])
89f6b3
+				len2 += 2 + strlen(args[i]);
89f6b3
+			if (argvals[i])
89f6b3
+				len2 += 4 + strlen(argvals[i]);
89f6b3
+		}
89f6b3
+		snprintf(cmd->obuf + strlen(cmd->obuf), len - strlen(cmd->obuf),
89f6b3
+			 "%04zx", len2);
89f6b3
+	}
89f6b3
+#endif
89f6b3
+	/* Add any args and argvals to the command message */
89f6b3
+	for (i = 0; i < argc; i++) {
89f6b3
+		if (args[i])
89f6b3
+			snprintf(cmd->obuf + strlen(cmd->obuf),
89f6b3
+				 len - strlen(cmd->obuf),
89f6b3
+				 "%02x%s", (unsigned int)strlen(args[i]),
89f6b3
+				 args[i]);
89f6b3
+		if (argvals[i])
89f6b3
+			snprintf(cmd->obuf + strlen(cmd->obuf),
89f6b3
+				 len - strlen(cmd->obuf), "%04x%s",
89f6b3
+				 (unsigned int)strlen(argvals[i]), argvals[i]);
89f6b3
+	}
89f6b3
+	return strlen(cmd->obuf);
89f6b3
+}
89f6b3
+
89f6b3
+int vdp_clif_command(struct clif *, char *, int);
89f6b3
+
89f6b3
+static int vdp_cmd_gettlv(struct clif *clif, int argc, char *argv[],
89f6b3
+			  struct cmd *cmd, int raw)
89f6b3
+{
89f6b3
+	int numargs = 0;
89f6b3
+	char **args;
89f6b3
+	char **argvals;
89f6b3
+	int i;
89f6b3
+
89f6b3
+	if (cmd->cmd != cmd_gettlv)
89f6b3
+		return cmd_invalid;
89f6b3
+
89f6b3
+	args = calloc(argc, sizeof(char *));
89f6b3
+	if (!args)
89f6b3
+		return cmd_failed;
89f6b3
+
89f6b3
+	argvals = calloc(argc, sizeof(char *));
89f6b3
+	if (!argvals) {
89f6b3
+		free(args);
89f6b3
+		return cmd_failed;
89f6b3
+	}
89f6b3
+
89f6b3
+	for (i = 0; i < argc; i++)
89f6b3
+		get_arg_value(argv[i], &args[i], &argvals[i]);
89f6b3
+	numargs = i;
89f6b3
+
89f6b3
+	/* Default is local tlv query */
89f6b3
+	if (!(cmd->ops & op_neighbor))
89f6b3
+		cmd->ops |= op_local;
89f6b3
+
89f6b3
+	if (numargs) {
89f6b3
+		/* Only commands with the config option should have arguments.*/
89f6b3
+		if (!(cmd->ops & op_config)) {
89f6b3
+			printf("%s\n", print_status(cmd_invalid));
89f6b3
+			goto out;
89f6b3
+		}
89f6b3
+
89f6b3
+		/* Commands to get neighbor TLVs cannot have arguments. */
89f6b3
+		if (cmd->ops & op_neighbor) {
89f6b3
+			printf("%s\n", print_status(cmd_invalid));
89f6b3
+			goto out;
89f6b3
+		}
89f6b3
+		cmd->ops |= op_arg;
89f6b3
+	}
89f6b3
+
89f6b3
+	for (i = 0; i < numargs; i++) {
89f6b3
+		if (argvals[i]) {
89f6b3
+			printf("%s\n", print_status(cmd_invalid));
89f6b3
+			goto out;
89f6b3
+		}
89f6b3
+	}
89f6b3
+
89f6b3
+	render_cmd(cmd, argc, args, argvals);
89f6b3
+	free(args);
89f6b3
+	free(argvals);
89f6b3
+	return vdp_clif_command(clif, cmd->obuf, raw);
89f6b3
+out:
89f6b3
+	free(args);
89f6b3
+	free(argvals);
89f6b3
+	return cmd_invalid;
89f6b3
+}
89f6b3
+
89f6b3
+static int vdp_cmd_settlv(struct clif *clif, int argc, char *argv[],
89f6b3
+			  struct cmd *cmd, int raw)
89f6b3
+{
89f6b3
+	int numargs = 0;
89f6b3
+	char **args;
89f6b3
+	char **argvals;
89f6b3
+	int i;
89f6b3
+
89f6b3
+	if (cmd->cmd != cmd_settlv)
89f6b3
+		return cmd_invalid;
89f6b3
+	args = calloc(argc, sizeof(char *));
89f6b3
+	if (!args)
89f6b3
+		return cmd_failed;
89f6b3
+
89f6b3
+	argvals = calloc(argc, sizeof(char *));
89f6b3
+	if (!argvals) {
89f6b3
+		free(args);
89f6b3
+		return cmd_failed;
89f6b3
+	}
89f6b3
+
89f6b3
+	for (i = 0; i < argc; i++)
89f6b3
+		get_arg_value(argv[i], &args[i], &argvals[i]);
89f6b3
+	numargs = i;
89f6b3
+
89f6b3
+	for (i = 0; i < numargs; i++) {
89f6b3
+		if (!argvals[i]) {
89f6b3
+			printf("%s\n", print_status(cmd_invalid));
89f6b3
+			goto out;
89f6b3
+		}
89f6b3
+	}
89f6b3
+
89f6b3
+	if (numargs)
89f6b3
+		cmd->ops |= (op_arg | op_argval);
89f6b3
+
89f6b3
+	render_cmd(cmd, argc, args, argvals);
89f6b3
+	free(args);
89f6b3
+	free(argvals);
89f6b3
+	return vdp_clif_command(clif, cmd->obuf, raw);
89f6b3
+out:
89f6b3
+	free(args);
89f6b3
+	free(argvals);
89f6b3
+	return cmd_invalid;
89f6b3
+}
89f6b3
+
89f6b3
+static int hex2u8(char *b)
89f6b3
+{
89f6b3
+	int hex = -1;
89f6b3
+
89f6b3
+	if (isxdigit(*b) && isxdigit(*(b + 1)))
89f6b3
+		sscanf(b, "%02x", &hex;;
89f6b3
+	return hex;
89f6b3
+}
89f6b3
+
89f6b3
+static int hex2u16(char *b)
89f6b3
+{
89f6b3
+	int hex = -1;
89f6b3
+
89f6b3
+	if (isxdigit(*b) && isxdigit(*(b + 1)) && isxdigit(*(b + 2))
89f6b3
+	    && isxdigit(*(b + 3)))
89f6b3
+		sscanf(b, "%04x", &hex;;
89f6b3
+	return hex;
89f6b3
+}
89f6b3
+
89f6b3
+static int hex2u32(char *b)
89f6b3
+{
89f6b3
+	int hex;
89f6b3
+	char *b_old = b;
89f6b3
+
89f6b3
+	for (hex = 0; hex < 8; ++hex)
89f6b3
+		if (!isxdigit(*b++))
89f6b3
+			return -1;
89f6b3
+	sscanf(b_old, "%08x", &hex;;
89f6b3
+	return hex;
89f6b3
+}
89f6b3
+
89f6b3
+static int vdp_parse_response(char *buf)
89f6b3
+{
89f6b3
+	return hex2u8(buf + CLIF_STAT_OFF);
89f6b3
+}
89f6b3
+
89f6b3
+static void print_pair(char *arg, size_t arglen, char *value, size_t valuelen)
89f6b3
+{
89f6b3
+	while (arglen--)
89f6b3
+		putchar(*arg++);
89f6b3
+	putchar('=');
89f6b3
+	while (valuelen--)
89f6b3
+		putchar(*value++);
89f6b3
+	putchar('\n');
89f6b3
+}
89f6b3
+
89f6b3
+static int print_arg_value(char *ibuf)
89f6b3
+{
89f6b3
+	int arglen, valuelen, offset = 0, ilen = strlen(ibuf);
89f6b3
+	char *arg, *value;
89f6b3
+
89f6b3
+	while (offset < ilen) {
89f6b3
+		/* Length of argument */
89f6b3
+		arglen = hex2u8(ibuf + offset);
89f6b3
+		if (arglen < 0)
89f6b3
+			break;
89f6b3
+		offset += 2;
89f6b3
+		arg = ibuf + offset;
89f6b3
+		offset += arglen;
89f6b3
+
89f6b3
+		/* Length of argument value */
89f6b3
+		valuelen = hex2u16(ibuf + offset);
89f6b3
+		if (valuelen < 0)
89f6b3
+			break;
89f6b3
+		offset += 4;
89f6b3
+		value = ibuf + offset;
89f6b3
+		offset += valuelen;
89f6b3
+
89f6b3
+		print_pair(arg, arglen, value, valuelen);
89f6b3
+	}
89f6b3
+	return offset;
89f6b3
+}
89f6b3
+
89f6b3
+static int get_tlvid(char *ibuf)
89f6b3
+{
89f6b3
+	return hex2u32(ibuf);
89f6b3
+}
89f6b3
+
89f6b3
+/*
89f6b3
+ * Print a TLV.
89f6b3
+ */
89f6b3
+static void print_tlv2(char *ibuf)
89f6b3
+{
89f6b3
+	size_t ilen = strlen(ibuf);
89f6b3
+	u16 tlv_type;
89f6b3
+	u16 tlv_len;
89f6b3
+	u32 tlvid;
89f6b3
+	int offset = 0;
89f6b3
+	int printed;
89f6b3
+	struct lldp_module *np;
89f6b3
+
89f6b3
+	while (ilen > 0) {
89f6b3
+		tlv_len = 2 * sizeof(u16);
89f6b3
+		if (ilen < 2 * sizeof(u16)) {
89f6b3
+			printf("corrupted TLV ilen:%zd, tlv_len:%d\n",
89f6b3
+				ilen, tlv_len);
89f6b3
+			break;
89f6b3
+		}
89f6b3
+		tlv_type = hex2u16(ibuf + offset);
89f6b3
+		tlv_len = tlv_type;
89f6b3
+		tlv_type >>= 9;
89f6b3
+		tlv_len &= 0x01ff;
89f6b3
+		offset += 2 * sizeof(u16);
89f6b3
+		ilen -= 2 * sizeof(u16);
89f6b3
+
89f6b3
+		if (ilen < (unsigned) 2 * tlv_len) {
89f6b3
+			printf("corrupted TLV ilen:%zd, tlv_len:%d\n",
89f6b3
+				ilen, tlv_len);
89f6b3
+			break;
89f6b3
+		}
89f6b3
+		tlvid = tlv_type;
89f6b3
+		if (tlvid == INVALID_TLVID) {
89f6b3
+			tlvid = get_tlvid(ibuf + offset);
89f6b3
+			offset += 8;
89f6b3
+		}
89f6b3
+		printed = 0;
89f6b3
+		LIST_FOREACH(np, &lldp_head, lldp) {
89f6b3
+			if (np->ops->print_tlv(tlvid, tlv_len, ibuf + offset)) {
89f6b3
+				printed = 1;
89f6b3
+				break;
89f6b3
+			}
89f6b3
+		}
89f6b3
+
89f6b3
+		if (!printed) {
89f6b3
+			if (tlvid < INVALID_TLVID)
89f6b3
+				printf("Unidentified TLV\n\ttype:%d %*.*s\n",
89f6b3
+					tlv_type, tlv_len*2, tlv_len*2,
89f6b3
+					ibuf+offset);
89f6b3
+			else
89f6b3
+				printf("Unidentified Org Specific TLV\n\t"
89f6b3
+				      "OUI: 0x%06x, Subtype: %d, Info: %*.*s\n",
89f6b3
+					tlvid >> 8, tlvid & 0x0ff,
89f6b3
+					tlv_len*2-8, tlv_len*2-8,
89f6b3
+					ibuf+offset);
89f6b3
+		}
89f6b3
+		if (tlvid > INVALID_TLVID)
89f6b3
+			offset += (2 * tlv_len - 8);
89f6b3
+		else
89f6b3
+			offset += 2 * tlv_len;
89f6b3
+		ilen -= 2 * tlv_len;
89f6b3
+		if (tlvid == END_OF_LLDPDU_TLV)
89f6b3
+			break;
89f6b3
+	}
89f6b3
+}
89f6b3
+
89f6b3
+/* Print reply from get command */
89f6b3
+static void print_tlvs(struct cmd *cmd, char *ibuf)
89f6b3
+{
89f6b3
+	if (cmd->ops & op_config) {
89f6b3
+		print_arg_value(ibuf);
89f6b3
+		return;
89f6b3
+	}
89f6b3
+	print_tlv2(ibuf);
89f6b3
+}
89f6b3
+
89f6b3
+static void print_cmd_response(char *ibuf, int status)
89f6b3
+{
89f6b3
+	struct cmd cmd;
89f6b3
+	unsigned char len;
89f6b3
+	int ioff;
89f6b3
+
89f6b3
+	if (status != cmd_success) {
89f6b3
+		printf("%s\n", print_status(status));
89f6b3
+		return;
89f6b3
+	}
89f6b3
+
89f6b3
+	cmd.cmd = hex2u8(ibuf + CMD_CODE);
89f6b3
+	cmd.ops = hex2u32(ibuf + CMD_OPS);
89f6b3
+	len = hex2u8(ibuf + CMD_IF_LEN);
89f6b3
+	ioff = CMD_IF;
89f6b3
+	if (len < sizeof(cmd.ifname)) {
89f6b3
+		memcpy(cmd.ifname, ibuf + CMD_IF, len);
89f6b3
+	} else {
89f6b3
+		printf("Response ifname too long: %*s\n", (int)len, cmd.ifname);
89f6b3
+		return;
89f6b3
+	}
89f6b3
+	cmd.ifname[len] = '\0';
89f6b3
+	ioff += len;
89f6b3
+
89f6b3
+	if (cmd.cmd == cmd_gettlv || cmd.cmd == cmd_settlv) {
89f6b3
+		cmd.tlvid = hex2u32(ibuf + ioff);
89f6b3
+		ioff += 2 * sizeof(cmd.tlvid);
89f6b3
+	}
89f6b3
+
89f6b3
+	switch (cmd.cmd) {
89f6b3
+	case cmd_gettlv:
89f6b3
+		print_tlvs(&cmd, ibuf + ioff);
89f6b3
+		break;
89f6b3
+	case cmd_settlv:
89f6b3
+		printf("%s", ibuf + ioff);
89f6b3
+		break;
89f6b3
+	default:
89f6b3
+		return;
89f6b3
+	}
89f6b3
+}
89f6b3
+
89f6b3
+static void vdp_print_response(char *buf, int status)
89f6b3
+{
89f6b3
+	switch (buf[CLIF_RSP_OFF]) {
89f6b3
+	case PING_CMD:
89f6b3
+		if (status)
89f6b3
+			printf("FAILED:%s\n", print_status(status));
89f6b3
+		else
89f6b3
+			printf("%s\n", buf + CLIF_RSP_OFF + 5);
89f6b3
+		break;
89f6b3
+	case ATTACH_CMD:
89f6b3
+	case DETACH_CMD:
89f6b3
+		if (status)
89f6b3
+			printf("FAILED:%s\n", print_status(status));
89f6b3
+		else
89f6b3
+			printf("OK\n");
89f6b3
+		break;
89f6b3
+	case CMD_REQUEST:
89f6b3
+		print_cmd_response(buf + CLIF_RSP_OFF, status);
89f6b3
+		break;
89f6b3
+	default:
89f6b3
+		printf("Unknown VDP command response: %s\n", buf);
89f6b3
+		break;
89f6b3
+	}
89f6b3
+}
89f6b3
+
89f6b3
+static void vdp_print_event_msg(char *buf)
89f6b3
+{
89f6b3
+	printf("%s buf:%s\n", __func__, buf);
89f6b3
+}
89f6b3
+
89f6b3
+/*
89f6b3
+ * Dummy function to avoid linkage of many sources
89f6b3
+ */
89f6b3
+int get_perm_hwaddr(UNUSED const char *ifname, UNUSED unsigned char *buf_perm,
89f6b3
+		    UNUSED unsigned char *buf_san)
89f6b3
+{
89f6b3
+	return -EIO;
89f6b3
+}
89f6b3
+
89f6b3
+static int show_raw;
89f6b3
+
89f6b3
+static const char *cli_version =
89f6b3
+	"vdptool v" LLDPTOOL_VERSION "\n"
89f6b3
+	"Copyright (c) 2014, IBM Corporation\n";
89f6b3
+
89f6b3
+
89f6b3
+static const char *cli_license =
89f6b3
+"This program is free software. You can distribute it and/or modify it\n"
89f6b3
+"under the terms of the GNU General Public License version 2.\n"
89f6b3
+"\n";
89f6b3
+/*
89f6b3
+"Alternatively, this software may be distributed under the terms of the\n"
89f6b3
+"BSD license. See README and COPYING for more details.\n";
89f6b3
+*/
89f6b3
+
89f6b3
+static const char *cli_full_license =
89f6b3
+"This program is free software; you can redistribute it and/or modify\n"
89f6b3
+"it under the terms of the GNU General Public License version 2 as\n"
89f6b3
+"published by the Free Software Foundation.\n"
89f6b3
+"\n"
89f6b3
+"This program is distributed in the hope that it will be useful,\n"
89f6b3
+"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
89f6b3
+"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
89f6b3
+"GNU General Public License for more details.\n"
89f6b3
+"\n"
89f6b3
+"You should have received a copy of the GNU General Public License\n"
89f6b3
+"along with this program; if not, write to the Free Software\n"
89f6b3
+"Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n"
89f6b3
+"\n"
89f6b3
+"Alternatively, this software may be distributed under the terms of the\n"
89f6b3
+"BSD license.\n"
89f6b3
+"\n"
89f6b3
+"Redistribution and use in source and binary forms, with or without\n"
89f6b3
+"modification, are permitted provided that the following conditions are\n"
89f6b3
+"met:\n"
89f6b3
+"\n"
89f6b3
+"1. Redistributions of source code must retain the above copyright\n"
89f6b3
+"   notice, this list of conditions and the following disclaimer.\n"
89f6b3
+"\n"
89f6b3
+"2. Redistributions in binary form must reproduce the above copyright\n"
89f6b3
+"   notice, this list of conditions and the following disclaimer in the\n"
89f6b3
+"   documentation and/or other materials provided with the distribution.\n"
89f6b3
+"\n"
89f6b3
+"3. Neither the name(s) of the above-listed copyright holder(s) nor the\n"
89f6b3
+"   names of its contributors may be used to endorse or promote products\n"
89f6b3
+"   derived from this software without specific prior written permission.\n"
89f6b3
+"\n"
89f6b3
+"THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
89f6b3
+"\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
89f6b3
+"LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
89f6b3
+"A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n"
89f6b3
+"OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
89f6b3
+"SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
89f6b3
+"LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
89f6b3
+"DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
89f6b3
+"THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
89f6b3
+"(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
89f6b3
+"OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
89f6b3
+"\n";
89f6b3
+
89f6b3
+static const char *commands_usage =
89f6b3
+"Usage:\n"
89f6b3
+"  vdptool <command> [options] [arg]   general command line usage format\n"
89f6b3
+"  vdptool                             go into interactive mode\n"
89f6b3
+"          <command> [options] [arg]   general interactive command format\n";
89f6b3
+
89f6b3
+static const char *commands_options =
89f6b3
+"Options:\n"
89f6b3
+"  -i [ifname]           network interface\n"
89f6b3
+"  -V [tlvid]            TLV identifier\n"
89f6b3
+"                        may be numeric or keyword (see below)\n"
89f6b3
+"  -c <argument list>    used with get TLV command to specify\n"
89f6b3
+"                        that the list of configuration elements\n"
89f6b3
+"  -n                    \"neighbor\" option for command (To be done)\n"
89f6b3
+"  -r                    show raw message\n"
89f6b3
+"  -R                    show only raw messages\n";
89f6b3
+
89f6b3
+static const char *commands_help =
89f6b3
+"Commands:\n"
89f6b3
+"  license    show license information\n"
89f6b3
+"  -h|help    show command usage information\n"
89f6b3
+"  -v|version show version\n"
89f6b3
+"  -p|ping    ping lldpad and query pid of lldpad\n"
89f6b3
+"  -q|quit    exit lldptool (interactive mode)\n"
89f6b3
+"  -t|get-tlv get tlvid value\n"
89f6b3
+"  -T|set-tlv set arg for tlvid to value\n";
89f6b3
+
89f6b3
+static struct clif *clif_conn;
89f6b3
+static int cli_quit;
89f6b3
+static int cli_attached;
89f6b3
+
89f6b3
+/*
89f6b3
+ * insert to head, so first one is last
89f6b3
+ */
89f6b3
+struct lldp_module *(*register_tlv_table[])(void) = {
89f6b3
+	vdp22_cli_register,
89f6b3
+	NULL,
89f6b3
+};
89f6b3
+
89f6b3
+static void init_modules(void)
89f6b3
+{
89f6b3
+	struct lldp_module *module;
89f6b3
+	struct lldp_module *premod = NULL;
89f6b3
+	int i = 0;
89f6b3
+
89f6b3
+	LIST_INIT(&lldp_head);
89f6b3
+	for (i = 0; register_tlv_table[i]; i++) {
89f6b3
+		module = register_tlv_table[i]();
89f6b3
+		if (premod)
89f6b3
+			LIST_INSERT_AFTER(premod, module, lldp);
89f6b3
+		else
89f6b3
+			LIST_INSERT_HEAD(&lldp_head, module, lldp);
89f6b3
+		premod = module;
89f6b3
+	}
89f6b3
+}
89f6b3
+
89f6b3
+void deinit_modules(void)
89f6b3
+{
89f6b3
+	struct lldp_module *module;
89f6b3
+
89f6b3
+	while (lldp_head.lh_first != NULL) {
89f6b3
+		module = lldp_head.lh_first;
89f6b3
+		LIST_REMOVE(lldp_head.lh_first, lldp);
89f6b3
+		module->ops->lldp_mod_unregister(module);
89f6b3
+	}
89f6b3
+}
89f6b3
+
89f6b3
+static void usage(void)
89f6b3
+{
89f6b3
+	fprintf(stderr, "%s\n", cli_version);
89f6b3
+	fprintf(stderr, "\n%s\n%s\n%s\n",
89f6b3
+		commands_usage, commands_options, commands_help);
89f6b3
+}
89f6b3
+
89f6b3
+static void print_raw_message(char *msg, int print)
89f6b3
+{
89f6b3
+	if (!print || !(print & SHOW_RAW))
89f6b3
+		return;
89f6b3
+
89f6b3
+	if (!(print & SHOW_RAW_ONLY)) {
89f6b3
+		switch (msg[MSG_TYPE]) {
89f6b3
+		case EVENT_MSG:
89f6b3
+			printf("event: ");
89f6b3
+			break;
89f6b3
+		case CMD_RESPONSE:
89f6b3
+			printf("rsp: ");
89f6b3
+			break;
89f6b3
+		default:
89f6b3
+			printf("cmd: ");
89f6b3
+			break;
89f6b3
+		}
89f6b3
+	}
89f6b3
+	printf("%s\n", msg);
89f6b3
+}
89f6b3
+
89f6b3
+static int parse_print_message(char *msg, int print)
89f6b3
+{
89f6b3
+	int status = 0;
89f6b3
+
89f6b3
+	status = vdp_parse_response(msg);
89f6b3
+	print_raw_message(msg, print);
89f6b3
+	if (print & SHOW_RAW_ONLY)
89f6b3
+		return status;
89f6b3
+
89f6b3
+	if (msg[MSG_TYPE] == CMD_RESPONSE)
89f6b3
+		vdp_print_response(msg, status);
89f6b3
+	else if (msg[MSG_TYPE] == MOD_CMD && msg[MOD_MSG_TYPE] == EVENT_MSG)
89f6b3
+		vdp_print_event_msg(&msg[MOD_MSG_TYPE]);
89f6b3
+	return status;
89f6b3
+}
89f6b3
+
89f6b3
+static void cli_close_connection(void)
89f6b3
+{
89f6b3
+	if (clif_conn == NULL)
89f6b3
+		return;
89f6b3
+
89f6b3
+	if (cli_attached) {
89f6b3
+		clif_detach(clif_conn);
89f6b3
+		cli_attached = 0;
89f6b3
+	}
89f6b3
+	clif_close(clif_conn);
89f6b3
+	clif_conn = NULL;
89f6b3
+}
89f6b3
+
89f6b3
+
89f6b3
+static void cli_msg_cb(char *msg, UNUSED size_t len)
89f6b3
+{
89f6b3
+	parse_print_message(msg, SHOW_OUTPUT | show_raw);
89f6b3
+}
89f6b3
+
89f6b3
+
89f6b3
+/* structure of the print argument bitmap:
89f6b3
+ *     SHOW_NO_OUTPUT (0x0) - don't print anything for the command
89f6b3
+ *     SHOW_OUTPUT (0x01)   - print output for the command
89f6b3
+ *     SHOW_RAW (0x02)      - print the raw clif command messages
89f6b3
+ *     SHOW_RAW_ONLY (0x04) - print only the raw clif command messages
89f6b3
+*/
89f6b3
+static int _clif_command(struct clif *clif, char *cmd, int print)
89f6b3
+{
89f6b3
+	char buf[MAX_CLIF_MSGBUF];
89f6b3
+	size_t len;
89f6b3
+	int ret;
89f6b3
+
89f6b3
+	print_raw_message(cmd, print);
89f6b3
+
89f6b3
+	if (clif_conn == NULL) {
89f6b3
+		printf("Not connected to lldpad - command dropped.\n");
89f6b3
+		return -1;
89f6b3
+	}
89f6b3
+	len = sizeof(buf) - 1;
89f6b3
+	ret = clif_request(clif, cmd, strlen(cmd), buf, &len, cli_msg_cb);
89f6b3
+	if (ret == -2) {
89f6b3
+		printf("'%s' command timed out.\n", cmd);
89f6b3
+		return -2;
89f6b3
+	} else if (ret < 0) {
89f6b3
+		printf("'%s' command failed.\n", cmd);
89f6b3
+		return -1;
89f6b3
+	}
89f6b3
+	if (print) {
89f6b3
+		buf[len] = '\0';
89f6b3
+		ret = parse_print_message(buf, print);
89f6b3
+	}
89f6b3
+
89f6b3
+	return ret;
89f6b3
+}
89f6b3
+
89f6b3
+int vdp_clif_command(struct clif *clif, char *cmd, int raw)
89f6b3
+{
89f6b3
+	return _clif_command(clif, cmd, SHOW_OUTPUT | raw);
89f6b3
+}
89f6b3
+
89f6b3
+static int cli_cmd_ping(struct clif *clif, UNUSED int argc, UNUSED char *argv[],
89f6b3
+			UNUSED struct cmd *command, int raw)
89f6b3
+{
89f6b3
+	return vdp_clif_command(clif, "P", raw);
89f6b3
+}
89f6b3
+
89f6b3
+static int
89f6b3
+cli_cmd_nop(UNUSED struct clif *clif, UNUSED int argc, UNUSED char *argv[],
89f6b3
+	    UNUSED struct cmd *command, UNUSED int raw)
89f6b3
+{
89f6b3
+	return 0;
89f6b3
+}
89f6b3
+
89f6b3
+static int
89f6b3
+cli_cmd_help(UNUSED struct clif *clif, UNUSED int argc, UNUSED char *argv[],
89f6b3
+	     UNUSED struct cmd *command, UNUSED int raw)
89f6b3
+{
89f6b3
+	struct lldp_module *np;
89f6b3
+
89f6b3
+	printf("%s\n%s\n%s", commands_usage, commands_options, commands_help);
89f6b3
+
89f6b3
+	printf("\nTLV identifiers:\n");
89f6b3
+	LIST_FOREACH(np, &lldp_head, lldp)
89f6b3
+		if (np->ops->print_help)
89f6b3
+			np->ops->print_help();
89f6b3
+	return 0;
89f6b3
+}
89f6b3
+
89f6b3
+static int
89f6b3
+cli_cmd_version(UNUSED struct clif *clif, UNUSED int argc, UNUSED char *argv[],
89f6b3
+		UNUSED struct cmd *command, UNUSED int raw)
89f6b3
+{
89f6b3
+	printf("%s\n", cli_version);
89f6b3
+	return 0;
89f6b3
+}
89f6b3
+
89f6b3
+static int
89f6b3
+cli_cmd_license(UNUSED struct clif *clif, UNUSED int argc, UNUSED char *argv[],
89f6b3
+		UNUSED struct cmd *command, UNUSED int raw)
89f6b3
+{
89f6b3
+	printf("%s\n", cli_full_license);
89f6b3
+	return 0;
89f6b3
+}
89f6b3
+
89f6b3
+static int
89f6b3
+cli_cmd_quit(UNUSED struct clif *clif, UNUSED int argc, UNUSED char *argv[],
89f6b3
+	     UNUSED struct cmd *command, UNUSED int raw)
89f6b3
+{
89f6b3
+	cli_quit = 1;
89f6b3
+	return 0;
89f6b3
+}
89f6b3
+
89f6b3
+static struct cli_cmd {
89f6b3
+	vdp22_cmd cmdcode;
89f6b3
+	const char *cmdstr;
89f6b3
+	int (*handler)(struct clif *clif, int argc, char *argv[],
89f6b3
+		       struct cmd *cmd, int raw);
89f6b3
+} cli_commands[] = {
89f6b3
+	{ cmd_ping,     "ping",      cli_cmd_ping },
89f6b3
+	{ cmd_help,     "help",      cli_cmd_help },
89f6b3
+	{ cmd_license,  "license",   cli_cmd_license },
89f6b3
+	{ cmd_version,  "version",   cli_cmd_version },
89f6b3
+	{ cmd_quit,     "quit",      cli_cmd_quit },
89f6b3
+	{ cmd_gettlv,   "gettlv",    vdp_cmd_gettlv },
89f6b3
+	{ cmd_gettlv,   "get-tlv",   vdp_cmd_gettlv },
89f6b3
+	{ cmd_settlv,   "settlv",    vdp_cmd_settlv },
89f6b3
+	{ cmd_settlv,   "set-tlv",   vdp_cmd_settlv },
89f6b3
+	{ cmd_nop,       NULL,       cli_cmd_nop }
89f6b3
+};
89f6b3
+
89f6b3
+u32 lookup_tlvid(char *tlvid_str)
89f6b3
+{
89f6b3
+	struct lldp_module *np;
89f6b3
+	u32 tlvid = INVALID_TLVID;
89f6b3
+
89f6b3
+	LIST_FOREACH(np, &lldp_head, lldp) {
89f6b3
+		if (np->ops->lookup_tlv_name) {
89f6b3
+			tlvid = np->ops->lookup_tlv_name(tlvid_str);
89f6b3
+			if (tlvid != INVALID_TLVID)
89f6b3
+				break;
89f6b3
+		}
89f6b3
+	}
89f6b3
+
89f6b3
+	return tlvid;
89f6b3
+}
89f6b3
+
89f6b3
+void print_args(int argc, char *argv[])
89f6b3
+{
89f6b3
+	int i;
89f6b3
+
89f6b3
+	for (i = 0; i < argc; i++)
89f6b3
+		printf("\tremaining arg %d = %s\n", i, argv[i]);
89f6b3
+}
89f6b3
+
89f6b3
+static struct option lldptool_opts[] = {
89f6b3
+	{"help", 0, NULL, 'h'},
89f6b3
+	{"version", 0, NULL, 'v'},
89f6b3
+	{"stats", 0, NULL, 'S'},
89f6b3
+	{"get-tlv", 0, NULL, 't'},
89f6b3
+	{"set-tlv", 0, NULL, 'T'},
89f6b3
+	{"get-lldp", 0, NULL, 'l'},
89f6b3
+	{"set-lldp", 0, NULL, 'L'},
89f6b3
+	{0, 0, 0, 0}
89f6b3
+};
89f6b3
+
89f6b3
+static int request(struct clif *clif, int argc, char *argv[])
89f6b3
+{
89f6b3
+	struct cli_cmd *cmd, *match = NULL;
89f6b3
+	struct cmd command;
89f6b3
+	int count;
89f6b3
+	int ret	= 0;
89f6b3
+	int newraw = 0;
89f6b3
+	int numargs = 0;
89f6b3
+	char **argptr = &argv[0];
89f6b3
+	char *end;
89f6b3
+	int c;
89f6b3
+	int option_index;
89f6b3
+
89f6b3
+	memset((void *)&command, 0, sizeof(command));
89f6b3
+	command.cmd = cmd_nop;
89f6b3
+	command.type = NEAREST_CUSTOMER_BRIDGE;
89f6b3
+	command.module_id = LLDP_MOD_VDP22;
89f6b3
+	command.tlvid = INVALID_TLVID;
89f6b3
+
89f6b3
+	opterr = 0;
89f6b3
+	for (;;) {
89f6b3
+		c = getopt_long(argc, argv, "i:tThcnvrRpqV:",
89f6b3
+				lldptool_opts, &option_index);
89f6b3
+		if (c < 0)
89f6b3
+			break;
89f6b3
+		switch (c) {
89f6b3
+		case '?':
89f6b3
+			printf("missing argument for option %s\n\n",
89f6b3
+			       argv[optind-1]);
89f6b3
+			usage();
89f6b3
+			return -1;
89f6b3
+		case 'i':
89f6b3
+			strncpy(command.ifname, optarg, IFNAMSIZ);
89f6b3
+			command.ifname[IFNAMSIZ] = '\0';
89f6b3
+			break;
89f6b3
+		case 'V':
89f6b3
+			if (command.tlvid != INVALID_TLVID) {
89f6b3
+				printf("\nInvalid command: multiple TLV identifiers: %s\n",
89f6b3
+				       optarg);
89f6b3
+				return -1;
89f6b3
+			}
89f6b3
+
89f6b3
+			/* Currently tlvid unset lookup and verify parameter */
89f6b3
+			errno = 0;
89f6b3
+			command.tlvid = strtoul(optarg, &end, 0);
89f6b3
+			if (!command.tlvid || errno || *end != '\0' ||
89f6b3
+			    end == optarg)
89f6b3
+				command.tlvid = lookup_tlvid(optarg);
89f6b3
+			if (command.tlvid == INVALID_TLVID) {
89f6b3
+				printf("\nInvalid TLV identifier: %s\n",
89f6b3
+					optarg);
89f6b3
+				return -1;
89f6b3
+			}
89f6b3
+			break;
89f6b3
+		case 'p':
89f6b3
+			command.cmd = cmd_ping;
89f6b3
+			break;
89f6b3
+		case 'q':
89f6b3
+			command.cmd = cmd_quit;
89f6b3
+			break;
89f6b3
+		case 't':
89f6b3
+			command.cmd = cmd_gettlv;
89f6b3
+			break;
89f6b3
+		case 'T':
89f6b3
+			command.cmd = cmd_settlv;
89f6b3
+			break;
89f6b3
+		case 'c':
89f6b3
+			command.ops |= op_config;
89f6b3
+			break;
89f6b3
+		case 'n':
89f6b3
+			command.ops |= op_neighbor;
89f6b3
+			break;
89f6b3
+		case 'h':
89f6b3
+			command.cmd = cmd_help;
89f6b3
+			break;
89f6b3
+		case 'r':
89f6b3
+			if (newraw) {
89f6b3
+				usage();
89f6b3
+				return -1;
89f6b3
+			}
89f6b3
+			newraw = SHOW_RAW;
89f6b3
+			break;
89f6b3
+		case 'R':
89f6b3
+			if (newraw) {
89f6b3
+				usage();
89f6b3
+				return -1;
89f6b3
+			}
89f6b3
+			newraw = (SHOW_RAW | SHOW_RAW_ONLY);
89f6b3
+			break;
89f6b3
+		case 'v':
89f6b3
+			command.cmd = cmd_version;
89f6b3
+			break;
89f6b3
+		default:
89f6b3
+			usage();
89f6b3
+			ret = -1;
89f6b3
+		}
89f6b3
+	}
89f6b3
+
89f6b3
+	/* if no command was supplied via an option flag, then
89f6b3
+	 * the first remaining argument should be the command.
89f6b3
+	 */
89f6b3
+	count = 0;
89f6b3
+	if (command.cmd == cmd_nop && optind < argc) {
89f6b3
+		cmd = cli_commands;
89f6b3
+		while (cmd->cmdcode != cmd_nop) {
89f6b3
+			if (strncasecmp(cmd->cmdstr, argv[optind],
89f6b3
+			    strlen(argv[optind])) == 0) {
89f6b3
+				match = cmd;
89f6b3
+				command.cmd = match->cmdcode;
89f6b3
+				count++;
89f6b3
+			}
89f6b3
+			cmd++;
89f6b3
+		}
89f6b3
+	}
89f6b3
+
89f6b3
+	if (count > 1) {
89f6b3
+		printf("Ambiguous command '%s'; possible commands:",
89f6b3
+			argv[optind]);
89f6b3
+		cmd = cli_commands;
89f6b3
+		while (cmd->cmdstr) {
89f6b3
+			if (strncasecmp(cmd->cmdstr, argv[optind],
89f6b3
+			    strlen(argv[optind])) == 0)
89f6b3
+				printf(" %s", cmd->cmdstr);
89f6b3
+			cmd++;
89f6b3
+		}
89f6b3
+		printf("\n");
89f6b3
+		ret = -1;
89f6b3
+	} else {
89f6b3
+		if (!match) {
89f6b3
+			cmd = cli_commands;
89f6b3
+			while (cmd->cmdcode != command.cmd)
89f6b3
+				cmd++;
89f6b3
+			match = cmd;
89f6b3
+		}
89f6b3
+		numargs = argc-optind - count;
89f6b3
+		if (numargs)
89f6b3
+			argptr = &argv[argc-numargs];
89f6b3
+		ret = match->handler(clif, numargs, argptr, &command, newraw);
89f6b3
+	}
89f6b3
+	return ret;
89f6b3
+}
89f6b3
+
89f6b3
+static void cli_recv_pending(struct clif *clif, int in_read)
89f6b3
+{
89f6b3
+	int first = 1;
89f6b3
+
89f6b3
+	if (clif == NULL)
89f6b3
+		return;
89f6b3
+	while (clif_pending(clif)) {
89f6b3
+		char buf[256];
89f6b3
+		size_t len = sizeof(buf) - 1;
89f6b3
+		if (clif_recv(clif, buf, &len) == 0) {
89f6b3
+			buf[len] = '\0';
89f6b3
+			if (in_read && first)
89f6b3
+				printf("\n");
89f6b3
+			first = 0;
89f6b3
+			cli_msg_cb(buf, len);
89f6b3
+		} else {
89f6b3
+			printf("Could not read pending message.\n");
89f6b3
+			break;
89f6b3
+		}
89f6b3
+	}
89f6b3
+}
89f6b3
+
89f6b3
+static char *do_readline(const char *prompt)
89f6b3
+{
89f6b3
+	size_t	size = 0;
89f6b3
+	ssize_t	rc;
89f6b3
+	char	*line = NULL;
89f6b3
+
89f6b3
+	fputs(prompt, stdout);
89f6b3
+	fflush(stdout);
89f6b3
+
89f6b3
+	rc = getline(&line, &size, stdin);
89f6b3
+	if (rc <= 0)
89f6b3
+		return NULL;
89f6b3
+	if (line[rc - 1] == '\n')
89f6b3
+		line[rc - 1] = 0;
89f6b3
+	return line;
89f6b3
+}
89f6b3
+
89f6b3
+static void cli_interactive(void)
89f6b3
+{
89f6b3
+	const int max_args = 20;
89f6b3
+	char *cmd, *argv[max_args], *pos;
89f6b3
+	int argc;
89f6b3
+
89f6b3
+	setlinebuf(stdout);
89f6b3
+	printf("\nInteractive mode\n\n");
89f6b3
+	do {
89f6b3
+		cli_recv_pending(clif_conn, 0);
89f6b3
+		alarm(1);
89f6b3
+		cmd = do_readline("> ");
89f6b3
+		alarm(0);
89f6b3
+		if (!cmd)
89f6b3
+			break;
89f6b3
+		argc = 1;
89f6b3
+		pos = cmd;
89f6b3
+		for (;;) {
89f6b3
+			while (*pos == ' ')
89f6b3
+				pos++;
89f6b3
+			if (*pos == '\0')
89f6b3
+				break;
89f6b3
+			argv[argc] = pos;
89f6b3
+			argc++;
89f6b3
+			if (argc == max_args)
89f6b3
+				break;
89f6b3
+			while (*pos != '\0' && *pos != ' ')
89f6b3
+				pos++;
89f6b3
+			if (*pos == ' ')
89f6b3
+				*pos++ = '\0';
89f6b3
+		}
89f6b3
+		if (argc) {
89f6b3
+			optind = 0;
89f6b3
+			request(clif_conn, argc, argv);
89f6b3
+		}
89f6b3
+		free(cmd);
89f6b3
+	} while (!cli_quit);
89f6b3
+}
89f6b3
+
89f6b3
+static void cli_terminate(UNUSED int sig)
89f6b3
+{
89f6b3
+	cli_close_connection();
89f6b3
+	exit(0);
89f6b3
+}
89f6b3
+
89f6b3
+static void cli_alarm(UNUSED int sig)
89f6b3
+{
89f6b3
+	if (clif_conn && _clif_command(clif_conn, "P", SHOW_NO_OUTPUT)) {
89f6b3
+		printf("Connection to lldpad lost - trying to reconnect\n");
89f6b3
+		cli_close_connection();
89f6b3
+	}
89f6b3
+	if (!clif_conn) {
89f6b3
+		clif_conn = clif_open();
89f6b3
+		if (clif_conn) {
89f6b3
+			char attach_str[9] = "";
89f6b3
+			u32 mod_id = LLDP_MOD_VDP22;
89f6b3
+			bin2hexstr((u8 *)&mod_id, 4, attach_str, 8);
89f6b3
+			printf("Connection to lldpad re-established\n");
89f6b3
+			if (clif_attach(clif_conn, attach_str) == 0)
89f6b3
+				cli_attached = 1;
89f6b3
+			else
89f6b3
+				printf("Warning: Failed to attach to lldpad.\n");
89f6b3
+		}
89f6b3
+	}
89f6b3
+	if (clif_conn)
89f6b3
+		cli_recv_pending(clif_conn, 1);
89f6b3
+	alarm(1);
89f6b3
+}
89f6b3
+
89f6b3
+
89f6b3
+int main(int argc, char *argv[])
89f6b3
+{
89f6b3
+	int interactive = 1;
89f6b3
+	int warning_displayed = 0;
89f6b3
+	int ret = 0;
89f6b3
+
89f6b3
+	if (argc > 1)
89f6b3
+		interactive = 0;
89f6b3
+	if (interactive)
89f6b3
+		printf("%s\n\n%s\n\n", cli_version, cli_license);
89f6b3
+	for (;;) {
89f6b3
+		clif_conn = clif_open();
89f6b3
+		if (clif_conn) {
89f6b3
+			if (warning_displayed)
89f6b3
+				printf("Connection established.\n");
89f6b3
+			break;
89f6b3
+		}
89f6b3
+
89f6b3
+		if (!interactive) {
89f6b3
+			perror("Failed to connect to lldpad - clif_open");
89f6b3
+			return -1;
89f6b3
+		}
89f6b3
+
89f6b3
+		if (!warning_displayed) {
89f6b3
+			printf("Could not connect to lldpad - re-trying\n");
89f6b3
+			warning_displayed = 1;
89f6b3
+		}
89f6b3
+		sleep(1);
89f6b3
+	}
89f6b3
+
89f6b3
+	init_modules();
89f6b3
+	signal(SIGINT, cli_terminate);
89f6b3
+	signal(SIGTERM, cli_terminate);
89f6b3
+	signal(SIGALRM, cli_alarm);
89f6b3
+
89f6b3
+	if (interactive) {
89f6b3
+		char attach_str[9] = "";
89f6b3
+		u32 mod_id = LLDP_MOD_VDP22;
89f6b3
+		bin2hexstr((u8 *)&mod_id, 4, attach_str, 8);
89f6b3
+		if (clif_attach(clif_conn, attach_str) == 0)
89f6b3
+			cli_attached = 1;
89f6b3
+		else
89f6b3
+			printf("Warning: Failed to attach to lldpad.\n");
89f6b3
+		cli_interactive();
89f6b3
+	} else {
89f6b3
+		ret = request(clif_conn, argc, &argv[0]);
89f6b3
+		ret = !!ret;
89f6b3
+	}
89f6b3
+	cli_close_connection();
89f6b3
+	deinit_modules();
89f6b3
+	return ret;
89f6b3
+}
89f6b3
-- 
89f6b3
2.1.0
89f6b3