fi
# Options
+# CDP
AC_ARG_ENABLE(cdp, AC_HELP_STRING([--enable-cdp],
[Enable Cisco Discovery Protocol]),
[enable_cdp=$enableval],[enable_cdp=yes])
AC_MSG_RESULT(no)
fi
+# FDP
AC_ARG_ENABLE(fdp, AC_HELP_STRING([--enable-fdp],
[Enable Foundry Discovery Protocol]),
[enable_fdp=$enableval],[enable_fdp=yes])
AC_MSG_RESULT(no)
fi
+# EDP
AC_ARG_ENABLE(edp, AC_HELP_STRING([--enable-edp],
[Enable Extreme Discovery Protocol]),
[enable_edp=$enableval],[enable_edp=yes])
AC_MSG_RESULT(no)
fi
+# SONMP
AC_ARG_ENABLE(sonmp, AC_HELP_STRING([--enable-sonmp],
[Enable SynOptics Network Management Protocol]),
[enable_sonmp=$enableval],[enable_sonmp=yes])
AC_MSG_RESULT(no)
fi
+#LLDPMED
+AC_ARG_ENABLE(lldpmed, AC_HELP_STRING([--enable-lldpmed],
+ [Enable LLDP-MED extension]),
+ [enable_lldpmed=$enableval],[enable_lldpmed=yes])
+AC_MSG_CHECKING(whether to enable LLDP-MED)
+if test x$enable_lldpmed = xyes; then
+ AC_MSG_RESULT(yes)
+ AC_DEFINE([ENABLE_LLDPMED],, [Enable LLDP-MED extension])
+else
+ AC_MSG_RESULT(no)
+fi
+
AC_OUTPUT
.Op Fl dvxcse
.Op Fl m Ar management
.Op Fl p Ar probe time
+.Op Fl M Ar class
.Sh DESCRIPTION
.Nm
is a daemon able to receive and send
to detect false positives like SONMP frames running through a switch
only supporting CDP. This value is only used when multiple protocols
are enabled.
+.It Fl M Ar class
+Enable emission of LLDP-MED frame. The class should be one of the
+following value:
+.Bl -tag -width "0:XX" -compact
+.It Ar 1
+Generic Endpoint (Class I)
+.It Ar 2
+Media Endpoint (Class II)
+.It Ar 3
+Communication Device Endpoints (Class III)
+.It Ar 4
+Network Connectivity Device
.El
.Sh FILES
.Bl -tag -width "/var/run/lldpd.socketXX" -compact
#include <linux/sockios.h>
#define SYSFS_PATH_MAX 256
-#define SYSFS_CLASS_NET "/sys/class/net/"
#define MAX_PORTS 1024
/* net/if.h */
freeifaddrs(ifap);
return -1;
}
+
+#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
struct lldp_mgmt mgmt;
struct lldp_aggreg aggreg;
struct lldp_macphy macphy;
+#ifdef ENABLE_LLDPMED
+ const u_int8_t med[] = LLDP_TLV_ORG_MED;
+ struct lldpmed_cap medcap;
+ struct lldp_org medhw, medfw, medsw, medsn,
+ medmodel, medasset, medmanuf;
+#endif
struct lldpd_vlan *vlan;
struct lldpd_port *port = &hardware->h_lport;
u_int c = -1, len = 0, v;
iov[c].iov_base = &macphy;
iov[c].iov_len = sizeof(macphy);
+#ifdef ENABLE_LLDPMED
+ if (global->g_lchassis.c_med_cap) {
+ /* LLDP-MED cap */
+ memset(&medcap, 0, sizeof(medcap));
+ medcap.tlv_head.type_len = LLDP_TLV_HEAD(LLDP_TLV_ORG,
+ sizeof(medcap.tlv_org_id) +
+ sizeof(medcap.tlv_org_subtype) +
+ sizeof(medcap.tlv_cap) + sizeof(medcap.tlv_type));
+ memcpy(medcap.tlv_org_id, med, sizeof(medcap.tlv_org_id));
+ medcap.tlv_org_subtype = LLDP_TLV_MED_CAP;
+ medcap.tlv_cap = htons(global->g_lchassis.c_med_cap);
+ medcap.tlv_type = global->g_lchassis.c_med_type;
+ IOV_NEW;
+ iov[c].iov_base = &medcap;
+ iov[c].iov_len = sizeof(medcap);
+
+ /* LLDP-MED inventory */
+#define LLDP_INVENTORY(value, target, subtype) \
+ if (value) { \
+ memset(&target, 0, sizeof(target)); \
+ len = (strlen(value)>32)?32:strlen(value); \
+ target.tlv_head.type_len = \
+ LLDP_TLV_HEAD(LLDP_TLV_ORG, \
+ sizeof(target.tlv_org_id) + \
+ sizeof(target.tlv_org_subtype) + \
+ len); \
+ memcpy(target.tlv_org_id, med, \
+ sizeof(target.tlv_org_id)); \
+ target.tlv_org_subtype = subtype; \
+ IOV_NEW; \
+ iov[c].iov_base = ⌖ \
+ iov[c].iov_len = sizeof(target); \
+ IOV_NEW; \
+ iov[c].iov_base = value; \
+ iov[c].iov_len = len; \
+ }
+ LLDP_INVENTORY(global->g_lchassis.c_med_hw,
+ medhw, LLDP_TLV_MED_IV_HW);
+ LLDP_INVENTORY(global->g_lchassis.c_med_fw,
+ medfw, LLDP_TLV_MED_IV_FW);
+ LLDP_INVENTORY(global->g_lchassis.c_med_sw,
+ medsw, LLDP_TLV_MED_IV_SW);
+ LLDP_INVENTORY(global->g_lchassis.c_med_sn,
+ medsn, LLDP_TLV_MED_IV_SN);
+ LLDP_INVENTORY(global->g_lchassis.c_med_manuf,
+ medmanuf, LLDP_TLV_MED_IV_MANUF);
+ LLDP_INVENTORY(global->g_lchassis.c_med_model,
+ medmodel, LLDP_TLV_MED_IV_MODEL);
+ LLDP_INVENTORY(global->g_lchassis.c_med_asset,
+ medasset, LLDP_TLV_MED_IV_ASSET);
+ }
+#endif
+
/* END */
memset(&end, 0, sizeof(end));
IOV_NEW;
#define LLDP_TLV_ORG_DOT1 {0x00, 0x80, 0xc2}
#define LLDP_TLV_ORG_DOT3 {0x00, 0x12, 0x0f}
+#define LLDP_TLV_ORG_MED {0x00, 0x12, 0xbb}
enum {
LLDP_TLV_DOT1_PVID = 1,
struct lldp_tlv_head tlv_head;
} __attribute__ ((__packed__));
+#ifdef ENABLE_LLDPMED
+enum {
+ LLDP_TLV_MED_CAP = 1,
+ LLDP_TLV_MED_POLICY = 2,
+ LLDP_TLV_MED_LOCATION = 3,
+ LLDP_TLV_MED_MDI = 4,
+ LLDP_TLV_MED_IV_HW = 5,
+ LLDP_TLV_MED_IV_FW = 6,
+ LLDP_TLV_MED_IV_SW = 7,
+ LLDP_TLV_MED_IV_SN = 8,
+ LLDP_TLV_MED_IV_MANUF = 9,
+ LLDP_TLV_MED_IV_MODEL = 10,
+ LLDP_TLV_MED_IV_ASSET = 11
+};
+
+#define LLDPMED_CLASS_I 1
+#define LLDPMED_CLASS_II 2
+#define LLDPMED_CLASS_III 3
+#define LLDPMED_NETWORK_DEVICE 4
+
+#define LLDPMED_CAP_CAP 0x01
+#define LLDPMED_CAP_POLICY 0x02
+#define LLDPMED_CAP_LOCATION 0x04
+#define LLDPMED_CAP_MDI1 0x08
+#define LLDPMED_CAP_MDI2 0x10
+#define LLDPMED_CAP_IV 0x20
+
+struct lldpmed_cap {
+ struct lldp_tlv_head tlv_head;
+ u_int8_t tlv_org_id[3];
+ u_int8_t tlv_org_subtype;
+ u_int16_t tlv_cap;
+ u_int8_t tlv_type;
+} __attribute__ ((__packed__));
+
+#endif /* ENABLE_LLDPMED */
+
+
#endif /* _LLDP_H */
int lldpd_guess_type(struct lldpd *, char *, int);
void lldpd_decode(struct lldpd *, char *, int,
struct lldpd_hardware *, int);
+#ifdef ENABLE_LLDPMED
+void lldpd_med(struct lldpd_chassis *);
+#endif
char **saved_argv;
void
lldpd_chassis_cleanup(struct lldpd_chassis *chassis)
{
+#ifdef ENABLE_LLDPMED
+ free(chassis->c_med_hw);
+ free(chassis->c_med_fw);
+ free(chassis->c_med_sn);
+ free(chassis->c_med_manuf);
+ free(chassis->c_med_model);
+ free(chassis->c_med_asset);
+#endif
free(chassis->c_id);
free(chassis->c_name);
free(chassis->c_descr);
}
}
+#ifdef ENABLE_LLDPMED
+void
+lldpd_med(struct lldpd_chassis *chassis)
+{
+ free(chassis->c_med_hw);
+ free(chassis->c_med_fw);
+ free(chassis->c_med_sn);
+ free(chassis->c_med_manuf);
+ free(chassis->c_med_model);
+ free(chassis->c_med_asset);
+ chassis->c_med_hw = dmi_hw();
+ chassis->c_med_fw = dmi_fw();
+ chassis->c_med_sn = dmi_sn();
+ chassis->c_med_manuf = dmi_manuf();
+ chassis->c_med_model = dmi_model();
+ chassis->c_med_asset = dmi_asset();
+}
+#endif
+
void
lldpd_loop(struct lldpd *cfg)
{
if (asprintf(&cfg->g_lchassis.c_descr, "%s %s %s %s",
un->sysname, un->release, un->version, un->machine) == -1)
fatal("failed to set system description");
- free(un);
/* Check forwarding */
cfg->g_lchassis.c_cap_enabled = 0;
}
close(f);
}
+#ifdef ENABLE_LLDPMED
+ if (cfg->g_lchassis.c_cap_available & LLDP_CAP_TELEPHONE)
+ cfg->g_lchassis.c_cap_enabled |= LLDP_CAP_TELEPHONE;
+ lldpd_med(&cfg->g_lchassis);
+ free(cfg->g_lchassis.c_med_sw);
+ cfg->g_lchassis.c_med_sw = strdup(un->release);
+#endif
+ free(un);
TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries)
hardware->h_flags = 0;
char *mgmtp = NULL;
char *popt, opts[] = "vdxm:p:@ ";
int probe = 0, i, found, vlan = 0;
+#ifdef ENABLE_LLDPMED
+ int lldpmed = 0;
+#endif
saved_argv = argv;
if (protos[i].enabled == 1) continue;
*(popt++) = protos[i].arg;
}
+#ifdef ENABLE_LLDPMED
+ *(popt++) = 'M';
+ *(popt++) = ':';
+#endif
*popt = '\0';
while ((ch = getopt(argc, argv, opts)) != -1) {
switch (ch) {
case 'm':
mgmtp = optarg;
break;
+#ifdef ENABLE_LLDPMED
+ case 'M':
+ lldpmed = atoi(optarg);
+ if ((lldpmed < 1) || (lldpmed > 4))
+ usage();
+ break;
+#endif
case 'p':
probe = atoi(optarg);
break;
/* Set system capabilities */
cfg->g_lchassis.c_cap_available = LLDP_CAP_BRIDGE | LLDP_CAP_WLAN |
LLDP_CAP_ROUTER;
+#ifdef ENABLE_LLDPMED
+ if (lldpmed > 0) {
+ if (lldpmed == LLDPMED_CLASS_III)
+ cfg->g_lchassis.c_cap_available |= LLDP_CAP_TELEPHONE;
+ cfg->g_lchassis.c_med_type = lldpmed;
+ cfg->g_lchassis.c_med_cap = LLDPMED_CAP_CAP | LLDPMED_CAP_IV;
+ }
+#endif
/* Set TTL */
cfg->g_lchassis.c_ttl = LLDPD_TTL;
#include "edp.h"
#endif
+#define SYSFS_CLASS_NET "/sys/class/net/"
+#define SYSFS_CLASS_DMI "/sys/class/dmi/id/"
#define LLDPD_TTL 120
#define LLDPD_TX_DELAY 30
#define LLDPD_TX_MSGDELAY 1
struct in_addr c_mgmt;
u_int32_t c_mgmt_if;
+
+#ifdef ENABLE_LLDPMED
+ u_int16_t c_med_cap;
+ u_int8_t c_med_type;
+ char *c_med_hw;
+ char *c_med_fw;
+ char *c_med_sw;
+ char *c_med_sn;
+ char *c_med_manuf;
+ char *c_med_model;
+ char *c_med_asset;
+#endif
+
};
+#ifndef ENABLE_LLDP_MED
#define STRUCT_LLDPD_CHASSIS "bCsswwwll"
+#else
+#define STRUCT_LLDPD_CHASSIS "bCsswwwllwbsssssss"
+#endif
struct lldpd_port {
u_int8_t p_id_subtype;
int iface_is_bond_slave(struct lldpd *,
const char *, const char *);
int iface_is_enslaved(struct lldpd *, const char *);
+#ifdef ENABLE_LLDPMED
+char *dmi_hw();
+char *dmi_fw();
+char *dmi_sn();
+char *dmi_manuf();
+char *dmi_model();
+char *dmi_asset();
+#endif
/* log.c */
void log_init(int);
{
const char* authorized[] = {
"/proc/sys/net/ipv4/ip_forward",
- "/sys/class/net/[^.][^/]*/brforward",
- "/sys/class/net/[^.][^/]*/brport",
+ SYSFS_CLASS_NET "[^.][^/]*/brforward",
+ SYSFS_CLASS_NET "[^.][^/]*/brport",
+ SYSFS_CLASS_DMI "product_version",
+ SYSFS_CLASS_DMI "product_serial",
+ SYSFS_CLASS_DMI "product_name",
+ SYSFS_CLASS_DMI "bios_version",
+ SYSFS_CLASS_DMI "sys_vendor",
+ SYSFS_CLASS_DMI "chassis_asset_tag",
NULL
};
char **f;