]> git.ipfire.org Git - thirdparty/lldpd.git/blob - src/daemon/edp.c
log: convert LLOG_* to log_* and add more debug logs
[thirdparty/lldpd.git] / src / daemon / edp.c
1 /* -*- mode: c; c-file-style: "openbsd" -*- */
2 /*
3 * Copyright (c) 2008 Vincent Bernat <bernat@luffy.cx>
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18 #include "lldpd.h"
19 #include "frame.h"
20
21 #ifdef ENABLE_EDP
22
23 #include <stdio.h>
24 #include <unistd.h>
25 #include <errno.h>
26 #include <arpa/inet.h>
27 #include <fnmatch.h>
28 #include <assert.h>
29
30 static int seq = 0;
31
32 int
33 edp_send(struct lldpd *global,
34 struct lldpd_hardware *hardware)
35 {
36 const u_int8_t mcastaddr[] = EDP_MULTICAST_ADDR;
37 const u_int8_t llcorg[] = LLC_ORG_EXTREME;
38 struct lldpd_chassis *chassis;
39 int length, i, v;
40 u_int8_t *packet, *pos, *pos_llc, *pos_len_eh, *pos_len_edp, *pos_edp, *tlv, *end;
41 u_int16_t checksum;
42 #ifdef ENABLE_DOT1
43 struct lldpd_vlan *vlan;
44 unsigned int state = 0;
45 #endif
46 u_int8_t edp_fakeversion[] = {7, 6, 4, 99};
47 /* Subsequent XXX can be replaced by other values. We place
48 them here to ensure the position of "" to be a bit
49 invariant with version changes. */
50 char *deviceslot[] = { "eth", "veth", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "", NULL };
51
52 log_debug("edp", "send EDP frame on port %s", hardware->h_ifname);
53
54 chassis = hardware->h_lport.p_chassis;
55 #ifdef ENABLE_DOT1
56 while (state != 2) {
57 #endif
58 length = hardware->h_mtu;
59 if ((packet = (u_int8_t*)malloc(length)) == NULL)
60 return ENOMEM;
61 memset(packet, 0, length);
62 pos = packet;
63 v = 0;
64
65 /* Ethernet header */
66 if (!(
67 POKE_BYTES(mcastaddr, sizeof(mcastaddr)) &&
68 POKE_BYTES(&hardware->h_lladdr, sizeof(hardware->h_lladdr)) &&
69 POKE_SAVE(pos_len_eh) && /* We compute the len later */
70 POKE_UINT16(0)))
71 goto toobig;
72
73 /* LLC */
74 if (!(
75 POKE_SAVE(pos_llc) && /* We need to save our
76 current position to
77 compute ethernet len */
78 /* SSAP and DSAP */
79 POKE_UINT8(0xaa) && POKE_UINT8(0xaa) &&
80 /* Control field */
81 POKE_UINT8(0x03) &&
82 /* ORG */
83 POKE_BYTES(llcorg, sizeof(llcorg)) &&
84 POKE_UINT16(LLC_PID_EDP)))
85 goto toobig;
86
87 /* EDP header */
88 if ((chassis->c_id_len != ETH_ALEN) ||
89 (chassis->c_id_subtype != LLDP_CHASSISID_SUBTYPE_LLADDR)) {
90 log_warnx("edp", "local chassis does not use MAC address as chassis ID!?");
91 free(packet);
92 return EINVAL;
93 }
94 if (!(
95 POKE_SAVE(pos_edp) && /* Save the start of EDP frame */
96 POKE_UINT8(1) && POKE_UINT8(0) &&
97 POKE_SAVE(pos_len_edp) && /* We compute the len
98 and the checksum
99 later */
100 POKE_UINT32(0) && /* Len + Checksum */
101 POKE_UINT16(seq) &&
102 POKE_UINT16(0) &&
103 POKE_BYTES(chassis->c_id, ETH_ALEN)))
104 goto toobig;
105 seq++;
106
107 #ifdef ENABLE_DOT1
108 switch (state) {
109 case 0:
110 #endif
111 /* Display TLV */
112 if (!(
113 POKE_START_EDP_TLV(EDP_TLV_DISPLAY) &&
114 POKE_BYTES(chassis->c_name, strlen(chassis->c_name)) &&
115 POKE_UINT8(0) && /* Add a NULL character
116 for better
117 compatibility */
118 POKE_END_EDP_TLV))
119 goto toobig;
120
121 /* Info TLV */
122 if (!(
123 POKE_START_EDP_TLV(EDP_TLV_INFO)))
124 goto toobig;
125 /* We try to emulate the slot thing */
126 for (i=0; deviceslot[i] != NULL; i++) {
127 if (strncmp(hardware->h_ifname, deviceslot[i],
128 strlen(deviceslot[i])) == 0) {
129 if (!(
130 POKE_UINT16(i) &&
131 POKE_UINT16(atoi(hardware->h_ifname +
132 strlen(deviceslot[i])))))
133 goto toobig;
134 break;
135 }
136 }
137 /* If we don't find a "slot", we say that the
138 interface is in slot 8 */
139 if (deviceslot[i] == NULL) {
140 if (!(
141 POKE_UINT16(8) &&
142 POKE_UINT16(hardware->h_ifindex)))
143 goto toobig;
144 }
145 if (!(
146 POKE_UINT16(0) && /* vchassis */
147 POKE_UINT32(0) && POKE_UINT16(0) && /* Reserved */
148 /* Version */
149 POKE_BYTES(edp_fakeversion, sizeof(edp_fakeversion)) &&
150 /* Connections, we say that we won't
151 have more interfaces than this
152 mask. */
153 POKE_UINT32(0xffffffff) &&
154 POKE_UINT32(0) && POKE_UINT32(0) && POKE_UINT32(0) &&
155 POKE_END_EDP_TLV))
156 goto toobig;
157
158 #ifdef ENABLE_DOT1
159 break;
160 case 1:
161 TAILQ_FOREACH(vlan, &hardware->h_lport.p_vlans,
162 v_entries) {
163 v++;
164 if (!(
165 POKE_START_EDP_TLV(EDP_TLV_VLAN) &&
166 POKE_UINT8(0) && /* Flags: no IP address */
167 POKE_UINT8(0) && /* Reserved */
168 POKE_UINT16(vlan->v_vid) &&
169 POKE_UINT32(0) && /* Reserved */
170 POKE_UINT32(0) && /* IP address */
171 /* VLAN name */
172 POKE_BYTES(vlan->v_name, strlen(vlan->v_name)) &&
173 POKE_UINT8(0) &&
174 POKE_END_EDP_TLV))
175 goto toobig;
176 }
177 break;
178 }
179
180 if ((state == 1) && (v == 0)) /* No VLAN, no need to send another TLV */
181 break;
182 #endif
183
184 /* Null TLV */
185 if (!(
186 POKE_START_EDP_TLV(EDP_TLV_NULL) &&
187 POKE_END_EDP_TLV &&
188 POKE_SAVE(end)))
189 goto toobig;
190
191 /* Compute len and checksum */
192 i = end - pos_llc; /* Ethernet length */
193 v = end - pos_edp; /* EDP length */
194 POKE_RESTORE(pos_len_eh);
195 if (!(POKE_UINT16(i))) goto toobig;
196 POKE_RESTORE(pos_len_edp);
197 if (!(POKE_UINT16(v))) goto toobig;
198 checksum = frame_checksum(pos_edp, v, 0);
199 if (!(POKE_UINT16(ntohs(checksum)))) goto toobig;
200
201 if (hardware->h_ops->send(global, hardware,
202 (char *)packet, end - packet) == -1) {
203 log_warn("edp", "unable to send packet on real device for %s",
204 hardware->h_ifname);
205 free(packet);
206 return ENETDOWN;
207 }
208 free(packet);
209
210 #ifdef ENABLE_DOT1
211 state++;
212 }
213 #endif
214
215 hardware->h_tx_cnt++;
216 return 0;
217 toobig:
218 free(packet);
219 return E2BIG;
220 }
221
222 #define CHECK_TLV_SIZE(x, name) \
223 do { if (tlv_len < (x)) { \
224 log_warnx("edp", name " EDP TLV too short received on %s", \
225 hardware->h_ifname); \
226 goto malformed; \
227 } } while (0)
228
229 int
230 edp_decode(struct lldpd *cfg, char *frame, int s,
231 struct lldpd_hardware *hardware,
232 struct lldpd_chassis **newchassis, struct lldpd_port **newport)
233 {
234 struct lldpd_chassis *chassis;
235 struct lldpd_port *port;
236 #ifdef ENABLE_DOT1
237 struct lldpd_mgmt *mgmt, *mgmt_next, *m;
238 struct lldpd_vlan *lvlan = NULL, *lvlan_next;
239 #endif
240 const unsigned char edpaddr[] = EDP_MULTICAST_ADDR;
241 int length, gotend = 0, gotvlans = 0, edp_len, tlv_len, tlv_type;
242 int edp_port, edp_slot;
243 u_int8_t *pos, *pos_edp, *tlv;
244 u_int8_t version[4];
245 #ifdef ENABLE_DOT1
246 struct in_addr address;
247 struct lldpd_port *oport;
248 #endif
249
250 log_debug("edp", "decode EDP frame on port %s",
251 hardware->h_ifname);
252
253 if ((chassis = calloc(1, sizeof(struct lldpd_chassis))) == NULL) {
254 log_warn("edp", "failed to allocate remote chassis");
255 return -1;
256 }
257 TAILQ_INIT(&chassis->c_mgmt);
258 if ((port = calloc(1, sizeof(struct lldpd_port))) == NULL) {
259 log_warn("edp", "failed to allocate remote port");
260 free(chassis);
261 return -1;
262 }
263 #ifdef ENABLE_DOT1
264 TAILQ_INIT(&port->p_vlans);
265 #endif
266
267 length = s;
268 pos = (u_int8_t*)frame;
269
270 if (length < 2*ETH_ALEN + sizeof(u_int16_t) + 8 /* LLC */ +
271 10 + ETH_ALEN /* EDP header */) {
272 log_warnx("edp", "too short EDP frame received on %s", hardware->h_ifname);
273 goto malformed;
274 }
275
276 if (PEEK_CMP(edpaddr, sizeof(edpaddr)) != 0) {
277 log_info("edp", "frame not targeted at EDP multicast address received on %s",
278 hardware->h_ifname);
279 goto malformed;
280 }
281 PEEK_DISCARD(ETH_ALEN); PEEK_DISCARD_UINT16;
282 PEEK_DISCARD(6); /* LLC: DSAP + SSAP + control + org */
283 if (PEEK_UINT16 != LLC_PID_EDP) {
284 log_debug("edp", "incorrect LLC protocol ID received on %s",
285 hardware->h_ifname);
286 goto malformed;
287 }
288
289 PEEK_SAVE(pos_edp); /* Save the start of EDP packet */
290 if (PEEK_UINT8 != 1) {
291 log_warnx("edp", "incorrect EDP version for frame received on %s",
292 hardware->h_ifname);
293 goto malformed;
294 }
295 PEEK_DISCARD_UINT8; /* Reserved */
296 edp_len = PEEK_UINT16;
297 PEEK_DISCARD_UINT16; /* Checksum */
298 PEEK_DISCARD_UINT16; /* Sequence */
299 if (PEEK_UINT16 != 0) { /* ID Type = 0 = MAC */
300 log_warnx("edp", "incorrect device id type for frame received on %s",
301 hardware->h_ifname);
302 goto malformed;
303 }
304 if (edp_len > length + 10) {
305 log_warnx("edp", "incorrect size for EDP frame received on %s",
306 hardware->h_ifname);
307 goto malformed;
308 }
309 chassis->c_ttl = LLDPD_TTL;
310 chassis->c_id_subtype = LLDP_CHASSISID_SUBTYPE_LLADDR;
311 chassis->c_id_len = ETH_ALEN;
312 if ((chassis->c_id = (char *)malloc(ETH_ALEN)) == NULL) {
313 log_warn("edp", "unable to allocate memory for chassis ID");
314 goto malformed;
315 }
316 PEEK_BYTES(chassis->c_id, ETH_ALEN);
317
318 /* Let's check checksum */
319 if (frame_checksum(pos_edp, edp_len, 0) != 0) {
320 log_warnx("edp", "incorrect EDP checksum for frame received on %s",
321 hardware->h_ifname);
322 goto malformed;
323 }
324
325 while (length && !gotend) {
326 if (length < 4) {
327 log_warnx("edp", "EDP TLV header is too large for "
328 "frame received on %s",
329 hardware->h_ifname);
330 goto malformed;
331 }
332 if (PEEK_UINT8 != EDP_TLV_MARKER) {
333 log_warnx("edp", "incorrect marker starting EDP TLV header for frame "
334 "received on %s",
335 hardware->h_ifname);
336 goto malformed;
337 }
338 tlv_type = PEEK_UINT8;
339 tlv_len = PEEK_UINT16 - 4;
340 PEEK_SAVE(tlv);
341 if ((tlv_len < 0) || (tlv_len > length)) {
342 log_debug("edp", "incorrect size in EDP TLV header for frame "
343 "received on %s",
344 hardware->h_ifname);
345 /* Some poor old Extreme Summit are quite bogus */
346 gotend = 1;
347 break;
348 }
349 switch (tlv_type) {
350 case EDP_TLV_INFO:
351 CHECK_TLV_SIZE(32, "Info");
352 port->p_id_subtype = LLDP_PORTID_SUBTYPE_IFNAME;
353 edp_slot = PEEK_UINT16; edp_port = PEEK_UINT16;
354 if (asprintf(&port->p_id, "%d/%d",
355 edp_slot + 1, edp_port + 1) == -1) {
356 log_warn("edp", "unable to allocate memory for "
357 "port ID");
358 goto malformed;
359 }
360 port->p_id_len = strlen(port->p_id);
361 if (asprintf(&port->p_descr, "Slot %d / Port %d",
362 edp_slot + 1, edp_port + 1) == -1) {
363 log_warn("edp", "unable to allocate memory for "
364 "port description");
365 goto malformed;
366 }
367 PEEK_DISCARD_UINT16; /* vchassis */
368 PEEK_DISCARD(6); /* Reserved */
369 PEEK_BYTES(version, 4);
370 if (asprintf(&chassis->c_descr,
371 "EDP enabled device, version %d.%d.%d.%d",
372 version[0], version[1],
373 version[2], version[3]) == -1) {
374 log_warn("edp", "unable to allocate memory for "
375 "chassis description");
376 goto malformed;
377 }
378 break;
379 case EDP_TLV_DISPLAY:
380 if ((chassis->c_name = (char *)calloc(1, tlv_len + 1)) == NULL) {
381 log_warn("edp", "unable to allocate memory for chassis "
382 "name");
383 goto malformed;
384 }
385 /* TLV display contains a lot of garbage */
386 PEEK_BYTES(chassis->c_name, tlv_len);
387 break;
388 case EDP_TLV_NULL:
389 if (tlv_len != 0) {
390 log_warnx("edp", "null tlv with incorrect size in frame "
391 "received on %s",
392 hardware->h_ifname);
393 goto malformed;
394 }
395 if (length)
396 log_debug("edp", "extra data after edp frame on %s",
397 hardware->h_ifname);
398 gotend = 1;
399 break;
400 case EDP_TLV_VLAN:
401 #ifdef ENABLE_DOT1
402 CHECK_TLV_SIZE(12, "VLAN");
403 if ((lvlan = (struct lldpd_vlan *)calloc(1,
404 sizeof(struct lldpd_vlan))) == NULL) {
405 log_warn("edp", "unable to allocate vlan");
406 goto malformed;
407 }
408 PEEK_DISCARD_UINT16; /* Flags + reserved */
409 lvlan->v_vid = PEEK_UINT16; /* VID */
410 PEEK_DISCARD(4); /* Reserved */
411 PEEK_BYTES(&address, sizeof(address));
412
413 if ((lvlan->v_name = (char *)calloc(1,
414 tlv_len + 1 - 12)) == NULL) {
415 log_warn("edp", "unable to allocate vlan name");
416 free(lvlan);
417 goto malformed;
418 }
419 PEEK_BYTES(lvlan->v_name, tlv_len - 12);
420
421 if (address.s_addr != INADDR_ANY) {
422 mgmt = lldpd_alloc_mgmt(LLDPD_AF_IPV4, &address,
423 sizeof(struct in_addr), 0);
424 if (mgmt == NULL) {
425 assert(errno == ENOMEM);
426 log_warn("edp", "Out of memory");
427 goto malformed;
428 }
429 TAILQ_INSERT_TAIL(&chassis->c_mgmt, mgmt, m_entries);
430 }
431 TAILQ_INSERT_TAIL(&port->p_vlans,
432 lvlan, v_entries);
433 #endif
434 gotvlans = 1;
435 break;
436 default:
437 log_debug("edp", "unknown EDP TLV type (%d) received on %s",
438 tlv_type, hardware->h_ifname);
439 hardware->h_rx_unrecognized_cnt++;
440 }
441 PEEK_DISCARD(tlv + tlv_len - pos);
442 }
443 if ((chassis->c_id == NULL) ||
444 (port->p_id == NULL) ||
445 (chassis->c_name == NULL) ||
446 (chassis->c_descr == NULL) ||
447 (port->p_descr == NULL) ||
448 (gotend == 0)) {
449 #ifdef ENABLE_DOT1
450 if (gotvlans && gotend) {
451 /* VLAN can be sent in a separate frames. We need to add
452 * those vlans to an existing port */
453 TAILQ_FOREACH(oport, &hardware->h_rports, p_entries) {
454 if (!((oport->p_protocol == LLDPD_MODE_EDP) &&
455 (oport->p_chassis->c_id_subtype ==
456 chassis->c_id_subtype) &&
457 (oport->p_chassis->c_id_len == chassis->c_id_len) &&
458 (memcmp(oport->p_chassis->c_id, chassis->c_id,
459 chassis->c_id_len) == 0)))
460 continue;
461 /* We attach the VLANs to the found port */
462 lldpd_vlan_cleanup(oport);
463 for (lvlan = TAILQ_FIRST(&port->p_vlans);
464 lvlan != NULL;
465 lvlan = lvlan_next) {
466 lvlan_next = TAILQ_NEXT(lvlan, v_entries);
467 TAILQ_REMOVE(&port->p_vlans, lvlan, v_entries);
468 TAILQ_INSERT_TAIL(&oport->p_vlans,
469 lvlan, v_entries);
470 }
471 /* And the IP addresses */
472 for (mgmt = TAILQ_FIRST(&chassis->c_mgmt);
473 mgmt != NULL;
474 mgmt = mgmt_next) {
475 mgmt_next = TAILQ_NEXT(mgmt, m_entries);
476 TAILQ_REMOVE(&chassis->c_mgmt, mgmt, m_entries);
477 /* Don't add an address that already exists! */
478 TAILQ_FOREACH(m, &chassis->c_mgmt, m_entries)
479 if (m->m_family == mgmt->m_family &&
480 !memcmp(&m->m_addr, &mgmt->m_addr,
481 sizeof(m->m_addr))) break;
482 if (m == NULL)
483 TAILQ_INSERT_TAIL(&oport->p_chassis->c_mgmt,
484 mgmt, m_entries);
485 }
486 }
487 /* We discard the remaining frame */
488 goto malformed;
489 }
490 #else
491 if (gotvlans)
492 goto malformed;
493 #endif
494 log_warnx("edp", "some mandatory tlv are missing for frame received on %s",
495 hardware->h_ifname);
496 goto malformed;
497 }
498 *newchassis = chassis;
499 *newport = port;
500 return 1;
501
502 malformed:
503 lldpd_chassis_cleanup(chassis, 1);
504 lldpd_port_cleanup(port, 1);
505 free(port);
506 return -1;
507 }
508
509 #endif /* ENABLE_EDP */