]> git.ipfire.org Git - thirdparty/lldpd.git/commitdiff
lldp: accept LLDP frames sent through S-VLAN/C-VLAN bridges
authorVincent Bernat <vincent@bernat.im>
Sat, 11 Jun 2016 16:46:59 +0000 (18:46 +0200)
committerVincent Bernat <vincent@bernat.im>
Sat, 11 Jun 2016 16:46:59 +0000 (18:46 +0200)
See #171.

src/daemon/interfaces.c
src/daemon/lldp-tlv.h
src/daemon/lldpd.c
src/daemon/lldpd.h
src/daemon/priv.c
src/daemon/protocols/lldp.c

index cefbec4d3cde87bfadfea4c9ca8981a83e3822b5..f0aacceaa6db52831c082390538d0c6005ebfa05 100644 (file)
@@ -32,19 +32,28 @@ void
 interfaces_setup_multicast(struct lldpd *cfg, const char *name,
     int remove)
 {
-       int i, rc;
+       int rc;
+       size_t i, j;
+       const u_int8_t *mac;
+       const u_int8_t zero[ETHER_ADDR_LEN] = {};
 
-       for (i=0; cfg->g_protocols[i].mode != 0; i++) {
+       for (i = 0; cfg->g_protocols[i].mode != 0; i++) {
                if (!cfg->g_protocols[i].enabled) continue;
-               if ((rc = priv_iface_multicast(name,
-                           cfg->g_protocols[i].mac, !remove)) != 0) {
-                       errno = rc;
-                       if (errno != ENOENT)
-                               log_debug("interfaces",
-                                   "unable to %s %s address to multicast filter for %s (%s)",
-                                   (remove)?"delete":"add",
-                                   cfg->g_protocols[i].name,
-                                   name, strerror(rc));
+               for (mac = cfg->g_protocols[i].mac1, j = 0;
+                    j < 3;
+                    mac += ETHER_ADDR_LEN,
+                    j++) {
+                       if (memcmp(mac, zero, ETHER_ADDR_LEN) == 0) break;
+                       if ((rc = priv_iface_multicast(name,
+                                   mac, !remove)) != 0) {
+                               errno = rc;
+                               if (errno != ENOENT)
+                                       log_debug("interfaces",
+                                           "unable to %s %s address to multicast filter for %s (%s)",
+                                           (remove)?"delete":"add",
+                                           cfg->g_protocols[i].name,
+                                           name, strerror(rc));
+                       }
                }
        }
 }
index b67e1a5cbc4189402809774ad45b554312edaa57..a8016bbf0c583157191e82724d5eec27ff73c6fb 100644 (file)
@@ -18,9 +18,9 @@
 #ifndef _LLDP_TLV_H
 #define _LLDP_TLV_H
 
-#define LLDP_MULTICAST_ADDR    {                                               \
-       0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e                                      \
-}
+#define LLDP_ADDR_NEAREST_BRIDGE               {0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e}
+#define LLDP_ADDR_NEAREST_NONTPMR_BRIDGE       {0x01, 0x80, 0xc2, 0x00, 0x00, 0x03}
+#define LLDP_ADDR_NEAREST_CUSTOMER_BRIDGE      {0x01, 0x80, 0xc2, 0x00, 0x00, 0x00}
 
 #define LLDP_TLV_END           0
 #define LLDP_TLV_CHASSIS_ID    1
index b464c2c01aaded734b2bb7340246e06fc453d3ce..e4d4a65a723883da988fd952b70e0afe066daeab 100644 (file)
@@ -44,7 +44,9 @@ static void            usage(void);
 static struct protocol protos[] =
 {
        { LLDPD_MODE_LLDP, 1, "LLDP", 'l', lldp_send, lldp_decode, NULL,
-         LLDP_MULTICAST_ADDR },
+         LLDP_ADDR_NEAREST_BRIDGE,
+         LLDP_ADDR_NEAREST_NONTPMR_BRIDGE,
+         LLDP_ADDR_NEAREST_CUSTOMER_BRIDGE },
 #ifdef ENABLE_CDP
        { LLDPD_MODE_CDPV1, 0, "CDPv1", 'c', cdpv1_send, cdp_decode, cdpv1_guess,
          CDP_MULTICAST_ADDR },
@@ -485,7 +487,9 @@ lldpd_guess_type(struct lldpd *cfg, char *frame, int s)
                if (!cfg->g_protocols[i].enabled)
                        continue;
                if (cfg->g_protocols[i].guess == NULL) {
-                       if (memcmp(frame, cfg->g_protocols[i].mac, ETHER_ADDR_LEN) == 0) {
+                       if (memcmp(frame, cfg->g_protocols[i].mac1, ETHER_ADDR_LEN) == 0 ||
+                           memcmp(frame, cfg->g_protocols[i].mac2, ETHER_ADDR_LEN) == 0 ||
+                           memcmp(frame, cfg->g_protocols[i].mac3, ETHER_ADDR_LEN) == 0) {
                                log_debug("decode", "guessed protocol is %s (from MAC address)",
                                    cfg->g_protocols[i].name);
                                return cfg->g_protocols[i].mode;
index 9ec91e9f13caee039908d294da208bf333915073..263f8e2d20b91a57108b0791b598e3624a4db53a 100644 (file)
@@ -92,7 +92,9 @@ struct protocol {
        int(*send)(PROTO_SEND_SIG);     /* How to send a frame */
        int(*decode)(PROTO_DECODE_SIG); /* How to decode a frame */
        int(*guess)(PROTO_GUESS_SIG);   /* Can be NULL, use MAC address in this case */
-       u_int8_t         mac[ETHER_ADDR_LEN];  /* Destination MAC address used by this protocol */
+       u_int8_t         mac1[ETHER_ADDR_LEN];  /* Destination MAC address used by this protocol */
+       u_int8_t         mac2[ETHER_ADDR_LEN];  /* Destination MAC address used by this protocol */
+       u_int8_t         mac3[ETHER_ADDR_LEN];  /* Destination MAC address used by this protocol */
 };
 
 #define SMART_HIDDEN(port) (port->p_hidden_in)
@@ -205,7 +207,7 @@ void         asroot_iface_mac(void);
 #endif
 int             priv_iface_init(int, char *);
 int     asroot_iface_init_os(int, char *, int *);
-int     priv_iface_multicast(const char *, u_int8_t *, int);
+int     priv_iface_multicast(const char *, const u_int8_t *, int);
 int     priv_iface_description(const char *, const char *);
 int     asroot_iface_description_os(const char *, const char *);
 int     priv_iface_promisc(const char*);
@@ -257,7 +259,9 @@ void         send_fd(enum priv_context, int);
    first byte is 1. if not, this can only be an EDP packet:
 
    tcpdump -dd "(ether[0] & 1 = 1 and
-                 ((ether proto 0x88cc and ether dst 01:80:c2:00:00:0e) or
+                 ((ether proto 0x88cc and (ether dst 01:80:c2:00:00:0e or
+                                           ether dst 01:80:c2:00:00:03 or
+                                           ether dst 01:80:c2:00:00:00)) or
                   (ether dst 01:e0:52:cc:cc:cc) or
                   (ether dst 01:00:0c:cc:cc:cc) or
                   (ether dst 01:00:81:00:01:00))) or
@@ -267,11 +271,13 @@ void       send_fd(enum priv_context, int);
 #define LLDPD_FILTER_F                         \
        { 0x30, 0, 0, 0x00000000 },             \
        { 0x54, 0, 0, 0x00000001 },             \
-       { 0x15, 0, 14, 0x00000001 },            \
+       { 0x15, 0, 16, 0x00000001 },            \
        { 0x28, 0, 0, 0x0000000c },             \
-       { 0x15, 0, 4, 0x000088cc },             \
+       { 0x15, 0, 6, 0x000088cc },             \
        { 0x20, 0, 0, 0x00000002 },             \
-       { 0x15, 0, 2, 0xc200000e },             \
+       { 0x15, 2, 0, 0xc200000e },             \
+       { 0x15, 1, 0, 0xc2000003 },             \
+       { 0x15, 0, 2, 0xc2000000 },             \
        { 0x28, 0, 0, 0x00000000 },             \
        { 0x15, 12, 13, 0x00000180 },           \
        { 0x20, 0, 0, 0x00000002 },             \
@@ -286,8 +292,8 @@ void         send_fd(enum priv_context, int);
        { 0x15, 0, 3, 0x2b000000 },             \
        { 0x28, 0, 0, 0x00000000 },             \
        { 0x15, 0, 1, 0x000000e0 },             \
-       { 0x6, 0, 0, 0x0000ffff },              \
-       { 0x6, 0, 0, 0x00000000 },
+       { 0x6, 0, 0, 0x00040000 },              \
+       { 0x6, 0, 0, 0x00000000 }
 
 /* This function is responsible to refresh information about interfaces. It is
  * OS specific but should be present for each OS. It can use the functions in
index c37685a0fc0b180f14cc17ab9770608a965bea12..7a65b120de79b6b8f6a70745450b164fb489fbe2 100644 (file)
@@ -130,7 +130,7 @@ priv_iface_init(int index, char *iface)
 }
 
 int
-priv_iface_multicast(const char *name, u_int8_t *mac, int add)
+priv_iface_multicast(const char *name, const u_int8_t *mac, int add)
 {
        int rc;
        enum priv_cmd cmd = PRIV_IFACE_MULTICAST;
index deddc3e757414224ab01f76b5024ba24e49fa5b2..74ca8387564ed36b4c6ed28b100661460d8efc2b 100644 (file)
@@ -69,7 +69,7 @@ static int _lldp_send(struct lldpd *global,
        struct lldpd_mgmt *mgmt;
        int proto;
 
-       u_int8_t mcastaddr[] = LLDP_MULTICAST_ADDR;
+       u_int8_t mcastaddr[] = LLDP_ADDR_NEAREST_BRIDGE;
 #ifdef ENABLE_DOT1
        const u_int8_t dot1[] = LLDP_TLV_ORG_DOT1;
        struct lldpd_vlan *vlan;
@@ -572,7 +572,7 @@ lldp_decode(struct lldpd *cfg, char *frame, int s,
 {
        struct lldpd_chassis *chassis;
        struct lldpd_port *port;
-       const char lldpaddr[] = LLDP_MULTICAST_ADDR;
+       char lldpaddr[ETHER_ADDR_LEN];
        const char dot1[] = LLDP_TLV_ORG_DOT1;
        const char dot3[] = LLDP_TLV_ORG_DOT3;
        const char med[] = LLDP_TLV_ORG_MED;
@@ -626,7 +626,10 @@ lldp_decode(struct lldpd *cfg, char *frame, int s,
                log_warnx("lldp", "too short frame received on %s", hardware->h_ifname);
                goto malformed;
        }
-       if (PEEK_CMP(lldpaddr, ETHER_ADDR_LEN) != 0) {
+       PEEK_BYTES(lldpaddr, ETHER_ADDR_LEN);
+       if (memcmp(lldpaddr, (const char [])LLDP_ADDR_NEAREST_BRIDGE, ETHER_ADDR_LEN) &&
+           memcmp(lldpaddr, (const char [])LLDP_ADDR_NEAREST_NONTPMR_BRIDGE, ETHER_ADDR_LEN) &&
+           memcmp(lldpaddr, (const char [])LLDP_ADDR_NEAREST_CUSTOMER_BRIDGE, ETHER_ADDR_LEN)) {
                log_info("lldp", "frame not targeted at LLDP multicast address received on %s",
                    hardware->h_ifname);
                goto malformed;