1 /* $OpenBSD: print-lldp.c,v 1.11 2025/01/02 01:21:35 dlg 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(const u_int8_t *, int); 91 const char *lldp_print_addr(int, const void *); 92 void lldp_print_id(int, const u_int8_t *, int); 93 94 void 95 lldp_print_str(const u_int8_t *str, int len) 96 { 97 int i; 98 printf("\""); 99 for (i = 0; i < len; i++) { 100 int ch = str[i]; 101 if (ch == '\r') 102 continue; 103 if (ch == '\n') 104 ch = ' '; 105 printf("%c", isprint(ch) ? ch : '.'); 106 } 107 printf("\""); 108 } 109 110 const char * 111 lldp_print_addr(int af, const void *addr) 112 { 113 static char buf[48]; 114 if (inet_ntop(af, addr, buf, sizeof(buf)) == NULL) 115 return ("?"); 116 return (buf); 117 } 118 119 void 120 lldp_print_id(int type, const u_int8_t *ptr, int len) 121 { 122 u_int8_t id; 123 const u_int8_t *data; 124 125 id = *(u_int8_t *)ptr; 126 len -= sizeof(u_int8_t); 127 data = ptr + sizeof(u_int8_t); 128 if (len <= 0) 129 return; 130 131 if (type == LLDP_TLV_CHASSIS_ID) { 132 switch (id) { 133 case LLDP_CHASSISID_SUBTYPE_CHASSIS: 134 printf("chassis "); 135 lldp_print_str(data, len); 136 break; 137 case LLDP_CHASSISID_SUBTYPE_IFALIAS: 138 printf("ifalias"); 139 break; 140 case LLDP_CHASSISID_SUBTYPE_PORT: 141 printf("port"); 142 break; 143 case LLDP_CHASSISID_SUBTYPE_LLADDR: 144 printf("lladdr %s", etheraddr_string(data)); 145 break; 146 case LLDP_CHASSISID_SUBTYPE_ADDR: 147 printf("addr"); 148 break; 149 case LLDP_CHASSISID_SUBTYPE_IFNAME: 150 printf("ifname "); 151 lldp_print_str(data, len); 152 break; 153 case LLDP_CHASSISID_SUBTYPE_LOCAL: 154 printf("local "); 155 lldp_print_str(data, len); 156 break; 157 default: 158 printf("unknown 0x%02x", id); 159 break; 160 } 161 162 } else if (type == LLDP_TLV_PORT_ID) { 163 switch (id) { 164 case LLDP_PORTID_SUBTYPE_IFALIAS: 165 printf("ifalias"); 166 break; 167 case LLDP_PORTID_SUBTYPE_PORT: 168 printf("port"); 169 break; 170 case LLDP_PORTID_SUBTYPE_LLADDR: 171 printf("lladdr %s", etheraddr_string(data)); 172 break; 173 case LLDP_PORTID_SUBTYPE_ADDR: 174 printf("addr"); 175 break; 176 case LLDP_PORTID_SUBTYPE_IFNAME: 177 printf("ifname "); 178 lldp_print_str(data, len); 179 break; 180 case LLDP_PORTID_SUBTYPE_AGENTCID: 181 printf("agentcid"); 182 break; 183 case LLDP_PORTID_SUBTYPE_LOCAL: 184 printf("local "); 185 lldp_print_str(data, len); 186 break; 187 default: 188 printf("unknown 0x%02x", id); 189 break; 190 } 191 } 192 } 193 194 static void 195 lldp_print_mgmt_addr(const u_int8_t *ptr, u_int len) 196 { 197 u_int alen; 198 u_int afnum; 199 const uint8_t *maddr; 200 uint32_t ifidx; 201 202 if (len < 1) { 203 printf(" unexpected len %u", len); 204 return; 205 } 206 alen = ptr[0]; 207 208 ptr++; 209 len--; 210 211 if (alen < 2 || alen > len) { 212 printf(" unexpected address len %u", len); 213 return; 214 } 215 afnum = ptr[0]; 216 maddr = ptr + 1; 217 218 ptr += alen; 219 len -= alen; 220 221 alen--; 222 switch (afnum) { 223 case AFNUM_INET: 224 if (alen != sizeof(struct in_addr)) 225 goto afnum_default; 226 printf(" %s", lldp_print_addr(AF_INET, maddr)); 227 break; 228 case AFNUM_INET6: 229 if (alen != sizeof(struct in6_addr)) 230 goto afnum_default; 231 printf(" %s", lldp_print_addr(AF_INET6, maddr)); 232 break; 233 case AFNUM_802: 234 if (alen != ETHER_ADDR_LEN) 235 goto afnum_default; 236 printf(" %s", etheraddr_string(maddr)); 237 break; 238 default: 239 afnum_default: 240 if (afnum < AFNUM_MAX) 241 printf(" %s", afnumber[afnum]); 242 else 243 printf(" afnum-%u", afnum); 244 printf(" len %u", alen); 245 break; 246 } 247 248 if (len < 5) { 249 printf(" unexpected interface len %u", len); 250 return; 251 } 252 253 ifidx = EXTRACT_32BITS(ptr + 1); 254 if (ifidx != 0) { 255 switch (*ptr) { 256 case LLDP_MGMT_IFACE_UNKNOWN: 257 printf(" Unknown"); 258 break; 259 case LLDP_MGMT_IFACE_IFINDEX: 260 printf(" ifIndex"); 261 break; 262 case LLDP_MGMT_IFACE_SYSPORT: 263 printf(" sysPort"); 264 break; 265 default: 266 printf(" iface-type-%u", *ptr); 267 break; 268 } 269 printf(" %u", ifidx); 270 } 271 272 ptr += 5; 273 len -= 5; 274 275 if (len < 1) { 276 printf(" unexpected oid len %u", len); 277 return; 278 } 279 alen = ptr[0]; 280 ptr++; 281 len--; 282 283 if (alen != len) { 284 printf(" unexpected oid len %u/%u", alen, len); 285 } 286 if (alen == 0) 287 return; 288 289 printf(" oid 0x"); 290 do { 291 printf("%02X", *ptr++); 292 } while (--alen > 0); 293 } 294 295 void 296 lldp_print(const u_char *p, u_int len) 297 { 298 u_int16_t tlv; 299 const u_int8_t *ptr = (u_int8_t *)p; 300 int n, type, vlen; 301 302 printf("LLDP"); 303 304 for (n = 0; n < len;) { 305 TCHECK2(*ptr, sizeof(tlv)); 306 307 tlv = EXTRACT_16BITS(ptr); 308 type = (tlv & 0xfe00) >> 9; 309 vlen = tlv & 0x1ff; 310 n += vlen; 311 312 ptr += sizeof(tlv); 313 TCHECK2(*ptr, vlen); 314 315 switch (type) { 316 case LLDP_TLV_END: 317 goto done; 318 break; 319 320 case LLDP_TLV_CHASSIS_ID: 321 printf(", ChassisId: "); 322 lldp_print_id(type, ptr, vlen); 323 break; 324 325 case LLDP_TLV_PORT_ID: 326 printf(", PortId: "); 327 lldp_print_id(type, ptr, vlen); 328 break; 329 330 case LLDP_TLV_TTL: 331 printf(", TTL: "); 332 if (vlen != 2) { 333 printf(" unexpected len %d", vlen); 334 break; 335 } 336 printf("%ds", EXTRACT_16BITS(ptr)); 337 break; 338 339 case LLDP_TLV_PORT_DESCR: 340 printf(", PortDescr: "); 341 lldp_print_str(ptr, vlen); 342 break; 343 344 case LLDP_TLV_SYSTEM_NAME: 345 printf(", SysName: "); 346 lldp_print_str(ptr, vlen); 347 break; 348 349 case LLDP_TLV_SYSTEM_DESCR: 350 printf(", SysDescr: "); 351 lldp_print_str(ptr, vlen); 352 break; 353 354 case LLDP_TLV_SYSTEM_CAP: 355 printf(", CAP:"); 356 if (vlen != 4) { 357 printf(" unexpected len %d", vlen); 358 break; 359 } 360 printb(" available", EXTRACT_16BITS(ptr), 361 LLDP_CAP_BITS); 362 printb(" enabled", EXTRACT_16BITS(ptr + 2), 363 LLDP_CAP_BITS); 364 break; 365 366 case LLDP_TLV_MANAGEMENT_ADDR: 367 printf(", MgmtAddr:"); 368 lldp_print_mgmt_addr(ptr, vlen); 369 break; 370 371 case LLDP_TLV_ORG: 372 printf(", Org:"); 373 if (vlen < 4) { 374 printf(" unexpected len %d", vlen); 375 } 376 printf(" %02X-%02X-%02X type %02x len %u", 377 ptr[0], ptr[1], ptr[2], ptr[3], len - 4); 378 break; 379 380 default: 381 printf(", type %d length %d", type, vlen); 382 break; 383 } 384 ptr += vlen; 385 } 386 387 done: 388 return; 389 390 trunc: 391 printf(" [|LLDP]"); 392 } 393 394