1 /* $OpenBSD: print-lldp.c,v 1.8 2015/01/16 06:40:21 deraadt 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", 139 ether_ntoa((struct ether_addr *)data)); 140 break; 141 case LLDP_CHASSISID_SUBTYPE_ADDR: 142 printf("addr"); 143 break; 144 case LLDP_CHASSISID_SUBTYPE_IFNAME: 145 printf("ifname "); 146 lldp_print_str(data, len); 147 break; 148 case LLDP_CHASSISID_SUBTYPE_LOCAL: 149 printf("local "); 150 lldp_print_str(data, len); 151 break; 152 default: 153 printf("unknown 0x%02x", id); 154 break; 155 } 156 157 } else if (type == LLDP_TLV_PORT_ID) { 158 switch (id) { 159 case LLDP_PORTID_SUBTYPE_IFALIAS: 160 printf("ifalias"); 161 break; 162 case LLDP_PORTID_SUBTYPE_PORT: 163 printf("port"); 164 break; 165 case LLDP_PORTID_SUBTYPE_LLADDR: 166 printf("lladdr %s", 167 ether_ntoa((struct ether_addr *)data)); 168 break; 169 case LLDP_PORTID_SUBTYPE_ADDR: 170 printf("addr"); 171 break; 172 case LLDP_PORTID_SUBTYPE_IFNAME: 173 printf("ifname "); 174 lldp_print_str(data, len); 175 break; 176 case LLDP_PORTID_SUBTYPE_AGENTCID: 177 printf("agentcid"); 178 break; 179 case LLDP_PORTID_SUBTYPE_LOCAL: 180 printf("local "); 181 lldp_print_str(data, len); 182 break; 183 default: 184 printf("unknown 0x%02x", id); 185 break; 186 } 187 } 188 } 189 190 void 191 lldp_print(const u_char *p, u_int len) 192 { 193 u_int16_t tlv; 194 u_int8_t *ptr = (u_int8_t *)p, v = 0; 195 int n, type, vlen, alen; 196 197 printf("LLDP"); 198 199 #define _ptrinc(_v) ptr += (_v); vlen -= (_v); 200 201 for (n = 0; n < len;) { 202 TCHECK2(*ptr, sizeof(tlv)); 203 204 tlv = EXTRACT_16BITS(ptr); 205 type = (tlv & 0xfe00) >> 9; 206 vlen = tlv & 0x1ff; 207 n += vlen; 208 209 ptr += sizeof(tlv); 210 TCHECK2(*ptr, vlen); 211 212 switch (type) { 213 case LLDP_TLV_END: 214 goto done; 215 break; 216 217 case LLDP_TLV_CHASSIS_ID: 218 printf(", ChassisId: "); 219 lldp_print_id(type, ptr, vlen); 220 break; 221 222 case LLDP_TLV_PORT_ID: 223 printf(", PortId: "); 224 lldp_print_id(type, ptr, vlen); 225 break; 226 227 case LLDP_TLV_TTL: 228 printf(", TTL: "); 229 TCHECK2(*ptr, 2); 230 printf("%ds", EXTRACT_16BITS(ptr)); 231 break; 232 233 case LLDP_TLV_PORT_DESCR: 234 printf(", PortDescr: "); 235 lldp_print_str(ptr, vlen); 236 break; 237 238 case LLDP_TLV_SYSTEM_NAME: 239 printf(", SysName: "); 240 lldp_print_str(ptr, vlen); 241 break; 242 243 case LLDP_TLV_SYSTEM_DESCR: 244 printf(", SysDescr: "); 245 lldp_print_str(ptr, vlen); 246 break; 247 248 case LLDP_TLV_SYSTEM_CAP: 249 printf(", CAP:"); 250 TCHECK2(*ptr, 4); 251 printb(" available", EXTRACT_16BITS(ptr), 252 LLDP_CAP_BITS); 253 _ptrinc(sizeof(u_int16_t)); 254 printb(" enabled", EXTRACT_16BITS(ptr), 255 LLDP_CAP_BITS); 256 break; 257 258 case LLDP_TLV_MANAGEMENT_ADDR: 259 printf(", MgmtAddr:"); 260 TCHECK2(*ptr, 2); 261 alen = *ptr - sizeof(u_int8_t); 262 _ptrinc(sizeof(u_int8_t)); 263 v = *ptr; 264 _ptrinc(sizeof(u_int8_t)); 265 if (v < AFNUM_MAX) 266 printf(" %s", afnumber[v]); 267 else 268 printf(" type %d", v); 269 TCHECK2(*ptr, alen); 270 switch (v) { 271 case AFNUM_INET: 272 if (alen != sizeof(struct in_addr)) 273 goto trunc; 274 printf(" %s", 275 lldp_print_addr(AF_INET, ptr)); 276 break; 277 case AFNUM_INET6: 278 if (alen != sizeof(struct in6_addr)) 279 goto trunc; 280 printf(" %s", 281 lldp_print_addr(AF_INET6, ptr)); 282 break; 283 } 284 _ptrinc(alen); 285 v = *(u_int8_t *)ptr; 286 break; 287 288 case LLDP_TLV_ORG: 289 printf(", Org"); 290 break; 291 292 default: 293 printf(", type %d length %d", type, vlen); 294 break; 295 } 296 ptr += vlen; 297 } 298 299 done: 300 return; 301 302 trunc: 303 printf(" [|LLDP]"); 304 } 305 306