]> git.ipfire.org Git - thirdparty/lldpd.git/blobdiff - src/lldpd.c
Add a summary of available options in usage() of lldpd and lldpctl
[thirdparty/lldpd.git] / src / lldpd.c
index 14b07d2da77a3453b2648b0f36921680a8afcc8e..ae85a5bdc19500ccefe6ce30bf7ee6ba9f18701c 100644 (file)
 #include <arpa/inet.h>
 #include <net/if_arp.h>
 
+#if LLDPD_FD_SETSIZE != FD_SETSIZE
+# warning "FD_SETSIZE is set to an inconsistent value."
+#endif
+
 #ifdef USE_SNMP
 #include <net-snmp/net-snmp-config.h>
 #include <net-snmp/net-snmp-includes.h>
@@ -95,7 +99,33 @@ extern const char    *__progname;
 static void
 usage(void)
 {
-       fprintf(stderr, "usage: %s [options]\n", __progname);
+       fprintf(stderr, "Usage: %s [OPTIONS ...]\n", __progname);
+
+       fprintf(stderr, "\n");
+
+       fprintf(stderr, "-d       Do not daemonize.\n");
+       fprintf(stderr, "-i       Disable LLDP-MED inventory TLV transmission.\n");
+       fprintf(stderr, "-k       Disable advertising of kernel release, version, machine.\n");
+       fprintf(stderr, "-m IP    Specify the management address of this system.\n");
+       fprintf(stderr, "-M class Enable emission of LLDP-MED frame. 'class' should be one of:\n");
+       fprintf(stderr, "             1 Generic Endpoint (Class I)\n");
+       fprintf(stderr, "             2 Media Endpoint (Class II)\n");
+       fprintf(stderr, "             3 Communication Device Endpoints (Class III)\n");
+       fprintf(stderr, "             4 Network Connectivity Device\n");
+       fprintf(stderr, "-x       Enable SNMP subagent.\n");
+#ifdef ENABLE_LISTENVLAN
+       fprintf(stderr, "-v       Listen on VLAN as well.\n");
+#endif
+       fprintf(stderr, "\n");
+
+       fprintf(stderr, "Protocol support. (Disabled by default)\n");
+       fprintf(stderr, "-c       Enable the support of CDP protocol. (Cisco)\n");
+       fprintf(stderr, "-e       Enable the support of EDP protocol. (Extreme)\n");
+       fprintf(stderr, "-f       Enable the support of FDP protocol. (Foundry)\n");
+       fprintf(stderr, "-s       Enable the support of SONMP protocol. (Nortel)\n");
+
+       fprintf(stderr, "\n");
+
        fprintf(stderr, "see manual page lldpd(8) for more information\n");
        exit(1);
 }
@@ -124,6 +154,7 @@ lldpd_alloc_hardware(struct lldpd *cfg, char *name)
 
        strlcpy(hardware->h_ifname, name, sizeof(hardware->h_ifname));
        hardware->h_lport.p_chassis = LOCAL_CHASSIS(cfg);
+       hardware->h_lport.p_chassis->c_refcount++;
        TAILQ_INIT(&hardware->h_rports);
 
 #ifdef ENABLE_LLDPMED
@@ -158,7 +189,7 @@ lldpd_vlan_cleanup(struct lldpd_port *port)
 /* If `all' is true, clear all information, including information that
    are not refreshed periodically. Port should be freed manually. */
 void
-lldpd_port_cleanup(struct lldpd_port *port, int all)
+lldpd_port_cleanup(struct lldpd *cfg, struct lldpd_port *port, int all)
 {
 #ifdef ENABLE_LLDPMED
        int i;
@@ -173,8 +204,10 @@ lldpd_port_cleanup(struct lldpd_port *port, int all)
        free(port->p_descr);
        if (all) {
                free(port->p_lastframe);
-               if (port->p_chassis) /* chassis may not have been attributed, yet */
+               if (port->p_chassis) /* chassis may not have been attributed, yet */
                        port->p_chassis->c_refcount--;
+                       port->p_chassis = NULL;
+               }
        }
 }
 
