]> git.ipfire.org Git - thirdparty/lldpd.git/commitdiff
Add FDP support
authorVincent Bernat <vbernat@wanadooportails.com>
Fri, 7 Nov 2008 11:17:50 +0000 (12:17 +0100)
committerVincent Bernat <vbernat@wanadooportails.com>
Fri, 7 Nov 2008 11:17:50 +0000 (12:17 +0100)
README
debian/control
man/lldpd.8
src/cdp.c
src/cdp.h
src/lldpd.c
src/lldpd.h

diff --git a/README b/README
index 75c8b56a046eab3ae95304fd6c66224c9eb034c5..87deb7b2e6458ff20da1b4ca10600b0d4bae6df4 100644 (file)
--- a/README
+++ b/README
@@ -22,14 +22,14 @@ on bridges. More complex setups may give false results.
 
 lldpctl allows to query information collected through the command line.
 
-lldpd also implements CDP (Cisco Discovery Protocol), SONMP (Nortel
-Discovery Protocol) and EDP (Extreme Discovery Protocol). However,
-recent versions of IOS should support LLDP and most Extreme stuff
-support LLDP. When a EDP, CDP or SONMP frame is received on a given
-interface, lldpd starts sending EDP, CDP or SONMP frame on this
-interface. Informations collected through EDP/CDP/SONMP are integrated
-with other informations and can be queried with lldpctl or through
-SNMP.
+lldpd also implements CDP (Cisco Discovery Protocol), FDP (Foundry
+Discovery Protocol), SONMP (Nortel Discovery Protocol) and EDP
+(Extreme Discovery Protocol). However, recent versions of IOS should
+support LLDP and most Extreme stuff support LLDP. When a EDP, CDP or
+SONMP frame is received on a given interface, lldpd starts sending
+EDP, CDP, FDP or SONMP frame on this interface. Informations collected
+through EDP/CDP/FDP/SONMP are integrated with other informations and
+can be queried with lldpctl or through SNMP.
 
 For bonding, you need 2.6.24 (in previous version, PACKET_ORIGDEV
 affected only non multicast packets). See:
index 70292a31055cd715b8b0e0065b84b0aab21ae847..2601ab5314f28cb654d16a85e8240d64e3e6a618 100644 (file)
@@ -19,4 +19,5 @@ Description: implementation of IEEE 802.1ab (LLDP)
  LLDP is to provide an inter-vendor compatible mechanism to deliver
  Link-Layer notifications to adjacent network devices.
  .
- This daemon is also able to deal with CDP, SONMP and EDP protocol.
+ This daemon is also able to deal with CDP, FDP, SONMP and EDP
+ protocol.
index 962c1caaf6b1eb765a93104c09f3821e0e8a4dcf..c5963ad426edf097d9ebe6f8be110c83ba3ceb25 100644 (file)
@@ -69,6 +69,9 @@ information about local system and remote systems through SNMP.
 .It Fl c
 Enable the support of CDP protocol to deal with Cisco routers that do
 not speak LLDP.
+.It Fl f
+Enable the support of FDP protocol to deal with Foundry routers that do
+not speak LLDP.
 .It Fl s
 Enable the support of SONMP protocol to deal with Nortel routers and
 switches that do not speak LLDP.
index 9ff735e5226a2c3f74ad74d8a72bff84b2287eac..3acc757e482cbfb97d2d2ad06da41a7776ae98ed 100644 (file)
--- a/src/cdp.c
+++ b/src/cdp.c
@@ -14,6 +14,7 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
+/* We also supports FDP which is very similar to CDPv1 */
 #include "lldpd.h"
 
 #include <errno.h>
@@ -25,8 +26,8 @@ cdp_send(struct lldpd *global, struct lldpd_chassis *chassis,
 {
        struct cdp_header ch;
        struct ethllc llc;
-       const u_int8_t mcastaddr[] = CDP_MULTICAST_ADDR;
-       const u_int8_t llcorg[] = LLC_ORG_CISCO;
+       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;
@@ -42,6 +43,14 @@ cdp_send(struct lldpd *global, struct lldpd_chassis *chassis,
                    sizeof(struct iovec))) == NULL)             \
                fatal(NULL);
 
