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