@@ -214,7 +247,7 @@ lldpd_remote_cleanup(struct lldpd *cfg, struct lldpd_hardware *hardware, int all
                }
                if (del) {
                        TAILQ_REMOVE(&hardware->h_rports, port, p_entries);
-                       lldpd_port_cleanup(port, 1);
+                       lldpd_port_cleanup(cfg, port, 1);
                        free(port);
                }
        }
@@ -224,7 +257,7 @@ void
 lldpd_hardware_cleanup(struct lldpd *cfg, struct lldpd_hardware *hardware)
 {
        int i;
-       lldpd_port_cleanup(&hardware->h_lport, 1);
+       lldpd_port_cleanup(cfg, &hardware->h_lport, 1);
        /* If we have a dedicated cleanup function, use it. Otherwise,
           we just free the hardware-dependent data and close all FD
           in h_recvfds and h_sendfd. */
@@ -232,7 +265,7 @@ lldpd_hardware_cleanup(struct lldpd *cfg, struct lldpd_hardware *hardware)
                hardware->h_ops->cleanup(cfg, hardware);
        else {
                free(hardware->h_data);
-               for (i=0; i < FD_SETSIZE; i++)
+               for (i=0; i < LLDPD_FD_SETSIZE; i++)
                        if (FD_ISSET(i, &hardware->h_recvfds))
                                close(i);
                if (hardware->h_sendfd) close(hardware->h_sendfd);
@@ -244,6 +277,7 @@ static void
 lldpd_cleanup(struct lldpd *cfg)
 {
        struct lldpd_hardware *hardware, *hardware_next;
+       struct lldpd_chassis *chassis, *chassis_next;
 
        for (hardware = TAILQ_FIRST(&cfg->g_hardware); hardware != NULL;
             hardware = hardware_next) {
@@ -255,6 +289,15 @@ lldpd_cleanup(struct lldpd *cfg)
                } else
                        lldpd_remote_cleanup(cfg, hardware, 0);
        }
+
+       for (chassis = TAILQ_FIRST(&cfg->g_chassis); chassis;
+            chassis = chassis_next) {
+               chassis_next = TAILQ_NEXT(chassis, c_entries);
+               if (chassis->c_refcount == 0) {
+                       TAILQ_REMOVE(&cfg->g_chassis, chassis, c_entries);
+                       lldpd_chassis_cleanup(chassis, 1);
+               }
+       }
 }
 
 static int
@@ -348,7 +391,7 @@ lldpd_decode(struct lldpd *cfg, char *frame, int s,
        if (oport) {
                /* The port is known, remove it before adding it back */
                TAILQ_REMOVE(&hardware->h_rports, oport, p_entries);
-               lldpd_port_cleanup(oport, 1);
+               lldpd_port_cleanup(cfg, oport, 1);
                free(oport);
        }
        if (ochassis) {
@@ -358,7 +401,6 @@ lldpd_decode(struct lldpd *cfg, char *frame, int s,
        } else {
                /* Chassis not known, add it */
                chassis->c_index = ++cfg->g_lastrid;
-               port->p_chassis = chassis;
                chassis->c_refcount = 0;
                TAILQ_INSERT_TAIL(&cfg->g_chassis, chassis, c_entries);
                i = 0; TAILQ_FOREACH(ochassis, &cfg->g_chassis, c_entries) i++;
@@ -374,6 +416,19 @@ lldpd_decode(struct lldpd *cfg, char *frame, int s,
        TAILQ_INSERT_TAIL(&hardware->h_rports, port, p_entries);
        port->p_chassis = chassis;
        port->p_chassis->c_refcount++;
+       /* Several cases are possible :
+            1. chassis is new, its refcount was 0. It is now attached
+               to this port, its refcount is 1.
+            2. chassis already exists and was attached to another
+               port, we increase its refcount accordingly.
+            3. chassis already exists and was attached to the same
+               port, its refcount was decreased with
+               lldpd_port_cleanup() and is now increased again.
+
+          In all cases, if the port already existed, it has been
+          freed with lldpd_port_cleanup() and therefore, the refcount
+          of the chassis that was attached to it is decreased.
+       */
        i = 0; TAILQ_FOREACH(oport, &hardware->h_rports, p_entries) i++;
        LLOG_DEBUG("Currently, %s known %d neighbors",
            hardware->h_ifname, i);
@@ -462,7 +517,7 @@ lldpd_recv_all(struct lldpd *cfg)
                                continue;
                        /* This is quite expensive but we don't rely on internal
                         * structure of fd_set. */
-                       for (n = 0; n < FD_SETSIZE; n++)
+                       for (n = 0; n < LLDPD_FD_SETSIZE; n++)
                                if (FD_ISSET(n, &hardware->h_recvfds)) {
                                        FD_SET(n, &rfds);
                                        if (nfds < n)
@@ -500,10 +555,10 @@ lldpd_recv_all(struct lldpd *cfg)
                }
 #endif /* USE_SNMP */
                TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries) {
-                       for (n = 0; n < FD_SETSIZE; n++)
+                       for (n = 0; n < LLDPD_FD_SETSIZE; n++)
                                if ((FD_ISSET(n, &hardware->h_recvfds)) &&
                                    (FD_ISSET(n, &rfds))) break;
-                       if (n == FD_SETSIZE) continue;
+                       if (n == LLDPD_FD_SETSIZE) continue;
                        if ((buffer = (char *)malloc(
                                        hardware->h_mtu)) == NULL) {
                                LLOG_WARN("failed to alloc reception buffer");
@@ -744,13 +799,14 @@ lldpd_main(int argc, char *argv[])
        int ch, debug = 0;
 #ifdef USE_SNMP
        int snmp = 0;
+       char *agentx = NULL;    /* AgentX socket */
 #endif
        char *mgmtp = NULL;
        char *popt, opts[] = 
 #ifdef ENABLE_LISTENVLAN
                "v"
 #endif
-               "kdxm:p:M:i@                    ";
+               "kdxX:m:p:M:i@                    ";
        int i, found, advertise_version = 1;
 #ifdef ENABLE_LISTENVLAN
        int vlan = 0;
@@ -805,10 +861,17 @@ lldpd_main(int argc, char *argv[])
                        usage();
                        break;
 #endif
-               case 'x':
 #ifdef USE_SNMP
+               case 'x':
                        snmp = 1;
+                       break;
+               case 'X':
+                       snmp = 1;
+                       agentx = optarg;
+                       break;
 #else
+               case 'x':
+               case 'X':
                        fprintf(stderr, "SNMP support is not built-in\n");
                        usage();
 #endif
@@ -828,6 +891,7 @@ lldpd_main(int argc, char *argv[])
        }
        
        log_init(debug, __progname);
+       tzset();                /* Get timezone info before chroot */
 
        if (!debug) {
                int pid;
@@ -893,14 +957,14 @@ lldpd_main(int argc, char *argv[])
        TAILQ_INIT(&cfg->g_hardware);
        TAILQ_INIT(&cfg->g_chassis);
        TAILQ_INSERT_TAIL(&cfg->g_chassis, lchassis, c_entries);
-       lchassis->c_refcount++;
+       lchassis->c_refcount++; /* We should always keep a reference to local chassis */
 
        TAILQ_INIT(&cfg->g_callbacks);
 
 #ifdef USE_SNMP
        if (snmp) {
                cfg->g_snmp = 1;
-               agent_init(cfg, debug);
+               agent_init(cfg, agentx, debug);
        }
 #endif /* USE_SNMP */