]> git.ipfire.org Git - thirdparty/lldpd.git/commitdiff
Change the way interface information are collected.
authorVincent Bernat <bernat@luffy.cx>
Tue, 2 Jun 2009 07:56:25 +0000 (09:56 +0200)
committerVincent Bernat <bernat@luffy.cx>
Tue, 2 Jun 2009 08:47:14 +0000 (10:47 +0200)
Move interface related stuff into interfaces.c.
A set of handlers are called sequentially to handle interfaces.

12 files changed:
src/Makefile.am
src/agent.c
src/cdp.c
src/dmi.c [new file with mode: 0644]
src/edp.c
src/features.c [deleted file]
src/interfaces.c [new file with mode: 0644]
src/lldp.c
src/lldpd.c
src/lldpd.h
src/priv.c
src/sonmp.c

index 2829b54f698dd427747c31fd6d1526d86d35d69c..0d267199f1858199f3c778ccf94eed6728435164 100644 (file)
@@ -1,7 +1,7 @@
 sbin_PROGRAMS = lldpd lldpctl
 
 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)
+lldpd_SOURCES = frame.h frame.c lldpd.c lldp.c cdp.c sonmp.c edp.c interfaces.c client.c priv.c privsep_fdpass.c dmi.c $(COMMON)
 lldpctl_SOURCES = lldpctl.c $(COMMON)
 
 lldpd_LDADD = @LIBOBJS@