+       /* Handle FDP */
+       if (version == 0) {
+               const u_int8_t fdpmcastaddr[] = FDP_MULTICAST_ADDR;
+               const u_int8_t fdpllcorg[] = LLC_ORG_FOUNDRY;
+               memcpy(mcastaddr, fdpmcastaddr, sizeof(mcastaddr));
+               memcpy(llcorg, fdpllcorg, sizeof(llcorg));
+       }
+
        /* Ether + LLC */
        memset(&llc, 0, sizeof(llc));
        memcpy(&llc.ether.shost, &hardware->h_lladdr,
@@ -58,7 +67,10 @@ cdp_send(struct lldpd *global, struct lldpd_chassis *chassis,
 
        /* CDP header */
        memset(&ch, 0, sizeof(ch));
-       ch.version = version;
+       if (version == 0)
+               ch.version = 1;
+       else
+               ch.version = version;
        ch.ttl = chassis->c_ttl;
        IOV_NEW;
        iov[c].iov_base = &ch;
@@ -104,20 +116,22 @@ cdp_send(struct lldpd *global, struct lldpd_chassis *chassis,
        iov[c].iov_base = hardware->h_lport.p_descr;
        iov[c].iov_len = strlen(hardware->h_lport.p_descr);
 
-       /* Capaibilities */
-       memset(&cap, 0, sizeof(cap));
-       cap.head.tlv_type = htons(CDP_TLV_CAPABILITIES);
-       cap.head.tlv_len = htons(sizeof(cap));
-       cap.cap = 0;
-       if (chassis->c_cap_enabled & LLDP_CAP_ROUTER)
-               cap.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 = &cap;
-       iov[c].iov_len = sizeof(cap);
-
+       /* 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;
+               if (chassis->c_cap_enabled & LLDP_CAP_ROUTER)
+                       cap.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 = &cap;
+               iov[c].iov_len = sizeof(cap);
+       }
+               
        /* Software version */
        memset(&soft, 0, sizeof(soft));
        soft.tlv_type = htons(CDP_TLV_SOFTWARE);
@@ -165,6 +179,7 @@ cdp_send(struct lldpd *global, struct lldpd_chassis *chassis,
        return 0;
 }
 
+/* cdp_decode also decodes FDP */
 int
 cdp_decode(struct lldpd *cfg, char *frame, int s,
     struct lldpd_hardware *hardware,
@@ -182,7 +197,8 @@ cdp_decode(struct lldpd *cfg, char *frame, int s,
        char *software = NULL, *platform = NULL;
        int software_len = 0, platform_len = 0;
        const unsigned char cdpaddr[] = CDP_MULTICAST_ADDR;
-       int i, f, len, rlen;
+       const unsigned char fdpaddr[] = CDP_MULTICAST_ADDR;
+       int i, f, len, rlen, fdp = 0;
 
        if ((chassis = calloc(1, sizeof(struct lldpd_chassis))) == NULL) {
                LLOG_WARN("failed to allocate remote chassis");
@@ -202,9 +218,13 @@ cdp_decode(struct lldpd *cfg, char *frame, int s,
 
        llc = (struct ethllc *)frame;
        if (memcmp(&llc->ether.dhost, cdpaddr, sizeof(cdpaddr)) != 0) {
-               LLOG_INFO("frame not targeted at CDP multicast address received on %s",
-                   hardware->h_ifname);
-               goto malformed;
+               if (memcmp(&llc->ether.dhost, fdpaddr, sizeof(fdpaddr)) != 0)
+                       fdp = 1;
+               else {
+                       LLOG_INFO("frame not targeted at CDP/FDP 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",
@@ -226,7 +246,7 @@ cdp_decode(struct lldpd *cfg, char *frame, int s,
        f = sizeof(struct ethllc);
        ch = (struct cdp_header *)(frame + f);
        if ((ch->version != 1) && (ch->version != 2)) {
-               LLOG_WARNX("incorrect CDP version (%d) for frame received on %s",
+               LLOG_WARNX("incorrect CDP/FDP version (%d) for frame received on %s",
                    ch->version, hardware->h_ifname);
                goto malformed;
        }
@@ -236,7 +256,7 @@ cdp_decode(struct lldpd *cfg, char *frame, int s,
        cksum = iov_checksum(&iov, 1, 1);
        /* An off-by-one error may happen. Just ignore it */
        if ((cksum != 0) && (cksum != 0xfffe)) {
-               LLOG_INFO("incorrect CDP checksum for frame received on %s (%d)",
+               LLOG_INFO("incorrect CDP/FDP checksum for frame received on %s (%d)",
                          hardware->h_ifname, cksum);
                goto malformed;
        }
@@ -244,7 +264,7 @@ cdp_decode(struct lldpd *cfg, char *frame, int s,
        f += sizeof(struct cdp_header);
        while (f < s) {
                if (f + sizeof(struct cdp_tlv_head) > s) {
-                       LLOG_WARNX("CDP TLV header is too large for "
+                       LLOG_WARNX("CDP/FDP TLV header is too large for "
                            "frame received on %s",
                            hardware->h_ifname);
                        goto malformed;
@@ -252,7 +272,7 @@ cdp_decode(struct lldpd *cfg, char *frame, int s,
                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)) {
-                       LLOG_WARNX("incorrect size in CDP TLV header for frame "
+                       LLOG_WARNX("incorrect size in CDP/FDP TLV header for frame "
                            "received on %s",
                            hardware->h_ifname);
                        goto malformed;
@@ -276,7 +296,7 @@ cdp_decode(struct lldpd *cfg, char *frame, int s,
                        break;
                case CDP_TLV_ADDRESSES:
                        if (len < 4) {
-                               LLOG_WARNX("incorrect size in CDP TLV header for frame "
+                               LLOG_WARNX("incorrect size in CDP/FDP TLV header for frame "
                                    "received on %s",
                                    hardware->h_ifname);
                                goto malformed;
@@ -332,6 +352,12 @@ cdp_decode(struct lldpd *cfg, char *frame, int s,
                        f += len;
                        break;
                case CDP_TLV_CAPABILITIES:
+                       if (fdp) {
+                               /* Capabilities are ignored with FDP */
+                               f += sizeof(struct cdp_tlv_head) + len;
+                               chassis->c_cap_enabled = chassis->c_cap_available = LLDP_CAP_BRIDGE;
+                               break;
+                       }
                        f += sizeof(struct cdp_tlv_head);
                        if (len != 4) {
                                LLOG_WARNX("incorrect size for capabilities TLV "
@@ -361,7 +387,7 @@ cdp_decode(struct lldpd *cfg, char *frame, int s,
                        f += len;
                        break;
                default:
-                       LLOG_DEBUG("unknown CDP TLV type (%d) received on %s",
+                       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;
                        hardware->h_rx_unrecognized_cnt++;
@@ -402,7 +428,7 @@ cdp_decode(struct lldpd *cfg, char *frame, int s,
            (port->p_descr == NULL) ||
            (chassis->c_ttl == 0) ||
            (chassis->c_cap_enabled == 0)) {
-               LLOG_WARNX("some mandatory tlv are missing for frame received on %s",
+               LLOG_WARNX("some mandatory CDP/FDP tlv are missing for frame received on %s",
                    hardware->h_ifname);
                goto malformed;
        }
@@ -436,6 +462,13 @@ cdpv2_send(struct lldpd *global, struct lldpd_chassis *chassis,
        return cdp_send(global, chassis, hardware, 2);
 }
 
+int
+fdp_send(struct lldpd *global, struct lldpd_chassis *chassis,
+    struct lldpd_hardware *hardware)
+{
+       return cdp_send(global, chassis, hardware, 0);
+}
+
 int
 cdp_guess(char *frame, int len, int version)
 {
index c18ebdf6eb4571048d945a8dffdd7262e6f15ea4..8694e679f67935ba013a0e49097cf8ff0041500d 100644 (file)
--- a/src/cdp.h
+++ b/src/cdp.h
 #define CDP_MULTICAST_ADDR     {                                               \
        0x01, 0x00, 0x0c, 0xcc, 0xcc, 0xcc                                      \
 }
+#define FDP_MULTICAST_ADDR     {                       \
+       0x01, 0xe0, 0x52, 0xcc, 0xcc, 0xcc,             \
+}
 #define LLC_ORG_CISCO { 0x00, 0x00, 0x0c }
+#define LLC_ORG_FOUNDRY { 0x00, 0xe0, 0x52 }
 #define LLC_PID_CDP 0x2000
 /* Other protocols */
 #define LLC_PID_DRIP 0x102
index 10fa5425df81ebd43e0455c3de2a39f62a04b211..48fb4836077b3a56510060a2d08c355a34566e16 100644 (file)
@@ -67,6 +67,15 @@ 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:e0:52:cc:cc:cc" */
+#define LLDPD_FILTER_FDP_F                     \
+        { 0x20, 0, 0, 0x00000002 },            \
+        { 0x15, 0, 3, 0x52cccccc },            \
+        { 0x28, 0, 0, 0x00000000 },            \
+        { 0x15, 0, 1, 0x000001e0 },            \
+        { 0x6, 0, 0, 0x0000ffff },             \
+        { 0x6, 0, 0, 0x00000000 },
+struct sock_filter lldpd_filter_fdp_f[] = { LLDPD_FILTER_FDP_F };
 /* "ether dst 01:00:0c:cc:cc:cc" */
 #define LLDPD_FILTER_CDP_F                     \
         { 0x20, 0, 0, 0x00000002 },            \
@@ -100,15 +109,18 @@ struct sock_filter lldpd_filter_edp_f[] = { LLDPD_FILTER_EDP_F };
        { 0x20, 0, 0, 0x00000002 },     \
        { 0x15, 0, 2, 0xc200000e },     \
        { 0x28, 0, 0, 0x00000000 },     \
-       { 0x15, 8, 9, 0x00000180 },     \
+       { 0x15, 11, 12, 0x00000180 },   \
        { 0x20, 0, 0, 0x00000002 },     \
        { 0x15, 0, 2, 0x2b000000 },     \
        { 0x28, 0, 0, 0x00000000 },     \
-       { 0x15, 4, 5, 0x000000e0 },     \
+       { 0x15, 7, 8, 0x000000e0 },     \
        { 0x15, 1, 0, 0x0ccccccc },     \
-       { 0x15, 0, 3, 0x81000100 },     \
+       { 0x15, 0, 2, 0x81000100 },     \
+       { 0x28, 0, 0, 0x00000000 },     \
+       { 0x15, 3, 4, 0x00000100 },     \
+       { 0x15, 0, 3, 0x52cccccc },     \
        { 0x28, 0, 0, 0x00000000 },     \
-       { 0x15, 0, 1, 0x00000100 },     \
+       { 0x15, 0, 1, 0x000001e0 },     \
        { 0x6, 0, 0, 0x0000ffff },      \
        { 0x6, 0, 0, 0x00000000 },
 struct sock_filter lldpd_filter_any_f[] = { LLDPD_FILTER_ANY_F };
@@ -125,6 +137,8 @@ struct protocol protos[] =
          SONMP_MULTICAST_ADDR, lldpd_filter_sonmp_f, sizeof(lldpd_filter_sonmp_f) },
        { LLDPD_MODE_EDP, 0, "EDP", 'e', edp_send, edp_decode, NULL,
          EDP_MULTICAST_ADDR, lldpd_filter_edp_f, sizeof(lldpd_filter_edp_f) },
+       { LLDPD_MODE_FDP, 0, "FDP", 'f', fdp_send, cdp_decode, NULL,
+         FDP_MULTICAST_ADDR, lldpd_filter_fdp_f, sizeof(lldpd_filter_fdp_f) },
        { 0, 0, "any", ' ', NULL, NULL, NULL,
          {0,0,0,0,0,0}, lldpd_filter_any_f, sizeof(lldpd_filter_any_f) }
 };
@@ -149,9 +163,9 @@ usage(void)
 {
        extern const char       *__progname;
 #ifndef USE_SNMP
-       fprintf(stderr, "usage: %s [-d] [-v] [-c] [-s] [-e] [-p|-P] [-m ip]\n", __progname);
+       fprintf(stderr, "usage: %s [-dvcse] [-p|-P] [-m ip]\n", __progname);
 #else /* USE_SNMP */
-       fprintf(stderr, "usage: %s [-d] [-v] [-c] [-s] [-e] [-p|-P] [-m ip] [-x]\n", __progname);
+       fprintf(stderr, "usage: %s [-dvcsex] [-p|-P] [-m ip]\n", __progname);
 #endif /* USE_SNMP */
        exit(1);
 }
index 38e6d4fea2163e3fdcd198cce13ed1abd93da132..d5ecf8baa9f066aef78dc359804ed49e04a95a2e 100644 (file)
@@ -111,6 +111,7 @@ struct lldpd_hardware {
 #define LLDPD_MODE_CDPV2 3
 #define LLDPD_MODE_SONMP 4
 #define LLDPD_MODE_EDP 5
+#define LLDPD_MODE_FDP 6
        int                      h_mode;
 
        int                      h_flags;
@@ -247,6 +248,7 @@ int  lldp_decode(PROTO_DECODE_SIG);
 /* cdp.c */
 int     cdpv1_send(PROTO_SEND_SIG);
 int     cdpv2_send(PROTO_SEND_SIG);
+int     fdp_send(PROTO_SEND_SIG);
 int     cdp_decode(PROTO_DECODE_SIG);
 int     cdpv1_guess(PROTO_GUESS_SIG);
 int     cdpv2_guess(PROTO_GUESS_SIG);