1 /* $OpenBSD: print-lldp.c,v 1.9 2016/11/28 17:47:15 jca Exp $ */ 2 3 /* 4 * Copyright (c) 2006 Reyk Floeter <reyk@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/time.h> 20 #include <sys/socket.h> 21 22 #include <net/if.h> 23 24 #include <netinet/in.h> 25 #include <netinet/if_ether.h> 26 #include <arpa/inet.h> 27 28 #include <ctype.h> 29 #include <stdio.h> 30 #include <string.h> 31 32 #include "addrtoname.h" 33 #include "extract.h" 34 #include "interface.h" 35 #include "afnum.h" 36 37 enum { 38 LLDP_TLV_END = 0, 39 LLDP_TLV_CHASSIS_ID = 1, 40 LLDP_TLV_PORT_ID = 2, 41 LLDP_TLV_TTL = 3, 42 LLDP_TLV_PORT_DESCR = 4, 43 LLDP_TLV_SYSTEM_NAME = 5, 44 LLDP_TLV_SYSTEM_DESCR = 6, 45 LLDP_TLV_SYSTEM_CAP = 7, 46 LLDP_TLV_MANAGEMENT_ADDR = 8, 47 LLDP_TLV_ORG = 127 48 }; 49 50 enum { 51 LLDP_CHASSISID_SUBTYPE_CHASSIS = 1, 52 LLDP_CHASSISID_SUBTYPE_IFALIAS = 2, 53 LLDP_CHASSISID_SUBTYPE_PORT = 3, 54 LLDP_CHASSISID_SUBTYPE_LLADDR = 4, 55 LLDP_CHASSISID_SUBTYPE_ADDR = 5, 56 LLDP_CHASSISID_SUBTYPE_IFNAME = 6, 57 LLDP_CHASSISID_SUBTYPE_LOCAL = 7 58 }; 59 60 enum { 61 LLDP_PORTID_SUBTYPE_IFALIAS = 1, 62 LLDP_PORTID_SUBTYPE_PORT = 2, 63 LLDP_PORTID_SUBTYPE_LLADDR = 3, 64 LLDP_PORTID_SUBTYPE_ADDR = 4, 65 LLDP_PORTID_SUBTYPE_IFNAME = 5, 66 LLDP_PORTID_SUBTYPE_AGENTCID = 6, 67 LLDP_PORTID_SUBTYPE_LOCAL = 7 68 }; 69 70 #define LLDP_CAP_OTHER 0x01 71 #define LLDP_CAP_REPEATER 0x02 72 #define LLDP_CAP_BRIDGE 0x04 73 #define LLDP_CAP_WLAN 0x08 74 #define LLDP_CAP_ROUTER 0x10 75 #define LLDP_CAP_TELEPHONE 0x20 76 #define LLDP_CAP_DOCSIS 0x40 77 #define LLDP_CAP_STATION 0x80 78 #define LLDP_CAP_BITS \ 79 "\20\01OTHER\02REPEATER\03BRIDGE\04WLAN\05ROUTER\06TELEPHONE" \ 80 "\07DOCSIS\10STATION" 81 82 enum { 83 LLDP_MGMT_IFACE_UNKNOWN = 1, 84 LLDP_MGMT_IFACE_IFINDEX = 2, 85 LLDP_MGMT_IFACE_SYSPORT = 3 86 }; 87 88 static const char *afnumber[] = AFNUM_NAME_STR; 89 90 void lldp_print_str(u_int8_t *, int); 91 const char *lldp_print_addr(int, const void *); 92 void lldp_print_id(int, u_int8_t *, int); 93 94 void 95 lldp_print_str(u_int8_t *str, int len) 96 { 97 int i; 98 printf("\""); 99 for (i = 0; i < len; i++) 100 printf("%c", isprint(str[i]) ? str[i] : '.'); 101 printf("\""); 102 } 103 104 const char * 105 lldp_print_addr(int af, const void *addr) 106 { 107 static char buf[48]; 108 if (inet_ntop(af, addr, buf, sizeof(buf)) == NULL) 109 return ("?"); 110 return (buf); 111 } 112 113 void 114 lldp_print_id(int type, u_int8_t *ptr, int len) 115 { 116 u_int8_t id; 117 u_int8_t *data; 118 119 id = *(u_int8_t *)ptr; 120 len -= sizeof(u_int8_t); 121 data = ptr + sizeof(u_int8_t); 122 if (len <= 0) 123 return; 124 125 if (type == LLDP_TLV_CHASSIS_ID) { 126 switch (id) { 127 case LLDP_CHASSISID_SUBTYPE_CHASSIS: 128 printf("chassis "); 129 lldp_print_str(data, len); 130 break; 131 case LLDP_CHASSISID_SUBTYPE_IFALIAS: 132 printf("ifalias"); 133 break; 134 case LLDP_CHASSISID_SUBTYPE_PORT: 135 printf("port"); 136 break; 137 case LLDP_CHASSISID_SUBTYPE_LLADDR: 138 printf("lladdr %s", etheraddr_string(data)); 139 break; 140 case LLDP_CHASSISID_SUBTYPE_ADDR: 141 printf("addr"); 142 break; 143 case LLDP_CHASSISID_SUBTYPE_IFNAME: 144 printf("ifname "); 145 lldp_print_str(data, len); 146 break; 147 case LLDP_CHASSISID_SUBTYPE_LOCAL: 148 printf("local "); 149 lldp_print_str(data, len); 150 break; 151 default: 152 printf("unknown 0x%02x", id); 153 break; 154 } 155 156 } else if (type == LLDP_TLV_PORT_ID) { 157 switch (id) { 158 case LLDP_PORTID_SUBTYPE_IFALIAS: 159 printf("ifalias"); 160 break; 161 case LLDP_PORTID_SUBTYPE_PORT: 162 printf("port"); 163 break; 164 case LLDP_PORTID_SUBTYPE_LLADDR: 165 printf("lladdr %s", etheraddr_string(data)); 166 break; 167 case LLDP_PORTID_SUBTYPE_ADDR: 168 printf("addr"); 169 break; 170 case LLDP_PORTID_SUBTYPE_IFNAME: 171 printf("ifname "); 172 lldp_print_str(data, len); 173 break; 174 case LLDP_PORTID_SUBTYPE_AGENTCID: 175 printf("agentcid"); 176 break; 177 case LLDP_PORTID_SUBTYPE_LOCAL: 178 printf("local "); 179 lldp_print_str(data, len); 180 break; 181 default: 182 printf("unknown 0x%02x", id); 183 break; 184 } 185 } 186 } 187 188 void 189 lldp_print(const u_char *p, u_int len) 190 { 191 u_int16_t tlv; 192 u_int8_t *ptr = (u_int8_t *)p, v = 0; 193 int n, type, vlen, alen; 194 195 printf("LLDP"); 196 197 #define _ptrinc(_v) ptr += (_v); vlen -= (_v); 198 199 for (n = 0; n < len;) { 200 TCHECK2(*ptr, sizeof(tlv)); 201 202 tlv = EXTRACT_16BITS(ptr); 203 type = (tlv & 0xfe00) >> 9; 204 vlen = tlv & 0x1ff; 205 n += vlen; 206 207 ptr += sizeof(tlv); 208 TCHECK2(*ptr, vlen); 209 210 switch (type) { 211 case LLDP_TLV_END: 212 goto done; 213 break; 214 215 case LLDP_TLV_CHASSIS_ID: 216 printf(", ChassisId: "); 217 lldp_print_id(type, ptr, vlen); 218 break; 219 220 case LLDP_TLV_PORT_ID: 221 printf(", PortId: "); 222 lldp_print_id(type, ptr, vlen); 223 break; 224 225 case LLDP_TLV_TTL: 226 printf(", TTL: "); 227 TCHECK2(*ptr, 2); 228 printf("%ds", EXTRACT_16BITS(ptr)); 229 break; 230 231 case LLDP_TLV_PORT_DESCR: 232 printf(", PortDescr: "); 233 lldp_print_str(ptr, vlen); 234 break; 235 236 case LLDP_TLV_SYSTEM_NAME: 237 printf(", SysName: "); 238 lldp_print_str(ptr, vlen); 239 break; 240 241 case LLDP_TLV_SYSTEM_DESCR: 242 printf(", SysDescr: "); 243 lldp_print_str(ptr, vlen); 244 break; 245 246 case LLDP_TLV_SYSTEM_CAP: 247 printf(", CAP:"); 248 TCHECK2(*ptr, 4); 249 printb(" available", EXTRACT_16BITS(ptr), 250 LLDP_CAP_BITS); 251 _ptrinc(sizeof(u_int16_t)); 252 printb(" enabled", EXTRACT_16BITS(ptr), 253 LLDP_CAP_BITS); 254 break; 255 256 case LLDP_TLV_MANAGEMENT_ADDR: 257 printf(", MgmtAddr:"); 258 TCHECK2(*ptr, 2); 259 alen = *ptr - sizeof(u_int8_t); 260 _ptrinc(sizeof(u_int8_t)); 261 v = *ptr; 262 _ptrinc(sizeof(u_int8_t)); 263 if (v < AFNUM_MAX) 264 printf(" %s", afnumber[v]); 265 else 266 printf(" type %d", v); 267 TCHECK2(*ptr, alen); 268 switch (v) { 269 case AFNUM_INET: 270 if (alen != sizeof(struct in_addr)) 271 goto trunc; 272 printf(" %s", 273 lldp_print_addr(AF_INET, ptr)); 274 break; 275 case AFNUM_INET6: 276 if (alen != sizeof(struct in6_addr)) 277 goto trunc; 278 printf(" %s", 279 lldp_print_addr(AF_INET6, ptr)); 280 break; 281 } 282 _ptrinc(alen); 283 v = *(u_int8_t *)ptr; 284 break; 285 286 case LLDP_TLV_ORG: 287 printf(", Org"); 288 break; 289 290 default: 291 printf(", type %d length %d", type, vlen); 292 break; 293 } 294 ptr += vlen; 295 } 296 297 done: 298 return; 299 300 trunc: 301 printf(" [|LLDP]"); 302 } 303 304