summaryrefslogtreecommitdiff
path: root/usr.sbin/tcpdump/print-lldp.c
diff options
context:
space:
mode:
authorReyk Floeter <reyk@cvs.openbsd.org>2006-03-28 15:48:35 +0000
committerReyk Floeter <reyk@cvs.openbsd.org>2006-03-28 15:48:35 +0000
commitd9940f1f9b9527cb02647235d5d3ab16e1efd331 (patch)
treeef52e3f672c65fe9de76e003c02ed7873badae63 /usr.sbin/tcpdump/print-lldp.c
parentcff9071d88082990af47a0a05d95dfb54bdff887 (diff)
Add a simple printer for IEEE 802.1AB LLDP, the Link Layer Discovery
Protocol. LLDP is used by some switch vendors as a replacement for the non-free Cizzco Discovery Protocol (CDP) due to some Cisco patentry... ok brad@
Diffstat (limited to 'usr.sbin/tcpdump/print-lldp.c')
-rw-r--r--usr.sbin/tcpdump/print-lldp.c287
1 files changed, 287 insertions, 0 deletions
diff --git a/usr.sbin/tcpdump/print-lldp.c b/usr.sbin/tcpdump/print-lldp.c
new file mode 100644
index 00000000000..38acdd4e5fc
--- /dev/null
+++ b/usr.sbin/tcpdump/print-lldp.c
@@ -0,0 +1,287 @@
+/* $OpenBSD: print-lldp.c,v 1.1 2006/03/28 15:48:33 reyk Exp $ */
+
+/*
+ * Copyright (c) 2006 Reyk Floeter <reyk@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/if_ether.h>
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "addrtoname.h"
+#include "interface.h"
+#include "afnum.h"
+
+enum {
+ LLDP_TLV_END = 0,
+ LLDP_TLV_CHASSIS_ID = 1,
+ LLDP_TLV_PORT_ID = 2,
+ LLDP_TLV_TTL = 3,
+ LLDP_TLV_PORT_DESCR = 4,
+ LLDP_TLV_SYSTEM_NAME = 5,
+ LLDP_TLV_SYSTEM_DESCR = 6,
+ LLDP_TLV_SYSTEM_CAP = 7,
+ LLDP_TLV_MANAGEMENT_ADDR = 8,
+ LLDP_TLV_ORG = 127
+};
+
+enum {
+ LLDP_CHASSISID_SUBTYPE_CHASSIS = 1,
+ LLDP_CHASSISID_SUBTYPE_IFALIAS = 2,
+ LLDP_CHASSISID_SUBTYPE_PORT = 3,
+ LLDP_CHASSISID_SUBTYPE_LLADDR = 4,
+ LLDP_CHASSISID_SUBTYPE_ADDR = 5,
+ LLDP_CHASSISID_SUBTYPE_IFNAME = 6,
+ LLDP_CHASSISID_SUBTYPE_LOCAL = 7
+};
+
+enum {
+ LLDP_PORTID_SUBTYPE_IFALIAS = 1,
+ LLDP_PORTID_SUBTYPE_PORT = 2,
+ LLDP_PORTID_SUBTYPE_LLADDR = 3,
+ LLDP_PORTID_SUBTYPE_ADDR = 4,
+ LLDP_PORTID_SUBTYPE_IFNAME = 5,
+ LLDP_PORTID_SUBTYPE_AGENTCID = 6,
+ LLDP_PORTID_SUBTYPE_LOCAL = 7
+};
+
+#define LLDP_CAP_OTHER 0x01
+#define LLDP_CAP_REPEATER 0x02
+#define LLDP_CAP_BRIDGE 0x04
+#define LLDP_CAP_WLAN 0x08
+#define LLDP_CAP_ROUTER 0x10
+#define LLDP_CAP_TELEPHONE 0x20
+#define LLDP_CAP_DOCSIS 0x40
+#define LLDP_CAP_STATION 0x80
+#define LLDP_CAP_BITS \
+ "\20\01OTHER\02REPEATER\03BRIDGE\04WLAN\05ROUTER\06TELEPHONE" \
+ "\07DOCSIS\10STATION"
+
+enum {
+ LLDP_MGMT_IFACE_UNKNOWN = 1,
+ LLDP_MGMT_IFACE_IFINDEX = 2,
+ LLDP_MGMT_IFACE_SYSPORT = 3
+};
+
+static const char *afnumber[] = AFNUM_NAME_STR;
+
+void
+lldp_print_str(u_int8_t *str, int len)
+{
+ int i;
+ printf("\"");
+ for (i = 0; i < len; i++)
+ printf("%c", isprint(str[i]) ? str[i] : '.');
+ printf("\"");
+}
+
+void
+lldp_print_id(int type, u_int8_t *ptr, int len)
+{
+ u_int8_t id;
+ u_int8_t *data;
+
+ id = *(u_int8_t *)ptr;
+ len -= sizeof(u_int8_t);
+ data = ptr + sizeof(u_int8_t);
+ if (len <= 0)
+ return;
+
+ if (type == LLDP_TLV_CHASSIS_ID) {
+ switch (id) {
+ case LLDP_CHASSISID_SUBTYPE_CHASSIS:
+ printf("chassis ");
+ lldp_print_str(data, len);
+ break;
+ case LLDP_CHASSISID_SUBTYPE_IFALIAS:
+ printf("ifalias");
+ break;
+ case LLDP_CHASSISID_SUBTYPE_PORT:
+ printf("port");
+ break;
+ case LLDP_CHASSISID_SUBTYPE_LLADDR:
+ printf("lladdr %s",
+ ether_ntoa((struct ether_addr *)data));
+ break;
+ case LLDP_CHASSISID_SUBTYPE_ADDR:
+ printf("addr");
+ break;
+ case LLDP_CHASSISID_SUBTYPE_IFNAME:
+ printf("ifname ");
+ lldp_print_str(data, len);
+ break;
+ case LLDP_CHASSISID_SUBTYPE_LOCAL:
+ printf("local ");
+ lldp_print_str(data, len);
+ break;
+ default:
+ printf("unknown 0x%02x", id);
+ break;
+ }
+
+ } else if (type == LLDP_TLV_PORT_ID) {
+ switch (id) {
+ case LLDP_PORTID_SUBTYPE_IFALIAS:
+ printf("ifalias");
+ break;
+ case LLDP_PORTID_SUBTYPE_PORT:
+ printf("port");
+ break;
+ case LLDP_PORTID_SUBTYPE_LLADDR:
+ printf("lladdr %s",
+ ether_ntoa((struct ether_addr *)data));
+ break;
+ case LLDP_PORTID_SUBTYPE_ADDR:
+ printf("addr");
+ break;
+ case LLDP_PORTID_SUBTYPE_IFNAME:
+ printf("ifname ");
+ lldp_print_str(data, len);
+ break;
+ case LLDP_PORTID_SUBTYPE_AGENTCID:
+ printf("agentcid");
+ break;
+ case LLDP_PORTID_SUBTYPE_LOCAL:
+ printf("local ");
+ lldp_print_str(data, len);
+ break;
+ default:
+ printf("unknown 0x%02x", id);
+ break;
+ }
+ }
+}
+
+void
+lldp_print(const u_char *p, u_int len)
+{
+ u_int16_t tlv;
+ u_int8_t *ptr = (u_int8_t *)p, v = 0;
+ int n, type, vlen, alen;
+
+ printf("LLDP");
+
+#define _ptrinc(_v) ptr += (_v); vlen -= (_v);
+
+ for (n = 0; n < len;) {
+ TCHECK2(*ptr, sizeof(tlv));
+
+ tlv = ntohs(*(u_int16_t *)ptr);
+ type = (tlv & 0xfe00) >> 9;
+ vlen = tlv & 0x1ff;
+ n += vlen;
+
+ ptr += sizeof(tlv);
+ TCHECK2(*ptr, vlen);
+
+ switch (type) {
+ case LLDP_TLV_END:
+ goto done;
+ break;
+
+ case LLDP_TLV_CHASSIS_ID:
+ printf(", Chassis ID: ");
+ lldp_print_id(type, ptr, vlen);
+ break;
+
+ case LLDP_TLV_PORT_ID:
+ printf(", Port ID: ");
+ lldp_print_id(type, ptr, vlen);
+ break;
+
+ case LLDP_TLV_TTL:
+ printf(", TTL: ");
+ TCHECK2(*ptr, 2);
+ printf("%ds", ntohs(*(u_int16_t *)ptr));
+ break;
+
+ case LLDP_TLV_PORT_DESCR:
+ printf(", Port Description: ");
+ lldp_print_str(ptr, vlen);
+ break;
+
+ case LLDP_TLV_SYSTEM_NAME:
+ printf(", System Name: ");
+ lldp_print_str(ptr, vlen);
+ break;
+
+ case LLDP_TLV_SYSTEM_DESCR:
+ printf(", System Description: ");
+ lldp_print_str(ptr, vlen);
+ break;
+
+ case LLDP_TLV_SYSTEM_CAP:
+ printf(", System Capabilities:");
+ TCHECK2(*ptr, 4);
+ printb(" available", ntohs(*(u_int16_t *)ptr),
+ LLDP_CAP_BITS);
+ _ptrinc(sizeof(u_int16_t));
+ printb(" enabled", ntohs(*(u_int16_t *)ptr),
+ LLDP_CAP_BITS);
+ break;
+
+ case LLDP_TLV_MANAGEMENT_ADDR:
+ printf(", Management Address:");
+ TCHECK2(*ptr, 2);
+ alen = *ptr - sizeof(u_int8_t);
+ _ptrinc(sizeof(u_int8_t));
+ v = *ptr;
+ _ptrinc(sizeof(u_int8_t));
+ if (v <= AFNUM_MAX)
+ printf(" %s", afnumber[v]);
+ else
+ printf(" type %d", v);
+ TCHECK2(*ptr, alen);
+ switch (v) {
+ case AFNUM_INET:
+ if (alen != sizeof(struct in_addr))
+ goto trunc;
+ printf(" %s",
+ inet_ntoa(*(struct in_addr*)ptr));
+ break;
+ }
+ _ptrinc(alen);
+ v = *(u_int8_t *)ptr;
+ break;
+
+ case LLDP_TLV_ORG:
+ printf(", Org Specific");
+ break;
+
+ default:
+ printf(", type %d length %d", type, vlen);
+ break;
+ }
+ ptr += vlen;
+ }
+
+ done:
+ return;
+
+ trunc:
+ printf(" [|LLDP]");
+}
+