index bb9178dc997e27aa53cee8e667ad96c5885f608d..01b50a18216c86d04d99def528c3efaa6fd67d1e 100644 (file)
@@ -56,18 +56,16 @@ header_portindexed_table(struct variable *vp, oid *name, size_t *length,
        port = name[*length - 1];
        distance = -1;
        TAILQ_FOREACH(hardware, &scfg->g_hardware, h_entries) {
-               if (INTERFACE_OPENED(hardware)) {
-                       aport = if_nametoindex(hardware->h_ifname);
-                       if (aport == port) {
-                                /* Exact match */
-                                return hardware;
-                       }
-                       if (aport < port)
-                               continue;
-                       if (aport - port < distance) {
-                               phardware = hardware;
-                               distance = aport - port;
-                       }
+               aport = hardware->h_ifindex;
+               if (aport == port) {
+                       /* Exact match */
+                       return hardware;
+               }
+               if (aport < port)
+                       continue;
+               if (aport - port < distance) {
+                       phardware = hardware;
+                       distance = aport - port;
                }
        }
        if (phardware == NULL)
@@ -119,7 +117,6 @@ header_tprindexed_table(struct variable *vp, oid *name, size_t *length,
         target = &name[vp->namelen];
         target_len = *length - vp->namelen;
        TAILQ_FOREACH(hardware, &scfg->g_hardware, h_entries) {
-               if (!INTERFACE_OPENED(hardware)) continue;
                TAILQ_FOREACH(port, &hardware->h_rports, p_entries) {
                         if ((variant == TPR_VARIANT_IP) &&
                             (port->p_chassis->c_mgmt.s_addr == INADDR_ANY))
@@ -129,7 +126,7 @@ header_tprindexed_table(struct variable *vp, oid *name, size_t *length,
                                    (port->p_lastchange - starttime.tv_sec)*100;
                        else
                                current[0] = 0;
-                        current[1] = if_nametoindex(hardware->h_ifname);
+                        current[1] = hardware->h_ifindex;
                         current[2] = port->p_chassis->c_index;
                        k = j = 0;
                        switch (variant) {
@@ -206,22 +203,20 @@ header_pvindexed_table(struct variable *vp, oid *name, size_t *length,
         target = &name[vp->namelen];
         target_len = *length - vp->namelen;
        TAILQ_FOREACH(hardware, &scfg->g_hardware, h_entries) {
-               if (INTERFACE_OPENED(hardware)) {
-                        TAILQ_FOREACH(vlan, &hardware->h_lport.p_vlans, v_entries) {
-                                current[0] = if_nametoindex(hardware->h_ifname);
-                                current[1] = vlan->v_vid;
-                                if ((result = snmp_oid_compare(current, 2, target,
-                                            target_len)) < 0)
-                                        continue;
-                                if ((result == 0) && !exact)
-                                        continue;
-                                if (result == 0)
-                                        return vlan;
-                                if (snmp_oid_compare(current, 2, best, 2) < 0) {
-                                        memcpy(best, current, sizeof(oid) * 2);
-                                        pvlan = vlan;
-                                }
-                        }
+               TAILQ_FOREACH(vlan, &hardware->h_lport.p_vlans, v_entries) {
+                       current[0] = hardware->h_ifindex;
+                       current[1] = vlan->v_vid;
+                       if ((result = snmp_oid_compare(current, 2, target,
+                                   target_len)) < 0)
+                               continue;
+                       if ((result == 0) && !exact)
+                               continue;
+                       if (result == 0)
+                               return vlan;
+                       if (snmp_oid_compare(current, 2, best, 2) < 0) {
+                               memcpy(best, current, sizeof(oid) * 2);
+                               pvlan = vlan;
+                       }
                }
        }
        if (pvlan == NULL)
@@ -259,7 +254,6 @@ header_tprvindexed_table(struct variable *vp, oid *name, size_t *length,
         target = &name[vp->namelen];
         target_len = *length - vp->namelen;
        TAILQ_FOREACH(hardware, &scfg->g_hardware, h_entries) {
-               if (!INTERFACE_OPENED(hardware)) continue;
                TAILQ_FOREACH(port, &hardware->h_rports, p_entries) {
                         TAILQ_FOREACH(vlan, &port->p_vlans, v_entries) {
                                if (port->p_lastchange > starttime.tv_sec)
@@ -267,7 +261,7 @@ header_tprvindexed_table(struct variable *vp, oid *name, size_t *length,
                                            (port->p_lastchange - starttime.tv_sec)*100;
                                else
                                        current[0] = 0;
-                                current[1] = if_nametoindex(hardware->h_ifname);
+                                current[1] = hardware->h_ifindex;
                                 current[2] = port->p_chassis->c_index;
                                 current[3] = vlan->v_vid;
                                 if ((result = snmp_oid_compare(current, 4, target,
index 8d804a0d72be772624b2fac20944187a57111058..e3c18ffafffe505a9901b77dc0f148bd56a79b70 100644 (file)
--- a/src/cdp.c
+++ b/src/cdp.c
@@ -165,7 +165,8 @@ cdp_send(struct lldpd *global,
        POKE_RESTORE(pos_checksum);
        if (!(POKE_UINT16(ntohs(checksum)))) goto toobig;
 
-       if (write(hardware->h_raw, packet, end - packet) == -1) {
+       if (hardware->h_ops->send(global, hardware,
+               (char *)packet, end - packet) == -1) {
                LLOG_WARN("unable to send packet on real device for %s",
                           hardware->h_ifname);
                free(packet);
diff --git a/src/dmi.c b/src/dmi.c
new file mode 100644 (file)
index 0000000..ccef56d
--- /dev/null
+++ b/src/dmi.c
@@ -0,0 +1,92 @@
+/*
+ * 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.
+ */
+
+#define INCLUDE_LINUX_IF_H
+#include "lldpd.h"
+#include <unistd.h>
+
+#ifdef ENABLE_LLDPMED
+       /* Fill in inventory stuff:
+           - hardware version: /sys/class/dmi/id/product_version
+           - firmware version: /sys/class/dmi/id/bios_version
+           - software version: `uname -r`
+           - serial number: /sys/class/dmi/id/product_serial
+           - manufacturer: /sys/class/dmi/id/sys_vendor
+           - model: /sys/class/dmi/id/product_name
+           - asset: /sys/class/dmi/id/chassis_asset_tag
+       */
+
+char*
+dmi_get(char *file)
+{
+       int dmi, s;
+       char buffer[100];
+       
+       if ((dmi = priv_open(file)) < 0) {
+               LLOG_DEBUG("cannot get DMI file %s", file);
+               return NULL;
+       }
+       memset(buffer, 0, sizeof(buffer));
+       if ((s = read(dmi, buffer, sizeof(buffer))) == -1) {
+               LLOG_DEBUG("cannot read DMI file %s", file);
+               close(dmi);
+               return NULL;
+       }
+       close(dmi);
+       buffer[sizeof(buffer) - 1] = '\0';
+       if ((s > 0) && (buffer[s-1] == '\n'))
+               buffer[s-1] = '\0';
+       if (strlen(buffer))
+               return strdup(buffer);
+       return NULL;
+}
+
+char*
+dmi_hw()
+{
+       return dmi_get(SYSFS_CLASS_DMI "product_version");
+}
+
+char*
+dmi_fw()
+{
+       return dmi_get(SYSFS_CLASS_DMI "bios_version");
+}
+
+char*
+dmi_sn()
+{
+       return dmi_get(SYSFS_CLASS_DMI "product_serial");
+}
+
+char*
+dmi_manuf()
+{
+       return dmi_get(SYSFS_CLASS_DMI "sys_vendor");
+}
+
+char*
+dmi_model()
+{
+       return dmi_get(SYSFS_CLASS_DMI "product_name");
+}
+
+char*
+dmi_asset()
+{
+       return dmi_get(SYSFS_CLASS_DMI "chassis_asset_tag");
+}
+#endif
index 7844f24730c28d04eed060de8505cb027885a002..b9197ed36f1e10f55ac8896565d082131d090d8e 100644 (file)
--- a/src/edp.c
+++ b/src/edp.c
@@ -135,7 +135,7 @@ edp_send(struct lldpd *global,
                        if (deviceslot[i] == NULL) {
                                if (!(
                                      POKE_UINT16(8) &&
-                                     POKE_UINT16(if_nametoindex(hardware->h_ifname))))
+                                     POKE_UINT16(hardware->h_ifindex)))
                                        goto toobig;
                        }
                        if (!(
@@ -194,7 +194,8 @@ edp_send(struct lldpd *global,
                checksum = frame_checksum(pos_edp, v, 0);
                if (!(POKE_UINT16(ntohs(checksum)))) goto toobig;
 
-               if (write(hardware->h_raw, packet, end - packet) == -1) {
+               if (hardware->h_ops->send(global, hardware,
+                       (char *)packet, end - packet) == -1) {
                        LLOG_WARN("unable to send packet on real device for %s",
                            hardware->h_ifname);
                        free(packet);
diff --git a/src/features.c b/src/features.c
deleted file mode 100644 (file)
index fe988b5..0000000
+++ /dev/null
@@ -1,396 +0,0 @@
-/*
- * 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.
- */
-
-#define INCLUDE_LINUX_IF_H
-#include "lldpd.h"
-
-#include <stdio.h>
-#include <unistd.h>
-#include <errno.h>
-#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <arpa/inet.h>
-#include <ifaddrs.h>
-#include <net/if_arp.h>
-#include <linux/if_vlan.h>
-#include <linux/if_bonding.h>
-#include <linux/if_bridge.h>
-#include <linux/wireless.h>
-#include <linux/sockios.h>
-
-#define SYSFS_PATH_MAX 256
-#define MAX_PORTS 1024
-#define MAX_BRIDGES 1024
-
-/* net/if.h */
-extern unsigned int if_nametoindex (__const char *__ifname) __THROW;
-extern char *if_indextoname (unsigned int __ifindex, char *__ifname) __THROW;
-
-static int
-old_iface_is_bridge(struct lldpd *cfg, const char *name)
-{
-       int ifindices[MAX_BRIDGES];
-       char ifname[IFNAMSIZ];
-       int num, i;
-       unsigned long args[3] = { BRCTL_GET_BRIDGES,
-                                 (unsigned long)ifindices, MAX_BRIDGES };
-       if ((num = ioctl(cfg->g_sock, SIOCGIFBR, args)) < 0) {
-               if (errno != ENOPKG)
-                       LLOG_INFO("unable to get available bridges");
-               return 0;
-       }
-       for (i = 0; i < num; i++) {
-               if (if_indextoname(ifindices[i], ifname) == NULL)
-                       LLOG_INFO("unable to get name of interface %d",
-                           ifindices[i]);
-               else if (strncmp(name, ifname, IFNAMSIZ) == 0)
-                       return 1;
-       }
-       return 0;
-}
-
-int
-iface_is_bridge(struct lldpd *cfg, const char *name)
-{
-       char path[SYSFS_PATH_MAX];
-       int f;
-
-       if ((snprintf(path, SYSFS_PATH_MAX,
-                   SYSFS_CLASS_NET "%s/" SYSFS_BRIDGE_FDB, name)) >= SYSFS_PATH_MAX)
-               LLOG_WARNX("path truncated");
-       if ((f = priv_open(path)) < 0) {
-               return old_iface_is_bridge(cfg, name);
-       }
-       close(f);
-       return 1;
-}
-
-static int
-old_iface_is_bridged_to(struct lldpd *cfg, const char *slave, const char *master)
-{
-       int j, index = if_nametoindex(slave);
-       int ifptindices[MAX_PORTS];
-       unsigned long args2[4] = { BRCTL_GET_PORT_LIST,
-                                  (unsigned long)ifptindices, MAX_PORTS, 0 };
-       struct ifreq ifr;
-
-       strncpy(ifr.ifr_name, master, IFNAMSIZ);
-       memset(ifptindices, 0, sizeof(ifptindices));
-       ifr.ifr_data = (char *)&args2;
-
-       if (ioctl(cfg->g_sock, SIOCDEVPRIVATE, &ifr) < 0) {
-               LLOG_WARN("unable to get bridge members for %s",
-                   ifr.ifr_name);
-               return 0;
-       }
-
-       for (j = 0; j < MAX_PORTS; j++) {
-               if (ifptindices[j] == index)
-                       return 1;
-       }
-
-       return 0;
-}
-
-int
-iface_is_bridged_to(struct lldpd *cfg, const char *slave, const char *master)
-{
-       char path[SYSFS_PATH_MAX];
-       int f;
-
-       /* Master should be a bridge, first */
-       if (!iface_is_bridge(cfg, master)) return 0;
-
-       if (snprintf(path, SYSFS_PATH_MAX,
-               SYSFS_CLASS_NET "%s/" SYSFS_BRIDGE_PORT_SUBDIR "/%s/port_no",
-               master, slave) >= SYSFS_PATH_MAX)
-               LLOG_WARNX("path truncated");
-       if ((f = priv_open(path)) < 0) {
-               return old_iface_is_bridged_to(cfg, slave, master);
-       }
-       close(f);
-       return 1;
-}
-
-int
-iface_is_vlan(struct lldpd *cfg, const char *name)
-{
-       struct vlan_ioctl_args ifv;
-       memset(&ifv, 0, sizeof(ifv));
-       ifv.cmd = GET_VLAN_REALDEV_NAME_CMD;
-       if ((strlcpy(ifv.device1, name, sizeof(ifv.device1))) >=
-           sizeof(ifv.device1))
-               LLOG_WARNX("device name truncated");
-       if (ioctl(cfg->g_sock, SIOCGIFVLAN, &ifv) >= 0)
-               return 1;
-       return 0;
-}
-
-int
-iface_is_wireless(struct lldpd *cfg, const char *name)
-{
-       struct iwreq iwr;
-       strlcpy(iwr.ifr_name, name, IFNAMSIZ);
-       if (ioctl(cfg->g_sock, SIOCGIWNAME, &iwr) >= 0)
-               return 1;
-       return 0;
-}
-
-int
-iface_is_bond(struct lldpd *cfg, const char *name)
-{
-       struct ifreq ifr;
-       struct ifbond ifb;
-       memset(&ifr, 0, sizeof(ifr));
-       memset(&ifb, 0, sizeof(ifb));
-       strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
-       ifr.ifr_data = &ifb;
-       if (ioctl(cfg->g_sock, SIOCBONDINFOQUERY, &ifr) >= 0)
-               return 1;
-       return 0;
-}
-
-int
-iface_is_bond_slave(struct lldpd *cfg, const char *slave, const char *master,
-    int *active)
-{
-       struct ifreq ifr;
-       struct ifbond ifb;
-       struct ifslave ifs;
-       memset(&ifr, 0, sizeof(ifr));
-       memset(&ifb, 0, sizeof(ifb));
-       strlcpy(ifr.ifr_name, master, sizeof(ifr.ifr_name));
-       ifr.ifr_data = &ifb;
-       if (ioctl(cfg->g_sock, SIOCBONDINFOQUERY, &ifr) >= 0) {
-               while (ifb.num_slaves--) {
-                       memset(&ifr, 0, sizeof(ifr));
-                       memset(&ifs, 0, sizeof(ifs));
-                       strlcpy(ifr.ifr_name, master, sizeof(ifr.ifr_name));
-                       ifr.ifr_data = &ifs;
-                       ifs.slave_id = ifb.num_slaves;
-                       if ((ioctl(cfg->g_sock, SIOCBONDSLAVEINFOQUERY, &ifr) >= 0) &&
-                           (strncmp(ifs.slave_name, slave, sizeof(ifs.slave_name)) == 0)) {
-                               if (active)
-                                       *active = ifs.state;
-                               return 1;
-                       }
-               }
-       }
-       return 0;
-}
-
-int
-iface_is_enslaved(struct lldpd *cfg, const char *name)
-{
-       struct ifaddrs *ifap, *ifa;
-       int master;
-
-       if (getifaddrs(&ifap) != 0) {
-               LLOG_WARN("unable to get interface list");
-               return -1;
-       }
-       for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
-               if (iface_is_bond_slave(cfg, name, ifa->ifa_name, NULL)) {
-                       master = if_nametoindex(ifa->ifa_name);
-                       freeifaddrs(ifap);
-                       return master;
-               }
-       }
-       freeifaddrs(ifap);
-       return -1;
-}
-
-int
-iface_is_slave_active(struct lldpd *cfg, int master, const char *slave)
-{
-       char mastername[IFNAMSIZ];
-       int active;
-       if (if_indextoname(master, mastername) == NULL) {
-               LLOG_WARNX("unable to get master name for %s",
-                   slave);
-               return 0;       /* Safest choice */
-       }
-       if (!iface_is_bond_slave(cfg, slave, mastername, &active)) {
-               LLOG_WARNX("unable to get slave status for %s",
-                   slave);
-               return 0;               /* Safest choice */
-       }
-       return (active == BOND_STATE_ACTIVE);
-}
-
-void
-iface_get_permanent_mac(struct lldpd *cfg, struct lldpd_hardware *hardware)
-{
-       int master, f, state = 0;
-       FILE *netbond;
-       const char *slaveif = "Slave Interface: ";
-       const char *hwaddr = "Permanent HW addr: ";
-       u_int8_t mac[ETHER_ADDR_LEN];
-       char bond[IFNAMSIZ];
-       char path[SYSFS_PATH_MAX];
-       char line[100];
-       if ((master = iface_is_enslaved(cfg, hardware->h_ifname)) == -1)
-               return;
-       /* We have a bond, we need to query it to get real MAC addresses */
-       if ((if_indextoname(master, bond)) == NULL) {
-               LLOG_WARNX("unable to get bond name");
-               return;
-       }
-
-       if (snprintf(path, SYSFS_PATH_MAX, "/proc/net/bonding/%s",
-               bond) >= SYSFS_PATH_MAX) {
-               LLOG_WARNX("path truncated");
-               return;
-       }
-       if ((f = priv_open(path)) < 0) {
-               if (snprintf(path, SYSFS_PATH_MAX, "/proc/self/net/bonding/%s",
-                       bond) >= SYSFS_PATH_MAX) {
-                       LLOG_WARNX("path truncated");
-                       return;
-               }
-               f = priv_open(path);
-       }
-       if (f < 0) {
-               LLOG_WARNX("unable to find %s in /proc/net/bonding or /proc/self/net/bonding",
-                   bond);
-               return;
-       }
-       if ((netbond = fdopen(f, "r")) == NULL) {
-               LLOG_WARN("unable to read stream from %s", path);
-               close(f);
-               return;
-       }
-       /* State 0:
-            We parse the file to search "Slave Interface: ". If found, go to
-            state 1.
-          State 1:
-            We parse the file to search "Permanent HW addr: ". If found, we get
-            the mac.
-       */
-       while (fgets(line, sizeof(line), netbond)) {
-               switch (state) {
-               case 0:
-                       if (strncmp(line, slaveif, strlen(slaveif)) == 0) {
-                               if (line[strlen(line)-1] == '\n')
-                                       line[strlen(line)-1] = '\0';
-                               if (strncmp(hardware->h_ifname,
-                                       line + strlen(slaveif),
-                                       sizeof(hardware->h_ifname)) == 0)
-                                       state++;
-                       }
-                       break;
-               case 1:
-                       if (strncmp(line, hwaddr, strlen(hwaddr)) == 0) {
-                               if (line[strlen(line)-1] == '\n')
-                                       line[strlen(line)-1] = '\0';
-                               if (sscanf(line + strlen(hwaddr),
-                                       "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
-                                       &mac[0], &mac[1], &mac[2],
-                                       &mac[3], &mac[4], &mac[5]) !=
-                                   ETHER_ADDR_LEN) {
-                                       LLOG_WARN("unable to parse %s",
-                                           line + strlen(hwaddr));
-                                       fclose(netbond);
-                                       return;
-                               }
-                               memcpy(hardware->h_lladdr, mac,
-                                   ETHER_ADDR_LEN);
-                               fclose(netbond);
-                               return;
-                       }
-                       break;
-               }
-       }
-       LLOG_WARNX("unable to find real mac address for %s",
-           bond);
-       fclose(netbond);
-}
-
-
-#ifdef ENABLE_LLDPMED
-       /* Fill in inventory stuff:
-           - hardware version: /sys/class/dmi/id/product_version
-           - firmware version: /sys/class/dmi/id/bios_version
-           - software version: `uname -r`
-           - serial number: /sys/class/dmi/id/product_serial
-           - manufacturer: /sys/class/dmi/id/sys_vendor
-           - model: /sys/class/dmi/id/product_name
-           - asset: /sys/class/dmi/id/chassis_asset_tag
-       */
-
-char*
-dmi_get(char *file)
-{
-       int dmi, s;
-       char buffer[100];
-       
-       if ((dmi = priv_open(file)) < 0) {
-               LLOG_DEBUG("cannot get DMI file %s", file);
-               return NULL;
-       }
-       memset(buffer, 0, sizeof(buffer));
-       if ((s = read(dmi, buffer, sizeof(buffer))) == -1) {
-               LLOG_DEBUG("cannot read DMI file %s", file);
-               close(dmi);
-               return NULL;
-       }
-       close(dmi);
-       buffer[sizeof(buffer) - 1] = '\0';
-       if ((s > 0) && (buffer[s-1] == '\n'))
-               buffer[s-1] = '\0';
-       if (strlen(buffer))
-               return strdup(buffer);
-       return NULL;
-}
-
-char*
-dmi_hw()
-{
-       return dmi_get(SYSFS_CLASS_DMI "product_version");
-}
-
-char*
-dmi_fw()
-{
-       return dmi_get(SYSFS_CLASS_DMI "bios_version");
-}
-
-char*
-dmi_sn()
-{
-       return dmi_get(SYSFS_CLASS_DMI "product_serial");
-}
-
-char*
-dmi_manuf()
-{
-       return dmi_get(SYSFS_CLASS_DMI "sys_vendor");
-}
-
-char*
-dmi_model()
-{
-       return dmi_get(SYSFS_CLASS_DMI "product_name");
-}
-
-char*
-dmi_asset()
-{
-       return dmi_get(SYSFS_CLASS_DMI "chassis_asset_tag");
-}
-#endif
diff --git a/src/interfaces.c b/src/interfaces.c
new file mode 100644 (file)
index 0000000..a4ea3fd
--- /dev/null
@@ -0,0 +1,750 @@
+/*
+ * 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.
+ */
+
+#define INCLUDE_LINUX_IF_H
+#include "lldpd.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <fnmatch.h>
+#include <arpa/inet.h>
+#include <ifaddrs.h>
+#include <net/if_arp.h>
+#include <linux/if_vlan.h>
+#include <linux/if_bonding.h>
+#include <linux/if_bridge.h>
+#include <linux/wireless.h>
+#include <linux/sockios.h>
+#include <linux/filter.h>
+#include <linux/if_vlan.h>
+#include <linux/if_packet.h>
+
+#define SYSFS_PATH_MAX 256
+#define MAX_PORTS 1024
+#define MAX_BRIDGES 1024
+
+/* BPF filter to get revelant information from interfaces */
+/* LLDP: "ether proto 0x88cc and ether dst 01:80:c2:00:00:0e" */
+/* FDP: "ether dst 01:e0:52:cc:cc:cc" */
+/* CDP: "ether dst 01:00:0c:cc:cc:cc" */
+/* SONMP: "ether dst 01:00:81:00:01:00" */
+/* EDP: "ether dst 00:e0:2b:00:00:00" */
+#define LLDPD_FILTER_F                 \
+       { 0x28, 0, 0, 0x0000000c },     \
+       { 0x15, 0, 4, 0x000088cc },     \
+       { 0x20, 0, 0, 0x00000002 },     \
+       { 0x15, 0, 2, 0xc200000e },     \
+       { 0x28, 0, 0, 0x00000000 },     \
+       { 0x15, 11, 12, 0x00000180 },   \
+       { 0x20, 0, 0, 0x00000002 },     \
+       { 0x15, 0, 2, 0x2b000000 },     \
+       { 0x28, 0, 0, 0x00000000 },     \
+       { 0x15, 7, 8, 0x000000e0 },     \
+       { 0x15, 1, 0, 0x0ccccccc },     \
+       { 0x15, 0, 2, 0x81000100 },     \
+       { 0x28, 0, 0, 0x00000000 },     \
+       { 0x15, 3, 4, 0x00000100 },     \
+       { 0x15, 0, 3, 0x52cccccc },     \
+       { 0x28, 0, 0, 0x00000000 },     \
+       { 0x15, 0, 1, 0x000001e0 },     \
+       { 0x6, 0, 0, 0x0000ffff },      \
+       { 0x6, 0, 0, 0x00000000 },
+static struct sock_filter lldpd_filter_f[] = { LLDPD_FILTER_F };
+
+/* net/if.h */
+extern unsigned int if_nametoindex (__const char *__ifname) __THROW;
+extern char *if_indextoname (unsigned int __ifindex, char *__ifname) __THROW;
+
+static int      iface_is_bridge(struct lldpd *, const char *);
+static int      iface_is_bridged_to(struct lldpd *,
+    const char *, const char *);
+static int      iface_is_wireless(struct lldpd *, const char *);
+static int      iface_is_vlan(struct lldpd *, const char *);
+static int      iface_is_bond(struct lldpd *, const char *);
+static int      iface_is_bond_slave(struct lldpd *,
+    const char *, const char *, int *);
+static int      iface_is_enslaved(struct lldpd *, const char *);
+#if 0
+static int      iface_is_slave_active(struct lldpd *, int, const char *);
+#endif
+static void     iface_get_permanent_mac(struct lldpd *, struct lldpd_hardware *);
+
+static void     iface_macphy(struct lldpd_hardware *);
+static void     iface_mtu(struct lldpd *, struct lldpd_hardware *);
+static void     iface_multicast(struct lldpd *, const char *, int);
+static int      iface_eth_init(struct lldpd *, struct lldpd_hardware *);
+
+static int      iface_eth_send(struct lldpd *, struct lldpd_hardware*, char *, size_t);
+static int      iface_eth_recv(struct lldpd *, struct lldpd_hardware*, int, char*, size_t);
+static int      iface_eth_close(struct lldpd *, struct lldpd_hardware *);
+struct lldpd_ops eth_ops = {
+       .send = iface_eth_send,
+       .recv = iface_eth_recv,
+       .cleanup = iface_eth_close,
+};
+
+static int
+old_iface_is_bridge(struct lldpd *cfg, const char *name)
+{
+       int ifindices[MAX_BRIDGES];
+       char ifname[IFNAMSIZ];
+       int num, i;
+       unsigned long args[3] = { BRCTL_GET_BRIDGES,
+                                 (unsigned long)ifindices, MAX_BRIDGES };
+       if ((num = ioctl(cfg->g_sock, SIOCGIFBR, args)) < 0) {
+               if (errno != ENOPKG)
+                       LLOG_INFO("unable to get available bridges");
+               return 0;
+       }
+       for (i = 0; i < num; i++) {
+               if (if_indextoname(ifindices[i], ifname) == NULL)
+                       LLOG_INFO("unable to get name of interface %d",
+                           ifindices[i]);
+               else if (strncmp(name, ifname, IFNAMSIZ) == 0)
+                       return 1;
+       }
+       return 0;
+}
+
+static int
+iface_is_bridge(struct lldpd *cfg, const char *name)
+{
+       char path[SYSFS_PATH_MAX];
+       int f;
+
+       if ((snprintf(path, SYSFS_PATH_MAX,
+                   SYSFS_CLASS_NET "%s/" SYSFS_BRIDGE_FDB, name)) >= SYSFS_PATH_MAX)
+               LLOG_WARNX("path truncated");
+       if ((f = priv_open(path)) < 0) {
+               return old_iface_is_bridge(cfg, name);
+       }
+       close(f);
+       return 1;
+}
+
+static int
+old_iface_is_bridged_to(struct lldpd *cfg, const char *slave, const char *master)
+{
+       int j, index = if_nametoindex(slave);
+       int ifptindices[MAX_PORTS];
+       unsigned long args2[4] = { BRCTL_GET_PORT_LIST,
+                                  (unsigned long)ifptindices, MAX_PORTS, 0 };
+       struct ifreq ifr;
+
+       strncpy(ifr.ifr_name, master, IFNAMSIZ);
+       memset(ifptindices, 0, sizeof(ifptindices));
+       ifr.ifr_data = (char *)&args2;
+
+       if (ioctl(cfg->g_sock, SIOCDEVPRIVATE, &ifr) < 0) {
+               LLOG_WARN("unable to get bridge members for %s",
+                   ifr.ifr_name);
+               return 0;
+       }
+
+       for (j = 0; j < MAX_PORTS; j++) {
+               if (ifptindices[j] == index)
+                       return 1;
+       }
+
+       return 0;
+}
+
+static int
+iface_is_bridged_to(struct lldpd *cfg, const char *slave, const char *master)
+{
+       char path[SYSFS_PATH_MAX];
+       int f;
+
+       /* Master should be a bridge, first */
+       if (!iface_is_bridge(cfg, master)) return 0;
+
+       if (snprintf(path, SYSFS_PATH_MAX,
+               SYSFS_CLASS_NET "%s/" SYSFS_BRIDGE_PORT_SUBDIR "/%s/port_no",
+               master, slave) >= SYSFS_PATH_MAX)
+               LLOG_WARNX("path truncated");
+       if ((f = priv_open(path)) < 0) {
+               return old_iface_is_bridged_to(cfg, slave, master);
+       }
+       close(f);
+       return 1;
+}
+
+static int
+iface_is_vlan(struct lldpd *cfg, const char *name)
+{
+       struct vlan_ioctl_args ifv;
+       memset(&ifv, 0, sizeof(ifv));
+       ifv.cmd = GET_VLAN_REALDEV_NAME_CMD;
+       if ((strlcpy(ifv.device1, name, sizeof(ifv.device1))) >=
+           sizeof(ifv.device1))
+               LLOG_WARNX("device name truncated");
+       if (ioctl(cfg->g_sock, SIOCGIFVLAN, &ifv) >= 0)
+               return 1;
+       return 0;
+}
+
+static int
+iface_is_wireless(struct lldpd *cfg, const char *name)
+{
+       struct iwreq iwr;
+       strlcpy(iwr.ifr_name, name, IFNAMSIZ);
+       if (ioctl(cfg->g_sock, SIOCGIWNAME, &iwr) >= 0)
+               return 1;
+       return 0;
+}
+
+static int
+iface_is_bond(struct lldpd *cfg, const char *name)
+{
+       struct ifreq ifr;
+       struct ifbond ifb;
+       memset(&ifr, 0, sizeof(ifr));
+       memset(&ifb, 0, sizeof(ifb));
+       strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+       ifr.ifr_data = &ifb;
+       if (ioctl(cfg->g_sock, SIOCBONDINFOQUERY, &ifr) >= 0)
+               return 1;
+       return 0;
+}
+
+static int
+iface_is_bond_slave(struct lldpd *cfg, const char *slave, const char *master,
+    int *active)
+{
+       struct ifreq ifr;
+       struct ifbond ifb;
+       struct ifslave ifs;
+       memset(&ifr, 0, sizeof(ifr));
+       memset(&ifb, 0, sizeof(ifb));
+       strlcpy(ifr.ifr_name, master, sizeof(ifr.ifr_name));
+       ifr.ifr_data = &ifb;
+       if (ioctl(cfg->g_sock, SIOCBONDINFOQUERY, &ifr) >= 0) {
+               while (ifb.num_slaves--) {
+                       memset(&ifr, 0, sizeof(ifr));
+                       memset(&ifs, 0, sizeof(ifs));
+                       strlcpy(ifr.ifr_name, master, sizeof(ifr.ifr_name));
+                       ifr.ifr_data = &ifs;
+                       ifs.slave_id = ifb.num_slaves;
+                       if ((ioctl(cfg->g_sock, SIOCBONDSLAVEINFOQUERY, &ifr) >= 0) &&
+                           (strncmp(ifs.slave_name, slave, sizeof(ifs.slave_name)) == 0)) {
+                               if (active)
+                                       *active = ifs.state;
+                               return 1;
+                       }
+               }
+       }
+       return 0;
+}
+
+static int
+iface_is_enslaved(struct lldpd *cfg, const char *name)
+{
+       struct ifaddrs *ifap, *ifa;
+       int master;
+
+       if (getifaddrs(&ifap) != 0) {
+               LLOG_WARN("unable to get interface list");
+               return -1;
+       }
+       for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
+               if (iface_is_bond_slave(cfg, name, ifa->ifa_name, NULL)) {
+                       master = if_nametoindex(ifa->ifa_name);
+                       freeifaddrs(ifap);
+                       return master;
+               }
+       }
+       freeifaddrs(ifap);
+       return -1;
+}
+
+#if 0
+static int
+iface_is_slave_active(struct lldpd *cfg, int master, const char *slave)
+{
+       char mastername[IFNAMSIZ];
+       int active;
+       if (if_indextoname(master, mastername) == NULL) {
+               LLOG_WARNX("unable to get master name for %s",
+                   slave);
+               return 0;       /* Safest choice */
+       }
+       if (!iface_is_bond_slave(cfg, slave, mastername, &active)) {
+               LLOG_WARNX("unable to get slave status for %s",
+                   slave);
+               return 0;               /* Safest choice */
+       }
+       return (active == BOND_STATE_ACTIVE);
+}
+#endif
+
+static void
+iface_get_permanent_mac(struct lldpd *cfg, struct lldpd_hardware *hardware)
+{
+       int master, f, state = 0;
+       FILE *netbond;
+       const char *slaveif = "Slave Interface: ";
+       const char *hwaddr = "Permanent HW addr: ";
+       u_int8_t mac[ETHER_ADDR_LEN];
+       char bond[IFNAMSIZ];
+       char path[SYSFS_PATH_MAX];
+       char line[100];
+       if ((master = iface_is_enslaved(cfg, hardware->h_ifname)) == -1)
+               return;
+       /* We have a bond, we need to query it to get real MAC addresses */
+       if ((if_indextoname(master, bond)) == NULL) {
+               LLOG_WARNX("unable to get bond name");
+               return;
+       }
+
+       if (snprintf(path, SYSFS_PATH_MAX, "/proc/net/bonding/%s",
+               bond) >= SYSFS_PATH_MAX) {
+               LLOG_WARNX("path truncated");
+               return;
+       }
+       if ((f = priv_open(path)) < 0) {
+               if (snprintf(path, SYSFS_PATH_MAX, "/proc/self/net/bonding/%s",
+                       bond) >= SYSFS_PATH_MAX) {
+                       LLOG_WARNX("path truncated");
+                       return;
+               }
+               f = priv_open(path);
+       }
+       if (f < 0) {
+               LLOG_WARNX("unable to find %s in /proc/net/bonding or /proc/self/net/bonding",
+                   bond);
+               return;
+       }
+       if ((netbond = fdopen(f, "r")) == NULL) {
+               LLOG_WARN("unable to read stream from %s", path);
+               close(f);
+               return;
+       }
+       /* State 0:
+            We parse the file to search "Slave Interface: ". If found, go to
+            state 1.
+          State 1:
+            We parse the file to search "Permanent HW addr: ". If found, we get
+            the mac.
+       */
+       while (fgets(line, sizeof(line), netbond)) {
+               switch (state) {
+               case 0:
+                       if (strncmp(line, slaveif, strlen(slaveif)) == 0) {
+                               if (line[strlen(line)-1] == '\n')
+                                       line[strlen(line)-1] = '\0';
+                               if (strncmp(hardware->h_ifname,
+                                       line + strlen(slaveif),
+                                       sizeof(hardware->h_ifname)) == 0)
+                                       state++;
+                       }
+                       break;
+               case 1:
+                       if (strncmp(line, hwaddr, strlen(hwaddr)) == 0) {
+                               if (line[strlen(line)-1] == '\n')
+                                       line[strlen(line)-1] = '\0';
+                               if (sscanf(line + strlen(hwaddr),
+                                       "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
+                                       &mac[0], &mac[1], &mac[2],
+                                       &mac[3], &mac[4], &mac[5]) !=
+                                   ETHER_ADDR_LEN) {
+                                       LLOG_WARN("unable to parse %s",
+                                           line + strlen(hwaddr));
+                                       fclose(netbond);
+                                       return;
+                               }
+                               memcpy(hardware->h_lladdr, mac,
+                                   ETHER_ADDR_LEN);
+                               fclose(netbond);
+                               return;
+                       }
+                       break;
+               }
+       }
+       LLOG_WARNX("unable to find real mac address for %s",
+           bond);
+       fclose(netbond);
+}
+
+/* Fill up MAC/PHY for a given hardware port */
+static void
+iface_macphy(struct lldpd_hardware *hardware)
+{
+#ifdef ENABLE_DOT3
+       struct ethtool_cmd ethc;
+       struct lldpd_port *port = &hardware->h_lport;
+       int j;
+       int advertised_ethtool_to_rfc3636[][2] = {
+               {ADVERTISED_10baseT_Half, LLDP_DOT3_LINK_AUTONEG_10BASE_T},
+               {ADVERTISED_10baseT_Full, LLDP_DOT3_LINK_AUTONEG_10BASET_FD},
+               {ADVERTISED_100baseT_Half, LLDP_DOT3_LINK_AUTONEG_100BASE_TX},
+               {ADVERTISED_100baseT_Full, LLDP_DOT3_LINK_AUTONEG_100BASE_TXFD},
+               {ADVERTISED_1000baseT_Half, LLDP_DOT3_LINK_AUTONEG_1000BASE_T},
+               {ADVERTISED_1000baseT_Full, LLDP_DOT3_LINK_AUTONEG_1000BASE_TFD},
+               {ADVERTISED_10000baseT_Full, LLDP_DOT3_LINK_AUTONEG_OTHER},
+               {ADVERTISED_Pause, LLDP_DOT3_LINK_AUTONEG_FDX_PAUSE},
+               {ADVERTISED_Asym_Pause, LLDP_DOT3_LINK_AUTONEG_FDX_APAUSE},
+               {ADVERTISED_2500baseX_Full, LLDP_DOT3_LINK_AUTONEG_OTHER},
+               {0,0}};
+
+       if (priv_ethtool(hardware->h_ifname, &ethc) == 0) {
+               port->p_autoneg_support = (ethc.supported & SUPPORTED_Autoneg) ? 1 : 0;
+               port->p_autoneg_enabled = (ethc.autoneg == AUTONEG_DISABLE) ? 0 : 1;
+               for (j=0; advertised_ethtool_to_rfc3636[j][0]; j++) {
+                       if (ethc.advertising & advertised_ethtool_to_rfc3636[j][0])
+                               port->p_autoneg_advertised |= 
+                                   advertised_ethtool_to_rfc3636[j][1];
+               }
+               switch (ethc.speed) {
+               case SPEED_10:
+                       port->p_mau_type = (ethc.duplex == DUPLEX_FULL) ? \
+                           LLDP_DOT3_MAU_10BASETFD : LLDP_DOT3_MAU_10BASETHD;
+                       if (ethc.port == PORT_BNC) port->p_mau_type = LLDP_DOT3_MAU_10BASE2;
+                       if (ethc.port == PORT_FIBRE)
+                               port->p_mau_type = (ethc.duplex == DUPLEX_FULL) ? \
+                                   LLDP_DOT3_MAU_10BASEFLDF : LLDP_DOT3_MAU_10BASEFLHD;
+                       break;
+               case SPEED_100:
+                       port->p_mau_type = (ethc.duplex == DUPLEX_FULL) ? \
+                           LLDP_DOT3_MAU_100BASETXFD : LLDP_DOT3_MAU_100BASETXHD;
+                       if (ethc.port == PORT_BNC)
+                               port->p_mau_type = (ethc.duplex == DUPLEX_FULL) ? \
+                                   LLDP_DOT3_MAU_100BASET2DF : LLDP_DOT3_MAU_100BASET2HD;
+                       if (ethc.port == PORT_FIBRE)
+                               port->p_mau_type = (ethc.duplex == DUPLEX_FULL) ? \
+                                   LLDP_DOT3_MAU_100BASEFXFD : LLDP_DOT3_MAU_100BASEFXHD;
+                       break;
+               case SPEED_1000:
+                       port->p_mau_type = (ethc.duplex == DUPLEX_FULL) ? \
+                           LLDP_DOT3_MAU_1000BASETFD : LLDP_DOT3_MAU_1000BASETHD;
+                       if (ethc.port == PORT_FIBRE)
+                               port->p_mau_type = (ethc.duplex == DUPLEX_FULL) ? \
+                                   LLDP_DOT3_MAU_1000BASEXFD : LLDP_DOT3_MAU_1000BASEXHD;
+                       break;
+               case SPEED_10000:
+                       port->p_mau_type = (ethc.port == PORT_FIBRE) ?  \
+                                       LLDP_DOT3_MAU_10GIGBASEX : LLDP_DOT3_MAU_10GIGBASER;
+                       break;
+               }
+               if (ethc.port == PORT_AUI) port->p_mau_type = LLDP_DOT3_MAU_AUI;
+       }
+#endif
+}
+
+static void
+iface_mtu(struct lldpd *cfg, struct lldpd_hardware *hardware)
+{
+       struct ifreq ifr;
+
+       /* get MTU */
+       memset(&ifr, 0, sizeof(ifr));
+       strlcpy(ifr.ifr_name, hardware->h_ifname, sizeof(ifr.ifr_name));
+       if (ioctl(cfg->g_sock, SIOCGIFMTU, (char*)&ifr) == -1) {
+               LLOG_WARN("unable to get MTU of %s, using 1500", hardware->h_ifname);
+               hardware->h_mtu = 1500;
+       } else
+               hardware->h_mtu = hardware->h_lport.p_mfs = ifr.ifr_mtu;
+}
+
+static void
+iface_multicast(struct lldpd *cfg, const char *name, int remove)
+{
+       int i, rc;
+
+       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)
+                               LLOG_INFO("unable to %s %s address to multicast filter for %s",
+                                   (remove)?"delete":"add",
+                                   cfg->g_protocols[i].name,
+                                   name);
+               }
+       }
+}
+
+static int
+iface_eth_init(struct lldpd *cfg, struct lldpd_hardware *hardware)
+{
+       int status;
+       const struct sock_fprog prog = {
+               .filter = lldpd_filter_f,
+               .len = sizeof(lldpd_filter_f) / sizeof(struct sock_filter)
+       };
+
+       status = priv_iface_eth_init(hardware);
+       if (status != 0)
+               return status;
+
+       /* fd to receive is the same as fd to send */
+       FD_SET(hardware->h_sendfd, &hardware->h_recvfds);
+
+       /* Set filter */
+       if (setsockopt(hardware->h_sendfd, SOL_SOCKET, SO_ATTACH_FILTER,
+                &prog, sizeof(prog)) < 0) {
+               LLOG_WARN("unable to change filter for %s", hardware->h_ifname);
+               return ENETDOWN;
+       }
+
+       iface_multicast(cfg, hardware->h_ifname, 0);
+
+       LLOG_DEBUG("interface %s initialized (fd=%d)", hardware->h_ifname,
+           hardware->h_sendfd);
+       return 0;
+}
+
+static int
+iface_eth_send(struct lldpd *cfg, struct lldpd_hardware *hardware,
+    char *buffer, size_t size)
+{
+       return write(hardware->h_sendfd,
+           buffer, size);
+}
+
+static int
+iface_eth_recv(struct lldpd *cfg, struct lldpd_hardware *hardware,
+    int fd, char *buffer, size_t size)
+{
+       int n;
+       struct sockaddr_ll from;
+       socklen_t fromlen;
+
+       fromlen = sizeof(from);
+       if ((n = recvfrom(fd,
+                   buffer,
+                   size, 0,
+                   (struct sockaddr *)&from,
+                   &fromlen)) == -1) {
+               LLOG_WARN("error while receiving frame on %s",
+                   hardware->h_ifname);
+               hardware->h_rx_discarded_cnt++;
+               return -1;
+       }
+       if (from.sll_pkttype == PACKET_OUTGOING)
+               return -1;
+       return n;
+}
+
+static int
+iface_eth_close(struct lldpd *cfg, struct lldpd_hardware *hardware)
+{
+       close(hardware->h_sendfd);
+       iface_multicast(cfg, hardware->h_ifname, 1);
+       return 0;
+}
+
+void
+lldpd_ifh_eth(struct lldpd *cfg, struct ifaddrs *ifap)
+{
+       struct ifaddrs *ifa;
+       struct sockaddr_ll *sdl;
+       struct lldpd_hardware *hardware;
+       struct lldpd_port *port;
+       u_int8_t *lladdr;
+
+       for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
+               /* First, check if this interface has already been handled */
+               if (!ifa->ifa_flags)
+                       continue;
+
+               if (ifa->ifa_addr == NULL ||
+                   ifa->ifa_addr->sa_family != PF_PACKET)
+                       continue;
+
+               sdl = (struct sockaddr_ll *)ifa->ifa_addr;
+               if (sdl->sll_hatype != ARPHRD_ETHER || !sdl->sll_halen)
+                       continue;
+
+               if (iface_is_bridge(cfg, ifa->ifa_name)) {
+                       LOCAL_CHASSIS(cfg)->c_cap_enabled |= LLDP_CAP_BRIDGE;
+                       continue;
+               }
+
+               /* If the interface is a bond or a VLAN, we don't handle it
+                * here. If it is enslaved, it should have been handled earlier,
+                * therefore, we don't test that here. */
+               if ((iface_is_vlan(cfg, ifa->ifa_name)) ||
+                   (iface_is_bond(cfg, ifa->ifa_name)))
+                       continue;
+
+               /* We request that the interface is able to do either multicast
+                * or broadcast to be able to send discovery frames. */
+                if (!(ifa->ifa_flags & (IFF_MULTICAST|IFF_BROADCAST)))
+                        continue;
+
+               if (iface_is_wireless(cfg, ifa->ifa_name))
+                       LOCAL_CHASSIS(cfg)->c_cap_enabled |= LLDP_CAP_WLAN;
+
+               if ((hardware = lldpd_get_hardware(cfg, ifa->ifa_name)) == NULL) {
+                       if  ((hardware = lldpd_alloc_hardware(cfg,
+                                   ifa->ifa_name)) == NULL) {
+                               LLOG_WARNX("Unable to allocate space for %s",
+                                   ifa->ifa_name);
+                               continue;
+                       }
+                       if (iface_eth_init(cfg, hardware) != 0) {
+                               LLOG_WARN("unable to initialize %s", hardware->h_ifname);
+                               lldpd_hardware_cleanup(cfg, hardware);
+                               continue;
+                       }
+                       hardware->h_ops = &eth_ops;
+                       TAILQ_INSERT_TAIL(&cfg->g_hardware, hardware, h_entries);
+               } else
+                       lldpd_port_cleanup(&hardware->h_lport, 0);
+
+               port = &hardware->h_lport;
+               hardware->h_flags = ifa->ifa_flags; /* Should be non-zero */
+               ifa->ifa_flags = 0;                 /* Future handlers
+                                                      don't have to
+                                                      care about this
+                                                      interface. */
+
+               /* Get local address */
+               lladdr = (u_int8_t*)(((struct sockaddr_ll *)ifa->ifa_addr)->sll_addr);
+               memcpy(&hardware->h_lladdr, lladdr, sizeof(hardware->h_lladdr));
+               iface_get_permanent_mac(cfg, hardware);
+
+               /* Port ID is the same as hardware address */
+               port->p_id_subtype = LLDP_PORTID_SUBTYPE_LLADDR;
+               if ((port->p_id = calloc(1, sizeof(hardware->h_lladdr))) == NULL)
+                       fatal(NULL);
+               memcpy(port->p_id, hardware->h_lladdr, sizeof(hardware->h_lladdr));
+               port->p_id_len = sizeof(hardware->h_lladdr);
+
+               /* Port description is its name */
+               port->p_descr = strdup(hardware->h_ifname);
+
+               /* Fill additional info */
+               iface_macphy(hardware);
+               iface_mtu(cfg, hardware);
+       }
+}
+
+void
+lldpd_ifh_vlan(struct lldpd *cfg, struct ifaddrs *ifap)
+{
+#ifdef ENABLE_DOT1
+       struct ifaddrs *ifa;
+       struct lldpd_vlan *vlan;
+       struct vlan_ioctl_args ifv;
+       struct lldpd_hardware *hardware;
+       struct lldpd_port *port;
+
+       for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
+               if (!ifa->ifa_flags)
+                       continue;
+               if (!iface_is_vlan(cfg, ifa->ifa_name))
+                       continue;
+
+               /* We need to find the physical interfaces of this
+                  vlan, through bonds and bridges. */
+               memset(&ifv, 0, sizeof(ifv));
+               ifv.cmd = GET_VLAN_REALDEV_NAME_CMD;
+               strlcpy(ifv.device1, ifa->ifa_name, sizeof(ifv.device1));
+               if (ioctl(cfg->g_sock, SIOCGIFVLAN, &ifv) >= 0) {
+                       /* Three cases:
+                           1. we get a real device
+                           2. we get a bond
+                           3. we get a bridge
+                       */
+                       if ((hardware = lldpd_get_hardware(cfg,
+                                   ifv.u.device2)) == NULL) {
+                               if (iface_is_bond(cfg, ifv.u.device2)) {
+                                       TAILQ_FOREACH(hardware, &cfg->g_hardware,
+                                           h_entries)
+                                           if (iface_is_bond_slave(cfg,
+                                                   hardware->h_ifname,
+                                                   ifv.u.device2, NULL))
+                                                   break;
+                               } else if (iface_is_bridge(cfg, ifv.u.device2)) {
+                                       TAILQ_FOREACH(hardware, &cfg->g_hardware,
+                                           h_entries)
+                                           if (iface_is_bridged_to(cfg,
+                                                   hardware->h_ifname,
+                                                   ifv.u.device2))
+                                                   break;
+                               }
+                       }
+                       if (!hardware) continue;
+                       port = &hardware->h_lport;
+                       if ((vlan = (struct lldpd_vlan *)
+                            calloc(1, sizeof(struct lldpd_vlan))) == NULL)
+                               continue;
+                       if ((vlan->v_name = strdup(ifa->ifa_name)) == NULL) {
+                               free(vlan);
+                               continue;
+                       }
+                       memset(&ifv, 0, sizeof(ifv));
+                       ifv.cmd = GET_VLAN_VID_CMD;
+                       strlcpy(ifv.device1, ifa->ifa_name, sizeof(ifv.device1));
+                       if (ioctl(cfg->g_sock, SIOCGIFVLAN, &ifv) < 0) {
+                               /* Dunno what happened */
+                               free(vlan->v_name);
+                               free(vlan);
+                       } else {
+                               vlan->v_vid = ifv.u.VID;
+                               TAILQ_INSERT_TAIL(&port->p_vlans, vlan, v_entries);
+                       }
+               }
+       }
+#endif
+}
+
+/* Find a management address in all available interfaces, even those that were
+   already handled. This is a special interface handler because it does not
+   really handle interface related information (management address is attached
+   to the local chassis). */
+void
+lldpd_ifh_mgmt(struct lldpd *cfg, struct ifaddrs *ifap)
+{
+       struct ifaddrs *ifa;
+       struct sockaddr_in *sa;
+
+       if (LOCAL_CHASSIS(cfg)->c_mgmt.s_addr != INADDR_ANY)
+               return;         /* We already have one */
+
+       for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
+               if ((ifa->ifa_addr != NULL) &&
+                   (ifa->ifa_addr->sa_family == AF_INET)) {
+                       /* We have an IPv4 address (IPv6 not handled yet) */
+                       sa = (struct sockaddr_in *)ifa->ifa_addr;
+                       if ((ntohl(*(u_int32_t*)&sa->sin_addr) != INADDR_LOOPBACK) &&
+                           (cfg->g_mgmt_pattern == NULL)) {
+                               memcpy(&LOCAL_CHASSIS(cfg)->c_mgmt,
+                                   &sa->sin_addr,
+                                   sizeof(struct in_addr));
+                               LOCAL_CHASSIS(cfg)->c_mgmt_if = if_nametoindex(ifa->ifa_name);
+                       } else if (cfg->g_mgmt_pattern != NULL) {
+                               char *ip;
+                               ip = inet_ntoa(sa->sin_addr);
+                               if (fnmatch(cfg->g_mgmt_pattern,
+                                       ip, 0) == 0) {
+                                       memcpy(&LOCAL_CHASSIS(cfg)->c_mgmt,
+                                           &sa->sin_addr,
+                                           sizeof(struct in_addr));
+                                       LOCAL_CHASSIS(cfg)->c_mgmt_if =
+                                           if_nametoindex(ifa->ifa_name);
+                               }
+                       }
+               }
+       }
+}
index d19ac3246c4ab413ee502ec3e0774490df83ee18..5aa9deee25d286435cf788a01eef3e28ab43a1db 100644 (file)
@@ -265,8 +265,8 @@ lldp_send(struct lldpd *global,
              POKE_END_LLDP_TLV))
                goto toobig;
 
-       if (write(hardware->h_raw, packet,
-               pos - packet) == -1) {
+       if (hardware->h_ops->send(global, hardware,
+               (char *)packet, pos - packet) == -1) {
                LLOG_WARN("unable to send packet on real device for %s",
                    hardware->h_ifname);
                free(packet);
index 034f47a2a41a26e1a9c511fdc0f449f35ee87fba..ee3ce70da3cefb950b044cf24a0fefe30ad9aaad 100644 (file)
@@ -22,7 +22,6 @@
 #include <signal.h>
 #include <sys/stat.h>
 #include <fcntl.h>
-#include <fnmatch.h>
 #include <time.h>
 #include <libgen.h>
 #include <sys/utsname.h>
 #include <sys/time.h>
 #include <sys/ioctl.h>
 #include <arpa/inet.h>
-#include <ifaddrs.h>
 #include <net/if_arp.h>
-#include <linux/filter.h>
-#include <linux/if_vlan.h>
-#include <linux/if_packet.h>
-#include <linux/sockios.h>
 
 #ifdef USE_SNMP
 #include <net-snmp/net-snmp-config.h>
 
 static void             usage(void);
 
-static int              lldpd_iface_init(struct lldpd *, struct lldpd_hardware *);
-static void             lldpd_iface_init_mtu(struct lldpd *, struct lldpd_hardware *);
-static int              lldpd_iface_close(struct lldpd *, struct lldpd_hardware *);
-static void             lldpd_iface_multicast(struct lldpd *, const char *, int);
-
-/* LLDP: "ether proto 0x88cc and ether dst 01:80:c2:00:00:0e" */
-/* FDP: "ether dst 01:e0:52:cc:cc:cc" */
-/* CDP: "ether dst 01:00:0c:cc:cc:cc" */
-/* SONMP: "ether dst 01:00:81:00:01:00" */
-/* EDP: "ether dst 00:e0:2b:00:00:00" */
-#define LLDPD_FILTER_F                 \
-       { 0x28, 0, 0, 0x0000000c },     \
-       { 0x15, 0, 4, 0x000088cc },     \
-       { 0x20, 0, 0, 0x00000002 },     \
-       { 0x15, 0, 2, 0xc200000e },     \
-       { 0x28, 0, 0, 0x00000000 },     \
-       { 0x15, 11, 12, 0x00000180 },   \
-       { 0x20, 0, 0, 0x00000002 },     \
-       { 0x15, 0, 2, 0x2b000000 },     \
-       { 0x28, 0, 0, 0x00000000 },     \
-       { 0x15, 7, 8, 0x000000e0 },     \
-       { 0x15, 1, 0, 0x0ccccccc },     \
-       { 0x15, 0, 2, 0x81000100 },     \
-       { 0x28, 0, 0, 0x00000000 },     \
-       { 0x15, 3, 4, 0x00000100 },     \
-       { 0x15, 0, 3, 0x52cccccc },     \
-       { 0x28, 0, 0, 0x00000000 },     \
-       { 0x15, 0, 1, 0x000001e0 },     \
-       { 0x6, 0, 0, 0x0000ffff },      \
-       { 0x6, 0, 0, 0x00000000 },
-static struct sock_filter lldpd_filter_f[] = { LLDPD_FILTER_F };
-
 static struct protocol protos[] =
 {
        { LLDPD_MODE_LLDP, 1, "LLDP", ' ', lldp_send, lldp_decode, NULL,
@@ -106,8 +68,9 @@ static struct protocol protos[] =
          {0,0,0,0,0,0} }
 };
 
-static
-struct lldpd_hardware  *lldpd_hardware_add(struct lldpd *, struct ifaddrs *);
+static void             lldpd_update_localchassis(struct lldpd *);
+static void             lldpd_update_localports(struct lldpd *);
+static void             lldpd_cleanup(struct lldpd *);
 static void             lldpd_loop(struct lldpd *);
 static void             lldpd_shutdown(int);
 static void             lldpd_exit();
@@ -133,79 +96,41 @@ usage(void)
        exit(1);
 }
 
-static void
-lldpd_iface_init_mtu(struct lldpd *global, struct lldpd_hardware *hardware)
-{
-       struct ifreq ifr;
-
-       /* get MTU */
-       memset(&ifr, 0, sizeof(ifr));
-       strlcpy(ifr.ifr_name, hardware->h_ifname, sizeof(ifr.ifr_name));
-       if (ioctl(global->g_sock, SIOCGIFMTU, (char*)&ifr) == -1) {
-               LLOG_WARN("unable to get MTU of %s, using 1500", hardware->h_ifname);
-               hardware->h_mtu = 1500;
-       } else
-               hardware->h_mtu = hardware->h_lport.p_mfs = ifr.ifr_mtu;
-}
-
-static int
-lldpd_iface_init(struct lldpd *global, struct lldpd_hardware *hardware)
-{
-       int status;
-       struct sock_fprog prog;
-
-       lldpd_iface_init_mtu(global, hardware);
-       status = priv_iface_init(hardware, -1);
-       if (status != 0)
-               return status;
-
-       /* Set filter */
-       prog.filter = lldpd_filter_f;
-       prog.len = sizeof(lldpd_filter_f) / sizeof(struct sock_filter);
-       if (setsockopt(hardware->h_raw, SOL_SOCKET, SO_ATTACH_FILTER,
-                &prog, sizeof(prog)) < 0) {
-               LLOG_WARN("unable to change filter for %s", hardware->h_ifname);
-               return ENETDOWN;
-       }
-
-       lldpd_iface_multicast(global, hardware->h_ifname, 0);
-
-       LLOG_DEBUG("interface %s initialized (fd=%d)", hardware->h_ifname,
-           hardware->h_raw);
-       return 0;
-}
-
-static void
-lldpd_iface_multicast(struct lldpd *global, const char *name, int remove)
+struct lldpd_hardware *
+lldpd_get_hardware(struct lldpd *cfg, char *name)
 {
-       int i, rc;
-
-       for (i=0; global->g_protocols[i].mode != 0; i++) {
-               if (!global->g_protocols[i].enabled) continue;
-               if ((rc = priv_iface_multicast(name,
-                           global->g_protocols[i].mac, !remove)) != 0) {
-                       errno = rc;
-                       if (errno != ENOENT)
-                               LLOG_INFO("unable to %s %s address to multicast filter for %s",
-                                   (remove)?"delete":"add",
-                                   global->g_protocols[i].name,
-                                   name);
-               }
+       struct lldpd_hardware *hardware;
+       TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries) {
+               if (strcmp(hardware->h_ifname, name) == 0)
+                       break;
        }
+       return hardware;
 }
 
-static int
-lldpd_iface_close(struct lldpd *global, struct lldpd_hardware *hardware)
+struct lldpd_hardware *
+lldpd_alloc_hardware(struct lldpd *cfg, char *name)
 {
-       char listen[IFNAMSIZ];
+       struct lldpd_hardware *hardware;
 
-       close(hardware->h_raw);
-       hardware->h_raw = -1;
+       if ((hardware = (struct lldpd_hardware *)
+               calloc(1, sizeof(struct lldpd_hardware))) == NULL)
+               return NULL;
 
-       memcpy(listen, hardware->h_ifname, IFNAMSIZ);
-       lldpd_iface_multicast(global, listen, 1);
+       strlcpy(hardware->h_ifname, name, sizeof(hardware->h_ifname));
+       hardware->h_lport.p_chassis = LOCAL_CHASSIS(cfg);
+       TAILQ_INIT(&hardware->h_rports);
 
-       return 0;
+#ifdef ENABLE_LLDPMED
+       if (LOCAL_CHASSIS(cfg)->c_med_cap_available) {
+               hardware->h_lport.p_med_cap_enabled = LLDPMED_CAP_CAP;
+               if (!cfg->g_noinventory)
+                       hardware->h_lport.p_med_cap_enabled |= LLDPMED_CAP_IV;
+       }
+#endif
+#ifdef ENABLE_DOT1
+       TAILQ_INIT(&hardware->h_lport.p_vlans);
+#endif
+       return hardware;
 }
 
 #ifdef ENABLE_DOT1
@@ -291,13 +216,26 @@ lldpd_remote_cleanup(struct lldpd *cfg, struct lldpd_hardware *hardware, int all
 }
 
 void
-lldpd_hardware_cleanup(struct lldpd_hardware *hardware)
+lldpd_hardware_cleanup(struct lldpd *cfg, struct lldpd_hardware *hardware)
 {
+       int i;
        lldpd_port_cleanup(&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. */
+       if (hardware->h_ops->cleanup)
+               hardware->h_ops->cleanup(cfg, hardware);
+       else {
+               free(hardware->h_data);
+               for (i=0; i < FD_SETSIZE; i++)
+                       if (FD_ISSET(i, &hardware->h_recvfds))
+                               close(i);
+               if (hardware->h_sendfd) close(hardware->h_sendfd);
+       }
        free(hardware);
 }
 
-void
+static void
 lldpd_cleanup(struct lldpd *cfg)
 {
        struct lldpd_hardware *hardware, *hardware_next;
@@ -305,213 +243,15 @@ lldpd_cleanup(struct lldpd *cfg)
        for (hardware = TAILQ_FIRST(&cfg->g_hardware); hardware != NULL;
             hardware = hardware_next) {
                hardware_next = TAILQ_NEXT(hardware, h_entries);
-               if (hardware->h_flags == 0) {
+               if (!hardware->h_flags) {
                        TAILQ_REMOVE(&cfg->g_hardware, hardware, h_entries);
-                       lldpd_iface_close(cfg, hardware);
                        lldpd_remote_cleanup(cfg, hardware, 1);
-                       lldpd_hardware_cleanup(hardware);
+                       lldpd_hardware_cleanup(cfg, hardware);
                } else
                        lldpd_remote_cleanup(cfg, hardware, 0);
        }
 }
 
-static struct lldpd_hardware *
-lldpd_hardware_add(struct lldpd *cfg, struct ifaddrs *ifa)
-{
-#if defined (ENABLE_DOT1) || defined (ENABLE_DOT3)
-       struct ifaddrs *oifap, *oifa;
-#endif
-       struct lldpd_hardware *hardware;
-       struct lldpd_port *port;
-#ifdef ENABLE_DOT1
-       struct lldpd_vlan *vlan;
-       struct vlan_ioctl_args ifv;
-#endif
-#ifdef ENABLE_DOT3
-       struct ethtool_cmd ethc;
-#endif
-       u_int8_t *lladdr;
-
-       TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries) {
-               if (strcmp(hardware->h_ifname, ifa->ifa_name) == 0)
-                       break;
-       }
-
-       if (hardware == NULL) {
-               if ((hardware = (struct lldpd_hardware *)
-                   calloc(1, sizeof(struct lldpd_hardware))) == NULL)
-                       return (NULL);
-               hardware->h_raw = -1;
-               hardware->h_lport.p_chassis = LOCAL_CHASSIS(cfg);
-               TAILQ_INIT(&hardware->h_rports);
-#ifdef ENABLE_LLDPMED
-               if (LOCAL_CHASSIS(cfg)->c_med_cap_available) {
-                       hardware->h_lport.p_med_cap_enabled = LLDPMED_CAP_CAP;
-                       if (!cfg->g_noinventory)
-                               hardware->h_lport.p_med_cap_enabled |= LLDPMED_CAP_IV;
-               }
-#endif
-#ifdef ENABLE_DOT1
-               TAILQ_INIT(&hardware->h_lport.p_vlans);
-       } else {
-               lldpd_port_cleanup(&hardware->h_lport, 0);
-#endif
-       }
-
-       port = &hardware->h_lport;
-       hardware->h_flags = ifa->ifa_flags;
-
-       strlcpy(hardware->h_ifname, ifa->ifa_name, sizeof(hardware->h_ifname));
-       lladdr = (u_int8_t*)(((struct sockaddr_ll *)ifa->ifa_addr)->sll_addr);
-       memcpy(&hardware->h_lladdr, lladdr, sizeof(hardware->h_lladdr));
-       iface_get_permanent_mac(cfg, hardware);
-       port->p_id_subtype = LLDP_PORTID_SUBTYPE_LLADDR;
-       if ((port->p_id = calloc(1, sizeof(hardware->h_lladdr))) == NULL)
-               fatal(NULL);
-       memcpy(port->p_id, hardware->h_lladdr, sizeof(hardware->h_lladdr));
-       port->p_id_len = sizeof(hardware->h_lladdr);
-       port->p_descr = strdup(hardware->h_ifname);
-
-       if (LOCAL_CHASSIS(cfg)->c_id == NULL) {
-               /* Use the first port's l2 addr as the chassis ID */
-               if ((LOCAL_CHASSIS(cfg)->c_id =
-                       malloc(sizeof(hardware->h_lladdr))) == NULL)
-                       fatal(NULL);
-               LOCAL_CHASSIS(cfg)->c_id_subtype = LLDP_CHASSISID_SUBTYPE_LLADDR;
-               LOCAL_CHASSIS(cfg)->c_id_len = sizeof(hardware->h_lladdr);
-               memcpy(LOCAL_CHASSIS(cfg)->c_id,
-                   hardware->h_lladdr, sizeof(hardware->h_lladdr));
-       }
-
-       /* Get VLANS and aggregation status */
-#if defined (ENABLE_DOT3) || defined (ENABLE_DOT1)
-       if (getifaddrs(&oifap) != 0)
-               fatal("lldpd_hardware_add: failed to get interface list");
-       for (oifa = oifap; oifa != NULL; oifa = oifa->ifa_next) {
-#ifdef ENABLE_DOT1
-               /* Check if we already have checked this one */
-               int skip = 0;
-               TAILQ_FOREACH(vlan, &port->p_vlans, v_entries) {
-                       if (strcmp(vlan->v_name, oifa->ifa_name) == 0) {
-                               skip = 1;
-                               break;
-                       }
-               }
-               if (skip) continue;
-#endif
-
-               /* Aggregation check */
-#ifdef ENABLE_DOT3
-               if (iface_is_bond_slave(cfg, hardware->h_ifname, oifa->ifa_name, NULL))
-                       port->p_aggregid = if_nametoindex(oifa->ifa_name);
-#endif
-
-#ifdef ENABLE_DOT1     
-               /* VLAN check */
-               memset(&ifv, 0, sizeof(ifv));
-               ifv.cmd = GET_VLAN_REALDEV_NAME_CMD;
-               strlcpy(ifv.device1, oifa->ifa_name, sizeof(ifv.device1));
-               if ((ioctl(cfg->g_sock, SIOCGIFVLAN, &ifv) >= 0) &&
-                   ((iface_is_bond_slave(cfg, hardware->h_ifname, ifv.u.device2, NULL)) ||
-                    (iface_is_bridged_to(cfg, hardware->h_ifname, ifv.u.device2)) ||
-                    (strncmp(hardware->h_ifname, ifv.u.device2, sizeof(ifv.u.device2)) == 0))) {
-                       if ((vlan = (struct lldpd_vlan *)
-                            calloc(1, sizeof(struct lldpd_vlan))) == NULL)
-                               continue;
-                       if ((vlan->v_name = strdup(oifa->ifa_name)) == NULL) {
-                               free(vlan);
-                               continue;
-                       }
-                       memset(&ifv, 0, sizeof(ifv));
-                       ifv.cmd = GET_VLAN_VID_CMD;
-                       strlcpy(ifv.device1, oifa->ifa_name, sizeof(ifv.device1));
-                       if (ioctl(cfg->g_sock, SIOCGIFVLAN, &ifv) < 0) {
-                               /* Dunno what happened */
-                               free(vlan->v_name);
-                               free(vlan);
-                       } else {
-                               vlan->v_vid = ifv.u.VID;
-                               TAILQ_INSERT_TAIL(&port->p_vlans, vlan, v_entries);
-                       }
-               }
-#endif
-       }
-       freeifaddrs(oifap);
-#endif
-
-#ifdef ENABLE_DOT3
-       /* MAC/PHY */
-       if (priv_ethtool(hardware->h_ifname, &ethc) == 0) {
-               int j;
-               int advertised_ethtool_to_rfc3636[][2] = {
-                       {ADVERTISED_10baseT_Half, LLDP_DOT3_LINK_AUTONEG_10BASE_T},
-                       {ADVERTISED_10baseT_Full, LLDP_DOT3_LINK_AUTONEG_10BASET_FD},
-                       {ADVERTISED_100baseT_Half, LLDP_DOT3_LINK_AUTONEG_100BASE_TX},
-                       {ADVERTISED_100baseT_Full, LLDP_DOT3_LINK_AUTONEG_100BASE_TXFD},
-                       {ADVERTISED_1000baseT_Half, LLDP_DOT3_LINK_AUTONEG_1000BASE_T},
-                       {ADVERTISED_1000baseT_Full, LLDP_DOT3_LINK_AUTONEG_1000BASE_TFD},
-                       {ADVERTISED_10000baseT_Full, LLDP_DOT3_LINK_AUTONEG_OTHER},
-                       {ADVERTISED_Pause, LLDP_DOT3_LINK_AUTONEG_FDX_PAUSE},
-                       {ADVERTISED_Asym_Pause, LLDP_DOT3_LINK_AUTONEG_FDX_APAUSE},
-                       {ADVERTISED_2500baseX_Full, LLDP_DOT3_LINK_AUTONEG_OTHER},
-                       {0,0}};
-
-               port->p_autoneg_support = (ethc.supported & SUPPORTED_Autoneg) ? 1 : 0;
-               port->p_autoneg_enabled = (ethc.autoneg == AUTONEG_DISABLE) ? 0 : 1;
-               for (j=0; advertised_ethtool_to_rfc3636[j][0]; j++) {
-                       if (ethc.advertising & advertised_ethtool_to_rfc3636[j][0])
-                               port->p_autoneg_advertised |= advertised_ethtool_to_rfc3636[j][1];
-               }
-               switch (ethc.speed) {
-               case SPEED_10:
-                       port->p_mau_type = (ethc.duplex == DUPLEX_FULL) ? \
-                               LLDP_DOT3_MAU_10BASETFD : LLDP_DOT3_MAU_10BASETHD;
-                       if (ethc.port == PORT_BNC) port->p_mau_type = LLDP_DOT3_MAU_10BASE2;
-                       if (ethc.port == PORT_FIBRE)
-                               port->p_mau_type = (ethc.duplex == DUPLEX_FULL) ? \
-                                       LLDP_DOT3_MAU_10BASEFLDF : LLDP_DOT3_MAU_10BASEFLHD;
-                       break;
-               case SPEED_100:
-                       port->p_mau_type = (ethc.duplex == DUPLEX_FULL) ? \
-                               LLDP_DOT3_MAU_100BASETXFD : LLDP_DOT3_MAU_100BASETXHD;
-                       if (ethc.port == PORT_BNC)
-                               port->p_mau_type = (ethc.duplex == DUPLEX_FULL) ? \
-                                       LLDP_DOT3_MAU_100BASET2DF : LLDP_DOT3_MAU_100BASET2HD;
-                       if (ethc.port == PORT_FIBRE)
-                               port->p_mau_type = (ethc.duplex == DUPLEX_FULL) ? \
-                                       LLDP_DOT3_MAU_100BASEFXFD : LLDP_DOT3_MAU_100BASEFXHD;
-                       break;
-               case SPEED_1000:
-                       port->p_mau_type = (ethc.duplex == DUPLEX_FULL) ? \
-                               LLDP_DOT3_MAU_1000BASETFD : LLDP_DOT3_MAU_1000BASETHD;
-                       if (ethc.port == PORT_FIBRE)
-                               port->p_mau_type = (ethc.duplex == DUPLEX_FULL) ? \
-                                       LLDP_DOT3_MAU_1000BASEXFD : LLDP_DOT3_MAU_1000BASEXHD;
-                       break;
-               case SPEED_10000:
-                       port->p_mau_type = (ethc.port == PORT_FIBRE) ? \
-                                       LLDP_DOT3_MAU_10GIGBASEX : LLDP_DOT3_MAU_10GIGBASER;
-                       break;
-               }
-               if (ethc.port == PORT_AUI) port->p_mau_type = LLDP_DOT3_MAU_AUI;
-       } else
-               LLOG_DEBUG("unable to get eth info for %s", hardware->h_ifname);
-#endif
-
-       if (!INTERFACE_OPENED(hardware)) {
-
-               if (lldpd_iface_init(cfg, hardware) != 0) {
-                       LLOG_WARN("unable to initialize %s", hardware->h_ifname);
-                       lldpd_hardware_cleanup(hardware);
-                       return (NULL);
-               }
-
-               TAILQ_INSERT_TAIL(&cfg->g_hardware, hardware, h_entries);
-       }
-
-       return (hardware);
-}
-
 static int
 lldpd_guess_type(struct lldpd *cfg, char *frame, int s)
 {
@@ -662,8 +402,6 @@ lldpd_recv_all(struct lldpd *cfg)
        struct lldpd_client *client, *client_next;
        fd_set rfds;
        struct timeval tv;
-       struct sockaddr_ll from;
-       socklen_t fromlen;
 #ifdef USE_SNMP
        int fakeblock = 0;
        struct timeval *tvp = &tv;
@@ -684,12 +422,16 @@ lldpd_recv_all(struct lldpd *cfg)
                
                TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries) {
                        /* Ignore if interface is down */
-                       if (((hardware->h_flags & IFF_UP) == 0) ||
-                           ((hardware->h_flags & IFF_RUNNING) == 0))
+                       if ((hardware->h_flags & IFF_RUNNING) == 0)
                                continue;
-                       FD_SET(hardware->h_raw, &rfds);
-                       if (nfds < hardware->h_raw)
-                               nfds = hardware->h_raw;
+                       /* This is quite expensive but we don't rely on internal
+                        * structure of fd_set. */
+                       for (n = 0; n < FD_SETSIZE; n++)
+                               if (FD_ISSET(n, &hardware->h_recvfds)) {
+                                       FD_SET(n, &rfds);
+                                       if (nfds < n)
+                                               nfds = n;
+                               }
                }
                TAILQ_FOREACH(client, &cfg->g_clients, next) {
                        FD_SET(client->fd, &rfds);
@@ -725,38 +467,24 @@ lldpd_recv_all(struct lldpd *cfg)
                }
 #endif /* USE_SNMP */
                TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries) {
-                       /* We could have received something on _real_
-                        * interface. However, even in this case, this could be
-                        * just an outgoing packet. We will try to handle both
-                        * cases, but maybe not in the same select. */
-                       if (FD_ISSET(hardware->h_raw, &rfds)) {
-                               if ((buffer = (char *)malloc(
-                                               hardware->h_mtu)) == NULL) {
-                                       LLOG_WARN("failed to alloc reception buffer");
-                                       continue;
-                               }
-                               fromlen = sizeof(from);
-                               if ((n = recvfrom(
-                                               hardware->h_raw,
-                                                   buffer,
-                                                   hardware->h_mtu, 0,
-                                                   (struct sockaddr *)&from,
-                                                   &fromlen)) == -1) {
-                                       LLOG_WARN("error while receiving frame on %s",
-                                           hardware->h_ifname);
-                                       hardware->h_rx_discarded_cnt++;
-                                       free(buffer);
-                                       continue;
-                               }
-                               if (from.sll_pkttype == PACKET_OUTGOING) {
-                                       free(buffer);
-                                       continue;
-                               }
-                               hardware->h_rx_cnt++;
-                               lldpd_decode(cfg, buffer, n, hardware);
+                       for (n = 0; n < FD_SETSIZE; n++)
+                               if ((FD_ISSET(n, &hardware->h_recvfds)) &&
+                                   (FD_ISSET(n, &rfds))) break;
+                       if (n == FD_SETSIZE) continue;
+                       if ((buffer = (char *)malloc(
+                                       hardware->h_mtu)) == NULL) {
+                               LLOG_WARN("failed to alloc reception buffer");
+                               continue;
+                       }
+                       if ((n = hardware->h_ops->recv(cfg, hardware,
+                                   n, buffer, hardware->h_mtu)) == -1) {
                                free(buffer);
+                               continue;
                        }
-                       
+                       hardware->h_rx_cnt++;
+                       lldpd_decode(cfg, buffer, n, hardware);
+                       free(buffer);
+                       break;
                }
                if (FD_ISSET(cfg->g_ctl, &rfds)) {
                        if (ctl_accept(cfg, cfg->g_ctl) == -1)
@@ -806,8 +534,7 @@ lldpd_send_all(struct lldpd *cfg)
        cfg->g_lastsent = time(NULL);
        TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries) {
                /* Ignore if interface is down */
-               if (((hardware->h_flags & IFF_UP) == 0) ||
-                   ((hardware->h_flags & IFF_RUNNING) == 0))
+               if ((hardware->h_flags & IFF_RUNNING) == 0)
                        continue;
 
                for (i=0; cfg->g_protocols[i].mode != 0; i++) {
@@ -853,20 +580,16 @@ lldpd_med(struct lldpd_chassis *chassis)
 #endif
 
 static void
-lldpd_loop(struct lldpd *cfg)
+lldpd_update_localchassis(struct lldpd *cfg)
 {
-       struct ifaddrs *ifap, *ifa;
-       struct sockaddr_ll *sdl;
-       struct lldpd_hardware *hardware;
+       struct utsname un;
+       char *hp;
        int f;
        char status;
-       struct utsname *un;
-       char *hp;
+       struct lldpd_hardware *hardware;
 
        /* Set system name and description */
-       if ((un = (struct utsname*)malloc(sizeof(struct utsname))) == NULL)
-               fatal(NULL);
-       if (uname(un) != 0)
+       if (uname(&un) != 0)
                fatal("failed to get system information");
        if ((hp = priv_gethostbyname()) == NULL)
                fatal("failed to get system name");
@@ -875,7 +598,7 @@ lldpd_loop(struct lldpd *cfg)
        if ((LOCAL_CHASSIS(cfg)->c_name = strdup(hp)) == NULL)
                fatal(NULL);
        if (asprintf(&LOCAL_CHASSIS(cfg)->c_descr, "%s %s %s %s",
-               un->sysname, un->release, un->version, un->machine) == -1)
+               un.sysname, un.release, un.version, un.machine) == -1)
                fatal("failed to set system description");
 
        /* Check forwarding */
@@ -891,77 +614,72 @@ lldpd_loop(struct lldpd *cfg)
                LOCAL_CHASSIS(cfg)->c_cap_enabled |= LLDP_CAP_TELEPHONE;
        lldpd_med(LOCAL_CHASSIS(cfg));
        free(LOCAL_CHASSIS(cfg)->c_med_sw);
-       LOCAL_CHASSIS(cfg)->c_med_sw = strdup(un->release);
+       LOCAL_CHASSIS(cfg)->c_med_sw = strdup(un.release);
 #endif
-       free(un);
 
+       /* Set chassis ID if needed */
+       if ((LOCAL_CHASSIS(cfg)->c_id == NULL) &&
+           (hardware = TAILQ_FIRST(&cfg->g_hardware))) {
+               if ((LOCAL_CHASSIS(cfg)->c_id =
+                       malloc(sizeof(hardware->h_lladdr))) == NULL)
+                       fatal(NULL);
+               LOCAL_CHASSIS(cfg)->c_id_subtype = LLDP_CHASSISID_SUBTYPE_LLADDR;
+               LOCAL_CHASSIS(cfg)->c_id_len = sizeof(hardware->h_lladdr);
+               memcpy(LOCAL_CHASSIS(cfg)->c_id,
+                   hardware->h_lladdr, sizeof(hardware->h_lladdr));
+       }
+}
+
+static void
+lldpd_update_localports(struct lldpd *cfg)
+{
+       struct ifaddrs *ifap;
+       struct lldpd_hardware *hardware;
+       lldpd_ifhandlers ifhs[] = {
+               lldpd_ifh_eth,  /* Handle classic ethernet interfaces */
+               lldpd_ifh_vlan, /* Handle VLAN */
+               lldpd_ifh_mgmt, /* Handle management address (if not already handled) */
+               NULL
+       };
+       lldpd_ifhandlers *ifh;
+
+       /* h_flags is set to 0 for each port. If the port is updated, h_flags
+        * will be set to a non-zero value. This will allow us to clean up any
+        * non up-to-date port */
        TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries)
            hardware->h_flags = 0;
 
-       if (getifaddrs(&ifap) != 0)
-               fatal("lldpd_loop: failed to get interface list");
-
        LOCAL_CHASSIS(cfg)->c_mgmt.s_addr = INADDR_ANY;
-       for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
-               if (LOCAL_CHASSIS(cfg)->c_mgmt.s_addr == INADDR_ANY)
-                       /* Get management address, if available */
-                       if ((ifa->ifa_addr != NULL) &&
-                           (ifa->ifa_addr->sa_family == AF_INET)) {
-                               struct sockaddr_in *sa;
-                               sa = (struct sockaddr_in *)ifa->ifa_addr;
-                               if ((ntohl(*(u_int32_t*)&sa->sin_addr) != INADDR_LOOPBACK) &&
-                                   (cfg->g_mgmt_pattern == NULL)) {
-                                       memcpy(&LOCAL_CHASSIS(cfg)->c_mgmt,
-                                           &sa->sin_addr,
-                                           sizeof(struct in_addr));
-                                       LOCAL_CHASSIS(cfg)->c_mgmt_if = if_nametoindex(ifa->ifa_name);
-                               }
-                               else if (cfg->g_mgmt_pattern != NULL) {
-                                       char *ip;
-                                       ip = inet_ntoa(sa->sin_addr);
-                                       if (fnmatch(cfg->g_mgmt_pattern,
-                                               ip, 0) == 0) {
-                                               memcpy(&LOCAL_CHASSIS(cfg)->c_mgmt,
-                                                   &sa->sin_addr,
-                                                   sizeof(struct in_addr));
-                                               LOCAL_CHASSIS(cfg)->c_mgmt_if =
-                                                   if_nametoindex(ifa->ifa_name);
-                                       }
-                               }
-                       }
-
-               if (ifa->ifa_addr == NULL ||
-                   ifa->ifa_addr->sa_family != PF_PACKET)
-                       continue;
-
-               sdl = (struct sockaddr_ll *)ifa->ifa_addr;
-               if (sdl->sll_hatype != ARPHRD_ETHER || !sdl->sll_halen)
-                       continue;
-
-               if (iface_is_bridge(cfg, ifa->ifa_name)) {
-                       LOCAL_CHASSIS(cfg)->c_cap_enabled |= LLDP_CAP_BRIDGE;
-                       continue;
-               }
-
-               if ((iface_is_vlan(cfg, ifa->ifa_name)) ||
-                   (iface_is_bond(cfg, ifa->ifa_name)))
-                       continue;
-
-                if (!(ifa->ifa_flags & (IFF_MULTICAST|IFF_BROADCAST)))
-                        continue;
-
-               if (iface_is_wireless(cfg, ifa->ifa_name))
-                       LOCAL_CHASSIS(cfg)->c_cap_enabled |= LLDP_CAP_WLAN;
-
-               if (lldpd_hardware_add(cfg, ifa) == NULL)
-                       LLOG_WARNX("failed to allocate port %s, skip it",
-                               ifa->ifa_name);
-       }
-
+       if (getifaddrs(&ifap) != 0)
+               fatal("lldpd_update_localports: failed to get interface list");
+
+       /* We will run the list of interfaces through a list of interface
+        * handlers. Each handler will create or update some hardware port (and
+        * will set h_flags to a non zero value. The handler can use the list of
+        * interfaces but this is not mandatory. If the interface handler
+        * handles an interface from the list, it should set ifa_flags to 0 to
+        * let know the other handlers that it took care of this interface. This
+        * means that more specific handlers should be before less specific
+        * ones. */
+       for (ifh = ifhs; *ifh != NULL; ifh++)
+               (*ifh)(cfg, ifap);
        freeifaddrs(ifap);
+}
 
+static void
+lldpd_loop(struct lldpd *cfg)
+{
+       /* Main loop.
+          
+          1. Update local ports information
+          2. Clean unwanted (removed) local ports
+          3. Update local chassis information
+          4. Send packets
+          5. Receive packets
+       */
+       lldpd_update_localports(cfg);
        lldpd_cleanup(cfg);
-
+       lldpd_update_localchassis(cfg);
        lldpd_send_all(cfg);
        lldpd_recv_all(cfg);
 }
@@ -979,12 +697,13 @@ static struct lldpd *gcfg = NULL;
 static void
 lldpd_exit()
 {
-       struct lldpd_hardware *hardware;
+       struct lldpd_hardware *hardware, *hardware_next;
        close(gcfg->g_ctl);
        priv_ctl_cleanup();
-       TAILQ_FOREACH(hardware, &gcfg->g_hardware, h_entries) {
-               if (INTERFACE_OPENED(hardware))
-                       lldpd_iface_close(gcfg, hardware);
+       for (hardware = TAILQ_FIRST(&gcfg->g_hardware); hardware != NULL;
+            hardware = hardware_next) {
+               hardware_next = TAILQ_NEXT(hardware, h_entries);
+               lldpd_hardware_cleanup(gcfg, hardware);
        }
 #ifdef USE_SNMP
        if (gcfg->g_snmp)
index 4765a6fb8480477c6c1853ff1ad981a72352c5a4..a5cebbd7078d800f34adb5275750b3ff00f2b859 100644 (file)
@@ -31,6 +31,7 @@
 #include <arpa/inet.h>
 #include <linux/if.h>
 #endif
+#include <ifaddrs.h>
 #include <net/ethernet.h>
 #include <netinet/in.h>
 #include <linux/ethtool.h>
@@ -193,15 +194,33 @@ struct lldpd_frame {
        unsigned char frame[];
 };
 
+struct lldpd_hardware;
+struct lldpd;
+struct lldpd_ops {
+       int(*send)(struct lldpd *,
+                  struct lldpd_hardware*,
+                  char *, size_t); /* Function to send a frame */
+       int(*recv)(struct lldpd *,
+                  struct lldpd_hardware*,
+                  int, char *, size_t); /* Function to receive a frame */
+       int(*cleanup)(struct lldpd *, struct lldpd_hardware *); /* Cleanup function. */
+};
+
 struct lldpd_hardware {
        TAILQ_ENTRY(lldpd_hardware)      h_entries;
 
-#define INTERFACE_OPENED(x) ((x)->h_raw != -1)
-       int                      h_raw;
+       fd_set                   h_recvfds; /* FD for reception */
+       int                      h_sendfd;  /* FD for sending, only used by h_ops */
+       struct lldpd_ops        *h_ops;     /* Hardware-dependent functions */
+       void                    *h_data;    /* Hardware-dependent data */
 
-       int                      h_flags;
        int                      h_mtu;
-       char                     h_ifname[IFNAMSIZ];
+       int                      h_flags; /* Packets will be sent only
+                                            if IFF_RUNNING. Will be
+                                            removed if this is left
+                                            to 0. */
+       int                      h_ifindex; /* Interface index, used by SNMP */
+       char                     h_ifname[IFNAMSIZ]; /* Should be unique */
        u_int8_t                 h_lladdr[ETHER_ADDR_LEN];
 
        u_int64_t                h_tx_cnt;
@@ -229,7 +248,6 @@ struct lldpd_client {
 #define PROTO_DECODE_SIG struct lldpd *, char *, int, struct lldpd_hardware *, struct lldpd_chassis **, struct lldpd_port **
 #define PROTO_GUESS_SIG char *, int
 
-struct lldpd;
 struct protocol {
 #define LLDPD_MODE_LLDP 1
 #define LLDPD_MODE_CDPV1 2
@@ -275,6 +293,8 @@ struct lldpd {
        TAILQ_HEAD(, lldpd_hardware) g_hardware;
 };
 
+typedef void(*lldpd_ifhandlers)(struct lldpd *, struct ifaddrs *);
+
 enum hmsg_type {
        HMSG_NONE,
        HMSG_GET_INTERFACES,
@@ -301,8 +321,9 @@ struct hmsg {
 #define MAX_HMSGSIZE           8192
 
 /* lldpd.c */
-void    lldpd_cleanup(struct lldpd *);
-void    lldpd_hardware_cleanup(struct lldpd_hardware *);
+struct lldpd_hardware  *lldpd_get_hardware(struct lldpd *, char *);
+struct lldpd_hardware  *lldpd_alloc_hardware(struct lldpd *, char *);
+void    lldpd_hardware_cleanup(struct lldpd*, struct lldpd_hardware *);
 #ifdef ENABLE_DOT1
 void    lldpd_vlan_cleanup(struct lldpd_port *);
 #endif
@@ -354,18 +375,12 @@ int        ctl_msg_unpack_list(char *, void *, unsigned int, struct hmsg *, void **);
 int     ctl_msg_pack_structure(char *, void *, unsigned int, struct hmsg *, void **);
 int     ctl_msg_unpack_structure(char *, void *, unsigned int, struct hmsg *, void **);
 
-/* features.c */
-int     iface_is_bridge(struct lldpd *, const char *);
-int     iface_is_bridged_to(struct lldpd *,
-    const char *, const char *);
-int     iface_is_wireless(struct lldpd *, const char *);
-int     iface_is_vlan(struct lldpd *, const char *);
-int     iface_is_bond(struct lldpd *, const char *);
-int     iface_is_bond_slave(struct lldpd *,
-    const char *, const char *, int *);
-int     iface_is_enslaved(struct lldpd *, const char *);
-int     iface_is_slave_active(struct lldpd *, int, const char *);
-void    iface_get_permanent_mac(struct lldpd *, struct lldpd_hardware *);
+/* interfaces.c */
+void    lldpd_ifh_eth(struct lldpd *, struct ifaddrs *);
+void    lldpd_ifh_vlan(struct lldpd *, struct ifaddrs *);
+void    lldpd_ifh_mgmt(struct lldpd *, struct ifaddrs *);
+
+/* dmi.c */
 #ifdef ENABLE_LLDPMED
 char   *dmi_hw();
 char   *dmi_fw();
@@ -422,7 +437,7 @@ void         priv_ctl_cleanup();
 char           *priv_gethostbyname();
 int             priv_open(char*);
 int             priv_ethtool(char*, struct ethtool_cmd*);
-int             priv_iface_init(struct lldpd_hardware *, int);
+int             priv_iface_eth_init(struct lldpd_hardware *);
 int     priv_iface_multicast(const char *, u_int8_t *, int);
 int     priv_snmp_socket(struct sockaddr_un *);
 
index 219ef1ddd2cd11f2b83c3f2fe9c55f9c9107532d..0091689204d699925a1e2e52ab33c63c110687c7 100644 (file)
@@ -152,17 +152,16 @@ priv_ethtool(char *ifname, struct ethtool_cmd *ethc)
 }
 
 int
-priv_iface_init(struct lldpd_hardware *hardware, int master)
+priv_iface_eth_init(struct lldpd_hardware *hardware)
 {
        int cmd, rc;
        cmd = PRIV_IFACE_INIT;
        must_write(remote, &cmd, sizeof(int));
-       must_write(remote, &master, sizeof(int));
        must_write(remote, hardware->h_ifname, IFNAMSIZ);
        must_read(remote, &rc, sizeof(int));
        if (rc != 0)
                return rc;      /* It's errno */
-       hardware->h_raw = receive_fd(remote);
+       hardware->h_sendfd = receive_fd(remote);
        return 0;
 }
 
@@ -328,8 +327,6 @@ asroot_ethtool()
        ifr.ifr_data = (caddr_t)&ethc;
        ethc.cmd = ETHTOOL_GSET;
        if ((rc = ioctl(sock, SIOCETHTOOL, &ifr)) != 0) {
-               LLOG_DEBUG("[priv]: unable to ioctl ETHTOOL for %s: %m",
-                   ifr.ifr_name);
                must_write(remote, &rc, sizeof(int));
                return;
        }
@@ -338,14 +335,12 @@ asroot_ethtool()
 }
 
 static void
-asroot_iface_init()
+asroot_iface_eth_init()
 {
        struct sockaddr_ll sa;
-       int un = 1;
-       int s, master;
+       int s;
        char ifname[IFNAMSIZ];
 
-       must_read(remote, &master, sizeof(int));
        must_read(remote, ifname, IFNAMSIZ);
        ifname[IFNAMSIZ-1] = '\0';
 
@@ -358,27 +353,12 @@ asroot_iface_init()
        memset(&sa, 0, sizeof(sa));
        sa.sll_family = AF_PACKET;
        sa.sll_protocol = 0;
-       if (master == -1)
-               sa.sll_ifindex = if_nametoindex(ifname);
-       else
-               sa.sll_ifindex = master;
+       sa.sll_ifindex = if_nametoindex(ifname);
        if (bind(s, (struct sockaddr*)&sa, sizeof(sa)) < 0) {
                must_write(remote, &errno, sizeof(errno));
                close(s);
                return;
        }
-
-       if (master != -1) {
-               /* With bonding, we need to listen to bond device. We use
-                * setsockopt() PACKET_ORIGDEV to get physical device instead of
-                * bond device */
-               if (setsockopt(s, SOL_PACKET,
-                       PACKET_ORIGDEV, &un, sizeof(un)) == -1) {
-                       LLOG_WARN("[priv]: unable to setsockopt for master bonding device of %s. "
-                            "You will get inaccurate results",
-                           ifname);
-                }
-       }
        errno = 0;
        must_write(remote, &errno, sizeof(errno));
        send_fd(remote, s);
@@ -454,7 +434,7 @@ static struct dispatch_actions actions[] = {
        {PRIV_GET_HOSTNAME, asroot_gethostbyname},
        {PRIV_OPEN, asroot_open},
        {PRIV_ETHTOOL, asroot_ethtool},
-       {PRIV_IFACE_INIT, asroot_iface_init},
+       {PRIV_IFACE_INIT, asroot_iface_eth_init},
        {PRIV_IFACE_MULTICAST, asroot_iface_multicast},
        {PRIV_SNMP_SOCKET, asroot_snmp_socket},
        {-1, NULL}
index e58fb989998b33c1816af976ee4e0028f94aa08c..cb201fb19101a8a05b1aebd4d37cf5ceb3a3a89d 100644 (file)
@@ -226,7 +226,7 @@ sonmp_send(struct lldpd *global,
              /* 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(hardware->h_ifindex) &&
              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 */
@@ -234,7 +234,8 @@ sonmp_send(struct lldpd *global,
              POKE_SAVE(end)))
                goto toobig;
 
-       if (write(hardware->h_raw, packet, end - packet) == -1) {
+       if (hardware->h_ops->send(global, hardware,
+               (char *)packet, end - packet) == -1) {
                LLOG_WARN("unable to send packet on real device for %s",
                           hardware->h_ifname);
                free(packet);
@@ -247,7 +248,8 @@ sonmp_send(struct lldpd *global,
        PEEK_DISCARD(ETH_ALEN - 1); /* Modify the last byte of the MAC address */
        POKE_UINT8(1);
 
-       if (write(hardware->h_raw, packet, end - packet) == -1) {
+       if (hardware->h_ops->send(global, hardware,
+               (char *)packet, end - packet) == -1) {
                LLOG_WARN("unable to send second SONMP packet on real device for %s",
                           hardware->h_ifname);
                free(packet);