+lldpd (0.4)
+
+ * Rewrite of packet builder and parser to be able to cope with
+ architecture that cannot do unaligned read. For decoder, we don't
+ cast structures any more since they can be unaligned. For encoder,
+ we use memcpy through the use of macro that build packets step by
+ step.
+
+ -- Vincent Bernat <bernat@luffy.cx>
+
lldpd (0.3.2)
* Fix LLDP-MED support
sbin_PROGRAMS = lldpd lldpctl
-COMMON = log.c ctl.c lldpd.h lldp.h cdp.h compat.h sonmp.h llc.h edp.h
-lldpd_SOURCES = lldpd.c lldp.c cdp.c sonmp.c edp.c iov.c features.c client.c priv.c privsep_fdpass.c $(COMMON)
+COMMON = log.c ctl.c lldpd.h lldp.h cdp.h compat.h sonmp.h edp.h
+lldpd_SOURCES = frame.h frame.c lldpd.c lldp.c cdp.c sonmp.c edp.c features.c client.c priv.c privsep_fdpass.c $(COMMON)
lldpctl_SOURCES = lldpctl.c $(COMMON)
lldpd_LDADD = @LIBOBJS@
/* We also supports FDP which is very similar to CDPv1 */
#include "lldpd.h"
+#include "frame.h"
#if defined (ENABLE_CDP) || defined (ENABLE_FDP)
+#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>
cdp_send(struct lldpd *global, struct lldpd_chassis *chassis,
struct lldpd_hardware *hardware, int version)
{
- struct cdp_header ch;
- struct ethllc llc;
u_int8_t mcastaddr[] = CDP_MULTICAST_ADDR;
u_int8_t llcorg[] = LLC_ORG_CISCO;
- struct iovec *iov = NULL;
- struct cdp_tlv_head device;
- struct cdp_tlv_head port;
- struct cdp_tlv_head soft;
- struct cdp_tlv_head platform;
- struct cdp_tlv_address_head ah;
- struct cdp_tlv_address_one ao;
- struct cdp_tlv_capabilities cap;
#ifdef ENABLE_FDP
char *capstr;
#endif
- unsigned int c = -1, i, len;
+ u_int16_t checksum;
+ int length;
+ u_int32_t cap;
+ u_int8_t *packet;
+ u_int8_t *pos, *pos_len_eh, *pos_llc, *pos_cdp, *pos_checksum, *tlv, *end;
-#define IOV_NEW \
- if ((iov = (struct iovec*)realloc(iov, (++c + 1) * \
- sizeof(struct iovec))) == NULL) \
- fatal(NULL);
-
- /* Handle FDP */
#ifdef ENABLE_FDP
if (version == 0) {
+ /* With FDP, change multicast address and LLC PID */
const u_int8_t fdpmcastaddr[] = FDP_MULTICAST_ADDR;
const u_int8_t fdpllcorg[] = LLC_ORG_FOUNDRY;
memcpy(mcastaddr, fdpmcastaddr, sizeof(mcastaddr));
}
#endif
- /* Ether + LLC */
- memset(&llc, 0, sizeof(llc));
- memcpy(&llc.ether.shost, &hardware->h_lladdr,
- sizeof(llc.ether.shost));
- memcpy(&llc.ether.dhost, &mcastaddr,
- sizeof(llc.ether.dhost));
- llc.dsap = llc.ssap = 0xaa;
- llc.control = 0x03;
- memcpy(llc.org, llcorg, sizeof(llc.org));
- llc.protoid = htons(LLC_PID_CDP);
- IOV_NEW;
- iov[c].iov_base = &llc;
- iov[c].iov_len = sizeof(llc);
+ length = hardware->h_mtu;
+ if ((packet = (u_int8_t*)malloc(length)) == NULL)
+ return ENOMEM;
+ memset(packet, 0, length);
+ pos = packet;
+
+ /* Ethernet header */
+ if (!(
+ POKE_BYTES(mcastaddr, sizeof(mcastaddr)) &&
+ POKE_BYTES(&hardware->h_lladdr, sizeof(hardware->h_lladdr)) &&
+ POKE_SAVE(pos_len_eh) && /* We compute the len later */
+ POKE_UINT16(0)))
+ goto toobig;
+
+ /* LLC */
+ if (!(
+ POKE_SAVE(pos_llc) &&
+ POKE_UINT8(0xaa) && /* SSAP */
+ POKE_UINT8(0xaa) && /* DSAP */
+ POKE_UINT8(0x03) && /* Control field */
+ POKE_BYTES(llcorg, sizeof(llcorg)) &&
+ POKE_UINT16(LLC_PID_CDP)))
+ goto toobig;
/* CDP header */
- memset(&ch, 0, sizeof(ch));
- if (version == 0)
- ch.version = 1;
- else
- ch.version = version;
- ch.ttl = chassis->c_ttl;
- IOV_NEW;
- iov[c].iov_base = &ch;
- iov[c].iov_len = sizeof(struct cdp_header);
+ if (!(
+ POKE_SAVE(pos_cdp) &&
+ POKE_UINT8(((version == 0) && 1) || version) &&
+ POKE_UINT8(chassis->c_ttl) &&
+ POKE_SAVE(pos_checksum) && /* Save checksum position */
+ POKE_UINT16(0)))
+ goto toobig;
/* Chassis ID */
- memset(&device, 0, sizeof(device));
- device.tlv_type = htons(CDP_TLV_CHASSIS);
- device.tlv_len = htons(sizeof(device) + strlen(chassis->c_name));
- IOV_NEW;
- iov[c].iov_base = &device;
- iov[c].iov_len = sizeof(device);
- IOV_NEW;
- iov[c].iov_base = chassis->c_name;
- iov[c].iov_len = strlen(chassis->c_name);
+ if (!(
+ POKE_START_CDP_TLV(CDP_TLV_CHASSIS) &&
+ POKE_BYTES(chassis->c_name, strlen(chassis->c_name)) &&
+ POKE_END_CDP_TLV))
+ goto toobig;
/* Adresses */
- memset(&ah, 0, sizeof(ah));
- ah.head.tlv_type = htons(CDP_TLV_ADDRESSES);
- ah.head.tlv_len = htons(sizeof(ah) + sizeof(ao));
- ah.nb = htonl(1);
- IOV_NEW;
- iov[c].iov_base = &ah;
- iov[c].iov_len = sizeof(ah);
- memset(&ao, 0, sizeof(ao));
- ao.ptype = 1;
- ao.plen = 1;
- ao.proto = CDP_ADDRESS_PROTO_IP;
- ao.alen = htons(sizeof(struct in_addr));
- memcpy(&ao.addr, &chassis->c_mgmt, sizeof(struct in_addr));
- IOV_NEW;
- iov[c].iov_base = &ao;
- iov[c].iov_len = sizeof(ao);
+ if (!(
+ POKE_START_CDP_TLV(CDP_TLV_ADDRESSES) &&
+ POKE_UINT32(1) && /* We ship only one address */
+ POKE_UINT8(1) && /* Type: NLPID */
+ POKE_UINT8(1) && /* Length: 1 */
+ POKE_UINT8(CDP_ADDRESS_PROTO_IP) && /* IP */
+ POKE_UINT16(sizeof(struct in_addr)) && /* Address length */
+ POKE_BYTES(&chassis->c_mgmt, sizeof(struct in_addr)) &&
+ POKE_END_CDP_TLV))
+ goto toobig;
/* Port ID */
- memset(&port, 0, sizeof(port));
- port.tlv_type = htons(CDP_TLV_PORT);
- port.tlv_len = htons(sizeof(port) + strlen(hardware->h_lport.p_descr));
- IOV_NEW;
- iov[c].iov_base = &port;
- iov[c].iov_len = sizeof(port);
- IOV_NEW;
- iov[c].iov_base = hardware->h_lport.p_descr;
- iov[c].iov_len = strlen(hardware->h_lport.p_descr);
+ if (!(
+ POKE_START_CDP_TLV(CDP_TLV_PORT) &&
+ POKE_BYTES(hardware->h_lport.p_descr,
+ strlen(hardware->h_lport.p_descr)) &&
+ POKE_END_CDP_TLV))
+ goto toobig;
/* Capabilities */
if (version != 0) {
- memset(&cap, 0, sizeof(cap));
- cap.head.tlv_type = htons(CDP_TLV_CAPABILITIES);
- cap.head.tlv_len = htons(sizeof(cap));
- cap.cap = 0;
+ cap = 0;
if (chassis->c_cap_enabled & LLDP_CAP_ROUTER)
- cap.cap |= CDP_CAP_ROUTER;
+ cap |= CDP_CAP_ROUTER;
if (chassis->c_cap_enabled & LLDP_CAP_BRIDGE)
- cap.cap |= CDP_CAP_BRIDGE;
- cap.cap = htonl(cap.cap);
- IOV_NEW;
- iov[c].iov_base = ∩
- iov[c].iov_len = sizeof(cap);
+ cap |= CDP_CAP_BRIDGE;
+ if (!(
+ POKE_START_CDP_TLV(CDP_TLV_CAPABILITIES) &&
+ POKE_UINT32(cap) &&
+ POKE_END_CDP_TLV))
+ goto toobig;
#ifdef ENABLE_FDP
} else {
/* With FDP, it seems that a string is used in place of an int */
- memset(&cap, 0, sizeof(cap));
if (chassis->c_cap_enabled & LLDP_CAP_ROUTER)
capstr = "Router";
else if (chassis->c_cap_enabled & LLDP_CAP_BRIDGE)
capstr = "Bridge";
else
capstr = "Host";
- cap.head.tlv_type = htons(CDP_TLV_CAPABILITIES);
- cap.head.tlv_len = htons(sizeof(struct cdp_tlv_head) +
- strlen(capstr));
- IOV_NEW;
- iov[c].iov_base = ∩
- iov[c].iov_len = sizeof(struct cdp_tlv_head);
- IOV_NEW;
- iov[c].iov_base = capstr;
- iov[c].iov_len = strlen(capstr);
+ if (!(
+ POKE_START_CDP_TLV(CDP_TLV_CAPABILITIES) &&
+ POKE_BYTES(capstr, strlen(capstr)) &&
+ POKE_END_CDP_TLV))
+ goto toobig;
#endif
}
/* Software version */
- memset(&soft, 0, sizeof(soft));
- soft.tlv_type = htons(CDP_TLV_SOFTWARE);
- soft.tlv_len = htons(sizeof(soft) + strlen(chassis->c_descr));
- IOV_NEW;
- iov[c].iov_base = &soft;
- iov[c].iov_len = sizeof(soft);
- IOV_NEW;
- iov[c].iov_base = chassis->c_descr;
- iov[c].iov_len = strlen(chassis->c_descr);
+ if (!(
+ POKE_START_CDP_TLV(CDP_TLV_SOFTWARE) &&
+ POKE_BYTES(chassis->c_descr, strlen(chassis->c_descr)) &&
+ POKE_END_CDP_TLV))
+ goto toobig;
/* Platform */
- memset(&platform, 0, sizeof(platform));
- platform.tlv_type = htons(CDP_TLV_PLATFORM);
- platform.tlv_len = htons(sizeof(platform) + strlen("Linux"));
- IOV_NEW;
- iov[c].iov_base = &platform;
- iov[c].iov_len = sizeof(platform);
- IOV_NEW;
- iov[c].iov_base = "Linux";
- iov[c].iov_len = strlen("Linux");
-
- c++;
+ if (!(
+ POKE_START_CDP_TLV(CDP_TLV_PLATFORM) &&
+ POKE_BYTES("Linux", strlen("Linux")) &&
+ POKE_END_CDP_TLV))
+ goto toobig;
+ POKE_SAVE(end);
/* Compute len and checksum */
- len = 0;
- for (i = 0; i < c; i++) {
- len += iov[i].iov_len;
- }
- len -= sizeof(struct ieee8023);
- llc.ether.size = htons(len);
- ch.checksum = iov_checksum(&iov[1], c - 1, (version != 0) ? 1 : 0);
+ POKE_RESTORE(pos_len_eh);
+ if (!(POKE_UINT16(end - pos_llc))) goto toobig;
+ checksum = frame_checksum(pos_cdp, end - pos_cdp, (version != 0) ? 1 : 0);
+ POKE_RESTORE(pos_checksum);
+ if (!(POKE_UINT16(ntohs(checksum)))) goto toobig;
- if (writev((hardware->h_raw_real > 0) ? hardware->h_raw_real :
- hardware->h_raw, iov, c) == -1) {
+ if (write((hardware->h_raw_real > 0) ? hardware->h_raw_real :
+ hardware->h_raw, packet, end - packet) == -1) {
LLOG_WARN("unable to send packet on real device for %s",
hardware->h_ifname);
- free(iov);
+ free(packet);
return ENETDOWN;
}
hardware->h_tx_cnt++;
- free(iov);
+ free(packet);
return 0;
+ toobig:
+ free(packet);
+ return -1;
}
+#define CHECK_TLV_SIZE(x, name) \
+ do { if (tlv_len < (x)) { \
+ LLOG_WARNX(name " CDP/FDP TLV too short received on %s",\
+ hardware->h_ifname); \
+ goto malformed; \
+ } } while (0)
/* cdp_decode also decodes FDP */
int
cdp_decode(struct lldpd *cfg, char *frame, int s,
{
struct lldpd_chassis *chassis;
struct lldpd_port *port;
- struct ethllc *llc;
- struct cdp_header *ch;
- struct cdp_tlv_head *tlv;
- struct cdp_tlv_address_head *ah;
- struct cdp_tlv_address_one *ao;
- struct iovec iov;
u_int16_t cksum;
- char *software = NULL, *platform = NULL;
- int software_len = 0, platform_len = 0;
+ u_int8_t *software = NULL, *platform = NULL;
+ int software_len = 0, platform_len = 0, proto, version, nb, caps;
const unsigned char cdpaddr[] = CDP_MULTICAST_ADDR;
#ifdef ENABLE_FDP
const unsigned char fdpaddr[] = CDP_MULTICAST_ADDR;
int fdp = 0;
#endif
- int i, f, len, rlen;
+ u_int8_t *pos, *tlv, *pos_address, *pos_next_address;
+ int length, len_eth, tlv_type, tlv_len, addresses_len, address_len;
if ((chassis = calloc(1, sizeof(struct lldpd_chassis))) == NULL) {
LLOG_WARN("failed to allocate remote chassis");
TAILQ_INIT(&port->p_vlans);
#endif
- if (s < sizeof(struct ethllc) + sizeof(struct cdp_header)) {
- LLOG_WARNX("too short frame received on %s", hardware->h_ifname);
+ length = s;
+ pos = (u_int8_t*)frame;
+
+ if (length < 2*ETH_ALEN + sizeof(u_int16_t) /* Ethernet */ +
+ 8 /* LLC */ + 4 /* CDP header */) {
+ LLOG_WARNX("too short CDP/FDP frame received on %s", hardware->h_ifname);
goto malformed;
}
- llc = (struct ethllc *)frame;
- if (memcmp(&llc->ether.dhost, cdpaddr, sizeof(cdpaddr)) != 0) {
+ if (PEEK_CMP(cdpaddr, sizeof(cdpaddr)) != 0) {
#ifdef ENABLE_FDP
- if (memcmp(&llc->ether.dhost, fdpaddr, sizeof(fdpaddr)) != 0)
+ PEEK_RESTORE((u_int8_t*)frame);
+ if (PEEK_CMP(fdpaddr, sizeof(fdpaddr)) != 0)
fdp = 1;
else {
#endif
}
#endif
}
- if (ntohs(llc->ether.size) > s - sizeof(struct ieee8023)) {
+ PEEK_DISCARD(ETH_ALEN); /* Don't care of source address */
+ len_eth = PEEK_UINT16;
+ if (len_eth > length) {
LLOG_WARNX("incorrect 802.3 frame size reported on %s",
hardware->h_ifname);
goto malformed;
}
- if (llc->protoid != htons(LLC_PID_CDP)) {
- if ((llc->protoid != htons(LLC_PID_DRIP)) &&
- (llc->protoid != htons(LLC_PID_PAGP)) &&
- (llc->protoid != htons(LLC_PID_PVSTP)) &&
- (llc->protoid != htons(LLC_PID_UDLD)) &&
- (llc->protoid != htons(LLC_PID_VTP)) &&
- (llc->protoid != htons(LLC_PID_DTP)) &&
- (llc->protoid != htons(LLC_PID_STP)))
+ PEEK_DISCARD(6); /* Skip beginning of LLC */
+ proto = PEEK_UINT16;
+ if (proto != LLC_PID_CDP) {
+ if ((proto != LLC_PID_DRIP) &&
+ (proto != LLC_PID_PAGP) &&
+ (proto != LLC_PID_PVSTP) &&
+ (proto != LLC_PID_UDLD) &&
+ (proto != LLC_PID_VTP) &&
+ (proto != LLC_PID_DTP) &&
+ (proto != LLC_PID_STP))
LLOG_DEBUG("incorrect LLC protocol ID received on %s",
hardware->h_ifname);
goto malformed;
}
- f = sizeof(struct ethllc);
- ch = (struct cdp_header *)(frame + f);
- if ((ch->version != 1) && (ch->version != 2)) {
- LLOG_WARNX("incorrect CDP/FDP version (%d) for frame received on %s",
- ch->version, hardware->h_ifname);
- goto malformed;
- }
- chassis->c_ttl = ntohs(ch->ttl);
- iov.iov_len = s - f;
- iov.iov_base = frame + f;
- cksum = iov_checksum(&iov, 1,
+
+ /* Check checksum */
+ cksum = frame_checksum(pos, len_eth - 8,
#ifdef ENABLE_FDP
!fdp /* fdp = 0 -> cisco checksum */
#else
goto malformed;
}
- f += sizeof(struct cdp_header);
- while (f < s) {
- if (f + sizeof(struct cdp_tlv_head) > s) {
+ /* Check version */
+ version = PEEK_UINT8;
+ if ((version != 1) && (version != 2)) {
+ LLOG_WARNX("incorrect CDP/FDP version (%d) for frame received on %s",
+ version, hardware->h_ifname);
+ goto malformed;
+ }
+ chassis->c_ttl = PEEK_UINT8; /* TTL */
+ PEEK_DISCARD_UINT16; /* Checksum, already checked */
+
+ while (length) {
+ if (length < 4) {
LLOG_WARNX("CDP/FDP TLV header is too large for "
"frame received on %s",
hardware->h_ifname);
goto malformed;
}
- tlv = (struct cdp_tlv_head *)(frame + f);
- len = ntohs(tlv->tlv_len) - sizeof(struct cdp_tlv_head);
- if ((len < 0) || (f + sizeof(struct cdp_tlv_head) + len > s)) {
+ tlv_type = PEEK_UINT16;
+ tlv_len = PEEK_UINT16 - 4;
+ PEEK_SAVE(tlv);
+ if ((tlv_len < 0) || (length < tlv_len)) {
LLOG_WARNX("incorrect size in CDP/FDP TLV header for frame "
"received on %s",
hardware->h_ifname);
goto malformed;
}
- switch (ntohs(tlv->tlv_type)) {
+ switch (tlv_type) {
case CDP_TLV_CHASSIS:
- f += sizeof(struct cdp_tlv_head);
- if ((chassis->c_name = (char *)calloc(1, len + 1)) == NULL) {
+ if ((chassis->c_name = (char *)calloc(1, tlv_len + 1)) == NULL) {
LLOG_WARN("unable to allocate memory for chassis name");
goto malformed;
}
- memcpy(chassis->c_name, frame + f, len);
+ PEEK_BYTES(chassis->c_name, tlv_len);
chassis->c_id_subtype = LLDP_CHASSISID_SUBTYPE_LOCAL;
- if ((chassis->c_id = (char *)malloc(len)) == NULL) {
+ if ((chassis->c_id = (char *)malloc(tlv_len)) == NULL) {
LLOG_WARN("unable to allocate memory for chassis ID");
goto malformed;
}
- memcpy(chassis->c_id, frame + f, len);
- chassis->c_id_len = len;
- f += len;
+ memcpy(chassis->c_id, chassis->c_name, tlv_len);
+ chassis->c_id_len = tlv_len;
break;
case CDP_TLV_ADDRESSES:
- if (len < 4) {
- LLOG_WARNX("incorrect size in CDP/FDP TLV header for frame "
- "received on %s",
- hardware->h_ifname);
- goto malformed;
- }
- ah = (struct cdp_tlv_address_head *)(frame + f);
- f += sizeof(struct cdp_tlv_address_head);
- len -= 4;
- for (i = 0; i < ntohl(ah->nb); i++) {
- if (len < sizeof(struct cdp_tlv_address_one) -
- sizeof(struct in_addr)) {
- LLOG_WARNX("incorrect size for address TLV in "
- "frame received from %s",
- hardware->h_ifname);
+ CHECK_TLV_SIZE(4, "Address");
+ addresses_len = tlv_len - 4;
+ for (nb = PEEK_UINT32; nb > 0; nb--) {
+ PEEK_SAVE(pos_address);
+ /* We first try to get the real length of the packet */
+ if (addresses_len < 2) {
+ LLOG_WARN("too short address subframe "
+ "received on %s",
+ hardware->h_ifname);
goto malformed;
}
- ao = (struct cdp_tlv_address_one *)(frame + f);
- rlen = 2 + ao->plen + 2 + ntohs(ao->alen);
- if (len < rlen) {
- LLOG_WARNX("incorrect address size in TLV "
- "received from %s",
- hardware->h_ifname);
+ PEEK_DISCARD_UINT8; addresses_len--;
+ address_len = PEEK_UINT8; addresses_len--;
+ if (addresses_len < address_len + 2) {
+ LLOG_WARN("too short address subframe "
+ "received on %s",
+ hardware->h_ifname);
goto malformed;
}
- if ((ao->ptype == 1) && (ao->plen == 1) &&
- (ao->proto == CDP_ADDRESS_PROTO_IP) &&
- (ntohs(ao->alen) == sizeof(struct in_addr)) &&
+ PEEK_DISCARD(address_len);
+ addresses_len -= address_len;
+ address_len = PEEK_UINT16; addresses_len -= 2;
+ if (addresses_len < address_len) {
+ LLOG_WARN("too short address subframe "
+ "received on %s",
+ hardware->h_ifname);
+ goto malformed;
+ }
+ PEEK_DISCARD(address_len);
+ PEEK_SAVE(pos_next_address);
+ /* Next, we go back and try to extract
+ IPv4 address */
+ PEEK_RESTORE(pos_address);
+ if ((PEEK_UINT8 == 1) && (PEEK_UINT8 == 1) &&
+ (PEEK_UINT8 == CDP_ADDRESS_PROTO_IP) &&
+ (PEEK_UINT16 == sizeof(struct in_addr)) &&
(chassis->c_mgmt.s_addr == INADDR_ANY))
- chassis->c_mgmt.s_addr = ao->addr.s_addr;
- f += rlen;
- len -= rlen;
- }
- if (len != 0) {
- LLOG_WARNX("not enough addresses found in TLV "
- "received from %s",
- hardware->h_ifname);
- goto malformed;
+ PEEK_BYTES(&chassis->c_mgmt,
+ sizeof(struct in_addr));
+ /* Go to the end of the address */
+ PEEK_RESTORE(pos_next_address);
}
break;
case CDP_TLV_PORT:
- f += sizeof(struct cdp_tlv_head);
- if ((port->p_descr = (char *)calloc(1, len + 1)) == NULL) {
+ if ((port->p_descr = (char *)calloc(1, tlv_len + 1)) == NULL) {
LLOG_WARN("unable to allocate memory for port description");
goto malformed;
}
- memcpy(port->p_descr, frame + f, len);
- port->p_id_subtype = LLDP_PORTID_SUBTYPE_LLADDR;
- if ((port->p_id = (char *)malloc(ETH_ALEN)) == NULL) {
+ PEEK_BYTES(port->p_descr, tlv_len);
+ port->p_id_subtype = LLDP_PORTID_SUBTYPE_IFNAME;
+ if ((port->p_id = (char *)calloc(1, tlv_len)) == NULL) {
LLOG_WARN("unable to allocate memory for port ID");
goto malformed;
}
- memcpy(port->p_id, llc->ether.shost, ETH_ALEN);
- port->p_id_len = ETH_ALEN;
- f += len;
+ memcpy(port->p_id, port->p_descr, tlv_len);
+ port->p_id_len = tlv_len;
break;
case CDP_TLV_CAPABILITIES:
- f += sizeof(struct cdp_tlv_head);
#ifdef ENABLE_FDP
if (fdp) {
/* Capabilities are string with FDP */
- if (!strncmp("Router", frame + f, len))
+ if (!strncmp("Router", (char*)pos, tlv_len))
chassis->c_cap_enabled = LLDP_CAP_ROUTER;
- else if (!strncmp("Switch", frame + f, len))
+ else if (!strncmp("Switch", (char*)pos, tlv_len))
chassis->c_cap_enabled = LLDP_CAP_BRIDGE;
- else if (!strncmp("Bridge", frame + f, len))
+ else if (!strncmp("Bridge", (char*)pos, tlv_len))
chassis->c_cap_enabled = LLDP_CAP_REPEATER;
else
chassis->c_cap_enabled = LLDP_CAP_STATION;
chassis->c_cap_available = chassis->c_cap_enabled;
- f += len;
break;
}
#endif
- if (len != 4) {
- LLOG_WARNX("incorrect size for capabilities TLV "
- "on frame received from %s",
- hardware->h_ifname);
- goto malformed;
- }
- if (ntohl(*(u_int32_t*)(frame + f)) & CDP_CAP_ROUTER)
+ CHECK_TLV_SIZE(4, "Capabilities");
+ caps = PEEK_UINT32;
+ if (caps & CDP_CAP_ROUTER)
chassis->c_cap_enabled |= LLDP_CAP_ROUTER;
- if (ntohl(*(u_int32_t*)(frame + f)) & 0x0e)
+ if (caps & 0x0e)
chassis->c_cap_enabled |= LLDP_CAP_BRIDGE;
if (chassis->c_cap_enabled == 0)
chassis->c_cap_enabled = LLDP_CAP_STATION;
chassis->c_cap_available = chassis->c_cap_enabled;
- f += 4;
break;
case CDP_TLV_SOFTWARE:
- f += sizeof(struct cdp_tlv_head);
- software_len = len;
- software = (char *)(frame + f);
- f += len;
+ software_len = tlv_len;
+ PEEK_SAVE(software);
break;
case CDP_TLV_PLATFORM:
- f += sizeof(struct cdp_tlv_head);
- platform_len = len;
- platform = (char *)(frame + f);
- f += len;
+ platform_len = tlv_len;
+ PEEK_SAVE(platform);
break;
default:
LLOG_DEBUG("unknown CDP/FDP TLV type (%d) received on %s",
- ntohs(tlv->tlv_type), hardware->h_ifname);
- f += sizeof(struct cdp_tlv_head) + len;
+ ntohs(tlv_type), hardware->h_ifname);
hardware->h_rx_unrecognized_cnt++;
}
+ PEEK_DISCARD(tlv + tlv_len - pos);
}
if (!software && platform) {
if ((chassis->c_descr = (char *)calloc(1,
#ifdef ENABLE_CDP
static int
-cdp_guess(char *frame, int len, int version)
+cdp_guess(char *pos, int length, int version)
{
const u_int8_t mcastaddr[] = CDP_MULTICAST_ADDR;
- struct cdp_header *ch;
- if (len < sizeof(struct ethllc) + sizeof(struct cdp_header))
+ if (length < 2*ETH_ALEN + sizeof(u_int16_t) /* Ethernet */ +
+ 8 /* LLC */ + 4 /* CDP header */)
return 0;
- if (memcmp(frame, mcastaddr, ETH_ALEN) != 0)
+ if (PEEK_CMP(mcastaddr, ETH_ALEN) != 0)
return 0;
- ch = (struct cdp_header *)(frame + sizeof(struct ethllc));
- return (ch->version == version);
+ PEEK_DISCARD(ETH_ALEN); PEEK_DISCARD_UINT16; /* Ethernet */
+ PEEK_DISCARD(8); /* LLC */
+ return (PEEK_UINT8 == version);
}
int
#define LLC_PID_DTP 0x2004
#define LLC_PID_STP 0x200a
-struct cdp_header {
- u_int8_t version;
- u_int8_t ttl;
- u_int16_t checksum;
-} __attribute__ ((__packed__));
-
-struct cdp_tlv_head {
- u_int16_t tlv_type;
- u_int16_t tlv_len;
-} __attribute__ ((__packed__));
-
enum {
CDP_TLV_CHASSIS = 1,
CDP_TLV_ADDRESSES = 2,
CDP_TLV_PLATFORM = 6
};
-struct cdp_tlv_address_head {
- struct cdp_tlv_head head;
- u_int32_t nb;
-} __attribute__ ((__packed__));
-
-struct cdp_tlv_address_one {
- u_int8_t ptype; /* Should be 1 */
- u_int8_t plen; /* Should be 1 */
#define CDP_ADDRESS_PROTO_IP 0xcc
- u_int8_t proto; /* 0xcc for IP */
- u_int16_t alen; /* Should be 4 */
- struct in_addr addr;
-} __attribute__ ((__packed__));
-
-struct cdp_tlv_capabilities {
- struct cdp_tlv_head head;
- u_int32_t cap;
-} __attribute__ ((__packed__));
#define CDP_CAP_ROUTER 1
#define CDP_CAP_BRIDGE 8
*/
#include "lldpd.h"
+#include "frame.h"
#ifdef ENABLE_EDP
#include <stdio.h>
+#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>
#include <fnmatch.h>
edp_send(struct lldpd *global, struct lldpd_chassis *chassis,
struct lldpd_hardware *hardware)
{
- struct edp_header eh;
- struct ethllc llc;
const u_int8_t mcastaddr[] = EDP_MULTICAST_ADDR;
const u_int8_t llcorg[] = LLC_ORG_EXTREME;
- struct iovec *iov = NULL;
+ int length, i, v;
+ u_int8_t *packet, *pos, *pos_llc, *pos_len_eh, *pos_len_edp, *pos_edp, *tlv, *end;
+ u_int16_t checksum;
#ifdef ENABLE_DOT1
- struct edp_tlv_vlan *ovlan = NULL;
struct lldpd_vlan *vlan;
unsigned int state = 0;
#endif
- struct edp_tlv_head device;
- struct edp_tlv_head null;
- struct edp_tlv_info info;
u_int8_t edp_fakeversion[] = {7, 6, 4, 99};
- unsigned int i, c, v, len;
/* Subsequent XXX can be replaced by other values. We place
them here to ensure the position of "" to be a bit
invariant with version changes. */
char *deviceslot[] = { "eth", "veth", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "", NULL };
-#define IOV_NEW \
- if ((iov = (struct iovec*)realloc(iov, (++c + 1) * \
- sizeof(struct iovec))) == NULL) \
- fatal(NULL);
-
#ifdef ENABLE_DOT1
while (state != 2) {
- free(iov); iov = NULL;
- free(ovlan); ovlan = NULL;
#endif
- c = v = -1;
+ length = hardware->h_mtu;
+ if ((packet = (u_int8_t*)malloc(length)) == NULL)
+ return ENOMEM;
+ memset(packet, 0, length);
+ pos = packet;
+ v = 0;
+
+ /* Ethernet header */
+ if (!(
+ POKE_BYTES(mcastaddr, sizeof(mcastaddr)) &&
+ POKE_BYTES(&hardware->h_lladdr, sizeof(hardware->h_lladdr)) &&
+ POKE_SAVE(pos_len_eh) && /* We compute the len later */
+ POKE_UINT16(0)))
+ goto toobig;
- /* Ether + LLC */
- memset(&llc, 0, sizeof(llc));
- memcpy(&llc.ether.shost, &hardware->h_lladdr,
- sizeof(llc.ether.shost));
- memcpy(&llc.ether.dhost, &mcastaddr,
- sizeof(llc.ether.dhost));
- llc.dsap = llc.ssap = 0xaa;
- llc.control = 0x03;
- memcpy(llc.org, llcorg, sizeof(llc.org));
- llc.protoid = htons(LLC_PID_EDP);
- IOV_NEW;
- iov[c].iov_base = &llc;
- iov[c].iov_len = sizeof(llc);
+ /* LLC */
+ if (!(
+ POKE_SAVE(pos_llc) && /* We need to save our
+ current position to
+ compute ethernet len */
+ /* SSAP and DSAP */
+ POKE_UINT8(0xaa) && POKE_UINT8(0xaa) &&
+ /* Control field */
+ POKE_UINT8(0x03) &&
+ /* ORG */
+ POKE_BYTES(llcorg, sizeof(llcorg)) &&
+ POKE_UINT16(LLC_PID_EDP)))
+ goto toobig;
/* EDP header */
- memset(&eh, 0, sizeof(eh));
- eh.version = 1;
- eh.sequence = htons(seq++);
if ((chassis->c_id_len != ETH_ALEN) ||
(chassis->c_id_subtype != LLDP_CHASSISID_SUBTYPE_LLADDR)) {
LLOG_WARNX("local chassis does not use MAC address as chassis ID!?");
+ free(packet);
return EINVAL;
}
- memcpy(&eh.mac, chassis->c_id, ETH_ALEN);
- IOV_NEW;
- iov[c].iov_base = &eh;
- iov[c].iov_len = sizeof(eh);
+ if (!(
+ POKE_SAVE(pos_edp) && /* Save the start of EDP frame */
+ POKE_UINT8(1) && POKE_UINT8(0) &&
+ POKE_SAVE(pos_len_edp) && /* We compute the len
+ and the checksum
+ later */
+ POKE_UINT32(0) && /* Len + Checksum */
+ POKE_UINT16(seq) &&
+ POKE_UINT16(0) &&
+ POKE_BYTES(&hardware->h_lladdr, sizeof(hardware->h_lladdr))))
+ goto toobig;
+ seq++;
#ifdef ENABLE_DOT1
switch (state) {
case 0:
#endif
/* Display TLV */
- memset(&device, 0, sizeof(device));
- device.tlv_marker = EDP_TLV_MARKER;
- device.tlv_type = EDP_TLV_DISPLAY;
- device.tlv_len = htons(sizeof(device) + strlen(chassis->c_name) + 1);
- IOV_NEW;
- iov[c].iov_base = &device;
- iov[c].iov_len = sizeof(device);
- IOV_NEW;
- iov[c].iov_base = chassis->c_name;
- iov[c].iov_len = strlen(chassis->c_name) + 1;
+ if (!(
+ POKE_START_EDP_TLV(EDP_TLV_DISPLAY) &&
+ POKE_BYTES(chassis->c_name, strlen(chassis->c_name)) &&
+ POKE_UINT8(0) && /* Add a NULL character
+ for better
+ compatibility */
+ POKE_END_EDP_TLV))
+ goto toobig;
/* Info TLV */
- memset(&info, 0, sizeof(info));
- info.head.tlv_marker = EDP_TLV_MARKER;
- info.head.tlv_type = EDP_TLV_INFO;
- info.head.tlv_len = htons(sizeof(info));
+ if (!(
+ POKE_START_EDP_TLV(EDP_TLV_INFO)))
+ goto toobig;
+ /* We try to emulate the slot thing */
for (i=0; deviceslot[i] != NULL; i++) {
if (strncmp(hardware->h_ifname, deviceslot[i],
strlen(deviceslot[i])) == 0) {
- info.slot = htons(i);
- info.port = htons(atoi(hardware->h_ifname +
- strlen(deviceslot[i])));
+ if (!(
+ POKE_UINT16(i) &&
+ POKE_UINT16(atoi(hardware->h_ifname +
+ strlen(deviceslot[i])))))
+ goto toobig;
break;
}
}
+ /* If we don't find a "slot", we say that the
+ interface is in slot 8 */
if (deviceslot[i] == NULL) {
- info.slot = htons(8);
- info.port = htons(if_nametoindex(hardware->h_ifname));
+ if (!(
+ POKE_UINT16(8) &&
+ POKE_UINT16(if_nametoindex(hardware->h_ifname))))
+ goto toobig;
}
- memcpy(info.version, edp_fakeversion, sizeof(info.version));
- info.connections[0] = info.connections[1] = 0xff;
- IOV_NEW;
- iov[c].iov_base = &info;
- iov[c].iov_len = sizeof(info);
+ if (!(
+ POKE_UINT16(0) && /* vchassis */
+ POKE_UINT32(0) && POKE_UINT16(0) && /* Reserved */
+ /* Version */
+ POKE_BYTES(edp_fakeversion, sizeof(edp_fakeversion)) &&
+ /* Connections, we say that we won't
+ have more interfaces than this
+ mask. */
+ POKE_UINT32(0xffffffff) &&
+ POKE_UINT32(0) && POKE_UINT32(0) && POKE_UINT32(0) &&
+ POKE_END_EDP_TLV))
+ goto toobig;
+
#ifdef ENABLE_DOT1
break;
case 1:
- v = 0;
- TAILQ_FOREACH(vlan, &hardware->h_lport.p_vlans,
- v_entries)
- v++;
- if (v == 0) {
- v = -1;
- break;
- }
- if ((ovlan = (struct edp_tlv_vlan*)malloc(
- v*sizeof(struct edp_tlv_vlan))) == NULL) {
- LLOG_WARN("no room for vlans");
- v = -1;
- }
TAILQ_FOREACH(vlan, &hardware->h_lport.p_vlans,
v_entries) {
- v--;
- memset(&ovlan[v], 0, sizeof(ovlan[v]));
- ovlan[v].head.tlv_marker = EDP_TLV_MARKER;
- ovlan[v].head.tlv_type = EDP_TLV_VLAN;
- ovlan[v].head.tlv_len = htons(sizeof(ovlan[v]) +
- strlen(vlan->v_name) + 1);
- ovlan[v].vid = htons(vlan->v_vid);
- IOV_NEW;
- iov[c].iov_base = &ovlan[v];
- iov[c].iov_len = sizeof(ovlan[v]);
- IOV_NEW;
- iov[c].iov_base = vlan->v_name;
- iov[c].iov_len = strlen(vlan->v_name) + 1;
+ v++;
+ if (!(
+ POKE_START_EDP_TLV(EDP_TLV_VLAN) &&
+ POKE_UINT8(0) && /* Flags: no IP address */
+ POKE_UINT8(0) && /* Reserved */
+ POKE_UINT16(vlan->v_vid) &&
+ POKE_UINT32(0) && /* Reserved */
+ POKE_UINT32(0) && /* IP address */
+ /* VLAN name */
+ POKE_BYTES(vlan->v_name, strlen(vlan->v_name)) &&
+ POKE_UINT8(0) &&
+ POKE_END_EDP_TLV))
+ goto toobig;
}
break;
}
#endif
/* Null TLV */
- memset(&null, 0, sizeof(null));
- null.tlv_marker = EDP_TLV_MARKER;
- null.tlv_type = EDP_TLV_NULL;
- null.tlv_len = htons(sizeof(null));
- IOV_NEW;
- iov[c].iov_base = &null;
- iov[c].iov_len = sizeof(null);
-
- c++;
+ if (!(
+ POKE_START_EDP_TLV(EDP_TLV_NULL) &&
+ POKE_END_EDP_TLV &&
+ POKE_SAVE(end)))
+ goto toobig;
/* Compute len and checksum */
- len = 0;
- for (i = 0; i < c; i++) {
- len += iov[i].iov_len;
- }
- len -= sizeof(struct ieee8023);
- llc.ether.size = htons(len);
- len = len + sizeof(struct ieee8023) - sizeof(struct ethllc);
- eh.len = htons(len);
- eh.checksum = iov_checksum(&iov[1], c - 1, 0);
+ i = end - pos_llc; /* Ethernet length */
+ v = end - pos_edp; /* EDP length */
+ POKE_RESTORE(pos_len_eh);
+ if (!(POKE_UINT16(i))) goto toobig;
+ POKE_RESTORE(pos_len_edp);
+ if (!(POKE_UINT16(v))) goto toobig;
+ checksum = frame_checksum(pos_edp, v, 0);
+ if (!(POKE_UINT16(ntohs(checksum)))) goto toobig;
- if (writev((hardware->h_raw_real > 0) ? hardware->h_raw_real :
- hardware->h_raw, iov, c) == -1) {
+ if (write((hardware->h_raw_real > 0) ? hardware->h_raw_real :
+ hardware->h_raw, packet, end - packet) == -1) {
LLOG_WARN("unable to send packet on real device for %s",
hardware->h_ifname);
-#ifdef ENABLE_DOT1
- free(ovlan);
-#endif
- free(iov);
+ free(packet);
return ENETDOWN;
}
+ free(packet);
#ifdef ENABLE_DOT1
state++;
#endif
hardware->h_tx_cnt++;
-#ifdef ENABLE_DOT1
- free(ovlan);
-#endif
- free(iov);
-
return 0;
+ toobig:
+ free(packet);
+ return E2BIG;
}
+#define CHECK_TLV_SIZE(x, name) \
+ do { if (tlv_len < (x)) { \
+ LLOG_WARNX(name " EDP TLV too short received on %s",\
+ hardware->h_ifname); \
+ goto malformed; \
+ } } while (0)
+
int
edp_decode(struct lldpd *cfg, char *frame, int s,
struct lldpd_hardware *hardware,
{
struct lldpd_chassis *chassis;
struct lldpd_port *port;
- struct ethllc *llc;
- struct edp_header *eh;
- struct edp_tlv_head *tlv;
- struct edp_tlv_info *info;
#ifdef ENABLE_DOT1
- struct edp_tlv_vlan *vlan;
- struct lldpd_vlan *lvlan, *lvlan_next;
+ struct lldpd_vlan *lvlan = NULL, *lvlan_next;
#endif
const unsigned char edpaddr[] = EDP_MULTICAST_ADDR;
- struct iovec iov;
- int f, len, gotend = 0, gotvlans = 0;
+ int length, gotend = 0, gotvlans = 0, edp_len, tlv_len, tlv_type;
+ int edp_port, edp_slot;
+ u_int8_t *pos, *pos_edp, *tlv;
+ u_int8_t version[4];
+ struct in_addr address;
if ((chassis = calloc(1, sizeof(struct lldpd_chassis))) == NULL) {
LLOG_WARN("failed to allocate remote chassis");
TAILQ_INIT(&port->p_vlans);
#endif
- if (s < sizeof(struct ethllc) + sizeof(struct edp_header)) {
- LLOG_WARNX("too short frame received on %s", hardware->h_ifname);
+ length = s;
+ pos = (u_int8_t*)frame;
+
+ if (length < 2*ETH_ALEN + sizeof(u_int16_t) + 8 /* LLC */ +
+ 10 + ETH_ALEN /* EDP header */) {
+ LLOG_WARNX("too short EDP frame received on %s", hardware->h_ifname);
goto malformed;
}
- llc = (struct ethllc *)frame;
- if (memcmp(&llc->ether.dhost, edpaddr, sizeof(edpaddr)) != 0) {
+ if (PEEK_CMP(edpaddr, sizeof(edpaddr)) != 0) {
LLOG_INFO("frame not targeted at EDP multicast address received on %s",
hardware->h_ifname);
goto malformed;
}
- if (ntohs(llc->ether.size) > s - sizeof(struct ieee8023)) {
- LLOG_WARNX("incorrect 802.3 frame size reported on %s",
- hardware->h_ifname);
- goto malformed;
- }
- if (llc->protoid != htons(LLC_PID_EDP)) {
+ PEEK_DISCARD(ETH_ALEN); PEEK_DISCARD_UINT16;
+ PEEK_DISCARD(6); /* LLC: DSAP + SSAP + control + org */
+ if (PEEK_UINT16 != LLC_PID_EDP) {
LLOG_DEBUG("incorrect LLC protocol ID received on %s",
hardware->h_ifname);
goto malformed;
}
- f = sizeof(struct ethllc);
- eh = (struct edp_header *)(frame + f);
- if (eh->version != 1) {
- LLOG_WARNX("incorrect EDP version (%d) for frame received on %s",
- eh->version, hardware->h_ifname);
+ PEEK_SAVE(pos_edp); /* Save the start of EDP packet */
+ if (PEEK_UINT8 != 1) {
+ LLOG_WARNX("incorrect EDP version for frame received on %s",
+ hardware->h_ifname);
goto malformed;
}
- if (eh->idtype != htons(0)) {
+ PEEK_DISCARD_UINT8; /* Reserved */
+ edp_len = PEEK_UINT16;
+ PEEK_DISCARD_UINT16; /* Checksum */
+ PEEK_DISCARD_UINT16; /* Sequence */
+ if (PEEK_UINT16 != 0) { /* ID Type = 0 = MAC */
LLOG_WARNX("incorrect device id type for frame received on %s",
hardware->h_ifname);
goto malformed;
}
- if (ntohs(eh->len) > s - f) {
+ if (edp_len > length + 10) {
LLOG_WARNX("incorrect size for EDP frame received on %s",
hardware->h_ifname);
goto malformed;
LLOG_WARN("unable to allocate memory for chassis ID");
goto malformed;
}
- memcpy(chassis->c_id, eh->mac, ETH_ALEN);
- /* We ignore reserved bytes and sequence number */
- iov.iov_len = ntohs(eh->len);
- iov.iov_base = frame + f;
- if (iov_checksum(&iov, 1, 0) != 0) {
+ PEEK_BYTES(chassis->c_id, ETH_ALEN);
+
+ /* Let's check checksum */
+ if (frame_checksum(pos_edp, edp_len, 0) != 0) {
LLOG_WARNX("incorrect EDP checksum for frame received on %s",
hardware->h_ifname);
goto malformed;
}
- f += sizeof(struct edp_header);
- while ((f < s) && !gotend) {
- if (f + sizeof(struct edp_tlv_head) > s) {
+ while (length && !gotend) {
+ if (length < 4) {
LLOG_WARNX("EDP TLV header is too large for "
"frame received on %s",
hardware->h_ifname);
goto malformed;
}
- tlv = (struct edp_tlv_head *)(frame + f);
- len = ntohs(tlv->tlv_len) - sizeof(struct edp_tlv_head);
- if ((len < 0) || (f + sizeof(struct edp_tlv_head) + len > s)) {
+ if (PEEK_UINT8 != EDP_TLV_MARKER) {
+ LLOG_WARNX("incorrect marker starting EDP TLV header for frame "
+ "received on %s",
+ hardware->h_ifname);
+ goto malformed;
+ }
+ tlv_type = PEEK_UINT8;
+ tlv_len = PEEK_UINT16 - 4;
+ PEEK_SAVE(tlv);
+ if ((tlv_len < 0) || (tlv_len > length)) {
LLOG_DEBUG("incorrect size in EDP TLV header for frame "
"received on %s",
hardware->h_ifname);
gotend = 1;
break;
}
- f += sizeof(struct edp_tlv_head);
- if (tlv->tlv_marker != EDP_TLV_MARKER) {
- LLOG_WARNX("incorrect marker starting EDP TLV header for frame "
- "received on %s",
- hardware->h_ifname);
- goto malformed;
- }
- switch (tlv->tlv_type) {
+ switch (tlv_type) {
case EDP_TLV_INFO:
- if (len != sizeof(struct edp_tlv_info) -
- sizeof(struct edp_tlv_head)) {
- LLOG_WARNX("wrong size for EDP TLV info for frame "
- "received on %s (%d vs %d)",
- hardware->h_ifname);
- goto malformed;
- }
- info = (struct edp_tlv_info *)(frame + f -
- sizeof(struct edp_tlv_head));
+ CHECK_TLV_SIZE(32, "Info");
port->p_id_subtype = LLDP_PORTID_SUBTYPE_IFNAME;
+ edp_slot = PEEK_UINT16; edp_port = PEEK_UINT16;
if (asprintf(&port->p_id, "%d/%d",
- ntohs(info->slot) + 1, ntohs(info->port) + 1) == -1) {
+ edp_slot + 1, edp_port + 1) == -1) {
LLOG_WARN("unable to allocate memory for "
"port ID");
goto malformed;
}
port->p_id_len = strlen(port->p_id);
if (asprintf(&port->p_descr, "Slot %d / Port %d",
- ntohs(info->slot) + 1, ntohs(info->port) + 1) == -1) {
+ edp_slot + 1, edp_port + 1) == -1) {
LLOG_WARN("unable to allocate memory for "
"port description");
goto malformed;
}
+ PEEK_DISCARD_UINT16; /* vchassis */
+ PEEK_DISCARD(6); /* Reserved */
+ PEEK_BYTES(version, 4);
if (asprintf(&chassis->c_descr,
"EDP enabled device, version %d.%d.%d.%d",
- info->version[0], info->version[1],
- info->version[2], info->version[3]) == -1) {
+ version[0], version[1],
+ version[2], version[3]) == -1) {
LLOG_WARN("unable to allocate memory for "
"chassis description");
goto malformed;
}
break;
case EDP_TLV_DISPLAY:
- if ((chassis->c_name = (char *)calloc(1, len + 1)) == NULL) {
+ if ((chassis->c_name = (char *)calloc(1, tlv_len + 1)) == NULL) {
LLOG_WARN("unable to allocate memory for chassis "
"name");
goto malformed;
}
/* TLV display contains a lot of garbage */
- strlcpy(chassis->c_name, frame + f, len);
+ PEEK_BYTES(chassis->c_name, tlv_len);
break;
case EDP_TLV_NULL:
- if (len != 0) {
+ if (tlv_len != 0) {
LLOG_WARNX("null tlv with incorrect size in frame "
"received on %s",
hardware->h_ifname);
goto malformed;
}
- if (f != s)
+ if (length)
LLOG_DEBUG("extra data after edp frame on %s",
hardware->h_ifname);
gotend = 1;
break;
case EDP_TLV_VLAN:
#ifdef ENABLE_DOT1
- if (len < sizeof(struct edp_tlv_vlan) -
- sizeof(struct edp_tlv_head)) {
- LLOG_WARNX("wrong size for EDP TLV vlan for frame "
- "received on %s (%d vs %d)",
- hardware->h_ifname);
- goto malformed;
- }
- vlan = (struct edp_tlv_vlan *)(frame + f -
- sizeof(struct edp_tlv_head));
+ CHECK_TLV_SIZE(12, "VLAN");
if ((lvlan = (struct lldpd_vlan *)calloc(1,
sizeof(struct lldpd_vlan))) == NULL) {
LLOG_WARN("unable to allocate vlan");
goto malformed;
}
- lvlan->v_vid = ntohs(vlan->vid);
- if ((lvlan->v_name = (char *)calloc(1, len + 1 -
- sizeof(struct edp_tlv_vlan) +
- sizeof(struct edp_tlv_head))) == NULL) {
+ PEEK_DISCARD_UINT16; /* Flags + reserved */
+ lvlan->v_vid = PEEK_UINT16; /* VID */
+ PEEK_DISCARD(4); /* Reserved */
+ PEEK_BYTES(&address, sizeof(address));
+
+ if ((lvlan->v_name = (char *)calloc(1,
+ tlv_len + 1 - 12)) == NULL) {
LLOG_WARN("unable to allocate vlan name");
+ free(lvlan);
goto malformed;
}
- strlcpy(lvlan->v_name, frame + f + sizeof(struct edp_tlv_vlan) -
- sizeof(struct edp_tlv_head), len -
- sizeof(struct edp_tlv_vlan) +
- sizeof(struct edp_tlv_head));
- if (vlan->ip.s_addr != INADDR_ANY) {
+ PEEK_BYTES(lvlan->v_name, tlv_len - 12);
+
+ if (address.s_addr != INADDR_ANY) {
if (chassis->c_mgmt.s_addr == INADDR_ANY)
- chassis->c_mgmt.s_addr = vlan->ip.s_addr;
+ chassis->c_mgmt.s_addr = address.s_addr;
else
/* We need to guess the good one */
if (cfg->g_mgmt_pattern != NULL) {
/* We can try to use this to prefer an address */
char *ip;
- ip = inet_ntoa(vlan->ip);
+ ip = inet_ntoa(address);
if (fnmatch(cfg->g_mgmt_pattern,
ip, 0) == 0)
- chassis->c_mgmt.s_addr = vlan->ip.s_addr;
+ chassis->c_mgmt.s_addr = address.s_addr;
}
}
TAILQ_INSERT_TAIL(&port->p_vlans,
break;
default:
LLOG_DEBUG("unknown EDP TLV type (%d) received on %s",
- tlv->tlv_type, hardware->h_ifname);
+ tlv_type, hardware->h_ifname);
hardware->h_rx_unrecognized_cnt++;
}
- f += len;
+ PEEK_DISCARD(tlv + tlv_len - pos);
}
if ((chassis->c_id == NULL) ||
(port->p_id == NULL) ||
#define EDP_TLV_MARKER 0x99
-#include "llc.h"
-
-struct edp_header {
- u_int8_t version;
- u_int8_t reserved;
- u_int16_t len;
- u_int16_t checksum;
- u_int16_t sequence;
- u_int16_t idtype; /* Should be 0 for MAC */
- u_int8_t mac[ETH_ALEN];
-} __attribute__ ((__packed__));
-
-struct edp_tlv_head {
- u_int8_t tlv_marker; /* 0x99 */
- u_int8_t tlv_type;
- u_int16_t tlv_len;
-} __attribute__ ((__packed__));
-
enum {
EDP_TLV_NULL = 0,
EDP_TLV_DISPLAY = 1,
EDP_TLV_ESRP = 8,
};
-struct edp_tlv_info {
- struct edp_tlv_head head;
- u_int16_t slot;
- u_int16_t port;
- u_int16_t vchassis;
- u_int8_t reserved[6];
- u_int8_t version[4];
- u_int8_t connections[16];
-} __attribute__ ((__packed__));
-
-#define EDP_VLAN_HAS_IP (1 << 8)
-struct edp_tlv_vlan {
- struct edp_tlv_head head;
- u_int8_t flags;
- u_int8_t reserved1[1];
- u_int16_t vid;
- u_int8_t reserved2[4];
- struct in_addr ip;
-} __attribute__ ((__packed__));
-
#endif /* _EDP_H */
--- /dev/null
+/*
+ * Copyright (c) 2009 Vincent Bernat <bernat@luffy.cx>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _FRAME_H
+#define _FRAME_H
+
+union {
+ uint8_t uint8;
+ uint16_t uint16;
+ uint32_t uint32;
+} types;
+
+/* This set of macro are used to build packets. The current position in buffer
+ * is `pos'. The length of the remaining space in buffer is `length'. `type'
+ * should be a member of `types'. This was stolen from ladvd which was adapted
+ * from Net::CDP. */
+
+#define POKE(value, type, func) \
+ ((length >= sizeof(type)) && \
+ ( \
+ type = func(value), \
+ memcpy(pos, &type, sizeof(type)), \
+ length -= sizeof(type), \
+ pos += sizeof(type), \
+ 1 \
+ ))
+#define POKE_UINT8(value) POKE(value, types.uint8, )
+#define POKE_UINT16(value) POKE(value, types.uint16, htons)
+#define POKE_UINT32(value) POKE(value, types.uint32, htonl)
+#define POKE_BYTES(value, bytes) \
+ ((length >= (bytes)) && \
+ ( \
+ memcpy(pos, value, bytes), \
+ length -= (bytes), \
+ pos += (bytes), \
+ 1 \
+ ))
+#define POKE_SAVE(where) \
+ (where = pos, 1)
+#define POKE_RESTORE(where) \
+ do { \
+ if ((where) > pos) \
+ length -= ((where) - pos); \
+ else \
+ length += (pos - (where)); \
+ pos = (where); \
+ } while(0)
+
+/* This set of macro are used to parse packets. The same variable as for POKE_*
+ * are used. There is no check on boundaries. */
+
+#define PEEK(type, func) \
+ ( \
+ memcpy(&type, pos, sizeof(type)), \
+ length -= sizeof(type), \
+ pos += sizeof(type), \
+ func(type) \
+ )
+#define PEEK_UINT8 PEEK(types.uint8, )
+#define PEEK_UINT16 PEEK(types.uint16, ntohs)
+#define PEEK_UINT32 PEEK(types.uint32, ntohl)
+#define PEEK_BYTES(value, bytes) \
+ do { \
+ memcpy(value, pos, bytes); \
+ length -= (bytes); \
+ pos += (bytes); \
+ } while (0)
+#define PEEK_DISCARD(bytes) \
+ do { \
+ length -= (bytes); \
+ pos += (bytes); \
+ } while (0)
+#define PEEK_DISCARD_UINT8 PEEK_DISCARD(1)
+#define PEEK_DISCARD_UINT16 PEEK_DISCARD(2)
+#define PEEK_DISCARD_UINT32 PEEK_DISCARD(3)
+#define PEEK_CMP(value, bytes) \
+ (length -= (bytes), \
+ pos += (bytes), \
+ memcmp(pos-bytes, value, bytes))
+#define PEEK_SAVE POKE_SAVE
+#define PEEK_RESTORE POKE_RESTORE
+
+/* LLDP specific. We need a `tlv' pointer. */
+#define POKE_START_LLDP_TLV(type) \
+ ( \
+ tlv = pos, \
+ POKE_UINT16(type << 9) \
+ )
+#define POKE_END_LLDP_TLV \
+ ( \
+ memcpy(&types.uint16, tlv, sizeof(uint16_t)), \
+ types.uint16 |= htons((pos - (tlv + 2)) & 0x01ff), \
+ memcpy(tlv, &types.uint16, sizeof(uint16_t)), \
+ 1 \
+ )
+
+/* Same for CDP */
+#define POKE_START_CDP_TLV(type) \
+ ( \
+ POKE_UINT16(type), \
+ tlv = pos, \
+ POKE_UINT16(0) \
+ )
+#define POKE_END_CDP_TLV \
+ ( \
+ types.uint16 = htons(pos - tlv + 2), \
+ memcpy(tlv, &types.uint16, sizeof(uint16_t)), \
+ 1 \
+ )
+
+/* Same for EDP */
+#define POKE_START_EDP_TLV(type) \
+ ( \
+ POKE_UINT8(EDP_TLV_MARKER), \
+ POKE_UINT8(type), \
+ tlv = pos, \
+ POKE_UINT16(0) \
+ )
+#define POKE_END_EDP_TLV POKE_END_CDP_TLV
+
+u_int16_t frame_checksum(const u_int8_t *, int, int);
+
+#endif /* _FRAME_H */
+++ /dev/null
-/*
- * Copyright (c) 2008 Vincent Bernat <bernat@luffy.cx>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include "lldpd.h"
-
-void
-iov_dump(struct lldpd_frame **buffer, struct iovec *iov, int count)
-{
- int i;
- int len = 0;
- void *p;
- for (i = 0; i < count; i++)
- len += iov[i].iov_len;
- if ((*buffer = (struct lldpd_frame *)malloc(len +
- sizeof(int))) == NULL) {
- LLOG_WARN("unable to allocate buffer");
- return;
- }
- memcpy(*buffer, &len, sizeof(int));
- p = (*buffer)->frame;
- for (i = 0; i < count; i++) {
- memcpy(p, iov[i].iov_base, iov[i].iov_len);
- p += iov[i].iov_len;
- }
-}
-
-u_int16_t
-iov_checksum(struct iovec *iov, int count, int cisco)
-{
- unsigned int sum = 0, v = 0;
- int len, oddbyte = 0, i;
- u_char *cp;
-
- /* We compute in network byte order */
- for (i = 0; i < count; i++) {
- len = iov[i].iov_len;
- cp = iov[i].iov_base;
- if (oddbyte) {
- sum += (v << 8) + *cp++;
- len--;
- }
- while ((len -= 2) >= 0) {
- sum += *cp++ << 8;
- sum += *cp++;
- }
- if ((oddbyte = len & 1) != 0)
- v = *cp;
- }
- /* The remaining byte seems to be handled oddly by Cisco. Any hint about
- * this is welcome. */
- if (oddbyte) {
- if (cisco)
- sum += v;
- else
- sum += v << 8;
- }
- sum = (sum >> 16) + (sum & 0xffff);
- sum += sum >> 16;
- sum = ntohs(sum);
- return (0xffff & ~sum);
-}
+++ /dev/null
-/*
- * Copyright (c) 2008 Vincent Bernat <bernat@luffy.cx>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _LLC_H
-#define _LLC_H
-
-struct ieee8023 {
- u_int8_t dhost[ETH_ALEN]; /* destination eth addr */
- u_int8_t shost[ETH_ALEN]; /* source ether addr */
- u_int16_t size; /* packet type ID field */
-} __attribute__ ((__packed__));
-
-struct ethllc {
- struct ieee8023 ether;
- u_int8_t dsap; /* destination SAP */
- u_int8_t ssap; /* source SAP */
- u_int8_t control; /* LLC control field */
- u_int8_t org[3];
- u_int16_t protoid;
-} __attribute__ ((__packed__));
-
-#endif
*/
#include "lldpd.h"
+#include "frame.h"
#include <unistd.h>
#include <errno.h>
int
lldp_send(struct lldpd *global, struct lldpd_chassis *chassis,
- struct lldpd_hardware *hardware)
+ struct lldpd_hardware *hardware)
{
- struct ether_header eh;
- const u_int8_t mcastaddr[] = LLDP_MULTICAST_ADDR;
- struct iovec *iov = NULL;
- struct lldp_id chid, pid;
- struct lldp_ttl ttl;
- struct lldp_end end;
- struct lldp_string name;
- struct lldp_string descr;
- struct lldp_string str;
- struct lldp_cap cap;
- struct lldp_mgmt mgmt;
+ struct lldpd_port *port;
+ struct lldpd_frame *frame;
+ int length;
+ u_int8_t *packet, *pos, *tlv;
+
+ u_int8_t mcastaddr[] = LLDP_MULTICAST_ADDR;
#ifdef ENABLE_DOT1
const u_int8_t dot1[] = LLDP_TLV_ORG_DOT1;
- struct lldp_vlan *ovlan = NULL;
- int v;
struct lldpd_vlan *vlan;
#endif
#ifdef ENABLE_DOT3
const u_int8_t dot3[] = LLDP_TLV_ORG_DOT3;
- struct lldp_aggreg aggreg;
- struct lldp_macphy macphy;
- struct lldp_mfs mfs;
#endif
#ifdef ENABLE_LLDPMED
int i;
const u_int8_t med[] = LLDP_TLV_ORG_MED;
- struct lldpmed_cap medcap;
- struct lldp_org medhw, medfw, medsw, medsn,
- medmodel, medasset, medmanuf, medloc[3];
#endif
- struct lldpd_port *port = &hardware->h_lport;
- u_int c = -1, len = 0;
- struct lldpd_frame *buffer;
-#define IOV_NEW \
- if ((iov = (struct iovec*)realloc(iov, (++c + 1) * \
- sizeof(struct iovec))) == NULL) \
- fatal(NULL);
+ port = &hardware->h_lport;
+ length = hardware->h_mtu;
+ if ((packet = (u_int8_t*)malloc(length)) == NULL)
+ return ENOMEM;
+ memset(packet, 0, length);
+ pos = packet;
/* Ethernet header */
- memset(&eh, 0, sizeof(eh));
- memcpy(&eh.ether_shost, &hardware->h_lladdr,
- sizeof(eh.ether_shost));
- memcpy(&eh.ether_dhost, &mcastaddr,
- sizeof(eh.ether_dhost));
- eh.ether_type = htons(ETHERTYPE_LLDP);
- IOV_NEW;
- iov[c].iov_base = &eh;
- iov[c].iov_len = sizeof(struct ether_header);
+ if (!(
+ /* LLDP multicast address */
+ POKE_BYTES(mcastaddr, sizeof(mcastaddr)) &&
+ /* Source MAC address */
+ POKE_BYTES(&hardware->h_lladdr, sizeof(hardware->h_lladdr)) &&
+ /* LLDP frame */
+ POKE_UINT16(ETHERTYPE_LLDP)))
+ goto toobig;
/* Chassis ID */
- memset(&chid, 0, sizeof(chid));
- len = chassis->c_id_len + sizeof(chid);
- chid.tlv_head.type_len = LLDP_TLV_HEAD(LLDP_TLV_CHASSIS_ID,
- len - sizeof(struct lldp_tlv_head));
- chid.tlv_id_subtype = chassis->c_id_subtype;
- IOV_NEW;
- iov[c].iov_base = &chid;
- iov[c].iov_len = sizeof(chid);
- IOV_NEW;
- iov[c].iov_base = chassis->c_id;
- iov[c].iov_len = chassis->c_id_len;
+ if (!(
+ POKE_START_LLDP_TLV(LLDP_TLV_CHASSIS_ID) &&
+ POKE_UINT8(chassis->c_id_subtype) &&
+ POKE_BYTES(chassis->c_id, chassis->c_id_len) &&
+ POKE_END_LLDP_TLV))
+ goto toobig;
/* Port ID */
- memset(&pid, 0, sizeof(pid));
- len = port->p_id_len + sizeof(pid);
- pid.tlv_head.type_len = LLDP_TLV_HEAD(LLDP_TLV_PORT_ID,
- len - sizeof(struct lldp_tlv_head));
- pid.tlv_id_subtype = port->p_id_subtype;
- IOV_NEW;
- iov[c].iov_base = &pid;
- iov[c].iov_len = sizeof(pid);
- IOV_NEW;
- iov[c].iov_base = port->p_id;
- iov[c].iov_len = port->p_id_len;
+ if (!(
+ POKE_START_LLDP_TLV(LLDP_TLV_PORT_ID) &&
+ POKE_UINT8(port->p_id_subtype) &&
+ POKE_BYTES(port->p_id, port->p_id_len) &&
+ POKE_END_LLDP_TLV))
+ goto toobig;
/* Time to live */
- memset(&ttl, 0, sizeof(ttl));
- len = sizeof(ttl);
- ttl.tlv_head.type_len = LLDP_TLV_HEAD(LLDP_TLV_TTL,
- len - sizeof(struct lldp_tlv_head));
- ttl.tlv_ttl = htons(chassis->c_ttl);
- IOV_NEW;
- iov[c].iov_base = &ttl;
- iov[c].iov_len = sizeof(ttl);
+ if (!(
+ POKE_START_LLDP_TLV(LLDP_TLV_TTL) &&
+ POKE_UINT16(chassis->c_ttl) &&
+ POKE_END_LLDP_TLV))
+ goto toobig;
/* System name */
- memset(&name, 0, sizeof(name));
- len = sizeof(name) + strlen(chassis->c_name);
- name.tlv_head.type_len = LLDP_TLV_HEAD(LLDP_TLV_SYSTEM_NAME,
- len - sizeof(struct lldp_tlv_head));
- IOV_NEW;
- iov[c].iov_base = &name;
- iov[c].iov_len = sizeof(name);
- IOV_NEW;
- iov[c].iov_base = chassis->c_name;
- iov[c].iov_len = strlen(chassis->c_name);
+ if (!(
+ POKE_START_LLDP_TLV(LLDP_TLV_SYSTEM_NAME) &&
+ POKE_BYTES(chassis->c_name, strlen(chassis->c_name)) &&
+ POKE_END_LLDP_TLV))
+ goto toobig;
/* System description */
- memset(&descr, 0, sizeof(descr));
- len = sizeof(descr) + strlen(chassis->c_descr);
- descr.tlv_head.type_len = LLDP_TLV_HEAD(LLDP_TLV_SYSTEM_DESCR,
- len - sizeof(struct lldp_tlv_head));
- IOV_NEW;
- iov[c].iov_base = &descr;
- iov[c].iov_len = sizeof(descr);
- IOV_NEW;
- iov[c].iov_base = chassis->c_descr;
- iov[c].iov_len = strlen(chassis->c_descr);
+ if (!(
+ POKE_START_LLDP_TLV(LLDP_TLV_SYSTEM_DESCR) &&
+ POKE_BYTES(chassis->c_descr, strlen(chassis->c_descr)) &&
+ POKE_END_LLDP_TLV))
+ goto toobig;
/* System capabilities */
- memset(&cap, 0, sizeof(cap));
- len = sizeof(cap);
- cap.tlv_head.type_len = LLDP_TLV_HEAD(LLDP_TLV_SYSTEM_CAP,
- len - sizeof(struct lldp_tlv_head));
- cap.tlv_cap_available = htons(chassis->c_cap_available);
- cap.tlv_cap_enabled = htons(chassis->c_cap_enabled);
- IOV_NEW;
- iov[c].iov_base = ∩
- iov[c].iov_len = len;
+ if (!(
+ POKE_START_LLDP_TLV(LLDP_TLV_SYSTEM_CAP) &&
+ POKE_UINT16(chassis->c_cap_available) &&
+ POKE_UINT16(chassis->c_cap_enabled) &&
+ POKE_END_LLDP_TLV))
+ goto toobig;
if (chassis->c_mgmt.s_addr != INADDR_ANY) {
/* Management address */
- memset(&mgmt, 0, sizeof(mgmt));
- len = sizeof(mgmt);
- mgmt.tlv_head.type_len = LLDP_TLV_HEAD(LLDP_TLV_MGMT_ADDR,
- len - sizeof(struct lldp_tlv_head));
- mgmt.mgmt_len = sizeof(struct in_addr) + sizeof(u_int8_t);
- mgmt.mgmt_subtype = LLDP_MGMT_ADDR_IP4;
- memcpy(&mgmt.mgmt_addr, &chassis->c_mgmt,
- sizeof(struct in_addr));
+ if (!(
+ POKE_START_LLDP_TLV(LLDP_TLV_MGMT_ADDR) &&
+ /* Size of the address, including its type */
+ POKE_UINT8(sizeof(struct in_addr) + 1) &&
+ /* Address is IPv4 */
+ POKE_UINT8(LLDP_MGMT_ADDR_IP4) &&
+ POKE_BYTES(&chassis->c_mgmt, sizeof(struct in_addr))))
+ goto toobig;
/* Interface port type, OID */
- if (chassis->c_mgmt_if == 0)
- mgmt.mgmt_iface_subtype =
- LLDP_MGMT_IFACE_UNKNOWN;
- else {
- mgmt.mgmt_iface_subtype =
- LLDP_MGMT_IFACE_IFINDEX;
- mgmt.mgmt_iface_id =
- htonl(chassis->c_mgmt_if);
+ if (chassis->c_mgmt_if == 0) {
+ if (!(
+ /* We don't know the management interface */
+ POKE_UINT8(LLDP_MGMT_IFACE_UNKNOWN) &&
+ POKE_UINT32(0)))
+ goto toobig;
+ } else {
+ if (!(
+ /* We have the index of the management interface */
+ POKE_UINT8(LLDP_MGMT_IFACE_IFINDEX) &&
+ POKE_UINT32(chassis->c_mgmt_if)))
+ goto toobig;
}
- IOV_NEW;
- iov[c].iov_base = &mgmt;
- iov[c].iov_len = len;
+ if (!(
+ /* We don't provide an OID for management */
+ POKE_UINT8(0) &&
+ POKE_END_LLDP_TLV))
+ goto toobig;
}
/* Port description */
- memset(&str, 0, sizeof(str));
- len = sizeof(str) + strlen(port->p_descr);
- str.tlv_head.type_len = LLDP_TLV_HEAD(LLDP_TLV_PORT_DESCR,
- len - sizeof(struct lldp_tlv_head));
- IOV_NEW;
- iov[c].iov_base = &str;
- iov[c].iov_len = sizeof(str);
- IOV_NEW;
- iov[c].iov_base = port->p_descr;
- iov[c].iov_len = strlen(port->p_descr);
+ if (!(
+ POKE_START_LLDP_TLV(LLDP_TLV_PORT_DESCR) &&
+ POKE_BYTES(port->p_descr, strlen(port->p_descr)) &&
+ POKE_END_LLDP_TLV))
+ goto toobig;
#ifdef ENABLE_DOT1
/* VLANs */
- v = 0;
- TAILQ_FOREACH(vlan, &port->p_vlans, v_entries)
- v++;
- if ((v > 0) &&
- ((ovlan = (struct lldp_vlan*)malloc(v*sizeof(struct lldp_vlan))) == NULL))
- LLOG_WARN("no room for vlans");
- else {
- TAILQ_FOREACH(vlan, &port->p_vlans, v_entries) {
- v--;
- memset(&ovlan[v], 0, sizeof(ovlan[v]));
- ovlan[v].tlv_head.type_len = LLDP_TLV_HEAD(LLDP_TLV_ORG,
- sizeof(ovlan[v].tlv_org_id) +
- sizeof(ovlan[v].tlv_org_subtype) + sizeof(ovlan[v].vid) +
- sizeof(ovlan[v].len) + strlen(vlan->v_name));
- memcpy(ovlan[v].tlv_org_id, dot1, sizeof(ovlan[v].tlv_org_id));
- ovlan[v].tlv_org_subtype = LLDP_TLV_DOT1_VLANNAME;
- ovlan[v].vid = htons(vlan->v_vid);
- ovlan[v].len = strlen(vlan->v_name);
- IOV_NEW;
- iov[c].iov_base = &ovlan[v];
- iov[c].iov_len = sizeof(ovlan[v]);
- IOV_NEW;
- iov[c].iov_base = vlan->v_name;
- iov[c].iov_len = strlen(vlan->v_name);
- }
+ TAILQ_FOREACH(vlan, &port->p_vlans, v_entries) {
+ if (!(
+ POKE_START_LLDP_TLV(LLDP_TLV_ORG) &&
+ POKE_BYTES(dot1, sizeof(dot1)) &&
+ POKE_UINT8(LLDP_TLV_DOT1_VLANNAME) &&
+ POKE_UINT16(vlan->v_vid) &&
+ POKE_UINT8(strlen(vlan->v_name)) &&
+ POKE_BYTES(vlan->v_name, strlen(vlan->v_name)) &&
+ POKE_END_LLDP_TLV))
+ goto toobig;
}
#endif
#ifdef ENABLE_DOT3
/* Aggregation status */
- memset(&aggreg, 0, sizeof(aggreg));
- aggreg.tlv_head.type_len = LLDP_TLV_HEAD(LLDP_TLV_ORG,
- sizeof(aggreg.tlv_org_id) +
- sizeof(aggreg.tlv_org_subtype) +
- sizeof(aggreg.status) + sizeof(aggreg.id));
- memcpy(aggreg.tlv_org_id, dot3, sizeof(aggreg.tlv_org_id));
- aggreg.tlv_org_subtype = LLDP_TLV_DOT3_LA;
- aggreg.status = (port->p_aggregid) ? 3:1; /* Bit 0 = capability ; Bit 1 = status */
- aggreg.id = htonl(port->p_aggregid);
- IOV_NEW;
- iov[c].iov_base = &aggreg;
- iov[c].iov_len = sizeof(aggreg);
+ if (!(
+ POKE_START_LLDP_TLV(LLDP_TLV_ORG) &&
+ POKE_BYTES(dot3, sizeof(dot3)) &&
+ POKE_UINT8(LLDP_TLV_DOT3_LA) &&
+ /* Bit 0 = capability ; Bit 1 = status */
+ POKE_UINT8((port->p_aggregid) ? 3:1) &&
+ POKE_UINT32(port->p_aggregid) &&
+ POKE_END_LLDP_TLV))
+ goto toobig;
/* MAC/PHY */
- memset(&macphy, 0, sizeof(macphy));
- macphy.tlv_head.type_len = LLDP_TLV_HEAD(LLDP_TLV_ORG,
- sizeof(macphy.tlv_org_id) +
- sizeof(macphy.tlv_org_subtype) +
- sizeof(macphy.autoneg) + sizeof(macphy.advertised) +
- sizeof(macphy.mau));
- memcpy(macphy.tlv_org_id, dot3, sizeof(macphy.tlv_org_id));
- macphy.tlv_org_subtype = LLDP_TLV_DOT3_MAC;
- macphy.autoneg = port->p_autoneg_support |
- (port->p_autoneg_enabled << 1);
- macphy.advertised = htons(port->p_autoneg_advertised);
- macphy.mau = htons(port->p_mau_type);
- IOV_NEW;
- iov[c].iov_base = &macphy;
- iov[c].iov_len = sizeof(macphy);
+ if (!(
+ POKE_START_LLDP_TLV(LLDP_TLV_ORG) &&
+ POKE_BYTES(dot3, sizeof(dot3)) &&
+ POKE_UINT8(LLDP_TLV_DOT3_MAC) &&
+ POKE_UINT8(port->p_autoneg_support |
+ (port->p_autoneg_enabled << 1)) &&
+ POKE_UINT16(port->p_autoneg_advertised) &&
+ POKE_UINT16(port->p_mau_type) &&
+ POKE_END_LLDP_TLV))
+ goto toobig;
/* MFS */
- memset(&mfs, 0, sizeof(mfs));
- mfs.tlv_head.type_len = LLDP_TLV_HEAD(LLDP_TLV_ORG,
- sizeof(mfs.tlv_org_id) +
- sizeof(mfs.tlv_org_subtype) +
- sizeof(mfs.mfs));
- memcpy(mfs.tlv_org_id, dot3, sizeof(mfs.tlv_org_id));
- mfs.tlv_org_subtype = LLDP_TLV_DOT3_MFS;
- mfs.mfs = htons(port->p_mfs);
- IOV_NEW;
- iov[c].iov_base = &mfs;
- iov[c].iov_len = sizeof(mfs);
+ if (!(
+ POKE_START_LLDP_TLV(LLDP_TLV_ORG) &&
+ POKE_BYTES(dot3, sizeof(dot3)) &&
+ POKE_UINT8(LLDP_TLV_DOT3_MFS) &&
+ POKE_UINT16(port->p_mfs) &&
+ POKE_END_LLDP_TLV))
+ goto toobig;
#endif
#ifdef ENABLE_LLDPMED
if (port->p_med_cap_enabled) {
/* LLDP-MED cap */
- memset(&medcap, 0, sizeof(medcap));
- medcap.tlv_head.type_len = LLDP_TLV_HEAD(LLDP_TLV_ORG,
- sizeof(medcap.tlv_org_id) +
- sizeof(medcap.tlv_org_subtype) +
- sizeof(medcap.tlv_cap) + sizeof(medcap.tlv_type));
- memcpy(medcap.tlv_org_id, med, sizeof(medcap.tlv_org_id));
- medcap.tlv_org_subtype = LLDP_TLV_MED_CAP;
- medcap.tlv_cap = htons(global->g_lchassis.c_med_cap_available);
- medcap.tlv_type = global->g_lchassis.c_med_type;
- IOV_NEW;
- iov[c].iov_base = &medcap;
- iov[c].iov_len = sizeof(medcap);
+ if (!(
+ POKE_START_LLDP_TLV(LLDP_TLV_ORG) &&
+ POKE_BYTES(med, sizeof(med)) &&
+ POKE_UINT8(LLDP_TLV_MED_CAP) &&
+ POKE_UINT16(chassis->c_med_cap_available) &&
+ POKE_UINT16(chassis->c_med_type) &&
+ POKE_END_LLDP_TLV))
+ goto toobig;
/* LLDP-MED inventory */
-#define LLDP_INVENTORY(value, target, subtype) \
+#define LLDP_INVENTORY(value, subtype) \
if (value) { \
- memset(&target, 0, sizeof(target)); \
- len = (strlen(value)>32)?32:strlen(value); \
- target.tlv_head.type_len = \
- LLDP_TLV_HEAD(LLDP_TLV_ORG, \
- sizeof(target.tlv_org_id) + \
- sizeof(target.tlv_org_subtype) + \
- len); \
- memcpy(target.tlv_org_id, med, \
- sizeof(target.tlv_org_id)); \
- target.tlv_org_subtype = subtype; \
- IOV_NEW; \
- iov[c].iov_base = ⌖ \
- iov[c].iov_len = sizeof(target); \
- IOV_NEW; \
- iov[c].iov_base = value; \
- iov[c].iov_len = len; \
+ if (!( \
+ POKE_START_LLDP_TLV(LLDP_TLV_ORG) && \
+ POKE_BYTES(med, sizeof(med)) && \
+ POKE_UINT8(subtype) && \
+ POKE_BYTES(value, \
+ (strlen(value)>32)?32:strlen(value)) && \
+ POKE_END_LLDP_TLV)) \
+ goto toobig; \
}
if (port->p_med_cap_enabled & LLDPMED_CAP_IV) {
- LLDP_INVENTORY(global->g_lchassis.c_med_hw,
- medhw, LLDP_TLV_MED_IV_HW);
- LLDP_INVENTORY(global->g_lchassis.c_med_fw,
- medfw, LLDP_TLV_MED_IV_FW);
- LLDP_INVENTORY(global->g_lchassis.c_med_sw,
- medsw, LLDP_TLV_MED_IV_SW);
- LLDP_INVENTORY(global->g_lchassis.c_med_sn,
- medsn, LLDP_TLV_MED_IV_SN);
- LLDP_INVENTORY(global->g_lchassis.c_med_manuf,
- medmanuf, LLDP_TLV_MED_IV_MANUF);
- LLDP_INVENTORY(global->g_lchassis.c_med_model,
- medmodel, LLDP_TLV_MED_IV_MODEL);
- LLDP_INVENTORY(global->g_lchassis.c_med_asset,
- medasset, LLDP_TLV_MED_IV_ASSET);
+ LLDP_INVENTORY(chassis->c_med_hw,
+ LLDP_TLV_MED_IV_HW);
+ LLDP_INVENTORY(chassis->c_med_fw,
+ LLDP_TLV_MED_IV_FW);
+ LLDP_INVENTORY(chassis->c_med_sw,
+ LLDP_TLV_MED_IV_SW);
+ LLDP_INVENTORY(chassis->c_med_sn,
+ LLDP_TLV_MED_IV_SN);
+ LLDP_INVENTORY(chassis->c_med_manuf,
+ LLDP_TLV_MED_IV_MANUF);
+ LLDP_INVENTORY(chassis->c_med_model,
+ LLDP_TLV_MED_IV_MODEL);
+ LLDP_INVENTORY(chassis->c_med_asset,
+ LLDP_TLV_MED_IV_ASSET);
}
/* LLDP-MED location */
for (i = 0; i < LLDPMED_LOCFORMAT_LAST; i++) {
if (port->p_med_location[i].format == i + 1) {
- memset(&medloc[i], 0, sizeof(struct lldp_org));
- medloc[i].tlv_head.type_len =
- LLDP_TLV_HEAD(LLDP_TLV_ORG,
- sizeof(medloc[i].tlv_org_id) +
- sizeof(medloc[i].tlv_org_subtype) + 1 +
- port->p_med_location[i].data_len);
- memcpy(medloc[i].tlv_org_id, med,
- sizeof(medloc[i].tlv_org_id));
- medloc[i].tlv_org_subtype = LLDP_TLV_MED_LOCATION;
- IOV_NEW;
- iov[c].iov_base = &medloc[i];
- iov[c].iov_len = sizeof(medloc[i]);
- IOV_NEW;
- iov[c].iov_base =
- &port->p_med_location[i].format;
- iov[c].iov_len = 1;
- IOV_NEW;
- iov[c].iov_base =
- port->p_med_location[i].data;
- iov[c].iov_len =
- port->p_med_location[i].data_len;
+ if (!(
+ POKE_START_LLDP_TLV(LLDP_TLV_ORG) &&
+ POKE_BYTES(med, sizeof(med)) &&
+ POKE_UINT8(LLDP_TLV_MED_LOCATION) &&
+ POKE_UINT8(port->p_med_location[i].format) &&
+ POKE_BYTES(port->p_med_location[i].data,
+ port->p_med_location[i].data_len) &&
+ POKE_END_LLDP_TLV))
+ goto toobig;
}
}
}
#endif
/* END */
- memset(&end, 0, sizeof(end));
- IOV_NEW;
- iov[c].iov_base = &end;
- iov[c].iov_len = sizeof(end);
+ if (!(
+ POKE_START_LLDP_TLV(LLDP_TLV_END) &&
+ POKE_END_LLDP_TLV))
+ goto toobig;
- c++;
if (!global->g_multi ||
(hardware->h_mode == LLDPD_MODE_ANY) ||
(hardware->h_mode == LLDPD_MODE_LLDP)) {
- if (writev((hardware->h_raw_real > 0) ? hardware->h_raw_real :
- hardware->h_raw, iov, c) == -1) {
+ if (write((hardware->h_raw_real > 0) ? hardware->h_raw_real :
+ hardware->h_raw, packet,
+ pos - packet) == -1) {
LLOG_WARN("unable to send packet on real device for %s",
hardware->h_ifname);
- free(iov);
-#ifdef ENABLE_DOT1
- free(ovlan);
-#endif
+ free(packet);
return ENETDOWN;
}
hardware->h_tx_cnt++;
}
- iov_dump(&buffer, iov, c);
- free(iov);
-#ifdef ENABLE_DOT1
- free(ovlan);
-#endif
- if (buffer != NULL) {
-
- /* We assume that LLDP frame is the reference */
+ /* We assume that LLDP frame is the reference */
+ if ((frame = (struct lldpd_frame*)malloc(
+ sizeof(int) + pos - packet)) != NULL) {
+ frame->size = pos - packet;
+ memcpy(&frame->frame, packet, frame->size);
if ((hardware->h_llastframe == NULL) ||
- (hardware->h_llastframe->size != buffer->size) ||
- (memcmp(hardware->h_llastframe->frame, buffer->frame,
- buffer->size) != 0)) {
+ (hardware->h_llastframe->size != frame->size) ||
+ (memcmp(hardware->h_llastframe->frame, frame->frame,
+ frame->size) != 0)) {
free(hardware->h_llastframe);
- hardware->h_llastframe = buffer;
- hardware->h_llastchange = time(NULL);
+ hardware->h_llastframe = frame;
+ hardware->h_llastchange = time(NULL);
} else
- free(buffer);
+ free(frame);
}
+ free(packet);
return 0;
+
+toobig:
+ free(packet);
+ return E2BIG;
}
+#define CHECK_TLV_SIZE(x, name) \
+ do { if (tlv_size < (x)) { \
+ LLOG_WARNX(name " TLV too short received on %s",\
+ hardware->h_ifname); \
+ goto malformed; \
+ } } while (0)
+
int
lldp_decode(struct lldpd *cfg, char *frame, int s,
struct lldpd_hardware *hardware,
{
struct lldpd_chassis *chassis;
struct lldpd_port *port;
- struct ether_header *ether;
const char lldpaddr[] = LLDP_MULTICAST_ADDR;
const char dot1[] = LLDP_TLV_ORG_DOT1;
const char dot3[] = LLDP_TLV_ORG_DOT3;
const char med[] = LLDP_TLV_ORG_MED;
- int f; /* Current position in frame */
- int size, type, subtype; /* TLV header */
+ char orgid[3];
+ int length, gotend = 0;
+ int tlv_size, tlv_type, tlv_subtype;
+ u_int8_t *pos, *tlv;
char *b;
- int gotend = 0;
+#ifdef ENABLE_DOT1
struct lldpd_vlan *vlan;
int vlan_len;
+#endif
if ((chassis = calloc(1, sizeof(struct lldpd_chassis))) == NULL) {
LLOG_WARN("failed to allocate remote chassis");
TAILQ_INIT(&port->p_vlans);
#endif
- if (s < sizeof(struct ether_header)) {
+ length = s;
+ pos = (u_int8_t*)frame;
+
+ if (length < 2*ETH_ALEN + sizeof(u_int16_t)) {
LLOG_WARNX("too short frame received on %s", hardware->h_ifname);
goto malformed;
}
- ether = (struct ether_header *)frame;
- if (memcmp(ether->ether_dhost, lldpaddr, sizeof(lldpaddr)) != 0) {
+ if (PEEK_CMP(lldpaddr, ETH_ALEN) != 0) {
LLOG_INFO("frame not targeted at LLDP multicast address received on %s",
hardware->h_ifname);
goto malformed;
}
- if (ETHERTYPE_LLDP != ntohs(ether->ether_type)) {
+ PEEK_DISCARD(ETH_ALEN); /* Skip source address */
+ if (PEEK_UINT16 != ETHERTYPE_LLDP) {
LLOG_INFO("non LLDP frame received on %s",
hardware->h_ifname);
goto malformed;
}
- f = sizeof(struct ether_header);
- while ((f < s) && (!gotend)) {
- if (f + 2 > s) {
+ while (length && (!gotend)) {
+ if (length < 2) {
LLOG_WARNX("tlv header too short received on %s",
hardware->h_ifname);
goto malformed;
}
- size = ntohs(*(u_int16_t*)(frame + f)) & 0x1ff;
- type = ntohs(*(u_int16_t*)(frame + f)) >> 9;
- f += 2;
- if (f + size > s) {
- LLOG_WARNX("tlv header too short received on %s",
+ tlv_size = PEEK_UINT16;
+ tlv_type = tlv_size >> 9;
+ tlv_size = tlv_size & 0x1ff;
+ PEEK_SAVE(tlv);
+ if (length < tlv_size) {
+ LLOG_WARNX("frame too short for tlv received on %s",
hardware->h_ifname);
goto malformed;
}
- switch (type) {
+ switch (tlv_type) {
case LLDP_TLV_END:
- if (size != 0) {
+ if (tlv_size != 0) {
LLOG_WARNX("lldp end received with size not null on %s",
hardware->h_ifname);
goto malformed;
}
- if (f != s)
+ if (length)
LLOG_DEBUG("extra data after lldp end on %s",
hardware->h_ifname);
gotend = 1;
break;
case LLDP_TLV_CHASSIS_ID:
case LLDP_TLV_PORT_ID:
- if (size < 2) {
- LLOG_WARNX("tlv id too small received on %s",
- hardware->h_ifname);
- goto malformed;
- }
- subtype = *(u_int8_t*)(frame + f);
- f++;
- if ((subtype == 0) || (subtype > 7)) {
+ CHECK_TLV_SIZE(2, "Port Id");
+ tlv_subtype = PEEK_UINT8;
+ if ((tlv_subtype == 0) || (tlv_subtype > 7)) {
LLOG_WARNX("unknown subtype for tlv id received on %s",
hardware->h_ifname);
goto malformed;
}
- if ((b = (char *)calloc(1, size - 1)) == NULL) {
+ if ((b = (char *)calloc(1, tlv_size - 1)) == NULL) {
LLOG_WARN("unable to allocate memory for id tlv "
"received on %s",
hardware->h_ifname);
goto malformed;
}
- memcpy(b, frame + f, size - 1);
- if (type == LLDP_TLV_PORT_ID) {
- port->p_id_subtype = subtype;
+ PEEK_BYTES(b, tlv_size - 1);
+ if (tlv_type == LLDP_TLV_PORT_ID) {
+ port->p_id_subtype = tlv_subtype;
port->p_id = b;
- port->p_id_len = size - 1;
+ port->p_id_len = tlv_size - 1;
} else {
- chassis->c_id_subtype = subtype;
+ chassis->c_id_subtype = tlv_subtype;
chassis->c_id = b;
- chassis->c_id_len = size - 1;
+ chassis->c_id_len = tlv_size - 1;
}
- f += size - 1;
break;
case LLDP_TLV_TTL:
- if (size < 2) {
- LLOG_WARNX("too short frame for ttl tlv received on %s",
- hardware->h_ifname);
- goto malformed;
- }
- chassis->c_ttl = ntohs(*(u_int16_t*)(frame + f));
- f += size;
+ CHECK_TLV_SIZE(2, "TTL");
+ chassis->c_ttl = PEEK_UINT16;
break;
case LLDP_TLV_PORT_DESCR:
case LLDP_TLV_SYSTEM_NAME:
case LLDP_TLV_SYSTEM_DESCR:
- if (size < 1) {
+ if (tlv_size < 1) {
LLOG_DEBUG("empty tlv received on %s",
hardware->h_ifname);
break;
}
- if ((b = (char *)calloc(1, size + 1)) == NULL) {
+ if ((b = (char *)calloc(1, tlv_size + 1)) == NULL) {
LLOG_WARN("unable to allocate memory for string tlv "
"received on %s",
hardware->h_ifname);
goto malformed;
}
- memcpy(b, frame + f, size);
- f += size;
- if (type == LLDP_TLV_PORT_DESCR)
+ PEEK_BYTES(b, tlv_size);
+ if (tlv_type == LLDP_TLV_PORT_DESCR)
port->p_descr = b;
- else if (type == LLDP_TLV_SYSTEM_NAME)
+ else if (tlv_type == LLDP_TLV_SYSTEM_NAME)
chassis->c_name = b;
else chassis->c_descr = b;
break;
case LLDP_TLV_SYSTEM_CAP:
- if (size < 4) {
- LLOG_WARNX("too short system cap tlv "
- "received on %s",
- hardware->h_ifname);
- goto malformed;
- }
- chassis->c_cap_available = ntohs(*(u_int16_t*)(frame + f));
- f += 2;
- chassis->c_cap_enabled = ntohs(*(u_int16_t*)(frame + f));
- f += size - 2;
+ CHECK_TLV_SIZE(4, "System capabilities");
+ chassis->c_cap_available = PEEK_UINT16;
+ chassis->c_cap_enabled = PEEK_UINT16;
break;
case LLDP_TLV_MGMT_ADDR:
- if (size < 11) {
- LLOG_WARNX("too short management tlv received on %s",
- hardware->h_ifname);
- goto malformed;
- }
+ CHECK_TLV_SIZE(11, "Management address");
if ((chassis->c_mgmt.s_addr == INADDR_ANY) &&
- (*(u_int8_t*)(frame + f) == 5) &&
- (*(u_int8_t*)(frame + f + 1) == 1)) {
+ (PEEK_UINT8 == 1+sizeof(struct in_addr)) &&
+ (PEEK_UINT8 == LLDP_MGMT_ADDR_IP4)) {
/* We have an IPv4 address, we ignore anything else */
- memcpy(&chassis->c_mgmt, frame + f + 2, sizeof(struct in_addr));
+ PEEK_BYTES(&chassis->c_mgmt, sizeof(struct in_addr));
chassis->c_mgmt_if = 0;
/* We only handle ifIndex subtype */
- if (*(u_int8_t*)(frame + f + 6) == LLDP_MGMT_IFACE_IFINDEX)
- chassis->c_mgmt_if = ntohl(*(u_int32_t*)(frame + f + 7));
+ if (PEEK_UINT8 == LLDP_MGMT_IFACE_IFINDEX)
+ chassis->c_mgmt_if = PEEK_UINT32;
}
- f += size;
break;
case LLDP_TLV_ORG:
- if (size < 4) {
- LLOG_WARNX("too short org tlv received on %s",
- hardware->h_ifname);
- goto malformed;
- }
- if (memcmp(dot1, frame + f, 3) == 0) {
+ CHECK_TLV_SIZE(4, "Organisational");
+ PEEK_BYTES(orgid, sizeof(orgid));
+ tlv_subtype = PEEK_UINT8;
+ if (memcmp(dot1, orgid, sizeof(orgid)) == 0) {
#ifndef ENABLE_DOT1
- f += size;
hardware->h_rx_unrecognized_cnt++;
#else
/* Dot1 */
- switch (*(u_int8_t*)(frame + f + 3)) {
+ switch (tlv_subtype) {
case LLDP_TLV_DOT1_VLANNAME:
- if ((size < 7) ||
- (size < 7 + *(u_int8_t*)(frame + f + 6))) {
- LLOG_WARNX("too short vlan tlv "
- "received on %s",
- hardware->h_ifname);
- goto malformed;
- }
- f += 4;
+ CHECK_TLV_SIZE(7, "VLAN");
if ((vlan = (struct lldpd_vlan *)calloc(1,
sizeof(struct lldpd_vlan))) == NULL) {
LLOG_WARN("unable to alloc vlan "
hardware->h_ifname);
goto malformed;
}
- vlan->v_vid = ntohs(*(u_int16_t*)(frame + f));
- f += 2;
- vlan_len = *(u_int8_t*)(frame + f);
- f += 1;
+ vlan->v_vid = PEEK_UINT16;
+ vlan_len = PEEK_UINT8;
+ CHECK_TLV_SIZE(7 + vlan_len, "VLAN");
if ((vlan->v_name =
(char *)calloc(1, vlan_len + 1)) == NULL) {
LLOG_WARN("unable to alloc vlan name for "
hardware->h_ifname);
goto malformed;
}
- memcpy(vlan->v_name, frame + f,
- vlan_len);
+ PEEK_BYTES(vlan->v_name, vlan_len);
TAILQ_INSERT_TAIL(&port->p_vlans,
vlan, v_entries);
- f += size - 7;
break;
case LLDP_TLV_DOT1_PVID:
- if (size < 6) {
- LLOG_WARNX("too short pvid tlv "
- "received on %s",
- hardware->h_ifname);
- goto malformed;
- }
- port->p_pvid =
- ntohs(*(u_int16_t*)(frame + f + 4));
- f += size;
+ CHECK_TLV_SIZE(6, "PVID");
+ port->p_pvid = PEEK_UINT16;
break;
default:
/* Unknown Dot1 TLV, ignore it */
- f += size;
hardware->h_rx_unrecognized_cnt++;
}
#endif
- } else if (memcmp(dot3, frame + f, 3) == 0) {
+ } else if (memcmp(dot3, orgid, sizeof(orgid)) == 0) {
#ifndef ENABLE_DOT3
- f += size;
hardware->h_rx_unrecognized_cnt++;
#else
/* Dot3 */
- subtype = *(u_int8_t*)(frame + f + 3);
- switch (subtype) {
+ switch (tlv_subtype) {
case LLDP_TLV_DOT3_MAC:
- f += 4;
- if (size < 9) {
- LLOG_WARNX("too short mac/phy tlv "
- "received on %s",
- hardware->h_ifname);
- goto malformed;
- }
- port->p_autoneg_support =
- *(u_int8_t*)(frame + f) && 0x1;
+ CHECK_TLV_SIZE(9, "MAC/PHY");
+ port->p_autoneg_support = PEEK_UINT8;
port->p_autoneg_enabled =
- *(u_int8_t*)(frame + f) && 0x2;
- f += 1;
+ port->p_autoneg_support && 0x2;
+ port->p_autoneg_support =
+ port->p_autoneg_support && 0x1;
port->p_autoneg_advertised =
- ntohs(*(u_int16_t*)(frame + f));
- f += 2;
- port->p_mau_type =
- ntohs(*(u_int16_t*)(frame + f));
- f += size - 7;
+ PEEK_UINT16;
+ port->p_mau_type = PEEK_UINT16;
break;
case LLDP_TLV_DOT3_LA:
- if (size < 9) {
- LLOG_WARNX("too short aggreg tlv "
- "received on %s",
- hardware->h_ifname);
- goto malformed;
- }
- port->p_aggregid =
- ntohl(*(u_int32_t*)(frame + f + 5));
- f += size;
+ CHECK_TLV_SIZE(9, "Link aggregation");
+ port->p_aggregid = PEEK_UINT32;
break;
case LLDP_TLV_DOT3_MFS:
- if (size < 6) {
- LLOG_WARNX("too short mfs tlv "
- "received on %s",
- hardware->h_ifname);
- goto malformed;
- }
- port->p_mfs =
- ntohs(*(u_int16_t*)(frame + f + 4));
- f += size;
+ CHECK_TLV_SIZE(6, "MFS");
+ port->p_mfs = PEEK_UINT16;
break;
default:
/* Unknown Dot3 TLV, ignore it */
- f += size;
hardware->h_rx_unrecognized_cnt++;
}
#endif
- } else if (memcmp(med, frame + f, 3) == 0) {
+ } else if (memcmp(med, orgid, sizeof(orgid)) == 0) {
/* LLDP-MED */
#ifndef ENABLE_LLDPMED
- f += size;
hardware->h_rx_unrecognized_cnt++;
#else
u_int32_t policy;
int loctype;
+ int power;
- subtype = *(u_int8_t*)(frame + f + 3);
- switch (subtype) {
+ switch (tlv_subtype) {
case LLDP_TLV_MED_CAP:
- f += 4;
- if (size < 7) {
- LLOG_WARNX("too short LLDP-MED cap "
- "tlv received on %s",
- hardware->h_ifname);
- goto malformed;
- }
- chassis->c_med_cap_available =
- ntohs(*(u_int16_t*)(frame + f));
- f += 2;
- chassis->c_med_type =
- *(u_int8_t*)(frame + f);
- f += size - 6;
+ CHECK_TLV_SIZE(7, "LLDP-MED capabilities");
+ chassis->c_med_cap_available = PEEK_UINT16;
+ chassis->c_med_type = PEEK_UINT8;
port->p_med_cap_enabled |=
LLDPMED_CAP_CAP;
break;
case LLDP_TLV_MED_POLICY:
- f += 4;
- if (size < 8) {
- LLOG_WARNX("too short LLDP-MED policy "
- "tlv received on %s",
- hardware->h_ifname);
- goto malformed;
- }
- policy = ntohl(*((u_int32_t *)(frame + f)));
+ CHECK_TLV_SIZE(8, "LLDP-MED policy");
+ policy = PEEK_UINT32;
if (((policy >> 24) < 1) ||
((policy >> 24) > LLDPMED_APPTYPE_LAST)) {
LLOG_INFO("unknown policy field %d "
"received on %s",
hardware->h_ifname);
- f += 4;
break;
}
port->p_med_policy[(policy >> 24) - 1].type =
(policy & 0x1C0) >> 6;
port->p_med_policy[(policy >> 24) - 1].dscp =
policy & 0x3F;
- f += size - 4;
port->p_med_cap_enabled |=
LLDPMED_CAP_POLICY;
break;
case LLDP_TLV_MED_LOCATION:
- f += 4;
- if (size <= 5) {
- LLOG_WARNX("too short LLDP-MED location "
- "tlv received on %s",
- hardware->h_ifname);
- goto malformed;
- }
- loctype = *(u_int8_t*)(frame + f);
- f += 1;
- if ((loctype < 1) || (loctype > LLDPMED_LOCFORMAT_LAST)) {
+ CHECK_TLV_SIZE(5, "LLDP-MED Location");
+ loctype = PEEK_UINT8;
+ if ((loctype < 1) ||
+ (loctype > LLDPMED_LOCFORMAT_LAST)) {
LLOG_INFO("unknown location type "
"received on %s",
hardware->h_ifname);
- f += size - 5;
break;
}
if ((port->p_med_location[loctype - 1].data =
- (char*)malloc(size - 5)) == NULL) {
+ (char*)malloc(tlv_size - 5)) == NULL) {
LLOG_WARN("unable to allocate memory "
"for LLDP-MED location for "
"frame received on %s",
hardware->h_ifname);
goto malformed;
}
- memcpy(port->p_med_location[loctype - 1].data,
- (char*)(frame + f),
- size - 5);
+ PEEK_BYTES(port->p_med_location[loctype - 1].data,
+ tlv_size - 5);
port->p_med_location[loctype - 1].data_len =
- size - 5;
+ tlv_size - 5;
port->p_med_location[loctype - 1].format = loctype;
- f += size - 5;
port->p_med_cap_enabled |=
LLDPMED_CAP_LOCATION;
break;
case LLDP_TLV_MED_MDI:
- f += 4;
- if (size < 7) {
- LLOG_WARNX("too short LLDP-MED PoE-MDI "
- "tlv received on %s",
- hardware->h_ifname);
- goto malformed;
- }
- switch (*(u_int8_t*)(frame + f) & 0xC0) {
+ CHECK_TLV_SIZE(7, "LLDP-MED PoE-MDI");
+ power = PEEK_UINT8;
+ switch (power & 0xC0) {
case 0x0:
port->p_med_pow_devicetype = LLDPMED_POW_TYPE_PSE;
port->p_med_cap_enabled |=
LLDPMED_CAP_MDI_PSE;
- switch (*(u_int8_t*)(frame + f) & 0x30) {
+ switch (power & 0x30) {
case 0x0:
port->p_med_pow_source =
LLDPMED_POW_SOURCE_UNKNOWN;
port->p_med_pow_devicetype = LLDPMED_POW_TYPE_PD;
port->p_med_cap_enabled |=
LLDPMED_CAP_MDI_PD;
- switch (*(u_int8_t*)(frame + f) & 0x30) {
+ switch (power & 0x30) {
case 0x0:
port->p_med_pow_source =
LLDPMED_POW_SOURCE_UNKNOWN;
port->p_med_pow_devicetype =
LLDPMED_POW_TYPE_RESERVED;
}
- switch (*(u_int8_t*)(frame + f) & 0x0F) {
+ switch (power & 0x0F) {
case 0x0:
port->p_med_pow_priority =
LLDPMED_POW_PRIO_UNKNOWN;
port->p_med_pow_priority =
LLDPMED_POW_PRIO_UNKNOWN;
}
- f += 1;
- port->p_med_pow_val =
- ntohs(*(u_int16_t*)(frame + f));
- f += size - 5;
+ port->p_med_pow_val = PEEK_UINT16;
break;
case LLDP_TLV_MED_IV_HW:
case LLDP_TLV_MED_IV_SW:
case LLDP_TLV_MED_IV_MANUF:
case LLDP_TLV_MED_IV_MODEL:
case LLDP_TLV_MED_IV_ASSET:
- f += 4;
- if (size <= 4)
+ if (tlv_size <= 4)
b = NULL;
else {
- if ((b = (char*)malloc(size - 3)) ==
+ if ((b = (char*)malloc(tlv_size - 3)) ==
NULL) {
LLOG_WARN("unable to allocate "
"memory for LLDP-MED "
hardware->h_ifname);
goto malformed;
}
- strlcpy(b,
- (char*)(frame + f),
- size - 3);
+ PEEK_BYTES(b, tlv_size - 4);
+ b[tlv_size - 4] = '\0';
}
- switch (subtype) {
+ switch (tlv_subtype) {
case LLDP_TLV_MED_IV_HW:
chassis->c_med_hw = b;
break;
free(b);
break;
}
- f += size - 4;
port->p_med_cap_enabled |=
LLDPMED_CAP_IV;
break;
default:
/* Unknown LLDP MED, ignore it */
- f += size;
hardware->h_rx_unrecognized_cnt++;
}
#endif /* ENABLE_LLDPMED */
LLOG_INFO("unknown org tlv received on %s",
hardware->h_ifname);
hardware->h_rx_unrecognized_cnt++;
- f += size;
}
break;
default:
LLOG_WARNX("unknown tlv (%d) received on %s",
- type, hardware->h_ifname);
+ tlv_type, hardware->h_ifname);
+ goto malformed;
+ }
+ if (pos > tlv + tlv_size) {
+ LLOG_WARNX("BUG: already past TLV!");
goto malformed;
}
+ PEEK_DISCARD(tlv + tlv_size - pos);
}
/* Some random check */
0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e \
}
-#define LLDP_TLV_HEAD(type, len) htons(((type) << 9) | (len))
-struct lldp_tlv_head {
- u_int16_t type_len;
-} __attribute__ ((__packed__));
-
enum {
LLDP_TLV_END = 0,
LLDP_TLV_CHASSIS_ID = 1,
LLDP_TLV_DOT3_MFS = 4
};
-/* Chassis ID or Port ID */
-struct lldp_id {
- struct lldp_tlv_head tlv_head;
- u_int8_t tlv_id_subtype;
-} __attribute__ ((__packed__));
-
enum {
LLDP_CHASSISID_SUBTYPE_CHASSIS = 1,
LLDP_CHASSISID_SUBTYPE_IFALIAS = 2,
LLDP_PORTID_SUBTYPE_LOCAL = 7
};
-struct lldp_ttl {
- struct lldp_tlv_head tlv_head;
- u_int16_t tlv_ttl;
-} __attribute__ ((__packed__));
-
-struct lldp_string {
- struct lldp_tlv_head tlv_head;
-} __attribute__ ((__packed__));
-
-struct lldp_cap {
- struct lldp_tlv_head tlv_head;
- u_int16_t tlv_cap_available;
- u_int16_t tlv_cap_enabled;
-} __attribute__ ((__packed__));
-
/* Operational MAU Type field, from RFC 3636 */
#define LLDP_DOT3_MAU_AUI 1
#define LLDP_DOT3_MAU_10BASE5 2
LLDP_MGMT_IFACE_SYSPORT = 3
};
-/* Supports only IPv4 */
-struct lldp_mgmt {
- struct lldp_tlv_head tlv_head;
- u_int8_t mgmt_len;
- u_int8_t mgmt_subtype; /* Should be 1 */
- struct in_addr mgmt_addr;
- u_int8_t mgmt_iface_subtype;
- u_int32_t mgmt_iface_id;
- u_int8_t mgmt_oid_len;
- u_int8_t mgmt_oid[0];
-} __attribute__ ((__packed__));
-
-struct lldp_org {
- struct lldp_tlv_head tlv_head;
- u_int8_t tlv_org_id[3];
- u_int8_t tlv_org_subtype;
-} __attribute__ ((__packed__));
-
-struct lldp_vlan {
- struct lldp_tlv_head tlv_head;
- u_int8_t tlv_org_id[3];
- u_int8_t tlv_org_subtype;
- u_int16_t vid;
- u_int8_t len;
-} __attribute__ ((__packed__));
-
-struct lldp_aggreg {
- struct lldp_tlv_head tlv_head;
- u_int8_t tlv_org_id[3];
- u_int8_t tlv_org_subtype;
- u_int8_t status;
- u_int32_t id;
-} __attribute__ ((__packed__));
-
-struct lldp_macphy {
- struct lldp_tlv_head tlv_head;
- u_int8_t tlv_org_id[3];
- u_int8_t tlv_org_subtype;
- u_int8_t autoneg;
- u_int16_t advertised;
- u_int16_t mau;
-} __attribute__ ((__packed__));
-
-struct lldp_mfs {
- struct lldp_tlv_head tlv_head;
- u_int8_t tlv_org_id[3];
- u_int8_t tlv_org_subtype;
- u_int16_t mfs;
-} __attribute__ ((__packed__));
-
-struct lldp_end {
- struct lldp_tlv_head tlv_head;
-} __attribute__ ((__packed__));
-
#ifdef ENABLE_LLDPMED
enum {
LLDP_TLV_MED_CAP = 1,
#define LLDPMED_CAP_MDI_PD 0x10
#define LLDPMED_CAP_IV 0x20
-struct lldpmed_cap {
- struct lldp_tlv_head tlv_head;
- u_int8_t tlv_org_id[3];
- u_int8_t tlv_org_subtype;
- u_int16_t tlv_cap;
- u_int8_t tlv_type;
-} __attribute__ ((__packed__));
#endif /* ENABLE_LLDPMED */
-
#endif /* _LLDP_H */
int guess = LLDPD_MODE_LLDP;
/* Discard VLAN frames */
- if ((s >= sizeof(struct ieee8023)) &&
- (((struct ieee8023*)frame)->size == htons(ETHERTYPE_VLAN)))
+ if ((s >= sizeof(struct ethhdr)) &&
+ (((struct ethhdr*)frame)->h_proto == htons(ETHERTYPE_VLAN)))
return;
if ((hardware->h_rlastframe != NULL) &&
#include <linux/ethtool.h>
#include "compat.h"
-#include "llc.h"
#include "lldp.h"
#if defined (ENABLE_CDP) || defined (ENABLE_FDP)
#include "cdp.h"
/* strlcpy.c */
size_t strlcpy(char *, const char *, size_t);
-/* iov.c */
-void iov_dump(struct lldpd_frame **, struct iovec *, int);
-u_int16_t iov_checksum(struct iovec *, int, int);
-
/* client.c */
struct client_handle {
enum hmsg_type type;
*/
#include "lldpd.h"
+#include "frame.h"
#ifdef ENABLE_SONMP
{
const u_int8_t mcastaddr[] = SONMP_MULTICAST_ADDR;
const u_int8_t llcorg[] = LLC_ORG_NORTEL;
- struct sonmp frame;
- memset(&frame, 0, sizeof(frame));
- memcpy(&frame.llc.ether.shost, &hardware->h_lladdr,
- sizeof(frame.llc.ether.shost));
- memcpy(&frame.llc.ether.dhost, &mcastaddr,
- sizeof(frame.llc.ether.dhost));
- frame.llc.ether.size = htons(sizeof(struct sonmp) -
- sizeof(struct ieee8023));
- frame.llc.dsap = frame.llc.ssap = 0xaa;
- frame.llc.control = 0x03;
- memcpy(frame.llc.org, llcorg, sizeof(frame.llc.org));
- frame.llc.protoid = htons(LLC_PID_SONMP_HELLO);
- memcpy(&frame.addr, &chassis->c_mgmt, sizeof(struct in_addr));
- frame.seg[2] = if_nametoindex(hardware->h_ifname);
- frame.chassis = 1; /* Other */
- frame.backplane = 12; /* Ethernet, Fast Ethernet and Gigabit */
- frame.links = 1; /* Dunno what it is */
- frame.state = SONMP_TOPOLOGY_NEW; /* Should work. We have no state */
+ u_int8_t *packet, *pos, *pos_pid, *end;
+ int length;
+
+ length = hardware->h_mtu;
+ if ((packet = (u_int8_t*)malloc(length)) == NULL)
+ return ENOMEM;
+ memset(packet, 0, length);
+ pos = packet;
+
+ /* Ethernet header */
+ if (!(
+ /* SONMP multicast address as target */
+ POKE_BYTES(mcastaddr, sizeof(mcastaddr)) &&
+ /* Source MAC addresss */
+ POKE_BYTES(&hardware->h_lladdr, sizeof(hardware->h_lladdr)) &&
+ /* SONMP frame is of fixed size */
+ POKE_UINT16(SONMP_SIZE)))
+ goto toobig;
+
+ /* LLC header */
+ if (!(
+ /* DSAP and SSAP */
+ POKE_UINT8(0xaa) && POKE_UINT8(0xaa) &&
+ /* Control field */
+ POKE_UINT8(0x03) &&
+ /* ORG */
+ POKE_BYTES(llcorg, sizeof(llcorg)) &&
+ POKE_SAVE(pos_pid) && /* We will modify PID later to
+ create a new frame */
+ POKE_UINT16(LLC_PID_SONMP_HELLO)))
+ goto toobig;
+
+ /* SONMP */
+ if (!(
+ /* Our IP address */
+ POKE_BYTES(&chassis->c_mgmt, sizeof(struct in_addr)) &&
+ /* Segment on three bytes, we don't have slots, so we
+ skip the first two bytes */
+ POKE_UINT16(0) &&
+ POKE_UINT8(if_nametoindex(hardware->h_ifname)) &&
+ POKE_UINT8(1) && /* Chassis: Other */
+ POKE_UINT8(12) && /* Back: Ethernet, Fast Ethernet and Gigabit */
+ POKE_UINT8(SONMP_TOPOLOGY_NEW) && /* Should work. We have no state */
+ POKE_UINT8(1) && /* Links: Dunno what it is */
+ POKE_SAVE(end)))
+ goto toobig;
if (write((hardware->h_raw_real > 0) ? hardware->h_raw_real :
- hardware->h_raw, &frame, sizeof(struct sonmp)) == -1) {
+ hardware->h_raw, packet, end - packet) == -1) {
LLOG_WARN("unable to send packet on real device for %s",
hardware->h_ifname);
+ free(packet);
return ENETDOWN;
}
- frame.llc.protoid = htons(LLC_PID_SONMP_FLATNET);
- frame.llc.ether.dhost[ETH_ALEN-1] = 1;
+ POKE_RESTORE(pos_pid); /* Modify LLC PID */
+ POKE_UINT16(LLC_PID_SONMP_FLATNET);
+ POKE_RESTORE(packet); /* Go to the beginning */
+ PEEK_DISCARD(ETH_ALEN - 1); /* Modify the last byte of the MAC address */
+ POKE_UINT8(1);
if (write((hardware->h_raw_real > 0) ? hardware->h_raw_real :
- hardware->h_raw, &frame, sizeof(struct sonmp)) == -1) {
+ hardware->h_raw, packet, end - packet) == -1) {
LLOG_WARN("unable to send second SONMP packet on real device for %s",
hardware->h_ifname);
+ free(packet);
return ENETDOWN;
}
+ free(packet);
hardware->h_tx_cnt++;
return 0;
+ toobig:
+ free(packet);
+ return -1;
}
int
struct lldpd_hardware *hardware,
struct lldpd_chassis **newchassis, struct lldpd_port **newport)
{
- struct sonmp *f;
const u_int8_t mcastaddr[] = SONMP_MULTICAST_ADDR;
struct lldpd_chassis *chassis;
struct lldpd_port *port;
- int i;
+ int length, i;
+ u_int8_t *pos;
+ u_int8_t seg[3], rchassis;
+ struct in_addr address;
if ((chassis = calloc(1, sizeof(struct lldpd_chassis))) == NULL) {
LLOG_WARN("failed to allocate remote chassis");
TAILQ_INIT(&port->p_vlans);
#endif
- if (s < sizeof(struct sonmp)) {
- LLOG_WARNX("too short frame received on %s", hardware->h_ifname);
+ length = s;
+ pos = (u_int8_t*)frame;
+ if (length < SONMP_SIZE) {
+ LLOG_WARNX("too short SONMP frame received on %s", hardware->h_ifname);
goto malformed;
}
- f = (struct sonmp *)frame;
- if (memcmp(f->llc.ether.dhost, mcastaddr,
- sizeof(mcastaddr)) != 0) {
+ if (PEEK_CMP(mcastaddr, sizeof(mcastaddr)) != 0)
/* There is two multicast address. We just handle only one of
* them. */
goto malformed;
- }
- if (f->llc.protoid != htons(LLC_PID_SONMP_HELLO)) {
- LLOG_DEBUG("incorrect LLC protocol ID received on %s",
+ /* We skip to LLC PID */
+ PEEK_DISCARD(ETH_ALEN); PEEK_DISCARD_UINT16;
+ PEEK_DISCARD(6);
+ if (PEEK_UINT16 != LLC_PID_SONMP_HELLO) {
+ LLOG_DEBUG("incorrect LLC protocol ID received for SONMP on %s",
hardware->h_ifname);
goto malformed;
}
}
chassis->c_id_len = sizeof(struct in_addr) + 1;
chassis->c_id[0] = 1;
- memcpy(chassis->c_id + 1, &f->addr, sizeof(struct in_addr));
- if (asprintf(&chassis->c_name, "%s", inet_ntoa(f->addr)) == -1) {
+ PEEK_BYTES(&address, sizeof(struct in_addr));
+ memcpy(chassis->c_id + 1, &address, sizeof(struct in_addr));
+ if (asprintf(&chassis->c_name, "%s", inet_ntoa(address)) == -1) {
LLOG_WARNX("unable to write chassis name for %s",
hardware->h_ifname);
goto malformed;
}
+ PEEK_BYTES(seg, sizeof(seg));
+ rchassis = PEEK_UINT8;
for (i=0; sonmp_chassis_types[i].type != 0; i++) {
- if (sonmp_chassis_types[i].type == f->chassis)
+ if (sonmp_chassis_types[i].type == rchassis)
break;
}
if (asprintf(&chassis->c_descr, "%s",
hardware->h_ifname);
goto malformed;
}
- memcpy(&chassis->c_mgmt, &f->addr, sizeof(struct in_addr));
+ memcpy(&chassis->c_mgmt, &address, sizeof(struct in_addr));
chassis->c_ttl = LLDPD_TTL;
port->p_id_subtype = LLDP_PORTID_SUBTYPE_LOCAL;
if (asprintf(&port->p_id, "%02x-%02x-%02x",
- f->seg[0], f->seg[1], f->seg[2]) == -1) {
+ seg[0], seg[1], seg[2]) == -1) {
LLOG_WARN("unable to allocate memory for port id on %s",
hardware->h_ifname);
goto malformed;
}
port->p_id_len = strlen(port->p_id);
- if ((f->seg[0] == 0) && (f->seg[1] == 0)) {
+ /* Port description depend on the number of segments */
+ if ((seg[0] == 0) && (seg[1] == 0)) {
if (asprintf(&port->p_descr, "port %d",
- *(u_int8_t *)(&f->seg[2])) == -1) {
+ seg[2]) == -1) {
LLOG_WARNX("unable to write port description for %s",
hardware->h_ifname);
goto malformed;
}
- } else if (f->seg[0] == 0) {
+ } else if (seg[0] == 0) {
if (asprintf(&port->p_descr, "port %d/%d",
- *(u_int8_t *)(&f->seg[1]),
- *(u_int8_t *)(&f->seg[2])) == -1) {
+ seg[1], seg[2]) == -1) {
LLOG_WARNX("unable to write port description for %s",
hardware->h_ifname);
goto malformed;
}
} else {
if (asprintf(&port->p_descr, "port %x:%x:%x",
- f->seg[0], f->seg[1], f->seg[2]) == -1) {
+ seg[0], seg[1], seg[2]) == -1) {
LLOG_WARNX("unable to write port description for %s",
hardware->h_ifname);
goto malformed;
#define LLC_ORG_NORTEL { 0x00, 0x00, 0x81 }
#define LLC_PID_SONMP_HELLO 0x01a2
#define LLC_PID_SONMP_FLATNET 0x01a1
-
-#include "llc.h"
-
-struct sonmp {
- struct ethllc llc;
- struct in_addr addr;
- u_int8_t seg[3];
- u_int8_t chassis;
- u_int8_t backplane;
- u_int8_t state;
- u_int8_t links;
-} __attribute__ ((__packed__));
+#define SONMP_SIZE (2*ETH_ALEN + sizeof(u_int16_t) + 8)
struct sonmp_chassis {
int type;