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