]> git.ipfire.org Git - thirdparty/lldpd.git/blame - src/lldp.c
Change the way interface information are collected.
[thirdparty/lldpd.git] / src / lldp.c
CommitLineData
43c02e7b
VB
1/*
2 * Copyright (c) 2008 Vincent Bernat <bernat@luffy.cx>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include "lldpd.h"
a8105c1b 18#include "frame.h"
43c02e7b
VB
19
20#include <unistd.h>
21#include <errno.h>
22#include <time.h>
23#include <sys/types.h>
24#include <sys/socket.h>
25#include <sys/ioctl.h>
26#include <netpacket/packet.h>
27#include <linux/sockios.h>
28
29int
77507b69 30lldp_send(struct lldpd *global,
a8105c1b 31 struct lldpd_hardware *hardware)
43c02e7b 32{
a8105c1b 33 struct lldpd_port *port;
77507b69 34 struct lldpd_chassis *chassis;
a8105c1b
VB
35 struct lldpd_frame *frame;
36 int length;
37 u_int8_t *packet, *pos, *tlv;
38
39 u_int8_t mcastaddr[] = LLDP_MULTICAST_ADDR;
a1347cd8
VB
40#ifdef ENABLE_DOT1
41 const u_int8_t dot1[] = LLDP_TLV_ORG_DOT1;
a1347cd8
VB
42 struct lldpd_vlan *vlan;
43#endif
44#ifdef ENABLE_DOT3
45 const u_int8_t dot3[] = LLDP_TLV_ORG_DOT3;
a1347cd8 46#endif
89840df0 47#ifdef ENABLE_LLDPMED
115ff55c 48 int i;
89840df0 49 const u_int8_t med[] = LLDP_TLV_ORG_MED;
89840df0 50#endif
43c02e7b 51
a8105c1b 52 port = &hardware->h_lport;
77507b69 53 chassis = port->p_chassis;
a8105c1b
VB
54 length = hardware->h_mtu;
55 if ((packet = (u_int8_t*)malloc(length)) == NULL)
56 return ENOMEM;
57 memset(packet, 0, length);
58 pos = packet;
43c02e7b
VB
59
60 /* Ethernet header */
a8105c1b
VB
61 if (!(
62 /* LLDP multicast address */
63 POKE_BYTES(mcastaddr, sizeof(mcastaddr)) &&
64 /* Source MAC address */
65 POKE_BYTES(&hardware->h_lladdr, sizeof(hardware->h_lladdr)) &&
66 /* LLDP frame */
67 POKE_UINT16(ETHERTYPE_LLDP)))
68 goto toobig;
43c02e7b
VB
69
70 /* Chassis ID */
a8105c1b
VB
71 if (!(
72 POKE_START_LLDP_TLV(LLDP_TLV_CHASSIS_ID) &&
73 POKE_UINT8(chassis->c_id_subtype) &&
74 POKE_BYTES(chassis->c_id, chassis->c_id_len) &&
75 POKE_END_LLDP_TLV))
76 goto toobig;
43c02e7b
VB
77
78 /* Port ID */
a8105c1b
VB
79 if (!(
80 POKE_START_LLDP_TLV(LLDP_TLV_PORT_ID) &&
81 POKE_UINT8(port->p_id_subtype) &&
82 POKE_BYTES(port->p_id, port->p_id_len) &&
83 POKE_END_LLDP_TLV))
84 goto toobig;
43c02e7b
VB
85
86 /* Time to live */
a8105c1b
VB
87 if (!(
88 POKE_START_LLDP_TLV(LLDP_TLV_TTL) &&
89 POKE_UINT16(chassis->c_ttl) &&
90 POKE_END_LLDP_TLV))
91 goto toobig;
43c02e7b
VB
92
93 /* System name */
a8105c1b
VB
94 if (!(
95 POKE_START_LLDP_TLV(LLDP_TLV_SYSTEM_NAME) &&
96 POKE_BYTES(chassis->c_name, strlen(chassis->c_name)) &&
97 POKE_END_LLDP_TLV))
98 goto toobig;
43c02e7b
VB
99
100 /* System description */
a8105c1b
VB
101 if (!(
102 POKE_START_LLDP_TLV(LLDP_TLV_SYSTEM_DESCR) &&
103 POKE_BYTES(chassis->c_descr, strlen(chassis->c_descr)) &&
104 POKE_END_LLDP_TLV))
105 goto toobig;
43c02e7b
VB
106
107 /* System capabilities */
a8105c1b
VB
108 if (!(
109 POKE_START_LLDP_TLV(LLDP_TLV_SYSTEM_CAP) &&
110 POKE_UINT16(chassis->c_cap_available) &&
111 POKE_UINT16(chassis->c_cap_enabled) &&
112 POKE_END_LLDP_TLV))
113 goto toobig;
43c02e7b
VB
114
115 if (chassis->c_mgmt.s_addr != INADDR_ANY) {
116 /* Management address */
a8105c1b
VB
117 if (!(
118 POKE_START_LLDP_TLV(LLDP_TLV_MGMT_ADDR) &&
119 /* Size of the address, including its type */
120 POKE_UINT8(sizeof(struct in_addr) + 1) &&
121 /* Address is IPv4 */
122 POKE_UINT8(LLDP_MGMT_ADDR_IP4) &&
123 POKE_BYTES(&chassis->c_mgmt, sizeof(struct in_addr))))
124 goto toobig;
43c02e7b
VB
125
126 /* Interface port type, OID */
a8105c1b
VB
127 if (chassis->c_mgmt_if == 0) {
128 if (!(
129 /* We don't know the management interface */
130 POKE_UINT8(LLDP_MGMT_IFACE_UNKNOWN) &&
131 POKE_UINT32(0)))
132 goto toobig;
133 } else {
134 if (!(
135 /* We have the index of the management interface */
136 POKE_UINT8(LLDP_MGMT_IFACE_IFINDEX) &&
137 POKE_UINT32(chassis->c_mgmt_if)))
138 goto toobig;
43c02e7b 139 }
a8105c1b
VB
140 if (!(
141 /* We don't provide an OID for management */
142 POKE_UINT8(0) &&
143 POKE_END_LLDP_TLV))
144 goto toobig;
43c02e7b
VB
145 }
146
147 /* Port description */
a8105c1b
VB
148 if (!(
149 POKE_START_LLDP_TLV(LLDP_TLV_PORT_DESCR) &&
150 POKE_BYTES(port->p_descr, strlen(port->p_descr)) &&
151 POKE_END_LLDP_TLV))
152 goto toobig;
43c02e7b 153
a1347cd8 154#ifdef ENABLE_DOT1
43c02e7b 155 /* VLANs */
a8105c1b
VB
156 TAILQ_FOREACH(vlan, &port->p_vlans, v_entries) {
157 if (!(
158 POKE_START_LLDP_TLV(LLDP_TLV_ORG) &&
159 POKE_BYTES(dot1, sizeof(dot1)) &&
160 POKE_UINT8(LLDP_TLV_DOT1_VLANNAME) &&
161 POKE_UINT16(vlan->v_vid) &&
162 POKE_UINT8(strlen(vlan->v_name)) &&
163 POKE_BYTES(vlan->v_name, strlen(vlan->v_name)) &&
164 POKE_END_LLDP_TLV))
165 goto toobig;
43c02e7b 166 }
a1347cd8 167#endif
43c02e7b 168
a1347cd8 169#ifdef ENABLE_DOT3
43c02e7b 170 /* Aggregation status */
a8105c1b
VB
171 if (!(
172 POKE_START_LLDP_TLV(LLDP_TLV_ORG) &&
173 POKE_BYTES(dot3, sizeof(dot3)) &&
174 POKE_UINT8(LLDP_TLV_DOT3_LA) &&
175 /* Bit 0 = capability ; Bit 1 = status */
176 POKE_UINT8((port->p_aggregid) ? 3:1) &&
177 POKE_UINT32(port->p_aggregid) &&
178 POKE_END_LLDP_TLV))
179 goto toobig;
43c02e7b
VB
180
181 /* MAC/PHY */
a8105c1b
VB
182 if (!(
183 POKE_START_LLDP_TLV(LLDP_TLV_ORG) &&
184 POKE_BYTES(dot3, sizeof(dot3)) &&
185 POKE_UINT8(LLDP_TLV_DOT3_MAC) &&
186 POKE_UINT8(port->p_autoneg_support |
187 (port->p_autoneg_enabled << 1)) &&
188 POKE_UINT16(port->p_autoneg_advertised) &&
189 POKE_UINT16(port->p_mau_type) &&
190 POKE_END_LLDP_TLV))
191 goto toobig;
548109b2
VB
192
193 /* MFS */
a8105c1b
VB
194 if (!(
195 POKE_START_LLDP_TLV(LLDP_TLV_ORG) &&
196 POKE_BYTES(dot3, sizeof(dot3)) &&
197 POKE_UINT8(LLDP_TLV_DOT3_MFS) &&
198 POKE_UINT16(port->p_mfs) &&
199 POKE_END_LLDP_TLV))
200 goto toobig;
a1347cd8 201#endif
43c02e7b 202
89840df0 203#ifdef ENABLE_LLDPMED
740593ff 204 if (port->p_med_cap_enabled) {
89840df0 205 /* LLDP-MED cap */
a8105c1b
VB
206 if (!(
207 POKE_START_LLDP_TLV(LLDP_TLV_ORG) &&
208 POKE_BYTES(med, sizeof(med)) &&
209 POKE_UINT8(LLDP_TLV_MED_CAP) &&
210 POKE_UINT16(chassis->c_med_cap_available) &&
bc08499a 211 POKE_UINT8(chassis->c_med_type) &&
a8105c1b
VB
212 POKE_END_LLDP_TLV))
213 goto toobig;
89840df0
VB
214
215 /* LLDP-MED inventory */
a8105c1b 216#define LLDP_INVENTORY(value, subtype) \
89840df0 217 if (value) { \
a8105c1b
VB
218 if (!( \
219 POKE_START_LLDP_TLV(LLDP_TLV_ORG) && \
220 POKE_BYTES(med, sizeof(med)) && \
221 POKE_UINT8(subtype) && \
222 POKE_BYTES(value, \
223 (strlen(value)>32)?32:strlen(value)) && \
224 POKE_END_LLDP_TLV)) \
225 goto toobig; \
89840df0 226 }
e809a587 227
740593ff 228 if (port->p_med_cap_enabled & LLDPMED_CAP_IV) {
a8105c1b
VB
229 LLDP_INVENTORY(chassis->c_med_hw,
230 LLDP_TLV_MED_IV_HW);
231 LLDP_INVENTORY(chassis->c_med_fw,
232 LLDP_TLV_MED_IV_FW);
233 LLDP_INVENTORY(chassis->c_med_sw,
234 LLDP_TLV_MED_IV_SW);
235 LLDP_INVENTORY(chassis->c_med_sn,
236 LLDP_TLV_MED_IV_SN);
237 LLDP_INVENTORY(chassis->c_med_manuf,
238 LLDP_TLV_MED_IV_MANUF);
239 LLDP_INVENTORY(chassis->c_med_model,
240 LLDP_TLV_MED_IV_MODEL);
241 LLDP_INVENTORY(chassis->c_med_asset,
242 LLDP_TLV_MED_IV_ASSET);
e809a587 243 }
115ff55c
VB
244
245 /* LLDP-MED location */
246 for (i = 0; i < LLDPMED_LOCFORMAT_LAST; i++) {
740593ff 247 if (port->p_med_location[i].format == i + 1) {
a8105c1b
VB
248 if (!(
249 POKE_START_LLDP_TLV(LLDP_TLV_ORG) &&
250 POKE_BYTES(med, sizeof(med)) &&
251 POKE_UINT8(LLDP_TLV_MED_LOCATION) &&
252 POKE_UINT8(port->p_med_location[i].format) &&
253 POKE_BYTES(port->p_med_location[i].data,
254 port->p_med_location[i].data_len) &&
255 POKE_END_LLDP_TLV))
256 goto toobig;
115ff55c
VB
257 }
258 }
89840df0
VB
259 }
260#endif
261
43c02e7b 262 /* END */
a8105c1b
VB
263 if (!(
264 POKE_START_LLDP_TLV(LLDP_TLV_END) &&
265 POKE_END_LLDP_TLV))
266 goto toobig;
43c02e7b 267
6e75df87
VB
268 if (hardware->h_ops->send(global, hardware,
269 (char *)packet, pos - packet) == -1) {
f2dcb180
VB
270 LLOG_WARN("unable to send packet on real device for %s",
271 hardware->h_ifname);
272 free(packet);
273 return ENETDOWN;
43c02e7b
VB
274 }
275
f2dcb180
VB
276 hardware->h_tx_cnt++;
277
a8105c1b
VB
278 /* We assume that LLDP frame is the reference */
279 if ((frame = (struct lldpd_frame*)malloc(
280 sizeof(int) + pos - packet)) != NULL) {
281 frame->size = pos - packet;
282 memcpy(&frame->frame, packet, frame->size);
77507b69
VB
283 if ((hardware->h_lport.p_lastframe == NULL) ||
284 (hardware->h_lport.p_lastframe->size != frame->size) ||
285 (memcmp(hardware->h_lport.p_lastframe->frame, frame->frame,
a8105c1b 286 frame->size) != 0)) {
77507b69
VB
287 free(hardware->h_lport.p_lastframe);
288 hardware->h_lport.p_lastframe = frame;
289 hardware->h_lport.p_lastchange = time(NULL);
43c02e7b 290 } else
a8105c1b 291 free(frame);
43c02e7b
VB
292 }
293
a8105c1b 294 free(packet);
43c02e7b 295 return 0;
a8105c1b
VB
296
297toobig:
298 free(packet);
299 return E2BIG;
43c02e7b
VB
300}
301
a8105c1b
VB
302#define CHECK_TLV_SIZE(x, name) \
303 do { if (tlv_size < (x)) { \
304 LLOG_WARNX(name " TLV too short received on %s",\
305 hardware->h_ifname); \
306 goto malformed; \
307 } } while (0)
308
43c02e7b
VB
309int
310lldp_decode(struct lldpd *cfg, char *frame, int s,
311 struct lldpd_hardware *hardware,
312 struct lldpd_chassis **newchassis, struct lldpd_port **newport)
313{
314 struct lldpd_chassis *chassis;
315 struct lldpd_port *port;
43c02e7b
VB
316 const char lldpaddr[] = LLDP_MULTICAST_ADDR;
317 const char dot1[] = LLDP_TLV_ORG_DOT1;
318 const char dot3[] = LLDP_TLV_ORG_DOT3;
6772b237 319 const char med[] = LLDP_TLV_ORG_MED;
a8105c1b
VB
320 char orgid[3];
321 int length, gotend = 0;
322 int tlv_size, tlv_type, tlv_subtype;
323 u_int8_t *pos, *tlv;
43c02e7b 324 char *b;
a8105c1b 325#ifdef ENABLE_DOT1
75b3469d
VB
326 struct lldpd_vlan *vlan;
327 int vlan_len;
a8105c1b 328#endif
43c02e7b
VB
329
330 if ((chassis = calloc(1, sizeof(struct lldpd_chassis))) == NULL) {
331 LLOG_WARN("failed to allocate remote chassis");
332 return -1;
333 }
334 if ((port = calloc(1, sizeof(struct lldpd_port))) == NULL) {
335 LLOG_WARN("failed to allocate remote port");
336 free(chassis);
337 return -1;
338 }
a1347cd8 339#ifdef ENABLE_DOT1
43c02e7b 340 TAILQ_INIT(&port->p_vlans);
a1347cd8 341#endif
43c02e7b 342
a8105c1b
VB
343 length = s;
344 pos = (u_int8_t*)frame;
345
346 if (length < 2*ETH_ALEN + sizeof(u_int16_t)) {
43c02e7b
VB
347 LLOG_WARNX("too short frame received on %s", hardware->h_ifname);
348 goto malformed;
349 }
a8105c1b 350 if (PEEK_CMP(lldpaddr, ETH_ALEN) != 0) {
43c02e7b
VB
351 LLOG_INFO("frame not targeted at LLDP multicast address received on %s",
352 hardware->h_ifname);
353 goto malformed;
354 }
a8105c1b
VB
355 PEEK_DISCARD(ETH_ALEN); /* Skip source address */
356 if (PEEK_UINT16 != ETHERTYPE_LLDP) {
43c02e7b
VB
357 LLOG_INFO("non LLDP frame received on %s",
358 hardware->h_ifname);
359 goto malformed;
360 }
361
a8105c1b
VB
362 while (length && (!gotend)) {
363 if (length < 2) {
43c02e7b
VB
364 LLOG_WARNX("tlv header too short received on %s",
365 hardware->h_ifname);
366 goto malformed;
367 }
a8105c1b
VB
368 tlv_size = PEEK_UINT16;
369 tlv_type = tlv_size >> 9;
370 tlv_size = tlv_size & 0x1ff;
371 PEEK_SAVE(tlv);
372 if (length < tlv_size) {
373 LLOG_WARNX("frame too short for tlv received on %s",
43c02e7b
VB
374 hardware->h_ifname);
375 goto malformed;
376 }
a8105c1b 377 switch (tlv_type) {
43c02e7b 378 case LLDP_TLV_END:
a8105c1b 379 if (tlv_size != 0) {
43c02e7b
VB
380 LLOG_WARNX("lldp end received with size not null on %s",
381 hardware->h_ifname);
382 goto malformed;
383 }
a8105c1b 384 if (length)
43c02e7b
VB
385 LLOG_DEBUG("extra data after lldp end on %s",
386 hardware->h_ifname);
387 gotend = 1;
388 break;
389 case LLDP_TLV_CHASSIS_ID:
390 case LLDP_TLV_PORT_ID:
a8105c1b
VB
391 CHECK_TLV_SIZE(2, "Port Id");
392 tlv_subtype = PEEK_UINT8;
393 if ((tlv_subtype == 0) || (tlv_subtype > 7)) {
43c02e7b
VB
394 LLOG_WARNX("unknown subtype for tlv id received on %s",
395 hardware->h_ifname);
396 goto malformed;
397 }
a8105c1b 398 if ((b = (char *)calloc(1, tlv_size - 1)) == NULL) {
43c02e7b
VB
399 LLOG_WARN("unable to allocate memory for id tlv "
400 "received on %s",
401 hardware->h_ifname);
402 goto malformed;
403 }
a8105c1b
VB
404 PEEK_BYTES(b, tlv_size - 1);
405 if (tlv_type == LLDP_TLV_PORT_ID) {
406 port->p_id_subtype = tlv_subtype;
43c02e7b 407 port->p_id = b;
a8105c1b 408 port->p_id_len = tlv_size - 1;
43c02e7b 409 } else {
a8105c1b 410 chassis->c_id_subtype = tlv_subtype;
43c02e7b 411 chassis->c_id = b;
a8105c1b 412 chassis->c_id_len = tlv_size - 1;
43c02e7b 413 }
43c02e7b
VB
414 break;
415 case LLDP_TLV_TTL:
a8105c1b
VB
416 CHECK_TLV_SIZE(2, "TTL");
417 chassis->c_ttl = PEEK_UINT16;
43c02e7b
VB
418 break;
419 case LLDP_TLV_PORT_DESCR:
420 case LLDP_TLV_SYSTEM_NAME:
421 case LLDP_TLV_SYSTEM_DESCR:
a8105c1b 422 if (tlv_size < 1) {
a700e935 423 LLOG_DEBUG("empty tlv received on %s",
43c02e7b 424 hardware->h_ifname);
a700e935 425 break;
43c02e7b 426 }
a8105c1b 427 if ((b = (char *)calloc(1, tlv_size + 1)) == NULL) {
43c02e7b
VB
428 LLOG_WARN("unable to allocate memory for string tlv "
429 "received on %s",
430 hardware->h_ifname);
431 goto malformed;
432 }
a8105c1b
VB
433 PEEK_BYTES(b, tlv_size);
434 if (tlv_type == LLDP_TLV_PORT_DESCR)
43c02e7b 435 port->p_descr = b;
a8105c1b 436 else if (tlv_type == LLDP_TLV_SYSTEM_NAME)
43c02e7b
VB
437 chassis->c_name = b;
438 else chassis->c_descr = b;
439 break;
440 case LLDP_TLV_SYSTEM_CAP:
a8105c1b
VB
441 CHECK_TLV_SIZE(4, "System capabilities");
442 chassis->c_cap_available = PEEK_UINT16;
443 chassis->c_cap_enabled = PEEK_UINT16;
43c02e7b
VB
444 break;
445 case LLDP_TLV_MGMT_ADDR:
a8105c1b 446 CHECK_TLV_SIZE(11, "Management address");
43c02e7b 447 if ((chassis->c_mgmt.s_addr == INADDR_ANY) &&
a8105c1b
VB
448 (PEEK_UINT8 == 1+sizeof(struct in_addr)) &&
449 (PEEK_UINT8 == LLDP_MGMT_ADDR_IP4)) {
43c02e7b 450 /* We have an IPv4 address, we ignore anything else */
a8105c1b 451 PEEK_BYTES(&chassis->c_mgmt, sizeof(struct in_addr));
43c02e7b
VB
452 chassis->c_mgmt_if = 0;
453 /* We only handle ifIndex subtype */
a8105c1b
VB
454 if (PEEK_UINT8 == LLDP_MGMT_IFACE_IFINDEX)
455 chassis->c_mgmt_if = PEEK_UINT32;
43c02e7b 456 }
43c02e7b
VB
457 break;
458 case LLDP_TLV_ORG:
a8105c1b
VB
459 CHECK_TLV_SIZE(4, "Organisational");
460 PEEK_BYTES(orgid, sizeof(orgid));
461 tlv_subtype = PEEK_UINT8;
462 if (memcmp(dot1, orgid, sizeof(orgid)) == 0) {
a1347cd8 463#ifndef ENABLE_DOT1
a1347cd8
VB
464 hardware->h_rx_unrecognized_cnt++;
465#else
43c02e7b 466 /* Dot1 */
a8105c1b 467 switch (tlv_subtype) {
75b3469d 468 case LLDP_TLV_DOT1_VLANNAME:
a8105c1b 469 CHECK_TLV_SIZE(7, "VLAN");
43c02e7b
VB
470 if ((vlan = (struct lldpd_vlan *)calloc(1,
471 sizeof(struct lldpd_vlan))) == NULL) {
efe3f9b0
VB
472 LLOG_WARN("unable to alloc vlan "
473 "structure for "
43c02e7b
VB
474 "tlv received on %s",
475 hardware->h_ifname);
476 goto malformed;
477 }
a8105c1b
VB
478 vlan->v_vid = PEEK_UINT16;
479 vlan_len = PEEK_UINT8;
480 CHECK_TLV_SIZE(7 + vlan_len, "VLAN");
43c02e7b
VB
481 if ((vlan->v_name =
482 (char *)calloc(1, vlan_len + 1)) == NULL) {
483 LLOG_WARN("unable to alloc vlan name for "
484 "tlv received on %s",
485 hardware->h_ifname);
486 goto malformed;
487 }
a8105c1b 488 PEEK_BYTES(vlan->v_name, vlan_len);
43c02e7b
VB
489 TAILQ_INSERT_TAIL(&port->p_vlans,
490 vlan, v_entries);
75b3469d
VB
491 break;
492 case LLDP_TLV_DOT1_PVID:
a8105c1b
VB
493 CHECK_TLV_SIZE(6, "PVID");
494 port->p_pvid = PEEK_UINT16;
75b3469d
VB
495 break;
496 default:
43c02e7b 497 /* Unknown Dot1 TLV, ignore it */
a1347cd8
VB
498 hardware->h_rx_unrecognized_cnt++;
499 }
500#endif
a8105c1b 501 } else if (memcmp(dot3, orgid, sizeof(orgid)) == 0) {
a1347cd8 502#ifndef ENABLE_DOT3
a1347cd8
VB
503 hardware->h_rx_unrecognized_cnt++;
504#else
43c02e7b 505 /* Dot3 */
a8105c1b 506 switch (tlv_subtype) {
43c02e7b 507 case LLDP_TLV_DOT3_MAC:
a8105c1b
VB
508 CHECK_TLV_SIZE(9, "MAC/PHY");
509 port->p_autoneg_support = PEEK_UINT8;
43c02e7b 510 port->p_autoneg_enabled =
a8105c1b
VB
511 port->p_autoneg_support && 0x2;
512 port->p_autoneg_support =
513 port->p_autoneg_support && 0x1;
43c02e7b 514 port->p_autoneg_advertised =
a8105c1b
VB
515 PEEK_UINT16;
516 port->p_mau_type = PEEK_UINT16;
43c02e7b
VB
517 break;
518 case LLDP_TLV_DOT3_LA:
a8105c1b 519 CHECK_TLV_SIZE(9, "Link aggregation");
a204514f 520 PEEK_DISCARD_UINT8;
a8105c1b 521 port->p_aggregid = PEEK_UINT32;
43c02e7b 522 break;
548109b2 523 case LLDP_TLV_DOT3_MFS:
a8105c1b
VB
524 CHECK_TLV_SIZE(6, "MFS");
525 port->p_mfs = PEEK_UINT16;
548109b2 526 break;
43c02e7b
VB
527 default:
528 /* Unknown Dot3 TLV, ignore it */
37387046 529 hardware->h_rx_unrecognized_cnt++;
43c02e7b 530 }
a1347cd8 531#endif
a8105c1b 532 } else if (memcmp(med, orgid, sizeof(orgid)) == 0) {
6772b237
VB
533 /* LLDP-MED */
534#ifndef ENABLE_LLDPMED
6772b237
VB
535 hardware->h_rx_unrecognized_cnt++;
536#else
e3a44efb
VB
537 u_int32_t policy;
538 int loctype;
a8105c1b 539 int power;
e3a44efb 540
a8105c1b 541 switch (tlv_subtype) {
6772b237 542 case LLDP_TLV_MED_CAP:
a8105c1b
VB
543 CHECK_TLV_SIZE(7, "LLDP-MED capabilities");
544 chassis->c_med_cap_available = PEEK_UINT16;
545 chassis->c_med_type = PEEK_UINT8;
740593ff 546 port->p_med_cap_enabled |=
40ecae87 547 LLDPMED_CAP_CAP;
6772b237 548 break;
efe3f9b0 549 case LLDP_TLV_MED_POLICY:
a8105c1b
VB
550 CHECK_TLV_SIZE(8, "LLDP-MED policy");
551 policy = PEEK_UINT32;
e3a44efb
VB
552 if (((policy >> 24) < 1) ||
553 ((policy >> 24) > LLDPMED_APPTYPE_LAST)) {
554 LLOG_INFO("unknown policy field %d "
555 "received on %s",
556 hardware->h_ifname);
e3a44efb
VB
557 break;
558 }
740593ff 559 port->p_med_policy[(policy >> 24) - 1].type =
e3a44efb 560 (policy >> 24);
740593ff 561 port->p_med_policy[(policy >> 24) - 1].unknown =
e3a44efb 562 ((policy & 0x800000) != 0);
740593ff 563 port->p_med_policy[(policy >> 24) - 1].tagged =
e3a44efb 564 ((policy & 0x400000) != 0);
740593ff 565 port->p_med_policy[(policy >> 24) - 1].vid =
e3a44efb 566 (policy & 0x001FFE00) >> 9;
740593ff 567 port->p_med_policy[(policy >> 24) - 1].priority =
e3a44efb 568 (policy & 0x1C0) >> 6;
740593ff 569 port->p_med_policy[(policy >> 24) - 1].dscp =
e3a44efb 570 policy & 0x3F;
740593ff 571 port->p_med_cap_enabled |=
40ecae87 572 LLDPMED_CAP_POLICY;
efe3f9b0
VB
573 break;
574 case LLDP_TLV_MED_LOCATION:
a8105c1b
VB
575 CHECK_TLV_SIZE(5, "LLDP-MED Location");
576 loctype = PEEK_UINT8;
577 if ((loctype < 1) ||
578 (loctype > LLDPMED_LOCFORMAT_LAST)) {
e3a44efb
VB
579 LLOG_INFO("unknown location type "
580 "received on %s",
581 hardware->h_ifname);
e3a44efb
VB
582 break;
583 }
740593ff 584 if ((port->p_med_location[loctype - 1].data =
a8105c1b 585 (char*)malloc(tlv_size - 5)) == NULL) {
efe3f9b0
VB
586 LLOG_WARN("unable to allocate memory "
587 "for LLDP-MED location for "
588 "frame received on %s",
589 hardware->h_ifname);
590 goto malformed;
591 }
a8105c1b
VB
592 PEEK_BYTES(port->p_med_location[loctype - 1].data,
593 tlv_size - 5);
740593ff 594 port->p_med_location[loctype - 1].data_len =
a8105c1b 595 tlv_size - 5;
740593ff 596 port->p_med_location[loctype - 1].format = loctype;
740593ff 597 port->p_med_cap_enabled |=
40ecae87 598 LLDPMED_CAP_LOCATION;
efe3f9b0
VB
599 break;
600 case LLDP_TLV_MED_MDI:
a8105c1b
VB
601 CHECK_TLV_SIZE(7, "LLDP-MED PoE-MDI");
602 power = PEEK_UINT8;
603 switch (power & 0xC0) {
994812b9 604 case 0x0:
740593ff
VB
605 port->p_med_pow_devicetype = LLDPMED_POW_TYPE_PSE;
606 port->p_med_cap_enabled |=
a49b3a79 607 LLDPMED_CAP_MDI_PSE;
a8105c1b 608 switch (power & 0x30) {
994812b9 609 case 0x0:
740593ff 610 port->p_med_pow_source =
994812b9
VB
611 LLDPMED_POW_SOURCE_UNKNOWN;
612 break;
613 case 0x10:
740593ff 614 port->p_med_pow_source =
994812b9
VB
615 LLDPMED_POW_SOURCE_PRIMARY;
616 break;
617 case 0x20:
740593ff 618 port->p_med_pow_source =
994812b9
VB
619 LLDPMED_POW_SOURCE_BACKUP;
620 break;
621 default:
740593ff 622 port->p_med_pow_source =
994812b9
VB
623 LLDPMED_POW_SOURCE_RESERVED;
624 }
625 break;
626 case 0x40:
740593ff
VB
627 port->p_med_pow_devicetype = LLDPMED_POW_TYPE_PD;
628 port->p_med_cap_enabled |=
a49b3a79 629 LLDPMED_CAP_MDI_PD;
a8105c1b 630 switch (power & 0x30) {
994812b9 631 case 0x0:
740593ff 632 port->p_med_pow_source =
994812b9
VB
633 LLDPMED_POW_SOURCE_UNKNOWN;
634 break;
635 case 0x10:
740593ff 636 port->p_med_pow_source =
994812b9
VB
637 LLDPMED_POW_SOURCE_PSE;
638 break;
639 case 0x20:
740593ff 640 port->p_med_pow_source =
994812b9
VB
641 LLDPMED_POW_SOURCE_LOCAL;
642 break;
643 default:
740593ff 644 port->p_med_pow_source =
994812b9
VB
645 LLDPMED_POW_SOURCE_BOTH;
646 }
647 break;
648 default:
740593ff 649 port->p_med_pow_devicetype =
994812b9
VB
650 LLDPMED_POW_TYPE_RESERVED;
651 }
a8105c1b 652 switch (power & 0x0F) {
994812b9 653 case 0x0:
740593ff 654 port->p_med_pow_priority =
994812b9
VB
655 LLDPMED_POW_PRIO_UNKNOWN;
656 break;
657 case 0x1:
740593ff 658 port->p_med_pow_priority =
994812b9
VB
659 LLDPMED_POW_PRIO_CRITICAL;
660 break;
661 case 0x2:
740593ff 662 port->p_med_pow_priority =
994812b9
VB
663 LLDPMED_POW_PRIO_HIGH;
664 break;
665 case 0x3:
740593ff 666 port->p_med_pow_priority =
994812b9
VB
667 LLDPMED_POW_PRIO_LOW;
668 break;
669 default:
740593ff 670 port->p_med_pow_priority =
994812b9
VB
671 LLDPMED_POW_PRIO_UNKNOWN;
672 }
a8105c1b 673 port->p_med_pow_val = PEEK_UINT16;
efe3f9b0 674 break;
6772b237
VB
675 case LLDP_TLV_MED_IV_HW:
676 case LLDP_TLV_MED_IV_SW:
677 case LLDP_TLV_MED_IV_FW:
678 case LLDP_TLV_MED_IV_SN:
679 case LLDP_TLV_MED_IV_MANUF:
680 case LLDP_TLV_MED_IV_MODEL:
681 case LLDP_TLV_MED_IV_ASSET:
a8105c1b 682 if (tlv_size <= 4)
6772b237
VB
683 b = NULL;
684 else {
a8105c1b 685 if ((b = (char*)malloc(tlv_size - 3)) ==
efe3f9b0
VB
686 NULL) {
687 LLOG_WARN("unable to allocate "
688 "memory for LLDP-MED "
689 "inventory for frame "
690 "received on %s",
691 hardware->h_ifname);
692 goto malformed;
693 }
a8105c1b
VB
694 PEEK_BYTES(b, tlv_size - 4);
695 b[tlv_size - 4] = '\0';
6772b237 696 }
a8105c1b 697 switch (tlv_subtype) {
6772b237
VB
698 case LLDP_TLV_MED_IV_HW:
699 chassis->c_med_hw = b;
700 break;
701 case LLDP_TLV_MED_IV_FW:
702 chassis->c_med_fw = b;
703 break;
704 case LLDP_TLV_MED_IV_SW:
705 chassis->c_med_sw = b;
706 break;
707 case LLDP_TLV_MED_IV_SN:
708 chassis->c_med_sn = b;
709 break;
710 case LLDP_TLV_MED_IV_MANUF:
711 chassis->c_med_manuf = b;
712 break;
713 case LLDP_TLV_MED_IV_MODEL:
397dee69 714 chassis->c_med_model = b;
6772b237
VB
715 break;
716 case LLDP_TLV_MED_IV_ASSET:
72c4c96f 717 chassis->c_med_asset = b;
6772b237
VB
718 break;
719 default:
720 LLOG_WARNX("should not be there!");
721 free(b);
722 break;
723 }
740593ff 724 port->p_med_cap_enabled |=
40ecae87 725 LLDPMED_CAP_IV;
6772b237
VB
726 break;
727 default:
728 /* Unknown LLDP MED, ignore it */
6772b237
VB
729 hardware->h_rx_unrecognized_cnt++;
730 }
731#endif /* ENABLE_LLDPMED */
43c02e7b 732 } else {
9ca19b69 733 LLOG_INFO("unknown org tlv received on %s",
43c02e7b 734 hardware->h_ifname);
37387046 735 hardware->h_rx_unrecognized_cnt++;
43c02e7b
VB
736 }
737 break;
738 default:
739 LLOG_WARNX("unknown tlv (%d) received on %s",
a8105c1b
VB
740 tlv_type, hardware->h_ifname);
741 goto malformed;
742 }
743 if (pos > tlv + tlv_size) {
744 LLOG_WARNX("BUG: already past TLV!");
43c02e7b
VB
745 goto malformed;
746 }
a8105c1b 747 PEEK_DISCARD(tlv + tlv_size - pos);
43c02e7b
VB
748 }
749
750 /* Some random check */
751 if ((chassis->c_id == NULL) ||
752 (port->p_id == NULL) ||
753 (chassis->c_ttl == 0) ||
754 (gotend == 0)) {
755 LLOG_WARNX("some mandatory tlv are missing for frame received on %s",
756 hardware->h_ifname);
757 goto malformed;
758 }
759#define NOTRECEIVED "Not received"
760 if (chassis->c_name == NULL) {
761 if ((chassis->c_name = (char *)calloc(1, strlen(NOTRECEIVED) + 1)) == NULL) {
762 LLOG_WARNX("unable to allocate null chassis name");
763 goto malformed;
764 }
765 memcpy(chassis->c_name, NOTRECEIVED, strlen(NOTRECEIVED));
766 }
767 if (chassis->c_descr == NULL) {
768 if ((chassis->c_descr = (char *)calloc(1, strlen(NOTRECEIVED) + 1)) == NULL) {
769 LLOG_WARNX("unable to allocate null chassis description");
770 goto malformed;
771 }
772 memcpy(chassis->c_descr, NOTRECEIVED, strlen(NOTRECEIVED));
773 }
774 if (port->p_descr == NULL) {
775 if ((port->p_descr = (char *)calloc(1, strlen(NOTRECEIVED) + 1)) == NULL) {
776 LLOG_WARNX("unable to allocate null port description");
777 goto malformed;
778 }
779 memcpy(port->p_descr, NOTRECEIVED, strlen(NOTRECEIVED));
780 }
781 *newchassis = chassis;
782 *newport = port;
783 return 1;
784malformed:
77507b69 785 lldpd_chassis_cleanup(chassis, 1);
a0edeaf8 786 lldpd_port_cleanup(port, 1);
43c02e7b
VB
787 return -1;
788}