1 /* -*- mode: c; c-file-style: "openbsd" -*- */
3 * Copyright (c) 2008 Vincent Bernat <bernat@luffy.cx>
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.
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.
26 #include <arpa/inet.h>
32 edp_send(struct lldpd
*global
,
33 struct lldpd_hardware
*hardware
)
35 const u_int8_t mcastaddr
[] = EDP_MULTICAST_ADDR
;
36 const u_int8_t llcorg
[] = LLC_ORG_EXTREME
;
37 struct lldpd_chassis
*chassis
;
39 u_int8_t
*packet
, *pos
, *pos_llc
, *pos_len_eh
, *pos_len_edp
, *pos_edp
, *tlv
, *end
;
42 struct lldpd_vlan
*vlan
;
43 unsigned int state
= 0;
45 u_int8_t edp_fakeversion
[] = {7, 6, 4, 99};
46 /* Subsequent XXX can be replaced by other values. We place
47 them here to ensure the position of "" to be a bit
48 invariant with version changes. */
49 char *deviceslot
[] = { "eth", "veth", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "", NULL
};
51 log_debug("edp", "send EDP frame on port %s", hardware
->h_ifname
);
53 chassis
= hardware
->h_lport
.p_chassis
;
57 length
= hardware
->h_mtu
;
58 if ((packet
= (u_int8_t
*)calloc(1, length
)) == NULL
)
65 POKE_BYTES(mcastaddr
, sizeof(mcastaddr
)) &&
66 POKE_BYTES(&hardware
->h_lladdr
, ETHER_ADDR_LEN
) &&
67 POKE_SAVE(pos_len_eh
) && /* We compute the len later */
73 POKE_SAVE(pos_llc
) && /* We need to save our
75 compute ethernet len */
77 POKE_UINT8(0xaa) && POKE_UINT8(0xaa) &&
81 POKE_BYTES(llcorg
, sizeof(llcorg
)) &&
82 POKE_UINT16(LLC_PID_EDP
)))
86 if ((chassis
->c_id_len
!= ETHER_ADDR_LEN
) ||
87 (chassis
->c_id_subtype
!= LLDP_CHASSISID_SUBTYPE_LLADDR
)) {
88 log_warnx("edp", "local chassis does not use MAC address as chassis ID!?");
93 POKE_SAVE(pos_edp
) && /* Save the start of EDP frame */
94 POKE_UINT8(1) && POKE_UINT8(0) &&
95 POKE_SAVE(pos_len_edp
) && /* We compute the len
98 POKE_UINT32(0) && /* Len + Checksum */
101 POKE_BYTES(chassis
->c_id
, ETHER_ADDR_LEN
)))
111 POKE_START_EDP_TLV(EDP_TLV_DISPLAY
) &&
112 POKE_BYTES(chassis
->c_name
, strlen(chassis
->c_name
)) &&
113 POKE_UINT8(0) && /* Add a NULL character
121 POKE_START_EDP_TLV(EDP_TLV_INFO
)))
123 /* We try to emulate the slot thing */
124 for (i
=0; deviceslot
[i
] != NULL
; i
++) {
125 if (strncmp(hardware
->h_ifname
, deviceslot
[i
],
126 strlen(deviceslot
[i
])) == 0) {
129 POKE_UINT16(atoi(hardware
->h_ifname
+
130 strlen(deviceslot
[i
])))))
135 /* If we don't find a "slot", we say that the
136 interface is in slot 8 */
137 if (deviceslot
[i
] == NULL
) {
140 POKE_UINT16(hardware
->h_ifindex
)))
144 POKE_UINT16(0) && /* vchassis */
145 POKE_UINT32(0) && POKE_UINT16(0) && /* Reserved */
147 POKE_BYTES(edp_fakeversion
, sizeof(edp_fakeversion
)) &&
148 /* Connections, we say that we won't
149 have more interfaces than this
151 POKE_UINT32(0xffffffff) &&
152 POKE_UINT32(0) && POKE_UINT32(0) && POKE_UINT32(0) &&
159 TAILQ_FOREACH(vlan
, &hardware
->h_lport
.p_vlans
,
163 POKE_START_EDP_TLV(EDP_TLV_VLAN
) &&
164 POKE_UINT8(0) && /* Flags: no IP address */
165 POKE_UINT8(0) && /* Reserved */
166 POKE_UINT16(vlan
->v_vid
) &&
167 POKE_UINT32(0) && /* Reserved */
168 POKE_UINT32(0) && /* IP address */
170 POKE_BYTES(vlan
->v_name
, strlen(vlan
->v_name
)) &&
178 if ((state
== 1) && (v
== 0)) {
179 /* No VLAN, no need to send another TLV */
187 POKE_START_EDP_TLV(EDP_TLV_NULL
) &&
192 /* Compute len and checksum */
193 i
= end
- pos_llc
; /* Ethernet length */
194 v
= end
- pos_edp
; /* EDP length */
195 POKE_RESTORE(pos_len_eh
);
196 if (!(POKE_UINT16(i
))) goto toobig
;
197 POKE_RESTORE(pos_len_edp
);
198 if (!(POKE_UINT16(v
))) goto toobig
;
199 checksum
= frame_checksum(pos_edp
, v
, 0);
200 if (!(POKE_UINT16(checksum
))) goto toobig
;
202 if (interfaces_send_helper(global
, hardware
,
203 (char *)packet
, end
- packet
) == -1) {
204 log_warn("edp", "unable to send packet on real device for %s",
216 hardware
->h_tx_cnt
++;
223 #define CHECK_TLV_SIZE(x, name) \
224 do { if (tlv_len < (x)) { \
225 log_warnx("edp", name " EDP TLV too short received on %s", \
226 hardware->h_ifname); \
231 edp_decode(struct lldpd
*cfg
, char *frame
, int s
,
232 struct lldpd_hardware
*hardware
,
233 struct lldpd_chassis
**newchassis
, struct lldpd_port
**newport
)
235 struct lldpd_chassis
*chassis
;
236 struct lldpd_port
*port
;
238 struct lldpd_mgmt
*mgmt
, *mgmt_next
, *m
;
239 struct lldpd_vlan
*lvlan
= NULL
, *lvlan_next
;
241 const unsigned char edpaddr
[] = EDP_MULTICAST_ADDR
;
242 int length
, gotend
= 0, gotvlans
= 0, edp_len
, tlv_len
, tlv_type
;
243 int edp_port
, edp_slot
;
244 u_int8_t
*pos
, *pos_edp
, *tlv
;
247 struct in_addr address
;
248 struct lldpd_port
*oport
;
251 log_debug("edp", "decode EDP frame on port %s",
254 if ((chassis
= calloc(1, sizeof(struct lldpd_chassis
))) == NULL
) {
255 log_warn("edp", "failed to allocate remote chassis");
258 TAILQ_INIT(&chassis
->c_mgmt
);
259 if ((port
= calloc(1, sizeof(struct lldpd_port
))) == NULL
) {
260 log_warn("edp", "failed to allocate remote port");
265 TAILQ_INIT(&port
->p_vlans
);
269 pos
= (u_int8_t
*)frame
;
271 if (length
< 2*ETHER_ADDR_LEN
+ sizeof(u_int16_t
) + 8 /* LLC */ +
272 10 + ETHER_ADDR_LEN
/* EDP header */) {
273 log_warnx("edp", "too short EDP frame received on %s", hardware
->h_ifname
);
277 if (PEEK_CMP(edpaddr
, sizeof(edpaddr
)) != 0) {
278 log_info("edp", "frame not targeted at EDP multicast address received on %s",
282 PEEK_DISCARD(ETHER_ADDR_LEN
); PEEK_DISCARD_UINT16
;
283 PEEK_DISCARD(6); /* LLC: DSAP + SSAP + control + org */
284 if (PEEK_UINT16
!= LLC_PID_EDP
) {
285 log_debug("edp", "incorrect LLC protocol ID received on %s",
290 (void)PEEK_SAVE(pos_edp
); /* Save the start of EDP packet */
291 if (PEEK_UINT8
!= 1) {
292 log_warnx("edp", "incorrect EDP version for frame received on %s",
296 PEEK_DISCARD_UINT8
; /* Reserved */
297 edp_len
= PEEK_UINT16
;
298 PEEK_DISCARD_UINT16
; /* Checksum */
299 PEEK_DISCARD_UINT16
; /* Sequence */
300 if (PEEK_UINT16
!= 0) { /* ID Type = 0 = MAC */
301 log_warnx("edp", "incorrect device id type for frame received on %s",
305 if (edp_len
> length
+ 10) {
306 log_warnx("edp", "incorrect size for EDP frame received on %s",
310 port
->p_ttl
= cfg
?cfg
->g_config
.c_tx_interval
* cfg
->g_config
.c_tx_hold
:0;
311 chassis
->c_id_subtype
= LLDP_CHASSISID_SUBTYPE_LLADDR
;
312 chassis
->c_id_len
= ETHER_ADDR_LEN
;
313 if ((chassis
->c_id
= (char *)malloc(ETHER_ADDR_LEN
)) == NULL
) {
314 log_warn("edp", "unable to allocate memory for chassis ID");
317 PEEK_BYTES(chassis
->c_id
, ETHER_ADDR_LEN
);
319 /* Let's check checksum */
320 if (frame_checksum(pos_edp
, edp_len
, 0) != 0) {
321 log_warnx("edp", "incorrect EDP checksum for frame received on %s",
326 while (length
&& !gotend
) {
328 log_warnx("edp", "EDP TLV header is too large for "
329 "frame received on %s",
333 if (PEEK_UINT8
!= EDP_TLV_MARKER
) {
334 log_warnx("edp", "incorrect marker starting EDP TLV header for frame "
339 tlv_type
= PEEK_UINT8
;
340 tlv_len
= PEEK_UINT16
- 4;
341 (void)PEEK_SAVE(tlv
);
342 if ((tlv_len
< 0) || (tlv_len
> length
)) {
343 log_debug("edp", "incorrect size in EDP TLV header for frame "
346 /* Some poor old Extreme Summit are quite bogus */
352 CHECK_TLV_SIZE(32, "Info");
353 port
->p_id_subtype
= LLDP_PORTID_SUBTYPE_IFNAME
;
354 edp_slot
= PEEK_UINT16
; edp_port
= PEEK_UINT16
;
355 if (asprintf(&port
->p_id
, "%d/%d",
356 edp_slot
+ 1, edp_port
+ 1) == -1) {
357 log_warn("edp", "unable to allocate memory for "
361 port
->p_id_len
= strlen(port
->p_id
);
362 if (asprintf(&port
->p_descr
, "Slot %d / Port %d",
363 edp_slot
+ 1, edp_port
+ 1) == -1) {
364 log_warn("edp", "unable to allocate memory for "
368 PEEK_DISCARD_UINT16
; /* vchassis */
369 PEEK_DISCARD(6); /* Reserved */
370 PEEK_BYTES(version
, 4);
371 if (asprintf(&chassis
->c_descr
,
372 "EDP enabled device, version %d.%d.%d.%d",
373 version
[0], version
[1],
374 version
[2], version
[3]) == -1) {
375 log_warn("edp", "unable to allocate memory for "
376 "chassis description");
380 case EDP_TLV_DISPLAY
:
381 if ((chassis
->c_name
= (char *)calloc(1, tlv_len
+ 1)) == NULL
) {
382 log_warn("edp", "unable to allocate memory for chassis "
386 /* TLV display contains a lot of garbage */
387 PEEK_BYTES(chassis
->c_name
, tlv_len
);
391 log_warnx("edp", "null tlv with incorrect size in frame "
397 log_debug("edp", "extra data after edp frame on %s",
403 CHECK_TLV_SIZE(12, "VLAN");
404 if ((lvlan
= (struct lldpd_vlan
*)calloc(1,
405 sizeof(struct lldpd_vlan
))) == NULL
) {
406 log_warn("edp", "unable to allocate vlan");
409 PEEK_DISCARD_UINT16
; /* Flags + reserved */
410 lvlan
->v_vid
= PEEK_UINT16
; /* VID */
411 PEEK_DISCARD(4); /* Reserved */
412 PEEK_BYTES(&address
, sizeof(address
));
414 if (address
.s_addr
!= INADDR_ANY
) {
415 mgmt
= lldpd_alloc_mgmt(LLDPD_AF_IPV4
, &address
,
416 sizeof(struct in_addr
), 0);
418 log_warn("edp", "Out of memory");
421 TAILQ_INSERT_TAIL(&chassis
->c_mgmt
, mgmt
, m_entries
);
424 if ((lvlan
->v_name
= (char *)calloc(1,
425 tlv_len
+ 1 - 12)) == NULL
) {
426 log_warn("edp", "unable to allocate vlan name");
429 PEEK_BYTES(lvlan
->v_name
, tlv_len
- 12);
431 TAILQ_INSERT_TAIL(&port
->p_vlans
,
438 log_debug("edp", "unknown EDP TLV type (%d) received on %s",
439 tlv_type
, hardware
->h_ifname
);
440 hardware
->h_rx_unrecognized_cnt
++;
442 PEEK_DISCARD(tlv
+ tlv_len
- pos
);
444 if ((chassis
->c_id
== NULL
) ||
445 (port
->p_id
== NULL
) ||
446 (chassis
->c_name
== NULL
) ||
447 (chassis
->c_descr
== NULL
) ||
448 (port
->p_descr
== NULL
) ||
451 if (gotvlans
&& gotend
) {
452 /* VLAN can be sent in a separate frames. We need to add
453 * those vlans to an existing port */
454 TAILQ_FOREACH(oport
, &hardware
->h_rports
, p_entries
) {
455 if (!((oport
->p_protocol
== LLDPD_MODE_EDP
) &&
456 (oport
->p_chassis
->c_id_subtype
==
457 chassis
->c_id_subtype
) &&
458 (oport
->p_chassis
->c_id_len
== chassis
->c_id_len
) &&
459 (memcmp(oport
->p_chassis
->c_id
, chassis
->c_id
,
460 chassis
->c_id_len
) == 0)))
462 /* We attach the VLANs to the found port */
463 lldpd_vlan_cleanup(oport
);
464 for (lvlan
= TAILQ_FIRST(&port
->p_vlans
);
466 lvlan
= lvlan_next
) {
467 lvlan_next
= TAILQ_NEXT(lvlan
, v_entries
);
468 TAILQ_REMOVE(&port
->p_vlans
, lvlan
, v_entries
);
469 TAILQ_INSERT_TAIL(&oport
->p_vlans
,
472 /* And the IP addresses */
473 for (mgmt
= TAILQ_FIRST(&chassis
->c_mgmt
);
476 mgmt_next
= TAILQ_NEXT(mgmt
, m_entries
);
477 TAILQ_REMOVE(&chassis
->c_mgmt
, mgmt
, m_entries
);
478 /* Don't add an address that already exists! */
479 TAILQ_FOREACH(m
, &chassis
->c_mgmt
, m_entries
)
480 if (m
->m_family
== mgmt
->m_family
&&
481 !memcmp(&m
->m_addr
, &mgmt
->m_addr
,
482 sizeof(m
->m_addr
))) break;
484 TAILQ_INSERT_TAIL(&oport
->p_chassis
->c_mgmt
,
488 /* We discard the remaining frame */
495 log_warnx("edp", "some mandatory tlv are missing for frame received on %s",
499 *newchassis
= chassis
;
507 lldpd_chassis_cleanup(chassis
, 1);
508 lldpd_port_cleanup(port
, 1);
513 #endif /* ENABLE_EDP */