]> git.ipfire.org Git - thirdparty/lldpd.git/blob - src/daemon/interfaces.c
dist: provide a complete changelog
[thirdparty/lldpd.git] / src / daemon / interfaces.c
1 /* -*- mode: c; c-file-style: "openbsd" -*- */
2 /*
3 * Copyright (c) 2008 Vincent Bernat <bernat@luffy.cx>
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
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>
22 #include <stddef.h>
23 #include <unistd.h>
24 #include <errno.h>
25 #include <assert.h>
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>
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>
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" */
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 }, \
85 { 0x6, 0, 0, 0x00000000 },
86
87 static struct sock_filter lldpd_filter_f[] = { LLDPD_FILTER_F };
88
89 /* net/if.h */
90 extern unsigned int if_nametoindex (__const char *__ifname) __THROW;
91 extern char *if_indextoname (unsigned int __ifindex, char *__ifname) __THROW;
92
93 struct lldpd_ops eth_ops;
94 struct lldpd_ops bond_ops;
95
96 static int
97 pattern_match(char *iface, char *list, int found)
98 {
99 char *interfaces = NULL;
100 char *pattern;
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
124 static int
125 old_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 };
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. */
136 return 0;
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
147 static int
148 iface_is_bridge(struct lldpd *cfg, const char *name)
149 {
150 #ifdef SYSFS_BRIDGE_FDB
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;
162 #else
163 return old_iface_is_bridge(cfg, name);
164 #endif
165 }
166
167 #ifdef ENABLE_DOT1
168 static int
169 old_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
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. */
185 return 0;
186
187 for (j = 0; j < MAX_PORTS; j++) {
188 if (ifptindices[j] == index)
189 return 1;
190 }
191
192 return 0;
193 }
194
195 static int
196 iface_is_bridged_to(struct lldpd *cfg, const char *slave, const char *master)
197 {
198 #ifdef SYSFS_BRIDGE_PORT_SUBDIR
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;
214 #else
215 return old_iface_is_bridged_to(cfg, slave, master);
216 #endif
217 }
218 #endif
219
220 static int
221 iface_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
234 static int
235 iface_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
244 static int
245 iface_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));
252 ifr.ifr_data = (char *)&ifb;
253 if (ioctl(cfg->g_sock, SIOCBONDINFOQUERY, &ifr) >= 0)
254 return 1;
255 return 0;
256 }
257
258 static int
259 iface_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));
268 ifr.ifr_data = (char *)&ifb;
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));
274 ifr.ifr_data = (char *)&ifs;
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
287 static int
288 iface_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
308 static void
309 iface_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
396 /* Generic minimal checks to handle a given interface. */
397 static int
398 iface_minimal_checks(struct lldpd *cfg, struct ifaddrs *ifa)
399 {
400 struct sockaddr_ll sdl;
401 struct ifreq ifr;
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
412 int is_bridge = iface_is_bridge(cfg, ifa->ifa_name);
413
414 if (!(LOCAL_CHASSIS(cfg)->c_cap_enabled & LLDP_CAP_BRIDGE) &&
415 is_bridge) {
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
432 memcpy(&sdl, ifa->ifa_addr, sizeof(struct sockaddr_ll));
433 if (sdl.sll_hatype != ARPHRD_ETHER || !sdl.sll_halen)
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
441 /* Check if the driver is whitelisted */
442 memset(&ifr, 0, sizeof(ifr));
443 strcpy(ifr.ifr_name, ifa->ifa_name);
444 memset(&ethc, 0, sizeof(ethc));
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! */
451 return 1;
452 }
453 }
454 }
455
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
463 /* Don't handle bond and VLAN, nor bridge */
464 if ((iface_is_vlan(cfg, ifa->ifa_name)) ||
465 (iface_is_bond(cfg, ifa->ifa_name)) ||
466 is_bridge)
467 return 0;
468
469 return 1;
470 }
471
472 static int
473 iface_set_filter(const char *name, int fd)
474 {
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
480 if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER,
481 &prog, sizeof(prog)) < 0) {
482 LLOG_WARN("unable to change filter for %s", name);
483 return ENETDOWN;
484 }
485 return 0;
486 }
487
488 /* Fill up port name and description */
489 static void
490 iface_port_name_desc(struct lldpd_hardware *hardware)
491 {
492 struct lldpd_port *port = &hardware->h_lport;
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)
530 fatal(NULL);
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);
535 }
536
537 /* Fill up MAC/PHY for a given hardware port */
538 static void
539 iface_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) {
559 port->p_macphy.autoneg_support = (ethc.supported & SUPPORTED_Autoneg) ? 1 : 0;
560 port->p_macphy.autoneg_enabled = (ethc.autoneg == AUTONEG_DISABLE) ? 0 : 1;
561 for (j=0; advertised_ethtool_to_rfc3636[j][0]; j++) {
562 if (ethc.advertising & advertised_ethtool_to_rfc3636[j][0])
563 port->p_macphy.autoneg_advertised |=
564 advertised_ethtool_to_rfc3636[j][1];
565 }
566 switch (ethc.speed) {
567 case SPEED_10:
568 port->p_macphy.mau_type = (ethc.duplex == DUPLEX_FULL) ? \
569 LLDP_DOT3_MAU_10BASETFD : LLDP_DOT3_MAU_10BASETHD;
570 if (ethc.port == PORT_BNC) port->p_macphy.mau_type = LLDP_DOT3_MAU_10BASE2;
571 if (ethc.port == PORT_FIBRE)
572 port->p_macphy.mau_type = (ethc.duplex == DUPLEX_FULL) ? \
573 LLDP_DOT3_MAU_10BASEFLDF : LLDP_DOT3_MAU_10BASEFLHD;
574 break;
575 case SPEED_100:
576 port->p_macphy.mau_type = (ethc.duplex == DUPLEX_FULL) ? \
577 LLDP_DOT3_MAU_100BASETXFD : LLDP_DOT3_MAU_100BASETXHD;
578 if (ethc.port == PORT_BNC)
579 port->p_macphy.mau_type = (ethc.duplex == DUPLEX_FULL) ? \
580 LLDP_DOT3_MAU_100BASET2DF : LLDP_DOT3_MAU_100BASET2HD;
581 if (ethc.port == PORT_FIBRE)
582 port->p_macphy.mau_type = (ethc.duplex == DUPLEX_FULL) ? \
583 LLDP_DOT3_MAU_100BASEFXFD : LLDP_DOT3_MAU_100BASEFXHD;
584 break;
585 case SPEED_1000:
586 port->p_macphy.mau_type = (ethc.duplex == DUPLEX_FULL) ? \
587 LLDP_DOT3_MAU_1000BASETFD : LLDP_DOT3_MAU_1000BASETHD;
588 if (ethc.port == PORT_FIBRE)
589 port->p_macphy.mau_type = (ethc.duplex == DUPLEX_FULL) ? \
590 LLDP_DOT3_MAU_1000BASEXFD : LLDP_DOT3_MAU_1000BASEXHD;
591 break;
592 case SPEED_10000:
593 port->p_macphy.mau_type = (ethc.port == PORT_FIBRE) ? \
594 LLDP_DOT3_MAU_10GIGBASEX : LLDP_DOT3_MAU_10GIGBASER;
595 break;
596 }
597 if (ethc.port == PORT_AUI) port->p_macphy.mau_type = LLDP_DOT3_MAU_AUI;
598 }
599 #endif
600 }
601
602 static void
603 iface_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
614 hardware->h_mtu = ifr.ifr_mtu;
615 }
616
617 static void
618 iface_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
636 static int
637 iface_eth_init(struct lldpd *cfg, struct lldpd_hardware *hardware)
638 {
639 int fd, status;
640
641 if ((fd = priv_iface_init(hardware->h_ifname)) == -1)
642 return -1;
643 hardware->h_sendfd = fd; /* Send */
644
645 /* Set filter */
646 if ((status = iface_set_filter(hardware->h_ifname, fd)) != 0) {
647 close(fd);
648 return status;
649 }
650
651 iface_multicast(cfg, hardware->h_ifname, 0);
652
653 levent_hardware_add_fd(hardware, fd); /* Receive */
654 LLOG_DEBUG("interface %s initialized (fd=%d)", hardware->h_ifname,
655 fd);
656 return 0;
657 }
658
659 static int
660 iface_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
667 static int
668 iface_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
691 static int
692 iface_eth_close(struct lldpd *cfg, struct lldpd_hardware *hardware)
693 {
694 iface_multicast(cfg, hardware->h_ifname, 1);
695 return 0;
696 }
697
698 void
699 lldpd_ifh_eth(struct lldpd *cfg, struct ifaddrs *ifap)
700 {
701 struct ifaddrs *ifa;
702 struct lldpd_hardware *hardware;
703
704 for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
705 if (!iface_minimal_checks(cfg, ifa))
706 continue;
707
708 if ((hardware = lldpd_get_hardware(cfg,
709 ifa->ifa_name,
710 if_nametoindex(ifa->ifa_name),
711 &eth_ops)) == NULL) {
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;
724 hardware->h_ifindex = if_nametoindex(ifa->ifa_name);
725 TAILQ_INSERT_TAIL(&cfg->g_hardware, hardware, h_entries);
726 } else {
727 if (hardware->h_flags) continue; /* Already seen this time */
728 lldpd_port_cleanup(&hardware->h_lport, 0);
729 }
730
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 */
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));
742
743 /* Fill information about port */
744 iface_port_name_desc(hardware);
745
746 /* Fill additional info */
747 iface_macphy(hardware);
748 iface_mtu(cfg, hardware);
749 }
750 }
751
752 void
753 lldpd_ifh_whitelist(struct lldpd *cfg, struct ifaddrs *ifap)
754 {
755 struct ifaddrs *ifa;
756
757 if (!cfg->g_interfaces)
758 return;
759
760 for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
761 if (ifa->ifa_flags == 0) continue; /* Already handled by someone else */
762 if (!pattern_match(ifa->ifa_name, cfg->g_interfaces, 0)) {
763 /* This interface was not found. We flag it. */
764 LLOG_DEBUG("blacklist %s", ifa->ifa_name);
765 ifa->ifa_flags = 0;
766 }
767 }
768 }
769
770 static int
771 iface_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;
783 levent_hardware_add_fd(hardware, fd);
784 if ((status = iface_set_filter(hardware->h_ifname, fd)) != 0) {
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 }
795 if ((status = iface_set_filter(mastername, fd)) != 0) {
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
812 levent_hardware_add_fd(hardware, fd);
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
820 static int
821 iface_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
847 static int
848 iface_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? */
870 if (from.sll_ifindex == hardware->h_ifindex)
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
880 static int
881 iface_bond_close(struct lldpd *cfg, struct lldpd_hardware *hardware)
882 {
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
889 void
890 lldpd_ifh_bond(struct lldpd *cfg, struct ifaddrs *ifap)
891 {
892 struct ifaddrs *ifa;
893 struct lldpd_hardware *hardware;
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
901 if ((hardware = lldpd_get_hardware(cfg,
902 ifa->ifa_name,
903 if_nametoindex(ifa->ifa_name),
904 &bond_ops)) == NULL) {
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;
920 hardware->h_ifindex = if_nametoindex(ifa->ifa_name);
921 TAILQ_INSERT_TAIL(&cfg->g_hardware, hardware, h_entries);
922 } else {
923 if (hardware->h_flags) continue; /* Already seen this time */
924 memset(hardware->h_data, 0, IFNAMSIZ);
925 if_indextoname(master, hardware->h_data);
926 lldpd_port_cleanup(&hardware->h_lport, 0);
927 }
928
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
935 /* Fill information about port */
936 iface_port_name_desc(hardware);
937
938 /* Fill additional info */
939 #ifdef ENABLE_DOT3
940 hardware->h_lport.p_aggregid = master;
941 #endif
942 iface_macphy(hardware);
943 iface_mtu(cfg, hardware);
944 }
945 }
946
947 #ifdef ENABLE_DOT1
948 static void
949 iface_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
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;
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);
974 return;
975 }
976 vlan->v_vid = ifv.u.VID;
977 TAILQ_INSERT_TAIL(&port->p_vlans, vlan, v_entries);
978 }
979
980 void
981 lldpd_ifh_vlan(struct lldpd *cfg, struct ifaddrs *ifap)
982 {
983 struct ifaddrs *ifa;
984 struct vlan_ioctl_args ifv;
985 struct lldpd_hardware *hardware;
986
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,
1005 ifv.u.device2,
1006 if_nametoindex(ifv.u.device2),
1007 NULL)) == NULL) {
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))
1014 iface_append_vlan(cfg,
1015 hardware, ifa);
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))
1022 iface_append_vlan(cfg,
1023 hardware, ifa);
1024 }
1025 } else iface_append_vlan(cfg,
1026 hardware, ifa);
1027 }
1028 }
1029 }
1030 #endif
1031
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
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). */
1047 void
1048 lldpd_ifh_mgmt(struct lldpd *cfg, struct ifaddrs *ifap)
1049 {
1050 struct ifaddrs *ifa;
1051 char addrstrbuf[INET6_ADDRSTRLEN];
1052 struct lldpd_mgmt *mgmt;
1053 void *sin_addr_ptr;
1054 size_t sin_addr_size;
1055 int af;
1056 int allnegative = 0;
1057
1058 lldpd_chassis_mgmt_cleanup(LOCAL_CHASSIS(cfg));
1059
1060 /* Is the pattern provided all negative? */
1061 if (cfg->g_mgmt_pattern == NULL) allnegative = 1;
1062 else if (cfg->g_mgmt_pattern[0] == '!') {
1063 /* If each comma is followed by '!', its an all
1064 negative pattern */
1065 char *sep = cfg->g_mgmt_pattern;
1066 while ((sep = strchr(sep, ',')) &&
1067 (*(++sep) == '!'));
1068 if (sep == NULL) allnegative = 1;
1069 }
1070
1071 /* Find management addresses */
1072 for (af = LLDPD_AF_UNSPEC + 1; af != LLDPD_AF_LAST; af++) {
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) {
1081 if (ifa->ifa_addr == NULL)
1082 continue;
1083 if (ifa->ifa_addr->sa_family != lldpd_af(af))
1084 continue;
1085
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;
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;
1098 break;
1099 default:
1100 assert(0);
1101 continue;
1102 }
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 }
1108 if (cfg->g_mgmt_pattern == NULL ||
1109 pattern_match(addrstrbuf, cfg->g_mgmt_pattern, allnegative)) {
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;
1116 }
1117 TAILQ_INSERT_TAIL(&LOCAL_CHASSIS(cfg)->c_mgmt, mgmt, m_entries);
1118
1119 /* Don't take additional address if the pattern is all negative. */
1120 if (allnegative) break;
1121 }
1122 }
1123 }
1124 }
1125
1126
1127 /* Fill out chassis ID if not already done. This handler is special
1128 because we will only handle interfaces that are already handled. */
1129 void
1130 lldpd_ifh_chassis(struct lldpd *cfg, struct ifaddrs *ifap)
1131 {
1132 struct ifaddrs *ifa;
1133 struct lldpd_hardware *hardware;
1134 char *name = NULL;
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) {
1141 if (ifa->ifa_flags) continue;
1142 if (cfg->g_cid_pattern &&
1143 !pattern_match(ifa->ifa_name, cfg->g_cid_pattern, 0)) continue;
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
1152 name = malloc(sizeof(hardware->h_lladdr));
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
1166 struct lldpd_ops eth_ops = {
1167 .send = iface_eth_send,
1168 .recv = iface_eth_recv,
1169 .cleanup = iface_eth_close,
1170 };
1171 struct lldpd_ops bond_ops = {
1172 .send = iface_bond_send,
1173 .recv = iface_bond_recv,
1174 .cleanup = iface_bond_close,
1175 };