From dc1539a44534a36fa8683ecfaddbbd6b34466b96 Mon Sep 17 00:00:00 2001 From: Vincent Bernat Date: Sun, 19 Oct 2008 03:49:15 +0200 Subject: [PATCH] Sometimes, CDP are transmitted over administration VLAN. We try to handle this case by handling this additional encapsulation on reception of CDP frame. Frames are still sent outside of the VLAN. --- src/cdp.c | 72 +++++++++++++++++++++++++++++++++++++++++------------ src/edp.c | 10 ++++---- src/llc.h | 14 +++++++++-- src/lldpd.c | 20 +++++++++------ src/sonmp.c | 12 ++++----- 5 files changed, 92 insertions(+), 36 deletions(-) diff --git a/src/cdp.c b/src/cdp.c index d2fb90e3..bd2d6fae 100644 --- a/src/cdp.c +++ b/src/cdp.c @@ -48,10 +48,10 @@ cdp_send(struct lldpd *global, struct lldpd_chassis *chassis, 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); + llc.llc.dsap = llc.llc.ssap = 0xaa; + llc.llc.control = 0x03; + memcpy(llc.llc.org, llcorg, sizeof(llc.llc.org)); + llc.llc.protoid = htons(LLC_PID_CDP); IOV_NEW; iov[c].iov_base = &llc; iov[c].iov_len = sizeof(llc); @@ -172,7 +172,8 @@ cdp_decode(struct lldpd *cfg, char *frame, int s, { struct lldpd_chassis *chassis; struct lldpd_port *port; - struct ethllc *llc; + struct ieee8023 *ether; + struct llc *llc; struct cdp_header *ch; struct cdp_tlv_head *tlv; struct cdp_tlv_address_head *ah; @@ -195,21 +196,46 @@ cdp_decode(struct lldpd *cfg, char *frame, int s, } TAILQ_INIT(&port->p_vlans); - if (s < sizeof(struct ethllc) + sizeof(struct cdp_header)) { + if (s < sizeof(struct ieee8023)) { LLOG_WARNX("too short frame received on %s", hardware->h_ifname); goto malformed; } - llc = (struct ethllc *)frame; - if (memcmp(&llc->ether.dhost, cdpaddr, sizeof(cdpaddr)) != 0) { + ether = (struct ieee8023*)frame; + if (memcmp(ðer->dhost, cdpaddr, sizeof(cdpaddr)) != 0) { LLOG_INFO("frame not targeted at CDP 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; + + /* Is it a CDP frame encapsulated into a VLAN? */ + if (ether->size == htons(ETHERTYPE_VLAN)) { + if (s < sizeof(struct ieee8023) + sizeof(struct ieee8021q) + + sizeof(struct llc) + sizeof(struct cdp_header)) { + LLOG_WARNX("too short frame received on %s", hardware->h_ifname); + goto malformed; + } + if (ntohs(((struct ieee8021q*)(frame + + sizeof(struct ieee8023)))->size) > + s - sizeof(struct ieee8023) - sizeof(struct ieee8021q)) { + LLOG_WARNX("incorrect 802.3/802.1q frame size reported on %s", + hardware->h_ifname); + goto malformed; + } + llc = (struct llc*)(frame + sizeof(struct ieee8023) + + sizeof(struct ieee8021q)); + } else { + if (s < sizeof(struct ethllc) + sizeof(struct cdp_header)) { + LLOG_WARNX("too short frame received on %s", hardware->h_ifname); + goto malformed; + } + + if (ntohs(ether->size) > s - sizeof(struct ieee8023)) { + LLOG_WARNX("incorrect 802.3 frame size reported on %s", + hardware->h_ifname); + goto malformed; + } + llc = (struct llc*)(frame + sizeof(struct ieee8023)); } if (llc->protoid != htons(LLC_PID_CDP)) { if ((llc->protoid != htons(LLC_PID_DRIP)) && @@ -223,7 +249,7 @@ cdp_decode(struct lldpd *cfg, char *frame, int s, hardware->h_ifname); goto malformed; } - f = sizeof(struct ethllc); + f = (void*)llc - (void*)frame + sizeof(struct llc); ch = (struct cdp_header *)(frame + f); if ((ch->version != 1) && (ch->version != 2)) { LLOG_WARNX("incorrect CDP version (%d) for frame received on %s", @@ -327,7 +353,7 @@ cdp_decode(struct lldpd *cfg, char *frame, int s, LLOG_WARN("unable to allocate memory for port ID"); goto malformed; } - memcpy(port->p_id, llc->ether.shost, ETH_ALEN); + memcpy(port->p_id, ether->shost, ETH_ALEN); port->p_id_len = ETH_ALEN; f += len; break; @@ -440,11 +466,25 @@ cdp_guess(char *frame, int len, int version) { const u_int8_t mcastaddr[] = CDP_MULTICAST_ADDR; struct cdp_header *ch; - if (len < sizeof(struct ethllc) + sizeof(struct cdp_header)) + if (len < sizeof(struct ieee8023)) return 0; if (memcmp(frame, mcastaddr, ETH_ALEN) != 0) return 0; - ch = (struct cdp_header *)(frame + sizeof(struct ethllc)); + /* Maybe this is encapsulated into a VLAN */ + if (((struct ieee8023*)frame)->size != htons(ETHERTYPE_VLAN)) { + /* Not a 802.1q frame */ + if (len < sizeof(struct ethllc) + + sizeof(struct cdp_header)) + return 0; + ch = (struct cdp_header *)(frame + sizeof(struct ethllc)); + } else { + /* 802.1q frame */ + if (len < sizeof(struct ieee8023) + sizeof(struct ieee8021q) + + sizeof(struct llc) + sizeof(struct cdp_header)) + return 0; + ch = (struct cdp_header *)(frame + sizeof(struct ieee8023) + + sizeof(struct ieee8021q) + sizeof(struct llc)); + } return (ch->version == version); } diff --git a/src/edp.c b/src/edp.c index 0275074d..ecc8546d 100644 --- a/src/edp.c +++ b/src/edp.c @@ -60,10 +60,10 @@ edp_send(struct lldpd *global, struct lldpd_chassis *chassis, 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); + llc.llc.dsap = llc.llc.ssap = 0xaa; + llc.llc.control = 0x03; + memcpy(llc.llc.org, llcorg, sizeof(llc.llc.org)); + llc.llc.protoid = htons(LLC_PID_EDP); IOV_NEW; iov[c].iov_base = &llc; iov[c].iov_len = sizeof(llc); @@ -241,7 +241,7 @@ edp_decode(struct lldpd *cfg, char *frame, int s, hardware->h_ifname); goto malformed; } - if (llc->protoid != htons(LLC_PID_EDP)) { + if (llc->llc.protoid != htons(LLC_PID_EDP)) { LLOG_DEBUG("incorrect LLC protocol ID received on %s", hardware->h_ifname); goto malformed; diff --git a/src/llc.h b/src/llc.h index 002ccf18..0ca0651f 100644 --- a/src/llc.h +++ b/src/llc.h @@ -23,8 +23,12 @@ struct ieee8023 { u_int16_t size; /* packet type ID field */ } __attribute__ ((__packed__)); -struct ethllc { - struct ieee8023 ether; +struct ieee8021q { + u_int16_t vid; + u_int16_t size; +} __attribute__ ((__packed__)); + +struct llc { u_int8_t dsap; /* destination SAP */ u_int8_t ssap; /* source SAP */ u_int8_t control; /* LLC control field */ @@ -32,4 +36,10 @@ struct ethllc { u_int16_t protoid; } __attribute__ ((__packed__)); +/* IEEE 802.3 + LLC */ +struct ethllc { + struct ieee8023 ether; + struct llc llc; +} __attribute__ ((__packed__)); + #endif diff --git a/src/lldpd.c b/src/lldpd.c index e4161b5f..c4e48fdd 100644 --- a/src/lldpd.c +++ b/src/lldpd.c @@ -64,14 +64,20 @@ void lldpd_iface_multicast(struct lldpd *, const char *, int); { 0x6, 0, 0, 0x0000ffff }, \ { 0x6, 0, 0, 0x00000000 }, struct sock_filter lldpd_filter_lldp_f[] = { LLDPD_FILTER_LLDP_F }; -/* "ether dst 01:00:0c:cc:cc:cc" */ +/* "(ether dst 01:00:0c:cc:cc:cc) or (vlan and ether dst 01:00:0c:cc:cc:cc)" */ #define LLDPD_FILTER_CDP_F \ - { 0x20, 0, 0, 0x00000002 }, \ - { 0x15, 0, 3, 0x0ccccccc }, \ - { 0x28, 0, 0, 0x00000000 }, \ - { 0x15, 0, 1, 0x00000100 }, \ - { 0x6, 0, 0, 0x0000ffff }, \ - { 0x6, 0, 0, 0x00000000 }, + { 0x20, 0, 0, 0x00000002 }, \ + { 0x15, 0, 2, 0x0ccccccc }, \ + { 0x28, 0, 0, 0x00000000 }, \ + { 0x15, 6, 0, 0x00000100 }, \ + { 0x28, 0, 0, 0x0000000c }, \ + { 0x15, 0, 5, 0x00008100 }, \ + { 0x20, 0, 0, 0x00000002 }, \ + { 0x15, 0, 3, 0x0ccccccc }, \ + { 0x28, 0, 0, 0x00000000 }, \ + { 0x15, 0, 1, 0x00000100 }, \ + { 0x6, 0, 0, 0x0000ffff }, \ + { 0x6, 0, 0, 0x00000000 }, struct sock_filter lldpd_filter_cdp_f[] = { LLDPD_FILTER_CDP_F }; /* "ether dst 01:00:81:00:01:00" */ #define LLDPD_FILTER_SONMP_F \ diff --git a/src/sonmp.c b/src/sonmp.c index 19067c70..19f9caa4 100644 --- a/src/sonmp.c +++ b/src/sonmp.c @@ -190,10 +190,10 @@ sonmp_send(struct lldpd *global, struct lldpd_chassis *chassis, 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); + frame.llc.llc.dsap = frame.llc.llc.ssap = 0xaa; + frame.llc.llc.control = 0x03; + memcpy(frame.llc.llc.org, llcorg, sizeof(frame.llc.llc.org)); + frame.llc.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 */ @@ -208,7 +208,7 @@ sonmp_send(struct lldpd *global, struct lldpd_chassis *chassis, return ENETDOWN; } - frame.llc.protoid = htons(LLC_PID_SONMP_FLATNET); + frame.llc.llc.protoid = htons(LLC_PID_SONMP_FLATNET); frame.llc.ether.dhost[ETH_ALEN-1] = 1; if (write((hardware->h_raw_real > 0) ? hardware->h_raw_real : @@ -255,7 +255,7 @@ sonmp_decode(struct lldpd *cfg, char *frame, int s, * them. */ goto malformed; } - if (f->llc.protoid != htons(LLC_PID_SONMP_HELLO)) { + if (f->llc.llc.protoid != htons(LLC_PID_SONMP_HELLO)) { LLOG_DEBUG("incorrect LLC protocol ID received on %s", hardware->h_ifname); goto malformed; -- 2.47.2