diff options
author | Reyk Floeter <reyk@cvs.openbsd.org> | 2006-03-28 15:48:35 +0000 |
---|---|---|
committer | Reyk Floeter <reyk@cvs.openbsd.org> | 2006-03-28 15:48:35 +0000 |
commit | d9940f1f9b9527cb02647235d5d3ab16e1efd331 (patch) | |
tree | ef52e3f672c65fe9de76e003c02ed7873badae63 /usr.sbin/tcpdump/print-lldp.c | |
parent | cff9071d88082990af47a0a05d95dfb54bdff887 (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.c | 287 |
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]"); +} + |