]> git.ipfire.org Git - thirdparty/lldpd.git/blame - src/lldp.c
Translate README into its markdown equivalent
[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) &&
3fd015c0
VB
186 POKE_UINT8(port->p_macphy.autoneg_support |
187 (port->p_macphy.autoneg_enabled << 1)) &&
188 POKE_UINT16(port->p_macphy.autoneg_advertised) &&
189 POKE_UINT16(port->p_macphy.mau_type) &&
a8105c1b
VB
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;
42ee7382
VB
201 /* Power */
202 if (port->p_power.devicetype) {
203 if (!(
204 POKE_START_LLDP_TLV(LLDP_TLV_ORG) &&
205 POKE_BYTES(dot3, sizeof(dot3)) &&
206 POKE_UINT8(LLDP_TLV_DOT3_POWER) &&
207 POKE_UINT8((
208 (((2 - port->p_power.devicetype) %(1<< 1))<<0) |
209 (( port->p_power.supported %(1<< 1))<<1) |
210 (( port->p_power.enabled %(1<< 1))<<2) |
211 (( port->p_power.paircontrol %(1<< 1))<<3))) &&
212 POKE_UINT8(port->p_power.pairs) &&
608cb51c
VB
213 POKE_UINT8(port->p_power.class)))
214 goto toobig;
215 /* 802.3at */
216 if (port->p_power.powertype != LLDP_DOT3_POWER_8023AT_OFF) {
217 if (!(
218 POKE_UINT8((
219 (((port->p_power.powertype ==
220 LLDP_DOT3_POWER_8023AT_TYPE1)?1:0) << 7) |
221 (((port->p_power.devicetype ==
222 LLDP_DOT3_POWER_PSE)?0:1) << 6) |
223 ((port->p_power.source %(1<< 2))<<4) |
224 ((port->p_power.priority %(1<< 2))<<0))) &&
225 POKE_UINT16(port->p_power.requested) &&
226 POKE_UINT16(port->p_power.allocated)))
227 goto toobig;
228 }
229 if (!(POKE_END_LLDP_TLV))
42ee7382
VB
230 goto toobig;
231 }
a1347cd8 232#endif
43c02e7b 233
89840df0 234#ifdef ENABLE_LLDPMED
740593ff 235 if (port->p_med_cap_enabled) {
89840df0 236 /* LLDP-MED cap */
a8105c1b
VB
237 if (!(
238 POKE_START_LLDP_TLV(LLDP_TLV_ORG) &&
239 POKE_BYTES(med, sizeof(med)) &&
240 POKE_UINT8(LLDP_TLV_MED_CAP) &&
241 POKE_UINT16(chassis->c_med_cap_available) &&
bc08499a 242 POKE_UINT8(chassis->c_med_type) &&
a8105c1b
VB
243 POKE_END_LLDP_TLV))
244 goto toobig;
89840df0
VB
245
246 /* LLDP-MED inventory */
a8105c1b 247#define LLDP_INVENTORY(value, subtype) \
89840df0 248 if (value) { \
a8105c1b
VB
249 if (!( \
250 POKE_START_LLDP_TLV(LLDP_TLV_ORG) && \
251 POKE_BYTES(med, sizeof(med)) && \
252 POKE_UINT8(subtype) && \
253 POKE_BYTES(value, \
254 (strlen(value)>32)?32:strlen(value)) && \
255 POKE_END_LLDP_TLV)) \
256 goto toobig; \
89840df0 257 }
e809a587 258
740593ff 259 if (port->p_med_cap_enabled & LLDPMED_CAP_IV) {
a8105c1b
VB
260 LLDP_INVENTORY(chassis->c_med_hw,
261 LLDP_TLV_MED_IV_HW);
262 LLDP_INVENTORY(chassis->c_med_fw,
263 LLDP_TLV_MED_IV_FW);
264 LLDP_INVENTORY(chassis->c_med_sw,
265 LLDP_TLV_MED_IV_SW);
266 LLDP_INVENTORY(chassis->c_med_sn,
267 LLDP_TLV_MED_IV_SN);
268 LLDP_INVENTORY(chassis->c_med_manuf,
269 LLDP_TLV_MED_IV_MANUF);
270 LLDP_INVENTORY(chassis->c_med_model,
271 LLDP_TLV_MED_IV_MODEL);
272 LLDP_INVENTORY(chassis->c_med_asset,
273 LLDP_TLV_MED_IV_ASSET);
e809a587 274 }
115ff55c
VB
275
276 /* LLDP-MED location */
277 for (i = 0; i < LLDPMED_LOCFORMAT_LAST; i++) {
740593ff 278 if (port->p_med_location[i].format == i + 1) {
a8105c1b
VB
279 if (!(
280 POKE_START_LLDP_TLV(LLDP_TLV_ORG) &&
281 POKE_BYTES(med, sizeof(med)) &&
282 POKE_UINT8(LLDP_TLV_MED_LOCATION) &&
283 POKE_UINT8(port->p_med_location[i].format) &&
284 POKE_BYTES(port->p_med_location[i].data,
285 port->p_med_location[i].data_len) &&
286 POKE_END_LLDP_TLV))
287 goto toobig;
115ff55c
VB
288 }
289 }
86f24df3
VB
290
291 /* LLDP-MED network policy */
292 for (i = 0; i < LLDPMED_APPTYPE_LAST; i++) {
293 if (port->p_med_policy[i].type == i + 1) {
294 if (!(
295 POKE_START_LLDP_TLV(LLDP_TLV_ORG) &&
296 POKE_BYTES(med, sizeof(med)) &&
297 POKE_UINT8(LLDP_TLV_MED_POLICY) &&
298 POKE_UINT32((
299 ((port->p_med_policy[i].type %(1<< 8))<<24) |
300 ((port->p_med_policy[i].unknown %(1<< 1))<<23) |
301 ((port->p_med_policy[i].tagged %(1<< 1))<<22) |
302 /*((0 %(1<< 1))<<21) |*/
303 ((port->p_med_policy[i].vid %(1<<12))<< 9) |
304 ((port->p_med_policy[i].priority %(1<< 3))<< 6) |
305 ((port->p_med_policy[i].dscp %(1<< 6))<< 0) )) &&
306 POKE_END_LLDP_TLV))
307 goto toobig;
308 }
309 }
009ddd23
VB
310
311 /* LLDP-MED POE-MDI */
312 if ((port->p_med_power.devicetype == LLDPMED_POW_TYPE_PSE) ||
313 (port->p_med_power.devicetype == LLDPMED_POW_TYPE_PD)) {
314 int devicetype = 0, source = 0;
315 if (!(
316 POKE_START_LLDP_TLV(LLDP_TLV_ORG) &&
317 POKE_BYTES(med, sizeof(med)) &&
318 POKE_UINT8(LLDP_TLV_MED_MDI)))
319 goto toobig;
320 switch (port->p_med_power.devicetype) {
321 case LLDPMED_POW_TYPE_PSE:
322 devicetype = 0;
323 switch (port->p_med_power.source) {
324 case LLDPMED_POW_SOURCE_PRIMARY: source = 1; break;
325 case LLDPMED_POW_SOURCE_BACKUP: source = 2; break;
326 case LLDPMED_POW_SOURCE_RESERVED: source = 3; break;
327 default: source = 0; break;
328 }
329 break;
330 case LLDPMED_POW_TYPE_PD:
331 devicetype = 1;
332 switch (port->p_med_power.source) {
333 case LLDPMED_POW_SOURCE_PSE: source = 1; break;
334 case LLDPMED_POW_SOURCE_LOCAL: source = 2; break;
335 case LLDPMED_POW_SOURCE_BOTH: source = 3; break;
336 default: source = 0; break;
337 }
338 break;
339 }
340 if (!(
341 POKE_UINT8((
342 ((devicetype %(1<< 2))<<6) |
343 ((source %(1<< 2))<<4) |
344 ((port->p_med_power.priority %(1<< 4))<<0) )) &&
345 POKE_UINT16(port->p_med_power.val) &&
346 POKE_END_LLDP_TLV))
347 goto toobig;
348 }
89840df0
VB
349 }
350#endif
351
43c02e7b 352 /* END */
a8105c1b
VB
353 if (!(
354 POKE_START_LLDP_TLV(LLDP_TLV_END) &&
355 POKE_END_LLDP_TLV))
356 goto toobig;
43c02e7b 357
6e75df87
VB
358 if (hardware->h_ops->send(global, hardware,
359 (char *)packet, pos - packet) == -1) {
f2dcb180
VB
360 LLOG_WARN("unable to send packet on real device for %s",
361 hardware->h_ifname);
362 free(packet);
363 return ENETDOWN;
43c02e7b
VB
364 }
365
f2dcb180
VB
366 hardware->h_tx_cnt++;
367
a8105c1b
VB
368 /* We assume that LLDP frame is the reference */
369 if ((frame = (struct lldpd_frame*)malloc(
370 sizeof(int) + pos - packet)) != NULL) {
371 frame->size = pos - packet;
372 memcpy(&frame->frame, packet, frame->size);
77507b69
VB
373 if ((hardware->h_lport.p_lastframe == NULL) ||
374 (hardware->h_lport.p_lastframe->size != frame->size) ||
375 (memcmp(hardware->h_lport.p_lastframe->frame, frame->frame,
a8105c1b 376 frame->size) != 0)) {
77507b69
VB
377 free(hardware->h_lport.p_lastframe);
378 hardware->h_lport.p_lastframe = frame;
379 hardware->h_lport.p_lastchange = time(NULL);
43c02e7b 380 } else
a8105c1b 381 free(frame);
43c02e7b
VB
382 }
383
a8105c1b 384 free(packet);
43c02e7b 385 return 0;
a8105c1b
VB
386
387toobig:
388 free(packet);
389 return E2BIG;
43c02e7b
VB
390}
391
a8105c1b
VB
392#define CHECK_TLV_SIZE(x, name) \
393 do { if (tlv_size < (x)) { \
394 LLOG_WARNX(name " TLV too short received on %s",\
395 hardware->h_ifname); \
396 goto malformed; \
397 } } while (0)
398
43c02e7b
VB
399int
400lldp_decode(struct lldpd *cfg, char *frame, int s,
401 struct lldpd_hardware *hardware,
402 struct lldpd_chassis **newchassis, struct lldpd_port **newport)
403{
404 struct lldpd_chassis *chassis;
405 struct lldpd_port *port;
43c02e7b
VB
406 const char lldpaddr[] = LLDP_MULTICAST_ADDR;
407 const char dot1[] = LLDP_TLV_ORG_DOT1;
408 const char dot3[] = LLDP_TLV_ORG_DOT3;
6772b237 409 const char med[] = LLDP_TLV_ORG_MED;
a8105c1b
VB
410 char orgid[3];
411 int length, gotend = 0;
412 int tlv_size, tlv_type, tlv_subtype;
413 u_int8_t *pos, *tlv;
43c02e7b 414 char *b;
a8105c1b 415#ifdef ENABLE_DOT1
75b3469d
VB
416 struct lldpd_vlan *vlan;
417 int vlan_len;
a8105c1b 418#endif
43c02e7b
VB
419
420 if ((chassis = calloc(1, sizeof(struct lldpd_chassis))) == NULL) {
421 LLOG_WARN("failed to allocate remote chassis");
422 return -1;
423 }
424 if ((port = calloc(1, sizeof(struct lldpd_port))) == NULL) {
425 LLOG_WARN("failed to allocate remote port");
426 free(chassis);
427 return -1;
428 }
a1347cd8 429#ifdef ENABLE_DOT1
43c02e7b 430 TAILQ_INIT(&port->p_vlans);
a1347cd8 431#endif
43c02e7b 432
a8105c1b
VB
433 length = s;
434 pos = (u_int8_t*)frame;
435
436 if (length < 2*ETH_ALEN + sizeof(u_int16_t)) {
43c02e7b
VB
437 LLOG_WARNX("too short frame received on %s", hardware->h_ifname);
438 goto malformed;
439 }
a8105c1b 440 if (PEEK_CMP(lldpaddr, ETH_ALEN) != 0) {
43c02e7b
VB
441 LLOG_INFO("frame not targeted at LLDP multicast address received on %s",
442 hardware->h_ifname);
443 goto malformed;
444 }
a8105c1b
VB
445 PEEK_DISCARD(ETH_ALEN); /* Skip source address */
446 if (PEEK_UINT16 != ETHERTYPE_LLDP) {
43c02e7b
VB
447 LLOG_INFO("non LLDP frame received on %s",
448 hardware->h_ifname);
449 goto malformed;
450 }
451
a8105c1b
VB
452 while (length && (!gotend)) {
453 if (length < 2) {
43c02e7b
VB
454 LLOG_WARNX("tlv header too short received on %s",
455 hardware->h_ifname);
456 goto malformed;
457 }
a8105c1b
VB
458 tlv_size = PEEK_UINT16;
459 tlv_type = tlv_size >> 9;
460 tlv_size = tlv_size & 0x1ff;
461 PEEK_SAVE(tlv);
462 if (length < tlv_size) {
463 LLOG_WARNX("frame too short for tlv received on %s",
43c02e7b
VB
464 hardware->h_ifname);
465 goto malformed;
466 }
a8105c1b 467 switch (tlv_type) {
43c02e7b 468 case LLDP_TLV_END:
a8105c1b 469 if (tlv_size != 0) {
43c02e7b
VB
470 LLOG_WARNX("lldp end received with size not null on %s",
471 hardware->h_ifname);
472 goto malformed;
473 }
a8105c1b 474 if (length)
43c02e7b
VB
475 LLOG_DEBUG("extra data after lldp end on %s",
476 hardware->h_ifname);
477 gotend = 1;
478 break;
479 case LLDP_TLV_CHASSIS_ID:
480 case LLDP_TLV_PORT_ID:
a8105c1b
VB
481 CHECK_TLV_SIZE(2, "Port Id");
482 tlv_subtype = PEEK_UINT8;
483 if ((tlv_subtype == 0) || (tlv_subtype > 7)) {
43c02e7b
VB
484 LLOG_WARNX("unknown subtype for tlv id received on %s",
485 hardware->h_ifname);
486 goto malformed;
487 }
a8105c1b 488 if ((b = (char *)calloc(1, tlv_size - 1)) == NULL) {
43c02e7b
VB
489 LLOG_WARN("unable to allocate memory for id tlv "
490 "received on %s",
491 hardware->h_ifname);
492 goto malformed;
493 }
a8105c1b
VB
494 PEEK_BYTES(b, tlv_size - 1);
495 if (tlv_type == LLDP_TLV_PORT_ID) {
496 port->p_id_subtype = tlv_subtype;
43c02e7b 497 port->p_id = b;
a8105c1b 498 port->p_id_len = tlv_size - 1;
43c02e7b 499 } else {
a8105c1b 500 chassis->c_id_subtype = tlv_subtype;
43c02e7b 501 chassis->c_id = b;
a8105c1b 502 chassis->c_id_len = tlv_size - 1;
43c02e7b 503 }
43c02e7b
VB
504 break;
505 case LLDP_TLV_TTL:
a8105c1b
VB
506 CHECK_TLV_SIZE(2, "TTL");
507 chassis->c_ttl = PEEK_UINT16;
43c02e7b
VB
508 break;
509 case LLDP_TLV_PORT_DESCR:
510 case LLDP_TLV_SYSTEM_NAME:
511 case LLDP_TLV_SYSTEM_DESCR:
a8105c1b 512 if (tlv_size < 1) {
a700e935 513 LLOG_DEBUG("empty tlv received on %s",
43c02e7b 514 hardware->h_ifname);
a700e935 515 break;
43c02e7b 516 }
a8105c1b 517 if ((b = (char *)calloc(1, tlv_size + 1)) == NULL) {
43c02e7b
VB
518 LLOG_WARN("unable to allocate memory for string tlv "
519 "received on %s",
520 hardware->h_ifname);
521 goto malformed;
522 }
a8105c1b
VB
523 PEEK_BYTES(b, tlv_size);
524 if (tlv_type == LLDP_TLV_PORT_DESCR)
43c02e7b 525 port->p_descr = b;
a8105c1b 526 else if (tlv_type == LLDP_TLV_SYSTEM_NAME)
43c02e7b
VB
527 chassis->c_name = b;
528 else chassis->c_descr = b;
529 break;
530 case LLDP_TLV_SYSTEM_CAP:
a8105c1b
VB
531 CHECK_TLV_SIZE(4, "System capabilities");
532 chassis->c_cap_available = PEEK_UINT16;
533 chassis->c_cap_enabled = PEEK_UINT16;
43c02e7b
VB
534 break;
535 case LLDP_TLV_MGMT_ADDR:
a8105c1b 536 CHECK_TLV_SIZE(11, "Management address");
43c02e7b 537 if ((chassis->c_mgmt.s_addr == INADDR_ANY) &&
a8105c1b
VB
538 (PEEK_UINT8 == 1+sizeof(struct in_addr)) &&
539 (PEEK_UINT8 == LLDP_MGMT_ADDR_IP4)) {
43c02e7b 540 /* We have an IPv4 address, we ignore anything else */
a8105c1b 541 PEEK_BYTES(&chassis->c_mgmt, sizeof(struct in_addr));
43c02e7b
VB
542 chassis->c_mgmt_if = 0;
543 /* We only handle ifIndex subtype */
a8105c1b
VB
544 if (PEEK_UINT8 == LLDP_MGMT_IFACE_IFINDEX)
545 chassis->c_mgmt_if = PEEK_UINT32;
43c02e7b 546 }
43c02e7b
VB
547 break;
548 case LLDP_TLV_ORG:
a8105c1b
VB
549 CHECK_TLV_SIZE(4, "Organisational");
550 PEEK_BYTES(orgid, sizeof(orgid));
551 tlv_subtype = PEEK_UINT8;
552 if (memcmp(dot1, orgid, sizeof(orgid)) == 0) {
a1347cd8 553#ifndef ENABLE_DOT1
a1347cd8
VB
554 hardware->h_rx_unrecognized_cnt++;
555#else
43c02e7b 556 /* Dot1 */
a8105c1b 557 switch (tlv_subtype) {
75b3469d 558 case LLDP_TLV_DOT1_VLANNAME:
a8105c1b 559 CHECK_TLV_SIZE(7, "VLAN");
43c02e7b
VB
560 if ((vlan = (struct lldpd_vlan *)calloc(1,
561 sizeof(struct lldpd_vlan))) == NULL) {
efe3f9b0
VB
562 LLOG_WARN("unable to alloc vlan "
563 "structure for "
43c02e7b
VB
564 "tlv received on %s",
565 hardware->h_ifname);
566 goto malformed;
567 }
a8105c1b
VB
568 vlan->v_vid = PEEK_UINT16;
569 vlan_len = PEEK_UINT8;
570 CHECK_TLV_SIZE(7 + vlan_len, "VLAN");
43c02e7b
VB
571 if ((vlan->v_name =
572 (char *)calloc(1, vlan_len + 1)) == NULL) {
573 LLOG_WARN("unable to alloc vlan name for "
574 "tlv received on %s",
575 hardware->h_ifname);
576 goto malformed;
577 }
a8105c1b 578 PEEK_BYTES(vlan->v_name, vlan_len);
43c02e7b
VB
579 TAILQ_INSERT_TAIL(&port->p_vlans,
580 vlan, v_entries);
75b3469d
VB
581 break;
582 case LLDP_TLV_DOT1_PVID:
a8105c1b
VB
583 CHECK_TLV_SIZE(6, "PVID");
584 port->p_pvid = PEEK_UINT16;
75b3469d
VB
585 break;
586 default:
43c02e7b 587 /* Unknown Dot1 TLV, ignore it */
a1347cd8
VB
588 hardware->h_rx_unrecognized_cnt++;
589 }
590#endif
a8105c1b 591 } else if (memcmp(dot3, orgid, sizeof(orgid)) == 0) {
a1347cd8 592#ifndef ENABLE_DOT3
a1347cd8
VB
593 hardware->h_rx_unrecognized_cnt++;
594#else
43c02e7b 595 /* Dot3 */
a8105c1b 596 switch (tlv_subtype) {
43c02e7b 597 case LLDP_TLV_DOT3_MAC:
a8105c1b 598 CHECK_TLV_SIZE(9, "MAC/PHY");
3fd015c0
VB
599 port->p_macphy.autoneg_support = PEEK_UINT8;
600 port->p_macphy.autoneg_enabled =
befbdf89 601 port->p_macphy.autoneg_support & 0x2;
3fd015c0 602 port->p_macphy.autoneg_support =
befbdf89 603 port->p_macphy.autoneg_support & 0x1;
3fd015c0 604 port->p_macphy.autoneg_advertised =
a8105c1b 605 PEEK_UINT16;
3fd015c0 606 port->p_macphy.mau_type = PEEK_UINT16;
43c02e7b
VB
607 break;
608 case LLDP_TLV_DOT3_LA:
a8105c1b 609 CHECK_TLV_SIZE(9, "Link aggregation");
a204514f 610 PEEK_DISCARD_UINT8;
a8105c1b 611 port->p_aggregid = PEEK_UINT32;
43c02e7b 612 break;
548109b2 613 case LLDP_TLV_DOT3_MFS:
a8105c1b
VB
614 CHECK_TLV_SIZE(6, "MFS");
615 port->p_mfs = PEEK_UINT16;
548109b2 616 break;
befbdf89
VB
617 case LLDP_TLV_DOT3_POWER:
618 CHECK_TLV_SIZE(7, "Power");
619 port->p_power.devicetype = PEEK_UINT8;
620 port->p_power.supported =
621 port->p_power.devicetype & 0x2;
622 port->p_power.enabled =
623 port->p_power.devicetype & 0x4;
624 port->p_power.paircontrol =
625 port->p_power.devicetype & 0x8;
626 port->p_power.devicetype =
627 (port->p_power.devicetype & 0x1)?
628 LLDP_DOT3_POWER_PSE:LLDP_DOT3_POWER_PD;
629 port->p_power.pairs = PEEK_UINT8;
630 port->p_power.class = PEEK_UINT8;
608cb51c
VB
631 /* 802.3at? */
632 if (tlv_size >= 12) {
633 port->p_power.powertype = PEEK_UINT8;
634 port->p_power.source =
635 (port->p_power.powertype & (1<<5 | 1<<4)) >> 4;
636 port->p_power.priority =
637 (port->p_power.powertype & (1<<1 | 1<<0));
638 port->p_power.powertype =
639 (port->p_power.powertype & (1<<7))?
640 LLDP_DOT3_POWER_8023AT_TYPE1:
641 LLDP_DOT3_POWER_8023AT_TYPE2;
642 port->p_power.requested = PEEK_UINT16;
643 port->p_power.allocated = PEEK_UINT16;
644 } else
645 port->p_power.powertype =
646 LLDP_DOT3_POWER_8023AT_OFF;
befbdf89 647 break;
43c02e7b
VB
648 default:
649 /* Unknown Dot3 TLV, ignore it */
37387046 650 hardware->h_rx_unrecognized_cnt++;
43c02e7b 651 }
a1347cd8 652#endif
a8105c1b 653 } else if (memcmp(med, orgid, sizeof(orgid)) == 0) {
6772b237
VB
654 /* LLDP-MED */
655#ifndef ENABLE_LLDPMED
6772b237
VB
656 hardware->h_rx_unrecognized_cnt++;
657#else
e3a44efb
VB
658 u_int32_t policy;
659 int loctype;
a8105c1b 660 int power;
e3a44efb 661
a8105c1b 662 switch (tlv_subtype) {
6772b237 663 case LLDP_TLV_MED_CAP:
a8105c1b
VB
664 CHECK_TLV_SIZE(7, "LLDP-MED capabilities");
665 chassis->c_med_cap_available = PEEK_UINT16;
666 chassis->c_med_type = PEEK_UINT8;
740593ff 667 port->p_med_cap_enabled |=
40ecae87 668 LLDPMED_CAP_CAP;
6772b237 669 break;
efe3f9b0 670 case LLDP_TLV_MED_POLICY:
a8105c1b
VB
671 CHECK_TLV_SIZE(8, "LLDP-MED policy");
672 policy = PEEK_UINT32;
e3a44efb
VB
673 if (((policy >> 24) < 1) ||
674 ((policy >> 24) > LLDPMED_APPTYPE_LAST)) {
675 LLOG_INFO("unknown policy field %d "
676 "received on %s",
e51da5ec 677 policy,
e3a44efb 678 hardware->h_ifname);
e3a44efb
VB
679 break;
680 }
740593ff 681 port->p_med_policy[(policy >> 24) - 1].type =
e3a44efb 682 (policy >> 24);
740593ff 683 port->p_med_policy[(policy >> 24) - 1].unknown =
e3a44efb 684 ((policy & 0x800000) != 0);
740593ff 685 port->p_med_policy[(policy >> 24) - 1].tagged =
e3a44efb 686 ((policy & 0x400000) != 0);
740593ff 687 port->p_med_policy[(policy >> 24) - 1].vid =
e3a44efb 688 (policy & 0x001FFE00) >> 9;
740593ff 689 port->p_med_policy[(policy >> 24) - 1].priority =
e3a44efb 690 (policy & 0x1C0) >> 6;
740593ff 691 port->p_med_policy[(policy >> 24) - 1].dscp =
e3a44efb 692 policy & 0x3F;
740593ff 693 port->p_med_cap_enabled |=
40ecae87 694 LLDPMED_CAP_POLICY;
efe3f9b0
VB
695 break;
696 case LLDP_TLV_MED_LOCATION:
a8105c1b
VB
697 CHECK_TLV_SIZE(5, "LLDP-MED Location");
698 loctype = PEEK_UINT8;
699 if ((loctype < 1) ||
700 (loctype > LLDPMED_LOCFORMAT_LAST)) {
e3a44efb
VB
701 LLOG_INFO("unknown location type "
702 "received on %s",
703 hardware->h_ifname);
e3a44efb
VB
704 break;
705 }
740593ff 706 if ((port->p_med_location[loctype - 1].data =
a8105c1b 707 (char*)malloc(tlv_size - 5)) == NULL) {
efe3f9b0
VB
708 LLOG_WARN("unable to allocate memory "
709 "for LLDP-MED location for "
710 "frame received on %s",
711 hardware->h_ifname);
712 goto malformed;
713 }
a8105c1b
VB
714 PEEK_BYTES(port->p_med_location[loctype - 1].data,
715 tlv_size - 5);
740593ff 716 port->p_med_location[loctype - 1].data_len =
a8105c1b 717 tlv_size - 5;
740593ff 718 port->p_med_location[loctype - 1].format = loctype;
740593ff 719 port->p_med_cap_enabled |=
40ecae87 720 LLDPMED_CAP_LOCATION;
efe3f9b0
VB
721 break;
722 case LLDP_TLV_MED_MDI:
a8105c1b
VB
723 CHECK_TLV_SIZE(7, "LLDP-MED PoE-MDI");
724 power = PEEK_UINT8;
725 switch (power & 0xC0) {
994812b9 726 case 0x0:
6d08df0e 727 port->p_med_power.devicetype = LLDPMED_POW_TYPE_PSE;
740593ff 728 port->p_med_cap_enabled |=
a49b3a79 729 LLDPMED_CAP_MDI_PSE;
a8105c1b 730 switch (power & 0x30) {
994812b9 731 case 0x0:
6d08df0e 732 port->p_med_power.source =
994812b9
VB
733 LLDPMED_POW_SOURCE_UNKNOWN;
734 break;
735 case 0x10:
6d08df0e 736 port->p_med_power.source =
994812b9
VB
737 LLDPMED_POW_SOURCE_PRIMARY;
738 break;
739 case 0x20:
6d08df0e 740 port->p_med_power.source =
994812b9
VB
741 LLDPMED_POW_SOURCE_BACKUP;
742 break;
743 default:
6d08df0e 744 port->p_med_power.source =
994812b9
VB
745 LLDPMED_POW_SOURCE_RESERVED;
746 }
747 break;
748 case 0x40:
6d08df0e 749 port->p_med_power.devicetype = LLDPMED_POW_TYPE_PD;
740593ff 750 port->p_med_cap_enabled |=
a49b3a79 751 LLDPMED_CAP_MDI_PD;
a8105c1b 752 switch (power & 0x30) {
994812b9 753 case 0x0:
6d08df0e 754 port->p_med_power.source =
994812b9
VB
755 LLDPMED_POW_SOURCE_UNKNOWN;
756 break;
757 case 0x10:
6d08df0e 758 port->p_med_power.source =
994812b9
VB
759 LLDPMED_POW_SOURCE_PSE;
760 break;
761 case 0x20:
6d08df0e 762 port->p_med_power.source =
994812b9
VB
763 LLDPMED_POW_SOURCE_LOCAL;
764 break;
765 default:
6d08df0e 766 port->p_med_power.source =
994812b9
VB
767 LLDPMED_POW_SOURCE_BOTH;
768 }
769 break;
770 default:
6d08df0e 771 port->p_med_power.devicetype =
994812b9
VB
772 LLDPMED_POW_TYPE_RESERVED;
773 }
009ddd23
VB
774 if (((power & 0x0F) < 0) ||
775 ((power & 0x0F) > LLDPMED_POW_PRIO_LOW))
6d08df0e 776 port->p_med_power.priority =
994812b9 777 LLDPMED_POW_PRIO_UNKNOWN;
009ddd23 778 else
6d08df0e 779 port->p_med_power.priority =
009ddd23 780 power & 0x0F;
6d08df0e 781 port->p_med_power.val = PEEK_UINT16;
efe3f9b0 782 break;
6772b237
VB
783 case LLDP_TLV_MED_IV_HW:
784 case LLDP_TLV_MED_IV_SW:
785 case LLDP_TLV_MED_IV_FW:
786 case LLDP_TLV_MED_IV_SN:
787 case LLDP_TLV_MED_IV_MANUF:
788 case LLDP_TLV_MED_IV_MODEL:
789 case LLDP_TLV_MED_IV_ASSET:
a8105c1b 790 if (tlv_size <= 4)
6772b237
VB
791 b = NULL;
792 else {
a8105c1b 793 if ((b = (char*)malloc(tlv_size - 3)) ==
efe3f9b0
VB
794 NULL) {
795 LLOG_WARN("unable to allocate "
796 "memory for LLDP-MED "
797 "inventory for frame "
798 "received on %s",
799 hardware->h_ifname);
800 goto malformed;
801 }
a8105c1b
VB
802 PEEK_BYTES(b, tlv_size - 4);
803 b[tlv_size - 4] = '\0';
6772b237 804 }
a8105c1b 805 switch (tlv_subtype) {
6772b237
VB
806 case LLDP_TLV_MED_IV_HW:
807 chassis->c_med_hw = b;
808 break;
809 case LLDP_TLV_MED_IV_FW:
810 chassis->c_med_fw = b;
811 break;
812 case LLDP_TLV_MED_IV_SW:
813 chassis->c_med_sw = b;
814 break;
815 case LLDP_TLV_MED_IV_SN:
816 chassis->c_med_sn = b;
817 break;
818 case LLDP_TLV_MED_IV_MANUF:
819 chassis->c_med_manuf = b;
820 break;
821 case LLDP_TLV_MED_IV_MODEL:
397dee69 822 chassis->c_med_model = b;
6772b237
VB
823 break;
824 case LLDP_TLV_MED_IV_ASSET:
72c4c96f 825 chassis->c_med_asset = b;
6772b237
VB
826 break;
827 default:
828 LLOG_WARNX("should not be there!");
829 free(b);
830 break;
831 }
740593ff 832 port->p_med_cap_enabled |=
40ecae87 833 LLDPMED_CAP_IV;
6772b237
VB
834 break;
835 default:
836 /* Unknown LLDP MED, ignore it */
6772b237
VB
837 hardware->h_rx_unrecognized_cnt++;
838 }
839#endif /* ENABLE_LLDPMED */
43c02e7b 840 } else {
9ca19b69 841 LLOG_INFO("unknown org tlv received on %s",
43c02e7b 842 hardware->h_ifname);
37387046 843 hardware->h_rx_unrecognized_cnt++;
43c02e7b
VB
844 }
845 break;
846 default:
847 LLOG_WARNX("unknown tlv (%d) received on %s",
a8105c1b
VB
848 tlv_type, hardware->h_ifname);
849 goto malformed;
850 }
851 if (pos > tlv + tlv_size) {
852 LLOG_WARNX("BUG: already past TLV!");
43c02e7b
VB
853 goto malformed;
854 }
a8105c1b 855 PEEK_DISCARD(tlv + tlv_size - pos);
43c02e7b
VB
856 }
857
858 /* Some random check */
859 if ((chassis->c_id == NULL) ||
860 (port->p_id == NULL) ||
861 (chassis->c_ttl == 0) ||
862 (gotend == 0)) {
863 LLOG_WARNX("some mandatory tlv are missing for frame received on %s",
864 hardware->h_ifname);
865 goto malformed;
866 }
867#define NOTRECEIVED "Not received"
868 if (chassis->c_name == NULL) {
869 if ((chassis->c_name = (char *)calloc(1, strlen(NOTRECEIVED) + 1)) == NULL) {
870 LLOG_WARNX("unable to allocate null chassis name");
871 goto malformed;
872 }
873 memcpy(chassis->c_name, NOTRECEIVED, strlen(NOTRECEIVED));
874 }
875 if (chassis->c_descr == NULL) {
876 if ((chassis->c_descr = (char *)calloc(1, strlen(NOTRECEIVED) + 1)) == NULL) {
877 LLOG_WARNX("unable to allocate null chassis description");
878 goto malformed;
879 }
880 memcpy(chassis->c_descr, NOTRECEIVED, strlen(NOTRECEIVED));
881 }
882 if (port->p_descr == NULL) {
883 if ((port->p_descr = (char *)calloc(1, strlen(NOTRECEIVED) + 1)) == NULL) {
884 LLOG_WARNX("unable to allocate null port description");
885 goto malformed;
886 }
887 memcpy(port->p_descr, NOTRECEIVED, strlen(NOTRECEIVED));
888 }
889 *newchassis = chassis;
890 *newport = port;
891 return 1;
892malformed:
77507b69 893 lldpd_chassis_cleanup(chassis, 1);
9898ac07 894 lldpd_port_cleanup(cfg, port, 1);
4e624dc2 895 free(port);
43c02e7b
VB
896 return -1;
897}