]> git.ipfire.org Git - thirdparty/lldpd.git/blame - src/daemon/interfaces.c
travis: use only two sets of configure options and check "distcheck" and "install...
[thirdparty/lldpd.git] / src / daemon / interfaces.c
CommitLineData
4b292b55 1/* -*- mode: c; c-file-style: "openbsd" -*- */
6e75df87
VB
2/*
3 * Copyright (c) 2008 Vincent Bernat <bernat@luffy.cx>
4 *
51434125 5 * Permission to use, copy, modify, and/or distribute this software for any
6e75df87
VB
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18#define INCLUDE_LINUX_IF_H
19#include "lldpd.h"
20
21#include <stdio.h>
06db3608 22#include <stddef.h>
6e75df87
VB
23#include <unistd.h>
24#include <errno.h>
e6b36c87 25#include <assert.h>
6e75df87
VB
26#include <sys/ioctl.h>
27#include <sys/types.h>
28#include <sys/stat.h>
29#include <fcntl.h>
30#include <fnmatch.h>
31#include <arpa/inet.h>
6e75df87
VB
32#include <net/if_arp.h>
33#include <linux/if_vlan.h>
34#include <linux/if_bonding.h>
35#include <linux/if_bridge.h>
36#include <linux/wireless.h>
37#include <linux/sockios.h>
38#include <linux/filter.h>
6e75df87
VB
39#include <linux/if_packet.h>
40
41#define SYSFS_PATH_MAX 256
42#define MAX_PORTS 1024
43#define MAX_BRIDGES 1024
44
45/* BPF filter to get revelant information from interfaces */
46/* LLDP: "ether proto 0x88cc and ether dst 01:80:c2:00:00:0e" */
47/* FDP: "ether dst 01:e0:52:cc:cc:cc" */
48/* CDP: "ether dst 01:00:0c:cc:cc:cc" */
49/* SONMP: "ether dst 01:00:81:00:01:00" */
50/* EDP: "ether dst 00:e0:2b:00:00:00" */
a2606cac
VB
51/* For optimization purpose, we first check if the first bit of the
52 first byte is 1. if not, this can only be an EDP packet:
53
54 tcpdump -dd "(ether[0] & 1 = 1 and
55 ((ether proto 0x88cc and ether dst 01:80:c2:00:00:0e) or
56 (ether dst 01:e0:52:cc:cc:cc) or
57 (ether dst 01:00:0c:cc:cc:cc) or
58 (ether dst 01:00:81:00:01:00))) or
59 (ether dst 00:e0:2b:00:00:00)"
60*/
61
62#define LLDPD_FILTER_F \
63 { 0x30, 0, 0, 0x00000000 }, \
64 { 0x54, 0, 0, 0x00000001 }, \
65 { 0x15, 0, 14, 0x00000001 }, \
66 { 0x28, 0, 0, 0x0000000c }, \
67 { 0x15, 0, 4, 0x000088cc }, \
68 { 0x20, 0, 0, 0x00000002 }, \
69 { 0x15, 0, 2, 0xc200000e }, \
70 { 0x28, 0, 0, 0x00000000 }, \
71 { 0x15, 12, 13, 0x00000180 }, \
72 { 0x20, 0, 0, 0x00000002 }, \
73 { 0x15, 0, 2, 0x52cccccc }, \
74 { 0x28, 0, 0, 0x00000000 }, \
75 { 0x15, 8, 9, 0x000001e0 }, \
76 { 0x15, 1, 0, 0x0ccccccc }, \
77 { 0x15, 0, 2, 0x81000100 }, \
78 { 0x28, 0, 0, 0x00000000 }, \
79 { 0x15, 4, 5, 0x00000100 }, \
80 { 0x20, 0, 0, 0x00000002 }, \
81 { 0x15, 0, 3, 0x2b000000 }, \
82 { 0x28, 0, 0, 0x00000000 }, \
83 { 0x15, 0, 1, 0x000000e0 }, \
84 { 0x6, 0, 0, 0x0000ffff }, \
6e75df87 85 { 0x6, 0, 0, 0x00000000 },
a2606cac 86
6e75df87
VB
87static struct sock_filter lldpd_filter_f[] = { LLDPD_FILTER_F };
88
89/* net/if.h */
90extern unsigned int if_nametoindex (__const char *__ifname) __THROW;
91extern char *if_indextoname (unsigned int __ifindex, char *__ifname) __THROW;
92
31ee070d
VB
93struct lldpd_ops eth_ops;
94struct lldpd_ops bond_ops;
6e75df87 95
5339e725 96static int
d4e4c804 97pattern_match(char *iface, char *list, int found)
5339e725
VB
98{
99 char *interfaces = NULL;
100 char *pattern;
5339e725
VB
101
102 if ((interfaces = strdup(list)) == NULL) {
103 LLOG_WARNX("unable to allocate memory");
104 return 0;
105 }
106
107 for (pattern = strtok(interfaces, ",");
108 pattern != NULL;
109 pattern = strtok(NULL, ",")) {
110 if ((pattern[0] == '!') &&
111 ((fnmatch(pattern + 1, iface, 0) == 0))) {
112 /* Blacklisted. No need to search further. */
113 found = 0;
114 break;
115 }
116 if (fnmatch(pattern, iface, 0) == 0)
117 found = 1;
118 }
119
120 free(interfaces);
121 return found;
122}
123
6e75df87
VB
124static int
125old_iface_is_bridge(struct lldpd *cfg, const char *name)
126{
127 int ifindices[MAX_BRIDGES];
128 char ifname[IFNAMSIZ];
129 int num, i;
130 unsigned long args[3] = { BRCTL_GET_BRIDGES,
131 (unsigned long)ifindices, MAX_BRIDGES };
b9f4c120
VB
132 if ((num = ioctl(cfg->g_sock, SIOCGIFBR, args)) < 0)
133 /* This can happen with a 64bit kernel and 32bit
134 userland, don't output anything about this to avoid
135 to fill logs. */
6e75df87 136 return 0;
6e75df87
VB
137 for (i = 0; i < num; i++) {
138 if (if_indextoname(ifindices[i], ifname) == NULL)
139 LLOG_INFO("unable to get name of interface %d",
140 ifindices[i]);
141 else if (strncmp(name, ifname, IFNAMSIZ) == 0)
142 return 1;
143 }
144 return 0;
145}
146
147static int
148iface_is_bridge(struct lldpd *cfg, const char *name)
149{
f4ed5af1 150#ifdef SYSFS_BRIDGE_FDB
6e75df87
VB
151 char path[SYSFS_PATH_MAX];
152 int f;
153
154 if ((snprintf(path, SYSFS_PATH_MAX,
155 SYSFS_CLASS_NET "%s/" SYSFS_BRIDGE_FDB, name)) >= SYSFS_PATH_MAX)
156 LLOG_WARNX("path truncated");
157 if ((f = priv_open(path)) < 0) {
158 return old_iface_is_bridge(cfg, name);
159 }
160 close(f);
161 return 1;
f4ed5af1
VB
162#else
163 return old_iface_is_bridge(cfg, name);
164#endif
6e75df87
VB
165}
166
7a008075 167#ifdef ENABLE_DOT1
6e75df87
VB
168static int
169old_iface_is_bridged_to(struct lldpd *cfg, const char *slave, const char *master)
170{
171 int j, index = if_nametoindex(slave);
172 int ifptindices[MAX_PORTS];
173 unsigned long args2[4] = { BRCTL_GET_PORT_LIST,
174 (unsigned long)ifptindices, MAX_PORTS, 0 };
175 struct ifreq ifr;
176
177 strncpy(ifr.ifr_name, master, IFNAMSIZ);
178 memset(ifptindices, 0, sizeof(ifptindices));
179 ifr.ifr_data = (char *)&args2;
180
b9f4c120
VB
181 if (ioctl(cfg->g_sock, SIOCDEVPRIVATE, &ifr) < 0)
182 /* This can happen with a 64bit kernel and 32bit
183 userland, don't output anything about this to avoid
184 to fill logs. */
6e75df87 185 return 0;
6e75df87
VB
186
187 for (j = 0; j < MAX_PORTS; j++) {
188 if (ifptindices[j] == index)
189 return 1;
190 }
191
192 return 0;
193}
194
195static int
196iface_is_bridged_to(struct lldpd *cfg, const char *slave, const char *master)
197{
f4ed5af1 198#ifdef SYSFS_BRIDGE_PORT_SUBDIR
6e75df87
VB
199 char path[SYSFS_PATH_MAX];
200 int f;
201
202 /* Master should be a bridge, first */
203 if (!iface_is_bridge(cfg, master)) return 0;
204
205 if (snprintf(path, SYSFS_PATH_MAX,
206 SYSFS_CLASS_NET "%s/" SYSFS_BRIDGE_PORT_SUBDIR "/%s/port_no",
207 master, slave) >= SYSFS_PATH_MAX)
208 LLOG_WARNX("path truncated");
209 if ((f = priv_open(path)) < 0) {
210 return old_iface_is_bridged_to(cfg, slave, master);
211 }
212 close(f);
213 return 1;
f4ed5af1
VB
214#else
215 return old_iface_is_bridged_to(cfg, slave, master);
216#endif
6e75df87 217}
7a008075 218#endif
6e75df87
VB
219
220static int
221iface_is_vlan(struct lldpd *cfg, const char *name)
222{
223 struct vlan_ioctl_args ifv;
224 memset(&ifv, 0, sizeof(ifv));
225 ifv.cmd = GET_VLAN_REALDEV_NAME_CMD;
226 if ((strlcpy(ifv.device1, name, sizeof(ifv.device1))) >=
227 sizeof(ifv.device1))
228 LLOG_WARNX("device name truncated");
229 if (ioctl(cfg->g_sock, SIOCGIFVLAN, &ifv) >= 0)
230 return 1;
231 return 0;
232}
233
234static int
235iface_is_wireless(struct lldpd *cfg, const char *name)
236{
237 struct iwreq iwr;
238 strlcpy(iwr.ifr_name, name, IFNAMSIZ);
239 if (ioctl(cfg->g_sock, SIOCGIWNAME, &iwr) >= 0)
240 return 1;
241 return 0;
242}
243
244static int
245iface_is_bond(struct lldpd *cfg, const char *name)
246{
247 struct ifreq ifr;
248 struct ifbond ifb;
249 memset(&ifr, 0, sizeof(ifr));
250 memset(&ifb, 0, sizeof(ifb));
251 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
8f88ff70 252 ifr.ifr_data = (char *)&ifb;
6e75df87
VB
253 if (ioctl(cfg->g_sock, SIOCBONDINFOQUERY, &ifr) >= 0)
254 return 1;
255 return 0;
256}
257
258static int
259iface_is_bond_slave(struct lldpd *cfg, const char *slave, const char *master,
260 int *active)
261{
262 struct ifreq ifr;
263 struct ifbond ifb;
264 struct ifslave ifs;
265 memset(&ifr, 0, sizeof(ifr));
266 memset(&ifb, 0, sizeof(ifb));
267 strlcpy(ifr.ifr_name, master, sizeof(ifr.ifr_name));
8f88ff70 268 ifr.ifr_data = (char *)&ifb;
6e75df87
VB
269 if (ioctl(cfg->g_sock, SIOCBONDINFOQUERY, &ifr) >= 0) {
270 while (ifb.num_slaves--) {
271 memset(&ifr, 0, sizeof(ifr));
272 memset(&ifs, 0, sizeof(ifs));
273 strlcpy(ifr.ifr_name, master, sizeof(ifr.ifr_name));
8f88ff70 274 ifr.ifr_data = (char *)&ifs;
6e75df87
VB
275 ifs.slave_id = ifb.num_slaves;
276 if ((ioctl(cfg->g_sock, SIOCBONDSLAVEINFOQUERY, &ifr) >= 0) &&
277 (strncmp(ifs.slave_name, slave, sizeof(ifs.slave_name)) == 0)) {
278 if (active)
279 *active = ifs.state;
280 return 1;
281 }
282 }
283 }
284 return 0;
285}
286
287static int
288iface_is_enslaved(struct lldpd *cfg, const char *name)
289{
290 struct ifaddrs *ifap, *ifa;
291 int master;
292
293 if (getifaddrs(&ifap) != 0) {
294 LLOG_WARN("unable to get interface list");
295 return -1;
296 }
297 for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
298 if (iface_is_bond_slave(cfg, name, ifa->ifa_name, NULL)) {
299 master = if_nametoindex(ifa->ifa_name);
300 freeifaddrs(ifap);
301 return master;
302 }
303 }
304 freeifaddrs(ifap);
305 return -1;
306}
307
6e75df87
VB
308static void
309iface_get_permanent_mac(struct lldpd *cfg, struct lldpd_hardware *hardware)
310{
311 int master, f, state = 0;
312 FILE *netbond;
313 const char *slaveif = "Slave Interface: ";
314 const char *hwaddr = "Permanent HW addr: ";
315 u_int8_t mac[ETHER_ADDR_LEN];
316 char bond[IFNAMSIZ];
317 char path[SYSFS_PATH_MAX];
318 char line[100];
319 if ((master = iface_is_enslaved(cfg, hardware->h_ifname)) == -1)
320 return;
321 /* We have a bond, we need to query it to get real MAC addresses */
322 if ((if_indextoname(master, bond)) == NULL) {
323 LLOG_WARNX("unable to get bond name");
324 return;
325 }
326
327 if (snprintf(path, SYSFS_PATH_MAX, "/proc/net/bonding/%s",
328 bond) >= SYSFS_PATH_MAX) {
329 LLOG_WARNX("path truncated");
330 return;
331 }
332 if ((f = priv_open(path)) < 0) {
333 if (snprintf(path, SYSFS_PATH_MAX, "/proc/self/net/bonding/%s",
334 bond) >= SYSFS_PATH_MAX) {
335 LLOG_WARNX("path truncated");
336 return;
337 }
338 f = priv_open(path);
339 }
340 if (f < 0) {
341 LLOG_WARNX("unable to find %s in /proc/net/bonding or /proc/self/net/bonding",
342 bond);
343 return;
344 }
345 if ((netbond = fdopen(f, "r")) == NULL) {
346 LLOG_WARN("unable to read stream from %s", path);
347 close(f);
348 return;
349 }
350 /* State 0:
351 We parse the file to search "Slave Interface: ". If found, go to
352 state 1.
353 State 1:
354 We parse the file to search "Permanent HW addr: ". If found, we get
355 the mac.
356 */
357 while (fgets(line, sizeof(line), netbond)) {
358 switch (state) {
359 case 0:
360 if (strncmp(line, slaveif, strlen(slaveif)) == 0) {
361 if (line[strlen(line)-1] == '\n')
362 line[strlen(line)-1] = '\0';
363 if (strncmp(hardware->h_ifname,
364 line + strlen(slaveif),
365 sizeof(hardware->h_ifname)) == 0)
366 state++;
367 }
368 break;
369 case 1:
370 if (strncmp(line, hwaddr, strlen(hwaddr)) == 0) {
371 if (line[strlen(line)-1] == '\n')
372 line[strlen(line)-1] = '\0';
373 if (sscanf(line + strlen(hwaddr),
374 "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
375 &mac[0], &mac[1], &mac[2],
376 &mac[3], &mac[4], &mac[5]) !=
377 ETHER_ADDR_LEN) {
378 LLOG_WARN("unable to parse %s",
379 line + strlen(hwaddr));
380 fclose(netbond);
381 return;
382 }
383 memcpy(hardware->h_lladdr, mac,
384 ETHER_ADDR_LEN);
385 fclose(netbond);
386 return;
387 }
388 break;
389 }
390 }
391 LLOG_WARNX("unable to find real mac address for %s",
392 bond);
393 fclose(netbond);
394}
395
849954d7
VB
396/* Generic minimal checks to handle a given interface. */
397static int
398iface_minimal_checks(struct lldpd *cfg, struct ifaddrs *ifa)
399{
06db3608 400 struct sockaddr_ll sdl;
58fe6128 401 struct ifreq ifr;
10935633
VB
402 struct ethtool_drvinfo ethc;
403 const char * const *rif;
404
405 /* White-list some drivers */
406 const char * const regular_interfaces[] = {
407 "dsa",
408 "veth",
409 NULL
410 };
411
a0aa43e9 412 int is_bridge = iface_is_bridge(cfg, ifa->ifa_name);
849954d7
VB
413
414 if (!(LOCAL_CHASSIS(cfg)->c_cap_enabled & LLDP_CAP_BRIDGE) &&
a0aa43e9 415 is_bridge) {
849954d7
VB
416 LOCAL_CHASSIS(cfg)->c_cap_enabled |= LLDP_CAP_BRIDGE;
417 return 0;
418 }
419
420 if (!(LOCAL_CHASSIS(cfg)->c_cap_enabled & LLDP_CAP_WLAN) &&
421 iface_is_wireless(cfg, ifa->ifa_name))
422 LOCAL_CHASSIS(cfg)->c_cap_enabled |= LLDP_CAP_WLAN;
423
424 /* First, check if this interface has already been handled */
425 if (!ifa->ifa_flags)
426 return 0;
427
428 if (ifa->ifa_addr == NULL ||
429 ifa->ifa_addr->sa_family != PF_PACKET)
430 return 0;
431
06db3608
VB
432 memcpy(&sdl, ifa->ifa_addr, sizeof(struct sockaddr_ll));
433 if (sdl.sll_hatype != ARPHRD_ETHER || !sdl.sll_halen)
849954d7
VB
434 return 0;
435
436 /* We request that the interface is able to do either multicast
437 * or broadcast to be able to send discovery frames. */
438 if (!(ifa->ifa_flags & (IFF_MULTICAST|IFF_BROADCAST)))
439 return 0;
440
10935633
VB
441 /* Check if the driver is whitelisted */
442 memset(&ifr, 0, sizeof(ifr));
443 strcpy(ifr.ifr_name, ifa->ifa_name);
3f0d19bb 444 memset(&ethc, 0, sizeof(ethc));
10935633
VB
445 ifr.ifr_data = (caddr_t) &ethc;
446 ethc.cmd = ETHTOOL_GDRVINFO;
447 if (ioctl(cfg->g_sock, SIOCETHTOOL, &ifr) == 0) {
448 for (rif = regular_interfaces; *rif; rif++) {
449 if (strcmp(ethc.driver, *rif) == 0) {
450 /* White listed! */
10935633
VB
451 return 1;
452 }
453 }
454 }
455
58fe6128
VB
456 /* Check queue len. If no queue, this usually means that this
457 is not a "real" interface. */
458 memset(&ifr, 0, sizeof(ifr));
459 strcpy(ifr.ifr_name, ifa->ifa_name);
460 if ((ioctl(cfg->g_sock, SIOCGIFTXQLEN, &ifr) < 0) || !ifr.ifr_qlen)
461 return 0;
462
a0aa43e9 463 /* Don't handle bond and VLAN, nor bridge */
849954d7 464 if ((iface_is_vlan(cfg, ifa->ifa_name)) ||
a0aa43e9
V
465 (iface_is_bond(cfg, ifa->ifa_name)) ||
466 is_bridge)
849954d7
VB
467 return 0;
468
469 return 1;
470}
471
472static int
6a2fa591 473iface_set_filter(const char *name, int fd)
849954d7 474{
3f0d19bb
VB
475 struct sock_fprog prog;
476 memset(&prog, 0, sizeof(struct sock_fprog));
477 prog.filter = lldpd_filter_f;
478 prog.len = sizeof(lldpd_filter_f) / sizeof(struct sock_filter);
479
849954d7
VB
480 if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER,
481 &prog, sizeof(prog)) < 0) {
6a2fa591 482 LLOG_WARN("unable to change filter for %s", name);
849954d7
VB
483 return ENETDOWN;
484 }
485 return 0;
486}
487
f8cb50fa 488/* Fill up port name and description */
849954d7 489static void
36bd79e3 490iface_port_name_desc(struct lldpd_hardware *hardware)
849954d7
VB
491{
492 struct lldpd_port *port = &hardware->h_lport;
36bd79e3
VB
493 char buffer[256]; /* 256 = IFALIASZ */
494 char path[SYSFS_PATH_MAX];
495 int f;
496
497 /* There are two cases:
498
499 1. We have a kernel recent enough to support ifAlias
500 _and_ a non empty ifAlias, then we will use it for
501 description and use ifname for port ID.
502
503 2. Otherwise, we will use the MAC address as ID and the
504 port name in description.
505 */
506
507 if ((snprintf(path, SYSFS_PATH_MAX,
508 SYSFS_CLASS_NET "%s/ifalias", hardware->h_ifname)) >= SYSFS_PATH_MAX)
509 LLOG_WARNX("path truncated");
510 memset(buffer, 0, sizeof(buffer));
511 if (((f = priv_open(path)) < 0) || (read(f, buffer, sizeof(buffer)-1) < 1)) {
512 /* Case 2: MAC address and port name */
513 close(f);
514 port->p_id_subtype = LLDP_PORTID_SUBTYPE_LLADDR;
515 if ((port->p_id =
516 calloc(1, sizeof(hardware->h_lladdr))) == NULL)
517 fatal(NULL);
518 memcpy(port->p_id, hardware->h_lladdr,
519 sizeof(hardware->h_lladdr));
520 port->p_id_len = sizeof(hardware->h_lladdr);
521 port->p_descr = strdup(hardware->h_ifname);
522 return;
523 }
524 /* Case 1: port name and port description */
525 close(f);
526 port->p_id_subtype = LLDP_PORTID_SUBTYPE_IFNAME;
527 port->p_id_len = strlen(hardware->h_ifname);
528 if ((port->p_id =
529 calloc(1, port->p_id_len)) == NULL)
849954d7 530 fatal(NULL);
36bd79e3
VB
531 memcpy(port->p_id, hardware->h_ifname, port->p_id_len);
532 if (buffer[strlen(buffer) - 1] == '\n')
533 buffer[strlen(buffer) - 1] = '\0';
534 port->p_descr = strdup(buffer);
849954d7
VB
535}
536
6e75df87
VB
537/* Fill up MAC/PHY for a given hardware port */
538static void
539iface_macphy(struct lldpd_hardware *hardware)
540{
541#ifdef ENABLE_DOT3
542 struct ethtool_cmd ethc;
543 struct lldpd_port *port = &hardware->h_lport;
544 int j;
545 int advertised_ethtool_to_rfc3636[][2] = {
546 {ADVERTISED_10baseT_Half, LLDP_DOT3_LINK_AUTONEG_10BASE_T},
547 {ADVERTISED_10baseT_Full, LLDP_DOT3_LINK_AUTONEG_10BASET_FD},
548 {ADVERTISED_100baseT_Half, LLDP_DOT3_LINK_AUTONEG_100BASE_TX},
549 {ADVERTISED_100baseT_Full, LLDP_DOT3_LINK_AUTONEG_100BASE_TXFD},
550 {ADVERTISED_1000baseT_Half, LLDP_DOT3_LINK_AUTONEG_1000BASE_T},
551 {ADVERTISED_1000baseT_Full, LLDP_DOT3_LINK_AUTONEG_1000BASE_TFD},
552 {ADVERTISED_10000baseT_Full, LLDP_DOT3_LINK_AUTONEG_OTHER},
553 {ADVERTISED_Pause, LLDP_DOT3_LINK_AUTONEG_FDX_PAUSE},
554 {ADVERTISED_Asym_Pause, LLDP_DOT3_LINK_AUTONEG_FDX_APAUSE},
555 {ADVERTISED_2500baseX_Full, LLDP_DOT3_LINK_AUTONEG_OTHER},
556 {0,0}};
557
558 if (priv_ethtool(hardware->h_ifname, &ethc) == 0) {
3fd015c0
VB
559 port->p_macphy.autoneg_support = (ethc.supported & SUPPORTED_Autoneg) ? 1 : 0;
560 port->p_macphy.autoneg_enabled = (ethc.autoneg == AUTONEG_DISABLE) ? 0 : 1;
6e75df87
VB
561 for (j=0; advertised_ethtool_to_rfc3636[j][0]; j++) {
562 if (ethc.advertising & advertised_ethtool_to_rfc3636[j][0])
3fd015c0 563 port->p_macphy.autoneg_advertised |=
6e75df87
VB
564 advertised_ethtool_to_rfc3636[j][1];
565 }
566 switch (ethc.speed) {
567 case SPEED_10:
3fd015c0 568 port->p_macphy.mau_type = (ethc.duplex == DUPLEX_FULL) ? \
6e75df87 569 LLDP_DOT3_MAU_10BASETFD : LLDP_DOT3_MAU_10BASETHD;
3fd015c0 570 if (ethc.port == PORT_BNC) port->p_macphy.mau_type = LLDP_DOT3_MAU_10BASE2;
6e75df87 571 if (ethc.port == PORT_FIBRE)
3fd015c0 572 port->p_macphy.mau_type = (ethc.duplex == DUPLEX_FULL) ? \
6e75df87
VB
573 LLDP_DOT3_MAU_10BASEFLDF : LLDP_DOT3_MAU_10BASEFLHD;
574 break;
575 case SPEED_100:
3fd015c0 576 port->p_macphy.mau_type = (ethc.duplex == DUPLEX_FULL) ? \
6e75df87
VB
577 LLDP_DOT3_MAU_100BASETXFD : LLDP_DOT3_MAU_100BASETXHD;
578 if (ethc.port == PORT_BNC)
3fd015c0 579 port->p_macphy.mau_type = (ethc.duplex == DUPLEX_FULL) ? \
6e75df87
VB
580 LLDP_DOT3_MAU_100BASET2DF : LLDP_DOT3_MAU_100BASET2HD;
581 if (ethc.port == PORT_FIBRE)
3fd015c0 582 port->p_macphy.mau_type = (ethc.duplex == DUPLEX_FULL) ? \
6e75df87
VB
583 LLDP_DOT3_MAU_100BASEFXFD : LLDP_DOT3_MAU_100BASEFXHD;
584 break;
585 case SPEED_1000:
3fd015c0 586 port->p_macphy.mau_type = (ethc.duplex == DUPLEX_FULL) ? \
6e75df87
VB
587 LLDP_DOT3_MAU_1000BASETFD : LLDP_DOT3_MAU_1000BASETHD;
588 if (ethc.port == PORT_FIBRE)
3fd015c0 589 port->p_macphy.mau_type = (ethc.duplex == DUPLEX_FULL) ? \
6e75df87
VB
590 LLDP_DOT3_MAU_1000BASEXFD : LLDP_DOT3_MAU_1000BASEXHD;
591 break;
592 case SPEED_10000:
3fd015c0 593 port->p_macphy.mau_type = (ethc.port == PORT_FIBRE) ? \
6e75df87
VB
594 LLDP_DOT3_MAU_10GIGBASEX : LLDP_DOT3_MAU_10GIGBASER;
595 break;
596 }
3fd015c0 597 if (ethc.port == PORT_AUI) port->p_macphy.mau_type = LLDP_DOT3_MAU_AUI;
6e75df87
VB
598 }
599#endif
600}
601
602static void
603iface_mtu(struct lldpd *cfg, struct lldpd_hardware *hardware)
604{
605 struct ifreq ifr;
606
607 /* get MTU */
608 memset(&ifr, 0, sizeof(ifr));
609 strlcpy(ifr.ifr_name, hardware->h_ifname, sizeof(ifr.ifr_name));
610 if (ioctl(cfg->g_sock, SIOCGIFMTU, (char*)&ifr) == -1) {
611 LLOG_WARN("unable to get MTU of %s, using 1500", hardware->h_ifname);
612 hardware->h_mtu = 1500;
613 } else
77c4d9d0 614 hardware->h_mtu = ifr.ifr_mtu;
6e75df87
VB
615}
616
617static void
618iface_multicast(struct lldpd *cfg, const char *name, int remove)
619{
620 int i, rc;
621
622 for (i=0; cfg->g_protocols[i].mode != 0; i++) {
623 if (!cfg->g_protocols[i].enabled) continue;
624 if ((rc = priv_iface_multicast(name,
625 cfg->g_protocols[i].mac, !remove)) != 0) {
626 errno = rc;
627 if (errno != ENOENT)
628 LLOG_INFO("unable to %s %s address to multicast filter for %s",
629 (remove)?"delete":"add",
630 cfg->g_protocols[i].name,
631 name);
632 }
633 }
634}
635
636static int
637iface_eth_init(struct lldpd *cfg, struct lldpd_hardware *hardware)
638{
849954d7 639 int fd, status;
6e75df87 640
849954d7
VB
641 if ((fd = priv_iface_init(hardware->h_ifname)) == -1)
642 return -1;
d6e889b6 643 hardware->h_sendfd = fd; /* Send */
6e75df87
VB
644
645 /* Set filter */
6a2fa591 646 if ((status = iface_set_filter(hardware->h_ifname, fd)) != 0) {
849954d7
VB
647 close(fd);
648 return status;
6e75df87
VB
649 }
650
651 iface_multicast(cfg, hardware->h_ifname, 0);
652
d6e889b6 653 levent_hardware_add_fd(hardware, fd); /* Receive */
6e75df87 654 LLOG_DEBUG("interface %s initialized (fd=%d)", hardware->h_ifname,
849954d7 655 fd);
6e75df87
VB
656 return 0;
657}
658
659static int
660iface_eth_send(struct lldpd *cfg, struct lldpd_hardware *hardware,
661 char *buffer, size_t size)
662{
663 return write(hardware->h_sendfd,
664 buffer, size);
665}
666
667static int
668iface_eth_recv(struct lldpd *cfg, struct lldpd_hardware *hardware,
669 int fd, char *buffer, size_t size)
670{
671 int n;
672 struct sockaddr_ll from;
673 socklen_t fromlen;
674
675 fromlen = sizeof(from);
676 if ((n = recvfrom(fd,
677 buffer,
678 size, 0,
679 (struct sockaddr *)&from,
680 &fromlen)) == -1) {
681 LLOG_WARN("error while receiving frame on %s",
682 hardware->h_ifname);
683 hardware->h_rx_discarded_cnt++;
684 return -1;
685 }
686 if (from.sll_pkttype == PACKET_OUTGOING)
687 return -1;
688 return n;
689}
690
691static int
692iface_eth_close(struct lldpd *cfg, struct lldpd_hardware *hardware)
693{
6e75df87
VB
694 iface_multicast(cfg, hardware->h_ifname, 1);
695 return 0;
696}
697
698void
699lldpd_ifh_eth(struct lldpd *cfg, struct ifaddrs *ifap)
700{
701 struct ifaddrs *ifa;
6e75df87 702 struct lldpd_hardware *hardware;
6e75df87
VB
703
704 for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
849954d7 705 if (!iface_minimal_checks(cfg, ifa))
6e75df87
VB
706 continue;
707
44002d66
VB
708 if ((hardware = lldpd_get_hardware(cfg,
709 ifa->ifa_name,
710 if_nametoindex(ifa->ifa_name),
711 &eth_ops)) == NULL) {
6e75df87
VB
712 if ((hardware = lldpd_alloc_hardware(cfg,
713 ifa->ifa_name)) == NULL) {
714 LLOG_WARNX("Unable to allocate space for %s",
715 ifa->ifa_name);
716 continue;
717 }
718 if (iface_eth_init(cfg, hardware) != 0) {
719 LLOG_WARN("unable to initialize %s", hardware->h_ifname);
720 lldpd_hardware_cleanup(cfg, hardware);
721 continue;
722 }
723 hardware->h_ops = &eth_ops;
44002d66 724 hardware->h_ifindex = if_nametoindex(ifa->ifa_name);
6e75df87 725 TAILQ_INSERT_TAIL(&cfg->g_hardware, hardware, h_entries);
cfe00f7f
VB
726 } else {
727 if (hardware->h_flags) continue; /* Already seen this time */
4b292b55 728 lldpd_port_cleanup(&hardware->h_lport, 0);
cfe00f7f 729 }
6e75df87 730
6e75df87
VB
731 hardware->h_flags = ifa->ifa_flags; /* Should be non-zero */
732 ifa->ifa_flags = 0; /* Future handlers
733 don't have to
734 care about this
735 interface. */
736
737 /* Get local address */
06db3608
VB
738 memcpy(&hardware->h_lladdr,
739 (u_int8_t*)((u_int8_t*)ifa->ifa_addr +
740 offsetof(struct sockaddr_ll, sll_addr)),
741 sizeof(hardware->h_lladdr));
6e75df87 742
36bd79e3
VB
743 /* Fill information about port */
744 iface_port_name_desc(hardware);
6e75df87
VB
745
746 /* Fill additional info */
747 iface_macphy(hardware);
748 iface_mtu(cfg, hardware);
749 }
750}
751
ba85f9f4
VB
752void
753lldpd_ifh_whitelist(struct lldpd *cfg, struct ifaddrs *ifap)
754{
755 struct ifaddrs *ifa;
ba85f9f4 756
8ec333bd 757 if (!cfg->g_config.c_iface_pattern)
ba85f9f4 758 return;
ba85f9f4
VB
759
760 for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
761 if (ifa->ifa_flags == 0) continue; /* Already handled by someone else */
8ec333bd 762 if (!pattern_match(ifa->ifa_name, cfg->g_config.c_iface_pattern, 0)) {
ba85f9f4
VB
763 /* This interface was not found. We flag it. */
764 LLOG_DEBUG("blacklist %s", ifa->ifa_name);
765 ifa->ifa_flags = 0;
766 }
767 }
ba85f9f4
VB
768}
769
849954d7
VB
770static int
771iface_bond_init(struct lldpd *cfg, struct lldpd_hardware *hardware)
772{
773 char *mastername = (char *)hardware->h_data; /* Master name */
774 int fd, status;
775 int un = 1;
776
777 if (!mastername) return -1;
778
779 /* First, we get a socket to the raw physical interface */
780 if ((fd = priv_iface_init(hardware->h_ifname)) == -1)
781 return -1;
782 hardware->h_sendfd = fd;
d6e889b6 783 levent_hardware_add_fd(hardware, fd);
6a2fa591 784 if ((status = iface_set_filter(hardware->h_ifname, fd)) != 0) {
849954d7
VB
785 close(fd);
786 return status;
787 }
788 iface_multicast(cfg, hardware->h_ifname, 0);
789
790 /* Then, we open a raw interface for the master */
791 if ((fd = priv_iface_init(mastername)) == -1) {
792 close(hardware->h_sendfd);
793 return -1;
794 }
6a2fa591 795 if ((status = iface_set_filter(mastername, fd)) != 0) {
849954d7
VB
796 close(hardware->h_sendfd);
797 close(fd);
798 return status;
799 }
800 /* With bonding and older kernels (< 2.6.27) we need to listen
801 * to bond device. We use setsockopt() PACKET_ORIGDEV to get
802 * physical device instead of bond device (works with >=
803 * 2.6.24). */
804 if (setsockopt(fd, SOL_PACKET,
805 PACKET_ORIGDEV, &un, sizeof(un)) == -1) {
806 LLOG_DEBUG("[priv]: unable to setsockopt for master bonding device of %s. "
807 "You will get inaccurate results",
808 hardware->h_ifname);
809 }
810 iface_multicast(cfg, mastername, 0);
811
d6e889b6 812 levent_hardware_add_fd(hardware, fd);
849954d7
VB
813 LLOG_DEBUG("interface %s initialized (fd=%d,master=%s[%d])",
814 hardware->h_ifname,
815 hardware->h_sendfd,
816 mastername, fd);
817 return 0;
818}
819
820static int
821iface_bond_send(struct lldpd *cfg, struct lldpd_hardware *hardware,
822 char *buffer, size_t size)
823{
824 /* With bonds, we have duplicate MAC address on different physical
825 * interfaces. We need to alter the source MAC address when we send on
826 * an inactive slave. */
827 char *master = (char*)hardware->h_data;
828 int active;
829 if (!iface_is_bond_slave(cfg, hardware->h_ifname, master, &active)) {
830 LLOG_WARNX("%s seems to not be enslaved anymore?",
831 hardware->h_ifname);
832 return 0;
833 }
834 if (active) {
835 /* We need to modify the source MAC address */
836 if (size < 2 * ETH_ALEN) {
837 LLOG_WARNX("packet to send on %s is too small!",
838 hardware->h_ifname);
839 return 0;
840 }
841 memset(buffer + ETH_ALEN, 0, ETH_ALEN);
842 }
843 return write(hardware->h_sendfd,
844 buffer, size);
845}
846
847static int
848iface_bond_recv(struct lldpd *cfg, struct lldpd_hardware *hardware,
849 int fd, char *buffer, size_t size)
850{
851 int n;
852 struct sockaddr_ll from;
853 socklen_t fromlen;
854
855 fromlen = sizeof(from);
856 if ((n = recvfrom(fd, buffer, size, 0,
857 (struct sockaddr *)&from,
858 &fromlen)) == -1) {
859 LLOG_WARN("error while receiving frame on %s",
860 hardware->h_ifname);
861 hardware->h_rx_discarded_cnt++;
862 return -1;
863 }
864 if (from.sll_pkttype == PACKET_OUTGOING)
865 return -1;
866 if (fd == hardware->h_sendfd)
867 /* We received this on the physical interface. */
868 return n;
869 /* We received this on the bonding interface. Is it really for us? */
44002d66 870 if (from.sll_ifindex == hardware->h_ifindex)
849954d7
VB
871 /* This is for us */
872 return n;
873 if (from.sll_ifindex == if_nametoindex((char*)hardware->h_data))
874 /* We don't know from which physical interface it comes (kernel
875 * < 2.6.24). In doubt, this is for us. */
876 return n;
877 return -1; /* Not for us */
878}
879
880static int
881iface_bond_close(struct lldpd *cfg, struct lldpd_hardware *hardware)
882{
849954d7
VB
883 iface_multicast(cfg, hardware->h_ifname, 1);
884 iface_multicast(cfg, (char*)hardware->h_data, 1);
885 free(hardware->h_data);
886 return 0;
887}
888
889void
890lldpd_ifh_bond(struct lldpd *cfg, struct ifaddrs *ifap)
891{
892 struct ifaddrs *ifa;
893 struct lldpd_hardware *hardware;
849954d7
VB
894 int master;
895 for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
896 if (!iface_minimal_checks(cfg, ifa))
897 continue;
898 if ((master = iface_is_enslaved(cfg, ifa->ifa_name)) == -1)
899 continue;
900
44002d66
VB
901 if ((hardware = lldpd_get_hardware(cfg,
902 ifa->ifa_name,
903 if_nametoindex(ifa->ifa_name),
904 &bond_ops)) == NULL) {
849954d7
VB
905 if ((hardware = lldpd_alloc_hardware(cfg,
906 ifa->ifa_name)) == NULL) {
907 LLOG_WARNX("Unable to allocate space for %s",
908 ifa->ifa_name);
909 continue;
910 }
911 hardware->h_data = (char *)calloc(1, IFNAMSIZ);
912 if_indextoname(master, hardware->h_data);
913 if (iface_bond_init(cfg, hardware) != 0) {
914 LLOG_WARN("unable to initialize %s",
915 hardware->h_ifname);
916 lldpd_hardware_cleanup(cfg, hardware);
917 continue;
918 }
919 hardware->h_ops = &bond_ops;
44002d66 920 hardware->h_ifindex = if_nametoindex(ifa->ifa_name);
849954d7
VB
921 TAILQ_INSERT_TAIL(&cfg->g_hardware, hardware, h_entries);
922 } else {
cfe00f7f 923 if (hardware->h_flags) continue; /* Already seen this time */
849954d7
VB
924 memset(hardware->h_data, 0, IFNAMSIZ);
925 if_indextoname(master, hardware->h_data);
4b292b55 926 lldpd_port_cleanup(&hardware->h_lport, 0);
849954d7
VB
927 }
928
849954d7
VB
929 hardware->h_flags = ifa->ifa_flags;
930 ifa->ifa_flags = 0;
931
932 /* Get local address */
933 iface_get_permanent_mac(cfg, hardware);
934
36bd79e3
VB
935 /* Fill information about port */
936 iface_port_name_desc(hardware);
849954d7
VB
937
938 /* Fill additional info */
7a008075 939#ifdef ENABLE_DOT3
e49b274a 940 hardware->h_lport.p_aggregid = master;
7a008075 941#endif
849954d7
VB
942 iface_macphy(hardware);
943 iface_mtu(cfg, hardware);
944 }
945}
946
5994b27d
VB
947#ifdef ENABLE_DOT1
948static void
949iface_append_vlan(struct lldpd *cfg,
950 struct lldpd_hardware *hardware, struct ifaddrs *ifa)
951{
952 struct lldpd_port *port = &hardware->h_lport;
953 struct lldpd_vlan *vlan;
954 struct vlan_ioctl_args ifv;
955
cfe00f7f
VB
956 /* Check if the VLAN is already here. */
957 TAILQ_FOREACH(vlan, &port->p_vlans, v_entries)
958 if (strncmp(ifa->ifa_name, vlan->v_name, IFNAMSIZ) == 0)
959 return;
5994b27d
VB
960 if ((vlan = (struct lldpd_vlan *)
961 calloc(1, sizeof(struct lldpd_vlan))) == NULL)
962 return;
963 if ((vlan->v_name = strdup(ifa->ifa_name)) == NULL) {
964 free(vlan);
965 return;
966 }
967 memset(&ifv, 0, sizeof(ifv));
968 ifv.cmd = GET_VLAN_VID_CMD;
969 strlcpy(ifv.device1, ifa->ifa_name, sizeof(ifv.device1));
970 if (ioctl(cfg->g_sock, SIOCGIFVLAN, &ifv) < 0) {
971 /* Dunno what happened */
972 free(vlan->v_name);
973 free(vlan);
6a2fa591 974 return;
5994b27d 975 }
6a2fa591
VB
976 vlan->v_vid = ifv.u.VID;
977 TAILQ_INSERT_TAIL(&port->p_vlans, vlan, v_entries);
5994b27d
VB
978}
979
6e75df87
VB
980void
981lldpd_ifh_vlan(struct lldpd *cfg, struct ifaddrs *ifap)
982{
6e75df87 983 struct ifaddrs *ifa;
6e75df87
VB
984 struct vlan_ioctl_args ifv;
985 struct lldpd_hardware *hardware;
6a2fa591 986
6e75df87
VB
987 for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
988 if (!ifa->ifa_flags)
989 continue;
990 if (!iface_is_vlan(cfg, ifa->ifa_name))
991 continue;
992
993 /* We need to find the physical interfaces of this
994 vlan, through bonds and bridges. */
995 memset(&ifv, 0, sizeof(ifv));
996 ifv.cmd = GET_VLAN_REALDEV_NAME_CMD;
997 strlcpy(ifv.device1, ifa->ifa_name, sizeof(ifv.device1));
998 if (ioctl(cfg->g_sock, SIOCGIFVLAN, &ifv) >= 0) {
999 /* Three cases:
1000 1. we get a real device
1001 2. we get a bond
1002 3. we get a bridge
1003 */
1004 if ((hardware = lldpd_get_hardware(cfg,
44002d66
VB
1005 ifv.u.device2,
1006 if_nametoindex(ifv.u.device2),
1007 NULL)) == NULL) {
6e75df87
VB
1008 if (iface_is_bond(cfg, ifv.u.device2)) {
1009 TAILQ_FOREACH(hardware, &cfg->g_hardware,
1010 h_entries)
1011 if (iface_is_bond_slave(cfg,
1012 hardware->h_ifname,
1013 ifv.u.device2, NULL))
5994b27d
VB
1014 iface_append_vlan(cfg,
1015 hardware, ifa);
6e75df87
VB
1016 } else if (iface_is_bridge(cfg, ifv.u.device2)) {
1017 TAILQ_FOREACH(hardware, &cfg->g_hardware,
1018 h_entries)
1019 if (iface_is_bridged_to(cfg,
1020 hardware->h_ifname,
1021 ifv.u.device2))
5994b27d
VB
1022 iface_append_vlan(cfg,
1023 hardware, ifa);
6e75df87 1024 }
5994b27d
VB
1025 } else iface_append_vlan(cfg,
1026 hardware, ifa);
6e75df87
VB
1027 }
1028 }
6e75df87 1029}
5994b27d 1030#endif
6e75df87 1031
e6b36c87
JV
1032#ifndef IN_IS_ADDR_LOOPBACK
1033#define IN_IS_ADDR_LOOPBACK(a) ((a)->s_addr == htonl(INADDR_LOOPBACK))
1034#endif
1035#ifndef IN_IS_ADDR_GLOBAL
1036#define IN_IS_ADDR_GLOBAL(a) (!IN_IS_ADDR_LOOPBACK(a))
1037#endif
1038#ifndef IN6_IS_ADDR_GLOBAL
1039#define IN6_IS_ADDR_GLOBAL(a) (!IN6_IS_ADDR_LOOPBACK(a) && \
1040 !IN6_IS_ADDR_LINKLOCAL(a))
1041#endif
1042
6e75df87
VB
1043/* Find a management address in all available interfaces, even those that were
1044 already handled. This is a special interface handler because it does not
1045 really handle interface related information (management address is attached
1046 to the local chassis). */
1047void
1048lldpd_ifh_mgmt(struct lldpd *cfg, struct ifaddrs *ifap)
1049{
1050 struct ifaddrs *ifa;
e6b36c87 1051 char addrstrbuf[INET6_ADDRSTRLEN];
5fb27919 1052 struct lldpd_mgmt *mgmt;
e6b36c87
JV
1053 void *sin_addr_ptr;
1054 size_t sin_addr_size;
e6b36c87 1055 int af;
d4e4c804 1056 int allnegative = 0;
e6b36c87 1057
5fb27919 1058 lldpd_chassis_mgmt_cleanup(LOCAL_CHASSIS(cfg));
6e75df87 1059
d4e4c804 1060 /* Is the pattern provided all negative? */
8ec333bd
VB
1061 if (cfg->g_config.c_mgmt_pattern == NULL) allnegative = 1;
1062 else if (cfg->g_config.c_mgmt_pattern[0] == '!') {
d4e4c804
VB
1063 /* If each comma is followed by '!', its an all
1064 negative pattern */
8ec333bd 1065 char *sep = cfg->g_config.c_mgmt_pattern;
d4e4c804
VB
1066 while ((sep = strchr(sep, ',')) &&
1067 (*(++sep) == '!'));
1068 if (sep == NULL) allnegative = 1;
1069 }
1070
e6b36c87
JV
1071 /* Find management addresses */
1072 for (af = LLDPD_AF_UNSPEC + 1; af != LLDPD_AF_LAST; af++) {
d4e4c804
VB
1073 /* We only take one of each address family, unless a
1074 pattern is provided and is not all negative. For
1075 example !*:*,!10.* will only blacklist
1076 addresses. We will pick the first IPv4 address not
1077 matching 10.*. */
1078 for (ifa = ifap;
1079 ifa != NULL;
1080 ifa = ifa->ifa_next) {
e6b36c87
JV
1081 if (ifa->ifa_addr == NULL)
1082 continue;
1083 if (ifa->ifa_addr->sa_family != lldpd_af(af))
1084 continue;
d4e4c804 1085
e6b36c87
JV
1086 switch (af) {
1087 case LLDPD_AF_IPV4:
1088 sin_addr_ptr = &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
1089 sin_addr_size = sizeof(struct in_addr);
1090 if (!IN_IS_ADDR_GLOBAL((struct in_addr *)sin_addr_ptr))
1091 continue;
e6b36c87
JV
1092 break;
1093 case LLDPD_AF_IPV6:
1094 sin_addr_ptr = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
1095 sin_addr_size = sizeof(struct in6_addr);
1096 if (!IN6_IS_ADDR_GLOBAL((struct in6_addr *)sin_addr_ptr))
1097 continue;
e6b36c87
JV
1098 break;
1099 default:
1100 assert(0);
d4e4c804 1101 continue;
e6b36c87 1102 }
d4e4c804
VB
1103 if (inet_ntop(lldpd_af(af), sin_addr_ptr,
1104 addrstrbuf, sizeof(addrstrbuf)) == NULL) {
1105 LLOG_WARN("unable to convert IP address to a string");
1106 continue;
1107 }
8ec333bd
VB
1108 if (cfg->g_config.c_mgmt_pattern == NULL ||
1109 pattern_match(addrstrbuf, cfg->g_config.c_mgmt_pattern, allnegative)) {
e6b36c87
JV
1110 mgmt = lldpd_alloc_mgmt(af, sin_addr_ptr, sin_addr_size,
1111 if_nametoindex(ifa->ifa_name));
1112 if (mgmt == NULL) {
1113 assert(errno == ENOMEM); /* anything else is a bug */
1114 LLOG_WARN("out of memory error");
1115 return;
6e75df87 1116 }
e6b36c87 1117 TAILQ_INSERT_TAIL(&LOCAL_CHASSIS(cfg)->c_mgmt, mgmt, m_entries);
d4e4c804
VB
1118
1119 /* Don't take additional address if the pattern is all negative. */
1120 if (allnegative) break;
6e75df87
VB
1121 }
1122 }
1123 }
1124}
31ee070d 1125
e6b36c87 1126
b4ac8083
VB
1127/* Fill out chassis ID if not already done. This handler is special
1128 because we will only handle interfaces that are already handled. */
1129void
1130lldpd_ifh_chassis(struct lldpd *cfg, struct ifaddrs *ifap)
1131{
1132 struct ifaddrs *ifa;
1133 struct lldpd_hardware *hardware;
5fd6695c 1134 char *name = NULL;
b4ac8083
VB
1135
1136 if (LOCAL_CHASSIS(cfg)->c_id != NULL &&
1137 LOCAL_CHASSIS(cfg)->c_id_subtype == LLDP_CHASSISID_SUBTYPE_LLADDR)
1138 return; /* We already have one */
1139
1140 for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
5339e725 1141 if (ifa->ifa_flags) continue;
8ec333bd
VB
1142 if (cfg->g_config.c_cid_pattern &&
1143 !pattern_match(ifa->ifa_name, cfg->g_config.c_cid_pattern, 0)) continue;
b4ac8083
VB
1144
1145 if ((hardware = lldpd_get_hardware(cfg,
1146 ifa->ifa_name,
1147 if_nametoindex(ifa->ifa_name),
1148 NULL)) == NULL)
1149 /* That's odd. Let's skip. */
1150 continue;
1151
5fd6695c 1152 name = malloc(sizeof(hardware->h_lladdr));
b4ac8083
VB
1153 if (!name) {
1154 LLOG_WARN("Not enough memory for chassis ID");
1155 return;
1156 }
1157 free(LOCAL_CHASSIS(cfg)->c_id);
1158 memcpy(name, hardware->h_lladdr, sizeof(hardware->h_lladdr));
1159 LOCAL_CHASSIS(cfg)->c_id = name;
1160 LOCAL_CHASSIS(cfg)->c_id_len = sizeof(hardware->h_lladdr);
1161 LOCAL_CHASSIS(cfg)->c_id_subtype = LLDP_CHASSISID_SUBTYPE_LLADDR;
1162 return;
1163 }
1164}
1165
31ee070d
VB
1166struct lldpd_ops eth_ops = {
1167 .send = iface_eth_send,
1168 .recv = iface_eth_recv,
1169 .cleanup = iface_eth_close,
1170};
1171struct lldpd_ops bond_ops = {
1172 .send = iface_bond_send,
1173 .recv = iface_bond_recv,
1174 .cleanup = iface_bond_close,
1175};