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