int exact, size_t *var_len, WriteMethod **write_method)
{
struct lldpd_chassis *chassis = LOCAL_CHASSIS(scfg);
+ struct lldpd_mgmt *mgmt;
if (!header_index_init(vp, name, length, exact, var_len, write_method)) return NULL;
- oid index[6] = {
- 1, 4,
- ((u_int8_t*)&chassis->c_mgmt.s_addr)[0],
- ((u_int8_t*)&chassis->c_mgmt.s_addr)[1],
- ((u_int8_t*)&chassis->c_mgmt.s_addr)[2],
- ((u_int8_t*)&chassis->c_mgmt.s_addr)[3] };
- if (header_index_add(index, 6,
- chassis) || header_index_best() != NULL)
- return chassis;
+ TAILQ_FOREACH(mgmt, &chassis->c_mgmt, m_entries) {
+ if (mgmt->m_family != LLDPD_AF_IPV4)
+ continue;
+ oid index[6] = {
+ 1, 4,
+ mgmt->m_addr.octets[0],
+ mgmt->m_addr.octets[1],
+ mgmt->m_addr.octets[2],
+ mgmt->m_addr.octets[3] };
+ if (header_index_add(index, 6, chassis))
+ return chassis;
+ }
- return NULL;
+ return header_index_best();
}
static struct lldpd_chassis*
{
struct lldpd_hardware *hardware;
struct lldpd_port *port;
+ struct lldpd_mgmt *mgmt;
if (!header_index_init(vp, name, length, exact, var_len, write_method)) return NULL;
TAILQ_FOREACH(hardware, &scfg->g_hardware, h_entries) {
TAILQ_FOREACH(port, &hardware->h_rports, p_entries) {
if (SMART_HIDDEN(port)) continue;
- if (port->p_chassis->c_mgmt.s_addr == INADDR_ANY)
- continue;
- oid index[9] = { lastchange(port),
- hardware->h_ifindex,
- port->p_chassis->c_index,
- 1, 4,
- ((u_int8_t*)&port->p_chassis->c_mgmt.s_addr)[0],
- ((u_int8_t*)&port->p_chassis->c_mgmt.s_addr)[1],
- ((u_int8_t*)&port->p_chassis->c_mgmt.s_addr)[2],
- ((u_int8_t*)&port->p_chassis->c_mgmt.s_addr)[3] };
- if (header_index_add(index, 9,
- port->p_chassis))
- return port->p_chassis;
+ TAILQ_FOREACH(mgmt, &port->p_chassis->c_mgmt, m_entries) {
+ if (mgmt->m_family != LLDPD_AF_IPV4)
+ continue;
+ oid index[9] = { lastchange(port),
+ hardware->h_ifindex,
+ port->p_chassis->c_index,
+ 1, 4,
+ mgmt->m_addr.octets[0],
+ mgmt->m_addr.octets[1],
+ mgmt->m_addr.octets[2],
+ mgmt->m_addr.octets[3] };
+ if (header_index_add(index, 9,
+ port->p_chassis))
+ return port->p_chassis;
+ }
}
}
return header_index_best();
case LLDP_SNMP_ADDR_LEN:
long_ret = 5;
return (u_char*)&long_ret;
+/* FIXME */
+/*
case LLDP_SNMP_ADDR_IFSUBTYPE:
- if (chassis->c_mgmt_if != 0)
+ if (chassis->c_mgmt4.iface != 0)
long_ret = LLDP_MGMT_IFACE_IFINDEX;
else
long_ret = 1;
return (u_char*)&long_ret;
case LLDP_SNMP_ADDR_IFID:
- long_ret = chassis->c_mgmt_if;
+ long_ret = chassis->c_mgmt4.iface;
return (u_char*)&long_ret;
+*/
case LLDP_SNMP_ADDR_OID:
*var_len = sizeof(zeroDotZero);
return (u_char*)zeroDotZero;
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>
+#include <assert.h>
static int
cdp_send(struct lldpd *global,
struct lldpd_hardware *hardware, int version)
{
struct lldpd_chassis *chassis;
+ struct lldpd_mgmt *mgmt;
u_int8_t mcastaddr[] = CDP_MULTICAST_ADDR;
u_int8_t llcorg[] = LLC_ORG_CISCO;
#ifdef ENABLE_FDP
goto toobig;
/* Adresses */
- if (!(
- POKE_START_CDP_TLV(CDP_TLV_ADDRESSES) &&
- POKE_UINT32(1) && /* We ship only one address */
- POKE_UINT8(1) && /* Type: NLPID */
- POKE_UINT8(1) && /* Length: 1 */
- POKE_UINT8(CDP_ADDRESS_PROTO_IP) && /* IP */
- POKE_UINT16(sizeof(struct in_addr)) && /* Address length */
- POKE_BYTES(&chassis->c_mgmt, sizeof(struct in_addr)) &&
- POKE_END_CDP_TLV))
- goto toobig;
+ TAILQ_FOREACH(mgmt, &chassis->c_mgmt, m_entries) {
+ if (mgmt->m_family == LLDPD_AF_IPV4) {
+ if (!(
+ POKE_START_CDP_TLV(CDP_TLV_ADDRESSES) &&
+ POKE_UINT32(1) && /* We ship only one address */
+ POKE_UINT8(1) && /* Type: NLPID */
+ POKE_UINT8(1) && /* Length: 1 */
+ POKE_UINT8(CDP_ADDRESS_PROTO_IP) && /* IP */
+ POKE_UINT16(sizeof(struct in_addr)) && /* Address length */
+ POKE_BYTES(&mgmt->m_addr, sizeof(struct in_addr)) &&
+ POKE_END_CDP_TLV)) {
+ goto toobig;
+ }
+ break;
+ }
+ }
/* Port ID */
if (!(
{
struct lldpd_chassis *chassis;
struct lldpd_port *port;
+ struct lldpd_mgmt *mgmt;
+ struct in_addr addr;
#if 0
u_int16_t cksum;
#endif
LLOG_WARN("failed to allocate remote chassis");
return -1;
}
+ TAILQ_INIT(&chassis->c_mgmt);
if ((port = calloc(1, sizeof(struct lldpd_port))) == NULL) {
LLOG_WARN("failed to allocate remote port");
free(chassis);
PEEK_RESTORE(pos_address);
if ((PEEK_UINT8 == 1) && (PEEK_UINT8 == 1) &&
(PEEK_UINT8 == CDP_ADDRESS_PROTO_IP) &&
- (PEEK_UINT16 == sizeof(struct in_addr)) &&
- (chassis->c_mgmt.s_addr == INADDR_ANY))
- PEEK_BYTES(&chassis->c_mgmt,
- sizeof(struct in_addr));
+ (PEEK_UINT16 == sizeof(struct in_addr))) {
+ PEEK_BYTES(&addr, sizeof(struct in_addr));
+ mgmt = lldpd_alloc_mgmt(LLDPD_AF_IPV4, &addr,
+ sizeof(struct in_addr), 0);
+ if (mgmt == NULL) {
+ assert(errno == ENOMEM);
+ LLOG_WARN("unable to allocate memory for management address");
+ goto malformed;
+ }
+ TAILQ_INSERT_TAIL(&chassis->c_mgmt, mgmt, m_entries);
+ }
/* Go to the end of the address */
PEEK_RESTORE(pos_next_address);
}
{
char *cid;
struct in_addr ip;
+ struct lldpd_mgmt *mgmt;
+ char addrbuf[INET6_ADDRSTRLEN];
if ((cid = (char *)malloc(chassis->c_id_len + 1)) == NULL)
fatal(NULL);
tag_datatag(w, "name", "SysName", chassis->c_name);
tag_datatag(w, "descr", "SysDescr", chassis->c_descr);
- if (chassis->c_mgmt.s_addr != INADDR_ANY)
- tag_datatag(w, "mgmt-ip", "MgmtIP", inet_ntoa(chassis->c_mgmt));
+ TAILQ_FOREACH(mgmt, &chassis->c_mgmt, m_entries) {
+ memset(addrbuf, 0, sizeof(addrbuf));
+ inet_ntop(lldpd_af(mgmt->m_family), &mgmt->m_addr, addrbuf, sizeof(addrbuf));
+ switch (mgmt->m_family) {
+ case LLDPD_AF_IPV4:
+ tag_datatag(w, "mgmt-ip", "MgmtIP", addrbuf);
+ break;
+ case LLDPD_AF_IPV6:
+ tag_datatag(w, "mgmt-ip6", "MgmtIPv6", addrbuf);
+ break;
+ }
+ }
display_cap(w, chassis, LLDP_CAP_OTHER, "Other");
display_cap(w, chassis, LLDP_CAP_REPEATER, "Repeater");
#include <errno.h>
#include <arpa/inet.h>
#include <fnmatch.h>
+#include <assert.h>
static int seq = 0;
{
struct lldpd_chassis *chassis;
struct lldpd_port *port;
+ struct lldpd_mgmt *mgmt, *m;
#ifdef ENABLE_DOT1
struct lldpd_vlan *lvlan = NULL, *lvlan_next;
#endif
LLOG_WARN("failed to allocate remote chassis");
return -1;
}
+ TAILQ_INIT(&chassis->c_mgmt);
if ((port = calloc(1, sizeof(struct lldpd_port))) == NULL) {
LLOG_WARN("failed to allocate remote port");
free(chassis);
PEEK_BYTES(lvlan->v_name, tlv_len - 12);
if (address.s_addr != INADDR_ANY) {
- if (chassis->c_mgmt.s_addr == INADDR_ANY)
- chassis->c_mgmt.s_addr = address.s_addr;
- else
- /* We need to guess the good one */
- if (cfg->g_mgmt_pattern != NULL) {
- /* We can try to use this to prefer an address */
- char *ip;
- ip = inet_ntoa(address);
- if (fnmatch(cfg->g_mgmt_pattern,
- ip, 0) == 0)
- chassis->c_mgmt.s_addr = address.s_addr;
- }
+ mgmt = lldpd_alloc_mgmt(LLDPD_AF_IPV4, &address,
+ sizeof(struct in_addr), 0);
+ if (mgmt == NULL) {
+ assert(errno == ENOMEM);
+ LLOG_WARN("Out of memory");
+ goto malformed;
+ }
+ TAILQ_INSERT_TAIL(&chassis->c_mgmt, mgmt, m_entries);
}
TAILQ_INSERT_TAIL(&port->p_vlans,
lvlan, v_entries);
lvlan, v_entries);
}
/* And the IP address */
- oport->p_chassis->c_mgmt.s_addr =
- chassis->c_mgmt.s_addr;
- break;
+ TAILQ_FOREACH(mgmt, &chassis->c_mgmt, m_entries) {
+ m = lldpd_alloc_mgmt(mgmt->m_family,
+ &mgmt->m_addr, mgmt->m_addrsize, mgmt->m_iface);
+ if (m == NULL) {
+ assert(errno == ENOMEM);
+ LLOG_WARN("Out of memory");
+ goto malformed;
+ }
+ TAILQ_INSERT_TAIL(&oport->p_chassis->c_mgmt, m, m_entries);
+ }
}
/* We discard the remaining frame */
goto malformed;
#include <stddef.h>
#include <unistd.h>
#include <errno.h>
+#include <assert.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
}
#endif
+#ifndef IN_IS_ADDR_LOOPBACK
+#define IN_IS_ADDR_LOOPBACK(a) ((a)->s_addr == htonl(INADDR_LOOPBACK))
+#endif
+#ifndef IN_IS_ADDR_GLOBAL
+#define IN_IS_ADDR_GLOBAL(a) (!IN_IS_ADDR_LOOPBACK(a))
+#endif
+#ifndef IN6_IS_ADDR_GLOBAL
+#define IN6_IS_ADDR_GLOBAL(a) (!IN6_IS_ADDR_LOOPBACK(a) && \
+ !IN6_IS_ADDR_LINKLOCAL(a))
+#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
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 */
+ char addrstrbuf[INET6_ADDRSTRLEN];
+ struct lldpd_mgmt *mgmt, *mgmt_next;
+ void *sin_addr_ptr;
+ size_t sin_addr_size;
+ char *mgmt_pattern_ptr;
+ int af;
+
+ for (mgmt = TAILQ_FIRST(&LOCAL_CHASSIS(cfg)->c_mgmt); mgmt;
+ mgmt = mgmt_next) {
+ mgmt_next = TAILQ_NEXT(mgmt, m_entries);
+ TAILQ_REMOVE(&LOCAL_CHASSIS(cfg)->c_mgmt, mgmt, m_entries);
+ free(mgmt);
+ }
- 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) */
- memcpy(&sa, ifa->ifa_addr, sizeof(struct sockaddr_in));
- 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);
+ /* Find management addresses */
+ for (af = LLDPD_AF_UNSPEC + 1; af != LLDPD_AF_LAST; af++) {
+ /* We only take one of each address family */
+ mgmt = NULL;
+ for (ifa = ifap; ifa != NULL && mgmt == NULL; ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr == NULL)
+ continue;
+ if (ifa->ifa_addr->sa_family != lldpd_af(af))
+ continue;
+ switch (af) {
+ case LLDPD_AF_IPV4:
+ sin_addr_ptr = &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
+ sin_addr_size = sizeof(struct in_addr);
+ if (!IN_IS_ADDR_GLOBAL((struct in_addr *)sin_addr_ptr))
+ continue;
+ mgmt_pattern_ptr = cfg->g_mgmt_pattern;
+ break;
+ case LLDPD_AF_IPV6:
+ sin_addr_ptr = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
+ sin_addr_size = sizeof(struct in6_addr);
+ if (!IN6_IS_ADDR_GLOBAL((struct in6_addr *)sin_addr_ptr))
+ continue;
+ mgmt_pattern_ptr = cfg->g_mgmt_pattern6;
+ break;
+ default:
+ assert(0);
+ }
+ inet_ntop(lldpd_af(af), sin_addr_ptr, addrstrbuf, sizeof(addrstrbuf));
+ if (mgmt_pattern_ptr == NULL ||
+ fnmatch(mgmt_pattern_ptr, addrstrbuf, 0) == 0) {
+ mgmt = lldpd_alloc_mgmt(af, sin_addr_ptr, sin_addr_size,
+ if_nametoindex(ifa->ifa_name));
+ if (mgmt == NULL) {
+ assert(errno == ENOMEM); /* anything else is a bug */
+ LLOG_WARN("out of memory error");
+ return;
}
+ TAILQ_INSERT_TAIL(&LOCAL_CHASSIS(cfg)->c_mgmt, mgmt, m_entries);
}
}
}
}
+
/* Fill out chassis ID if not already done. This handler is special
because we will only handle interfaces that are already handled. */
void
#include <unistd.h>
#include <errno.h>
+#include <assert.h>
#include <time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netpacket/packet.h>
#include <linux/sockios.h>
+inline static int
+lldpd_af_to_lldp_proto(int af)
+{
+ switch (af) {
+ case LLDPD_AF_IPV4:
+ return LLDP_MGMT_ADDR_IP4;
+ case LLDPD_AF_IPV6:
+ return LLDP_MGMT_ADDR_IP6;
+ default:
+ return LLDP_MGMT_ADDR_NONE;
+ }
+}
+
+inline static int
+lldpd_af_from_lldp_proto(int proto)
+{
+ switch (proto) {
+ case LLDP_MGMT_ADDR_IP4:
+ return LLDPD_AF_IPV4;
+ case LLDP_MGMT_ADDR_IP6:
+ return LLDPD_AF_IPV6;
+ default:
+ return LLDPD_AF_UNSPEC;
+ }
+}
+
int
lldp_send(struct lldpd *global,
struct lldpd_hardware *hardware)
struct lldpd_frame *frame;
int length;
u_int8_t *packet, *pos, *tlv;
+ struct lldpd_mgmt *mgmt;
+ int proto;
u_int8_t mcastaddr[] = LLDP_MULTICAST_ADDR;
#ifdef ENABLE_DOT1
POKE_END_LLDP_TLV))
goto toobig;
- if (chassis->c_mgmt.s_addr != INADDR_ANY) {
- /* Management address */
+ /* Management addresses */
+ TAILQ_FOREACH(mgmt, &chassis->c_mgmt, m_entries) {
+ proto = lldpd_af_to_lldp_proto(mgmt->m_family);
+ assert(proto != LLDP_MGMT_ADDR_NONE);
if (!(
- POKE_START_LLDP_TLV(LLDP_TLV_MGMT_ADDR) &&
- /* Size of the address, including its type */
- POKE_UINT8(sizeof(struct in_addr) + 1) &&
- /* Address is IPv4 */
- POKE_UINT8(LLDP_MGMT_ADDR_IP4) &&
- POKE_BYTES(&chassis->c_mgmt, sizeof(struct in_addr))))
+ POKE_START_LLDP_TLV(LLDP_TLV_MGMT_ADDR) &&
+ /* Size of the address, including its type */
+ POKE_UINT8(mgmt->m_addrsize + 1) &&
+ POKE_UINT8(proto) &&
+ POKE_BYTES(&mgmt->m_addr, mgmt->m_addrsize)))
goto toobig;
/* Interface port type, OID */
- if (chassis->c_mgmt_if == 0) {
+ if (mgmt->m_iface == 0) {
if (!(
- /* We don't know the management interface */
- POKE_UINT8(LLDP_MGMT_IFACE_UNKNOWN) &&
- POKE_UINT32(0)))
+ /* We don't know the management interface */
+ POKE_UINT8(LLDP_MGMT_IFACE_UNKNOWN) &&
+ POKE_UINT32(0)))
goto toobig;
} else {
if (!(
- /* We have the index of the management interface */
- POKE_UINT8(LLDP_MGMT_IFACE_IFINDEX) &&
- POKE_UINT32(chassis->c_mgmt_if)))
+ /* We have the index of the management interface */
+ POKE_UINT8(LLDP_MGMT_IFACE_IFINDEX) &&
+ POKE_UINT32(mgmt->m_iface)))
goto toobig;
}
if (!(
- /* We don't provide an OID for management */
- POKE_UINT8(0) &&
- POKE_END_LLDP_TLV))
+ /* We don't provide an OID for management */
+ POKE_UINT8(0) &&
+ POKE_END_LLDP_TLV))
goto toobig;
}
struct lldpd_ppvid *ppvid;
struct lldpd_pi *pi;
#endif
+ struct lldpd_mgmt *mgmt;
+ int af;
+ u_int8_t addr_str_length, addr_str_buffer[32];
+ u_int8_t addr_family, addr_length, *addr_ptr, iface_subtype;
+ u_int32_t iface_number, iface;
if ((chassis = calloc(1, sizeof(struct lldpd_chassis))) == NULL) {
LLOG_WARN("failed to allocate remote chassis");
return -1;
}
+ TAILQ_INIT(&chassis->c_mgmt);
if ((port = calloc(1, sizeof(struct lldpd_port))) == NULL) {
LLOG_WARN("failed to allocate remote port");
free(chassis);
chassis->c_cap_enabled = PEEK_UINT16;
break;
case LLDP_TLV_MGMT_ADDR:
- CHECK_TLV_SIZE(11, "Management address");
- if ((chassis->c_mgmt.s_addr == INADDR_ANY) &&
- (PEEK_UINT8 == 1+sizeof(struct in_addr)) &&
- (PEEK_UINT8 == LLDP_MGMT_ADDR_IP4)) {
- /* We have an IPv4 address, we ignore anything else */
- PEEK_BYTES(&chassis->c_mgmt, sizeof(struct in_addr));
- chassis->c_mgmt_if = 0;
- /* We only handle ifIndex subtype */
- if (PEEK_UINT8 == LLDP_MGMT_IFACE_IFINDEX)
- chassis->c_mgmt_if = PEEK_UINT32;
+ CHECK_TLV_SIZE(1, "Management address");
+ addr_str_length = PEEK_UINT8;
+ CHECK_TLV_SIZE(addr_str_length, "Management address");
+ PEEK_BYTES(addr_str_buffer, addr_str_length);
+ addr_length = addr_str_length - 1;
+ addr_family = addr_str_buffer[0];
+ addr_ptr = &addr_str_buffer[1];
+ CHECK_TLV_SIZE(5, "Management address");
+ iface_subtype = PEEK_UINT8;
+ iface_number = PEEK_UINT32;
+
+ af = lldpd_af_from_lldp_proto(addr_family);
+ if (af == LLDPD_AF_UNSPEC)
+ break;
+ if (iface_subtype == LLDP_MGMT_IFACE_IFINDEX)
+ iface = iface_number;
+ else
+ iface = 0;
+ mgmt = lldpd_alloc_mgmt(af, addr_ptr, addr_length, iface);
+ if (mgmt == NULL) {
+ assert(errno == ENOMEM);
+ LLOG_WARN("unable to allocate memory "
+ "for management address");
+ goto malformed;
}
+ TAILQ_INSERT_TAIL(&chassis->c_mgmt, mgmt, m_entries);
break;
case LLDP_TLV_ORG:
CHECK_TLV_SIZE(4, "Organisational");
/* see http://www.iana.org/assignments/address-family-numbers */
enum {
+ LLDP_MGMT_ADDR_NONE = 0,
LLDP_MGMT_ADDR_IP4 = 1,
LLDP_MGMT_ADDR_IP6 = 2
};
#include <fcntl.h>
#include <time.h>
#include <libgen.h>
+#include <assert.h>
#include <sys/utsname.h>
#include <sys/types.h>
#include <sys/wait.h>
fprintf(stderr, "-k Disable advertising of kernel release, version, machine.\n");
fprintf(stderr, "-S descr Override the default system description.\n");
fprintf(stderr, "-P name Override the default hardware platform.\n");
- fprintf(stderr, "-m IP Specify the management address of this system.\n");
+ fprintf(stderr, "-4 IP Specify the IPv4 management address of this system.\n");
+ fprintf(stderr, "-m IP Same as '-4', for backward compatibility.\n");
+ fprintf(stderr, "-6 IP Specify the IPv6 management address of this system.\n");
fprintf(stderr, "-H mode Specify the behaviour when detecting multiple neighbors.\n");
fprintf(stderr, "-I iface Limit interfaces to use.\n");
#ifdef ENABLE_LLDPMED
}
}
+struct lldpd_mgmt *
+lldpd_alloc_mgmt(int family, void *addrptr, size_t addrsize, u_int32_t iface)
+{
+ struct lldpd_mgmt *mgmt;
+
+ if (family <= LLDPD_AF_UNSPEC || family >= LLDPD_AF_LAST) {
+ errno = EAFNOSUPPORT;
+ return NULL;
+ }
+ if (addrsize > LLDPD_MGMT_MAXADDRSIZE) {
+ errno = EOVERFLOW;
+ return NULL;
+ }
+ mgmt = calloc(1, sizeof(struct lldpd_mgmt));
+ if (mgmt == NULL) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ mgmt->m_family = family;
+ assert(addrsize <= LLDPD_MGMT_MAXADDRSIZE);
+ memcpy(&mgmt->m_addr, addrptr, addrsize);
+ mgmt->m_addrsize = addrsize;
+ mgmt->m_iface = iface;
+ return mgmt;
+}
+
void
lldpd_chassis_cleanup(struct lldpd_chassis *chassis, int all)
{
TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries)
hardware->h_flags = 0;
- LOCAL_CHASSIS(cfg)->c_mgmt.s_addr = INADDR_ANY;
if (getifaddrs(&ifap) != 0)
fatal("lldpd_update_localports: failed to get interface list");
int snmp = 0;
char *agentx = NULL; /* AgentX socket */
#endif
- char *mgmtp = NULL;
+ char *mgmtp = NULL, *mgmtp6 = NULL;
char *cidp = NULL;
char *interfaces = NULL;
char *popt, opts[] =
- "H:hkrdxX:m:I:C:p:M:P:S:i@ ";
+ "H:hkrdxX:m:4:6:I:C:p:M:P:S:i@ ";
int i, found, advertise_version = 1;
#ifdef ENABLE_LLDPMED
int lldpmed = 0, noinventory = 0;
case 'r':
receiveonly = 1;
break;
- case 'm':
+ case 'm': /* fall through */
+ case '4':
mgmtp = optarg;
break;
+ case '6':
+ mgmtp6 = optarg;
case 'I':
interfaces = optarg;
break;
fatal(NULL);
cfg->g_mgmt_pattern = mgmtp;
+ cfg->g_mgmt_pattern6 = mgmtp6;
cfg->g_cid_pattern = cidp;
cfg->g_interfaces = interfaces;
cfg->g_smart = smart;
fatal(NULL);
lchassis->c_cap_available = LLDP_CAP_BRIDGE | LLDP_CAP_WLAN |
LLDP_CAP_ROUTER;
+ TAILQ_INIT(&lchassis->c_mgmt);
#ifdef ENABLE_LLDPMED
if (lldpmed > 0) {
if (lldpmed == LLDPMED_CLASS_III)
#define LLDPD_PPVID_CAP_SUPPORTED (1 << 1)
#define LLDPD_PPVID_CAP_ENABLED (1 << 2)
+enum {
+ LLDPD_AF_UNSPEC = 0,
+ LLDPD_AF_IPV4,
+ LLDPD_AF_IPV6,
+ LLDPD_AF_LAST
+};
+
+inline static int
+lldpd_af(int af)
+{
+ switch (af) {
+ case LLDPD_AF_IPV4:
+ return AF_INET;
+ case LLDPD_AF_IPV6:
+ return AF_INET6;
+ case LLDPD_AF_LAST:
+ return AF_MAX;
+ default:
+ return AF_UNSPEC;
+ }
+}
+
struct lldpd_ppvid {
TAILQ_ENTRY(lldpd_ppvid) p_entries;
u_int8_t p_cap_status;
MARSHAL(lldpd_dot3_power);
#endif
+#define LLDPD_MGMT_MAXADDRSIZE 16 /* sizeof(struct in6_addr) */
+struct lldpd_mgmt {
+ TAILQ_ENTRY(lldpd_mgmt) m_entries;
+ int m_family;
+ union {
+ struct in_addr inet;
+ struct in6_addr inet6;
+ u_int8_t octets[LLDPD_MGMT_MAXADDRSIZE];
+ } m_addr;
+ size_t m_addrsize;
+ u_int32_t m_iface;
+};
+MARSHAL_BEGIN(lldpd_mgmt)
+MARSHAL_TQE(lldpd_mgmt, m_entries)
+MARSHAL_END;
+
struct lldpd_chassis {
TAILQ_ENTRY(lldpd_chassis) c_entries;
u_int16_t c_refcount; /* Reference count by ports */
u_int16_t c_ttl;
- struct in_addr c_mgmt;
- u_int32_t c_mgmt_if;
+ TAILQ_HEAD(, lldpd_mgmt) c_mgmt;
#ifdef ENABLE_LLDPMED
u_int16_t c_med_cap_available;
MARSHAL_FSTR(lldpd_chassis, c_id, c_id_len)
MARSHAL_STR(lldpd_chassis, c_name)
MARSHAL_STR(lldpd_chassis, c_descr)
+MARSHAL_SUBTQ(lldpd_chassis, lldpd_mgmt, c_mgmt)
#ifdef ENABLE_LLDPMED
MARSHAL_STR(lldpd_chassis, c_med_hw)
MARSHAL_STR(lldpd_chassis, c_med_fw)
TAILQ_HEAD(, lldpd_callback) g_callbacks;
- char *g_mgmt_pattern;
+ char *g_mgmt_pattern, *g_mgmt_pattern6;
char *g_cid_pattern;
char *g_interfaces;
#endif
void lldpd_remote_cleanup(struct lldpd *, struct lldpd_hardware *, int);
void lldpd_port_cleanup(struct lldpd*, struct lldpd_port *, int);
+struct lldpd_mgmt *lldpd_alloc_mgmt(int family, void *addr, size_t addrsize, u_int32_t iface);
void lldpd_chassis_cleanup(struct lldpd_chassis *, int);
int lldpd_callback_add(struct lldpd *, int, void(*fn)(CALLBACK_SIG), void *);
void lldpd_callback_del(struct lldpd *, int, void(*fn)(CALLBACK_SIG));
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>
+#include <assert.h>
static struct sonmp_chassis sonmp_chassis_types[] = {
{1, "unknown (via SONMP)"},
const u_int8_t mcastaddr[] = SONMP_MULTICAST_ADDR;
const u_int8_t llcorg[] = LLC_ORG_NORTEL;
struct lldpd_chassis *chassis;
+ struct lldpd_mgmt *mgmt;
u_int8_t *packet, *pos, *pos_pid, *end;
int length;
+ struct in_addr address;
chassis = hardware->h_lport.p_chassis;
length = hardware->h_mtu;
POKE_UINT16(LLC_PID_SONMP_HELLO)))
goto toobig;
+
+ address.s_addr = htonl(INADDR_ANY);
+ TAILQ_FOREACH(mgmt, &chassis->c_mgmt, m_entries) {
+ if (mgmt->m_family == LLDPD_AF_IPV4) {
+ address.s_addr = mgmt->m_addr.inet.s_addr;
+ }
+ break;
+ }
+
/* SONMP */
if (!(
- /* Our IP address */
- POKE_BYTES(&chassis->c_mgmt, sizeof(struct in_addr)) &&
- /* Segment on three bytes, we don't have slots, so we
+ /* Our IP address */
+ POKE_BYTES(&address, sizeof(struct in_addr)) &&
+ /* Segment on three bytes, we don't have slots, so we
skip the first two bytes */
- POKE_UINT16(0) &&
- 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 */
- POKE_UINT8(1) && /* Links: Dunno what it is */
- POKE_SAVE(end)))
+ POKE_UINT16(0) &&
+ 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 */
+ POKE_UINT8(1) && /* Links: Dunno what it is */
+ POKE_SAVE(end)))
goto toobig;
-
+
if (hardware->h_ops->send(global, hardware,
(char *)packet, end - packet) == -1) {
LLOG_WARN("unable to send packet on real device for %s",
const u_int8_t mcastaddr[] = SONMP_MULTICAST_ADDR;
struct lldpd_chassis *chassis;
struct lldpd_port *port;
+ struct lldpd_mgmt *mgmt;
int length, i;
u_int8_t *pos;
u_int8_t seg[3], rchassis;
LLOG_WARN("failed to allocate remote chassis");
return -1;
}
+ TAILQ_INIT(&chassis->c_mgmt);
if ((port = calloc(1, sizeof(struct lldpd_port))) == NULL) {
LLOG_WARN("failed to allocate remote port");
free(chassis);
hardware->h_ifname);
goto malformed;
}
- memcpy(&chassis->c_mgmt, &address, sizeof(struct in_addr));
+ mgmt = lldpd_alloc_mgmt(LLDPD_AF_IPV4, &address, sizeof(struct in_addr), 0);
+ if (mgmt == NULL) {
+ assert(errno == ENOMEM);
+ LLOG_WARN("unable to allocate memory for management address");
+ goto malformed;
+ }
+ TAILQ_INSERT_TAIL(&chassis->c_mgmt, mgmt, m_entries);
chassis->c_ttl = LLDPD_TTL;
port->p_id_subtype = LLDP_PORTID_SUBTYPE_LOCAL;
chassis.c_name = "First chassis";
chassis.c_descr = "Chassis description";
chassis.c_cap_available = chassis.c_cap_enabled = LLDP_CAP_ROUTER;
- chassis.c_mgmt.s_addr = inet_addr("172.17.142.37");
+ TAILQ_INIT(&chassis.c_mgmt);
+ in_addr_t addr = inet_addr("172.17.142.37");
+ struct lldpd_mgmt *mgmt = lldpd_alloc_mgmt(LLDPD_AF_IPV4,
+ &addr, sizeof(in_addr_t), 0);
+ if (mgmt == NULL)
+ ck_abort();
+ TAILQ_INSERT_TAIL(&chassis.c_mgmt, mgmt, m_entries);
/* Build packet */
n = cdpv1_send(NULL, &hardware);
chassis.c_descr = "Chassis description";
chassis.c_cap_available = chassis.c_cap_enabled =
LLDP_CAP_ROUTER | LLDP_CAP_BRIDGE;
- chassis.c_mgmt.s_addr = inet_addr("172.17.142.36");
+ TAILQ_INIT(&chassis.c_mgmt);
+ in_addr_t addr = inet_addr("172.17.142.36");
+ struct lldpd_mgmt *mgmt = lldpd_alloc_mgmt(LLDPD_AF_IPV4,
+ &addr, sizeof(in_addr_t), 0);
+ if (mgmt == NULL)
+ ck_abort();
+ TAILQ_INSERT_TAIL(&chassis.c_mgmt, mgmt, m_entries);
/* Build packet */
n = cdpv2_send(NULL, &hardware);
ck_assert_int_eq(nchassis->c_id_len, 2);
fail_unless(memcmp(nchassis->c_id, "R1", 2) == 0);
ck_assert_str_eq(nchassis->c_name, "R1");
- ck_assert_int_eq(nchassis->c_mgmt.s_addr,
+ ck_assert_int_eq(nchassis->c_mgmt.tqh_first->m_addr.inet.s_addr,
(u_int32_t)inet_addr("192.168.10.1"));
- ck_assert_int_eq(nchassis->c_mgmt_if, 0);
+ ck_assert_int_eq(nchassis->c_mgmt.tqh_first->m_iface, 0);
ck_assert_int_eq(nport->p_id_subtype,
LLDP_PORTID_SUBTYPE_IFNAME);
ck_assert_int_eq(nport->p_id_len, strlen("Ethernet0"));
fail_unless(memcmp(nchassis->c_id,
"rtbg6test01", strlen("rtbg6test01")) == 0);
ck_assert_str_eq(nchassis->c_name, "rtbg6test01");
- ck_assert_int_eq(nchassis->c_mgmt.s_addr,
+ ck_assert_int_eq(TAILQ_FIRST(&nchassis->c_mgmt)->m_addr.inet.s_addr,
(u_int32_t)inet_addr("172.66.55.3"));
- ck_assert_int_eq(nchassis->c_mgmt_if, 0);
+ ck_assert_int_eq(TAILQ_FIRST(&nchassis->c_mgmt)->m_iface, 0);
ck_assert_int_eq(nport->p_id_subtype,
LLDP_PORTID_SUBTYPE_IFNAME);
ck_assert_int_eq(nport->p_id_len, strlen("FastEthernet0/0"));
fail("unable to find our previous port?");
return;
}
- ck_assert_int_eq(nport->p_chassis->c_mgmt.s_addr,
+ ck_assert_int_eq(TAILQ_FIRST(&nport->p_chassis->c_mgmt)->m_addr.inet.s_addr,
(u_int32_t)inet_addr("10.50.0.63"));
if (TAILQ_EMPTY(&nport->p_vlans)) {
fail("no VLAN");
LLDP_CAP_WLAN | LLDP_CAP_ROUTER | LLDP_CAP_BRIDGE);
ck_assert_int_eq(nchassis->c_cap_enabled,
LLDP_CAP_ROUTER | LLDP_CAP_BRIDGE);
- ck_assert_int_eq(nchassis->c_mgmt.s_addr,
+ ck_assert_int_eq(nchassis->c_mgmt.tqh_first->m_addr.inet.s_addr,
(u_int32_t)inet_addr("10.238.80.75"));
- ck_assert_int_eq(nchassis->c_mgmt_if, 3);
+ ck_assert_int_eq(nchassis->c_mgmt.tqh_first->m_iface, 3);
#ifdef ENABLE_DOT3
ck_assert_int_eq(nport->p_aggregid, 0);
ck_assert_int_eq(nport->p_macphy.autoneg_enabled, 1);
.c_cap_available = LLDP_CAP_BRIDGE | LLDP_CAP_WLAN | LLDP_CAP_ROUTER,
.c_cap_enabled = LLDP_CAP_ROUTER,
.c_ttl = 60,
- .c_mgmt = { .s_addr = 251789504 }, /* 192.0.2.15 */
- .c_mgmt_if = 3,
+ .c_mgmt4 = {
+ .family = AF_INET,
+ .address = { .inet = { 251789504 } }, /* 192.0.2.15 */
+ .addrsize = sizeof(struct in_addr),
+ .iface = 3
+ },
#ifdef ENABLE_LLDPMED
.c_med_cap_available = LLDPMED_CAP_CAP | LLDPMED_CAP_IV | \
LLDPMED_CAP_LOCATION | LLDPMED_CAP_POLICY | \
.c_cap_available = LLDP_CAP_ROUTER,
.c_cap_enabled = LLDP_CAP_ROUTER,
.c_ttl = 60,
- .c_mgmt = { .s_addr = 285343936 }, /* 192.0.2.17 */
- .c_mgmt_if = 5,
+ .c_mgmt4 = {
+ .family = AF_INET,
+ .address = { .inet = { 285343936 } }, /* 192.0.2.17 */
+ .addrsize = sizeof(struct in_addr),
+ .iface = 5
+ },
#ifdef ENABLE_LLDPMED
.c_med_hw = "Hardware 2",
/* We skip c_med_fw */
chassis.c_id_subtype = LLDP_CHASSISID_SUBTYPE_LLADDR;
chassis.c_id = macaddress;
chassis.c_id_len = ETH_ALEN;
- chassis.c_mgmt.s_addr = inet_addr("172.17.142.37");
+ TAILQ_INIT(&chassis.c_mgmt);
+ in_addr_t addr = inet_addr("172.17.142.37");
+ struct lldpd_mgmt *mgmt = lldpd_alloc_mgmt(LLDPD_AF_IPV4,
+ &addr, sizeof(in_addr_t), 0);
+ if (mgmt == NULL)
+ ck_abort();
+ TAILQ_INSERT_TAIL(&chassis.c_mgmt, mgmt, m_entries);
/* Build packet */
n = sonmp_send(NULL, &hardware);
fail_unless(memcmp(nchassis->c_id, cid, 5) == 0);
ck_assert_str_eq(nchassis->c_name, "172.16.101.168");
ck_assert_str_eq(nchassis->c_descr, "Nortel Ethernet Routing 8610 L3 Switch");
- ck_assert_int_eq(nchassis->c_mgmt.s_addr,
+ ck_assert_int_eq(TAILQ_FIRST(&nchassis->c_mgmt)->m_addr.inet.s_addr,
(u_int32_t)inet_addr("172.16.101.168"));
- ck_assert_int_eq(nchassis->c_mgmt_if, 0);
+ ck_assert_int_eq(TAILQ_FIRST(&nchassis->c_mgmt)->m_iface, 0);
ck_assert_str_eq(nport->p_descr, "port 2/8");
ck_assert_int_eq(nport->p_id_subtype,
LLDP_PORTID_SUBTYPE_LOCAL);