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