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

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