1 /* -*- mode: c; c-file-style: "openbsd" -*- */
3 * Copyright (c) 2012 Vincent Bernat <bernat@luffy.cx>
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.
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.
25 #include <arpa/inet.h>
31 case LLDPD_AF_IPV4
: return AF_INET
;
32 case LLDPD_AF_IPV6
: return AF_INET6
;
33 case LLDPD_AF_LAST
: return AF_MAX
;
34 default: return AF_UNSPEC
;
38 /* Generic ethernet interface initialization */
40 * Enable multicast on the given interface.
43 interfaces_setup_multicast(struct lldpd
*cfg
, const char *name
,
49 const u_int8_t zero
[ETHER_ADDR_LEN
] = {};
51 for (i
= 0; cfg
->g_protocols
[i
].mode
!= 0; i
++) {
52 if (!cfg
->g_protocols
[i
].enabled
) continue;
53 for (mac
= cfg
->g_protocols
[i
].mac1
, j
= 0;
55 mac
+= ETHER_ADDR_LEN
,
57 if (memcmp(mac
, zero
, ETHER_ADDR_LEN
) == 0) break;
58 if ((rc
= priv_iface_multicast(name
,
59 mac
, !remove
)) != 0) {
62 log_debug("interfaces",
63 "unable to %s %s address to multicast filter for %s (%s)",
64 (remove
)?"delete":"add",
65 cfg
->g_protocols
[i
].name
,
75 * @param iff interface to be freed
78 interfaces_free_device(struct interfaces_device
*iff
)
89 * Free a list of interfaces.
91 * @param ifs list of interfaces to be freed
94 interfaces_free_devices(struct interfaces_device_list
*ifs
)
96 struct interfaces_device
*iff
, *iff_next
;
98 for (iff
= TAILQ_FIRST(ifs
);
101 iff_next
= TAILQ_NEXT(iff
, next
);
102 interfaces_free_device(iff
);
110 * @param ifaddr Address to be freed
113 interfaces_free_address(struct interfaces_address
*ifaddr
)
119 * Free a list of addresses.
121 * @param ifaddrs list of addresses
124 interfaces_free_addresses(struct interfaces_address_list
*ifaddrs
)
126 struct interfaces_address
*ifa
, *ifa_next
;
127 if (!ifaddrs
) return;
128 for (ifa
= TAILQ_FIRST(ifaddrs
);
131 ifa_next
= TAILQ_NEXT(ifa
, next
);
132 interfaces_free_address(ifa
);
138 * Find the appropriate interface from the name.
140 * @param interfaces List of available interfaces
141 * @param device Name of the device we search for
142 * @return The interface or NULL if not found
144 struct interfaces_device
*
145 interfaces_nametointerface(struct interfaces_device_list
*interfaces
,
148 struct interfaces_device
*iface
;
149 TAILQ_FOREACH(iface
, interfaces
, next
) {
150 if (!strncmp(iface
->name
, device
, IFNAMSIZ
))
153 log_debug("interfaces", "cannot get interface for index %s",
159 * Find the appropriate interface from the index.
161 * @param interfaces List of available interfaces
162 * @param index Index of the device we search for
163 * @return The interface or NULL if not found
165 struct interfaces_device
*
166 interfaces_indextointerface(struct interfaces_device_list
*interfaces
,
169 struct interfaces_device
*iface
;
170 TAILQ_FOREACH(iface
, interfaces
, next
) {
171 if (iface
->index
== index
)
174 log_debug("interfaces", "cannot get interface for index %d",
180 interfaces_helper_whitelist(struct lldpd
*cfg
,
181 struct interfaces_device_list
*interfaces
)
183 struct interfaces_device
*iface
;
185 if (!cfg
->g_config
.c_iface_pattern
)
188 TAILQ_FOREACH(iface
, interfaces
, next
) {
189 int m
= pattern_match(iface
->name
, cfg
->g_config
.c_iface_pattern
, 0);
192 log_debug("interfaces", "blacklist %s", iface
->name
);
196 log_debug("interfaces", "whitelist %s (consider it as a physical interface)",
198 iface
->type
|= IFACE_PHYSICAL_T
;
206 iface_append_vlan(struct lldpd
*cfg
,
207 struct interfaces_device
*vlan
,
208 struct interfaces_device
*lower
)
210 struct lldpd_hardware
*hardware
=
211 lldpd_get_hardware(cfg
, lower
->name
, lower
->index
);
212 struct lldpd_port
*port
;
213 struct lldpd_vlan
*v
;
217 if (hardware
== NULL
) {
218 log_debug("interfaces",
219 "cannot find real interface %s for VLAN %s",
220 lower
->name
, vlan
->name
);
223 port
= &hardware
->h_lport
;
225 for (int i
= 0; (i
< VLAN_BITMAP_LEN
); i
++) {
226 if (vlan
->vlan_bmap
[i
] == 0)
228 for (unsigned bit
= 0; bit
< 32; bit
++) {
229 uint32_t mask
= 1L << bit
;
230 if (!(vlan
->vlan_bmap
[i
] & mask
))
232 vlan_id
= (i
* 32) + bit
;
233 if (asprintf(&name
, "vlan%d", vlan_id
) == -1)
236 /* Check if the VLAN is already here. */
237 TAILQ_FOREACH(v
, &port
->p_vlans
, v_entries
)
238 if (strncmp(name
, v
->v_name
, IFNAMSIZ
) == 0) {
243 if ((v
= (struct lldpd_vlan
*)
244 calloc(1, sizeof(struct lldpd_vlan
))) == NULL
) {
251 port
->p_pvid
= vlan
->pvid
;
252 log_debug("interfaces", "append VLAN %s for %s",
255 TAILQ_INSERT_TAIL(&port
->p_vlans
, v
, v_entries
);
261 * Append VLAN to the lowest possible interface.
263 * @param vlan The VLAN interface (used to get VLAN ID).
264 * @param upper The upper interface we are currently examining.
265 * @param depth Depth of the stack (avoid infinite recursion)
267 * Initially, upper == vlan. This function will be called recursively.
270 iface_append_vlan_to_lower(struct lldpd
*cfg
,
271 struct interfaces_device_list
*interfaces
,
272 struct interfaces_device
*vlan
,
273 struct interfaces_device
*upper
,
277 log_warnx("interfaces",
278 "BUG: maximum depth reached when applying VLAN %s (loop?)",
283 struct interfaces_device
*lower
;
284 log_debug("interfaces",
285 "looking to apply VLAN %s to physical interface behind %s",
286 vlan
->name
, upper
->name
);
288 /* Easy: check if we have a lower interface. */
290 log_debug("interfaces", "VLAN %s on lower interface %s",
291 vlan
->name
, upper
->name
);
292 iface_append_vlan_to_lower(cfg
,
299 /* Other easy case, we have a physical interface. */
300 if (upper
->type
& IFACE_PHYSICAL_T
) {
301 log_debug("interfaces", "VLAN %s on physical interface %s",
302 vlan
->name
, upper
->name
);
303 iface_append_vlan(cfg
, vlan
, upper
);
307 /* We can now search for interfaces that have our interface as an upper
309 TAILQ_FOREACH(lower
, interfaces
, next
) {
310 if (lower
->upper
!= upper
) continue;
311 log_debug("interfaces", "VLAN %s on lower interface %s",
312 vlan
->name
, upper
->name
);
313 iface_append_vlan_to_lower(cfg
,
314 interfaces
, vlan
, lower
, depth
);
319 interfaces_helper_vlan(struct lldpd
*cfg
,
320 struct interfaces_device_list
*interfaces
)
322 struct interfaces_device
*iface
;
324 TAILQ_FOREACH(iface
, interfaces
, next
) {
325 if (!(iface
->type
& IFACE_VLAN_T
) && is_bitmap_empty(iface
->vlan_bmap
))
328 /* We need to find the physical interfaces of this
329 vlan, through bonds and bridges. */
330 log_debug("interfaces", "search physical interface for VLAN interface %s",
332 iface_append_vlan_to_lower(cfg
, interfaces
,
338 /* Fill out chassis ID if not already done. Only physical interfaces are
341 interfaces_helper_chassis(struct lldpd
*cfg
,
342 struct interfaces_device_list
*interfaces
)
344 struct interfaces_device
*iface
;
345 struct lldpd_hardware
*hardware
;
348 LOCAL_CHASSIS(cfg
)->c_cap_enabled
&=
349 ~(LLDP_CAP_BRIDGE
| LLDP_CAP_WLAN
| LLDP_CAP_STATION
);
350 TAILQ_FOREACH(iface
, interfaces
, next
) {
351 if (iface
->type
& IFACE_BRIDGE_T
)
352 LOCAL_CHASSIS(cfg
)->c_cap_enabled
|= LLDP_CAP_BRIDGE
;
353 if (iface
->type
& IFACE_WIRELESS_T
)
354 LOCAL_CHASSIS(cfg
)->c_cap_enabled
|= LLDP_CAP_WLAN
;
356 if ((LOCAL_CHASSIS(cfg
)->c_cap_available
& LLDP_CAP_STATION
) &&
357 (LOCAL_CHASSIS(cfg
)->c_cap_enabled
== 0))
358 LOCAL_CHASSIS(cfg
)->c_cap_enabled
= LLDP_CAP_STATION
;
360 if (LOCAL_CHASSIS(cfg
)->c_id
!= NULL
&&
361 LOCAL_CHASSIS(cfg
)->c_id_subtype
== LLDP_CHASSISID_SUBTYPE_LLADDR
)
362 return; /* We already have one */
364 TAILQ_FOREACH(iface
, interfaces
, next
) {
365 if (!(iface
->type
& IFACE_PHYSICAL_T
)) continue;
366 if (cfg
->g_config
.c_cid_pattern
&&
367 !pattern_match(iface
->name
, cfg
->g_config
.c_cid_pattern
, 0)) continue;
369 if ((hardware
= lldpd_get_hardware(cfg
,
371 iface
->index
)) == NULL
)
372 /* That's odd. Let's skip. */
375 name
= malloc(ETHER_ADDR_LEN
);
377 log_warn("interfaces", "not enough memory for chassis ID");
380 free(LOCAL_CHASSIS(cfg
)->c_id
);
381 memcpy(name
, hardware
->h_lladdr
, ETHER_ADDR_LEN
);
382 LOCAL_CHASSIS(cfg
)->c_id
= name
;
383 LOCAL_CHASSIS(cfg
)->c_id_len
= ETHER_ADDR_LEN
;
384 LOCAL_CHASSIS(cfg
)->c_id_subtype
= LLDP_CHASSISID_SUBTYPE_LLADDR
;
389 #undef IN_IS_ADDR_LOOPBACK
390 #define IN_IS_ADDR_LOOPBACK(a) ((a)->s_addr == htonl(INADDR_LOOPBACK))
391 #undef IN_IS_ADDR_ANY
392 #define IN_IS_ADDR_ANY(a) ((a)->s_addr == htonl(INADDR_ANY))
393 #undef IN_IS_ADDR_LINKLOCAL
394 #define IN_IS_ADDR_LINKLOCAL(a) (((a)->s_addr & htonl(0xffff0000)) == htonl(0xa9fe0000))
395 #undef IN_IS_ADDR_GLOBAL
396 #define IN_IS_ADDR_GLOBAL(a) (!IN_IS_ADDR_LOOPBACK(a) && !IN_IS_ADDR_ANY(a) && !IN_IS_ADDR_LINKLOCAL(a))
397 #undef IN6_IS_ADDR_GLOBAL
398 #define IN6_IS_ADDR_GLOBAL(a) \
399 (!IN6_IS_ADDR_LOOPBACK(a) && !IN6_IS_ADDR_LINKLOCAL(a))
401 /* Add management addresses for the given family. We only take one of each
402 address family, unless a pattern is provided and is not all negative. For
403 example !*:*,!10.* will only blacklist addresses. We will pick the first IPv4
404 address not matching 10.*.
407 interfaces_helper_mgmt_for_af(struct lldpd
*cfg
,
409 struct interfaces_address_list
*addrs
,
410 struct interfaces_device_list
*interfaces
,
411 int global
, int allnegative
)
413 struct interfaces_address
*addr
;
414 struct interfaces_device
*device
;
415 struct lldpd_mgmt
*mgmt
;
416 char addrstrbuf
[INET6_ADDRSTRLEN
];
418 union lldpd_address in_addr
;
421 TAILQ_FOREACH(addr
, addrs
, next
) {
422 if (addr
->address
.ss_family
!= lldpd_af(af
))
427 in_addr_size
= sizeof(struct in_addr
);
428 memcpy(&in_addr
, &((struct sockaddr_in
*)&addr
->address
)->sin_addr
,
431 if (!IN_IS_ADDR_GLOBAL(&in_addr
.inet
))
434 if (!IN_IS_ADDR_LINKLOCAL(&in_addr
.inet
))
439 in_addr_size
= sizeof(struct in6_addr
);
440 memcpy(&in_addr
, &((struct sockaddr_in6
*)&addr
->address
)->sin6_addr
,
443 if (!IN6_IS_ADDR_GLOBAL(&in_addr
.inet6
))
446 if (!IN6_IS_ADDR_LINKLOCAL(&in_addr
.inet6
))
454 if (inet_ntop(lldpd_af(af
), &in_addr
,
455 addrstrbuf
, sizeof(addrstrbuf
)) == NULL
) {
456 log_warn("interfaces", "unable to convert IP address to a string");
459 if (cfg
->g_config
.c_mgmt_pattern
== NULL
||
460 /* Match on IP address */
461 pattern_match(addrstrbuf
, cfg
->g_config
.c_mgmt_pattern
, allnegative
) ||
462 /* Match on interface name */
463 ((device
= interfaces_indextointerface(interfaces
, addr
->index
)) &&
464 pattern_match(device
->name
, cfg
->g_config
.c_mgmt_pattern
, allnegative
))) {
465 mgmt
= lldpd_alloc_mgmt(af
, &in_addr
, in_addr_size
,
468 assert(errno
== ENOMEM
); /* anything else is a bug */
469 log_warn("interfaces", "out of memory error");
472 log_debug("interfaces", "add management address %s", addrstrbuf
);
473 TAILQ_INSERT_TAIL(&LOCAL_CHASSIS(cfg
)->c_mgmt
, mgmt
, m_entries
);
476 /* Don't take additional address if the pattern is all negative. */
477 if (allnegative
) break;
483 /* Find a management address in all available interfaces, even those that were
484 already handled. This is a special interface handler because it does not
485 really handle interface related information (management address is attached
486 to the local chassis). */
488 interfaces_helper_mgmt(struct lldpd
*cfg
,
489 struct interfaces_address_list
*addrs
,
490 struct interfaces_device_list
*interfaces
)
494 const char *pattern
= cfg
->g_config
.c_mgmt_pattern
;
496 lldpd_chassis_mgmt_cleanup(LOCAL_CHASSIS(cfg
));
497 if (!cfg
->g_config
.c_mgmt_advertise
)
500 /* Is the pattern provided an actual IP address? */
501 if (pattern
&& strpbrk(pattern
, "!,*?") == NULL
) {
502 struct in6_addr addr
;
504 struct lldpd_mgmt
*mgmt
;
505 struct interfaces_address
*ifaddr
;
507 for (af
= LLDPD_AF_UNSPEC
+ 1;
508 af
!= LLDPD_AF_LAST
; af
++) {
510 case LLDPD_AF_IPV4
: addr_size
= sizeof(struct in_addr
); break;
511 case LLDPD_AF_IPV6
: addr_size
= sizeof(struct in6_addr
); break;
514 if (inet_pton(lldpd_af(af
), pattern
, &addr
) == 1)
517 if (af
!= LLDPD_AF_LAST
) {
518 /* Try to get the index if possible. */
519 TAILQ_FOREACH(ifaddr
, addrs
, next
) {
520 if (ifaddr
->address
.ss_family
!= lldpd_af(af
))
522 if (LLDPD_AF_IPV4
== af
) {
523 struct sockaddr_in
*sa_sin
;
524 sa_sin
= (struct sockaddr_in
*)&ifaddr
->address
;
525 if ((sa_sin
->sin_addr
.s_addr
) == ((struct in_addr
*)&addr
)->s_addr
)
528 else if (LLDPD_AF_IPV6
== af
) {
529 if (0 == memcmp(&addr
,
530 &((struct sockaddr_in6
*)&ifaddr
->address
)->sin6_addr
,
536 mgmt
= lldpd_alloc_mgmt(af
, &addr
, addr_size
, ifaddr
? ifaddr
->index
: 0);
538 log_warn("interfaces", "out of memory error");
541 log_debug("interfaces", "add exact management address %s",
543 TAILQ_INSERT_TAIL(&LOCAL_CHASSIS(cfg
)->c_mgmt
, mgmt
, m_entries
);
546 /* else: could be an interface name */
549 /* Is the pattern provided all negative? */
550 if (pattern
== NULL
) allnegative
= 1;
551 else if (pattern
[0] == '!') {
552 /* If each comma is followed by '!', its an all
554 const char *sep
= pattern
;
555 while ((sep
= strchr(sep
, ',')) &&
557 if (sep
== NULL
) allnegative
= 1;
560 /* Find management addresses */
561 for (af
= LLDPD_AF_UNSPEC
+ 1; af
!= LLDPD_AF_LAST
; af
++) {
562 (void)(interfaces_helper_mgmt_for_af(cfg
, af
, addrs
, interfaces
, 1, allnegative
) ||
563 interfaces_helper_mgmt_for_af(cfg
, af
, addrs
, interfaces
, 0, allnegative
));
567 /* Fill up port name and description */
569 interfaces_helper_port_name_desc(struct lldpd
*cfg
,
570 struct lldpd_hardware
*hardware
,
571 struct interfaces_device
*iface
)
573 struct lldpd_port
*port
= &hardware
->h_lport
;
575 /* We need to set the portid to what the client configured.
576 This can be done from the CLI.
578 int has_alias
= (iface
->alias
!= NULL
&& strlen(iface
->alias
) != 0);
579 int portid_type
= cfg
->g_config
.c_lldp_portid_type
;
580 if (portid_type
== LLDP_PORTID_SUBTYPE_IFNAME
||
581 (portid_type
== LLDP_PORTID_SUBTYPE_UNKNOWN
&& has_alias
) ||
582 (port
->p_id_subtype
== LLDP_PORTID_SUBTYPE_LOCAL
&& has_alias
)) {
583 if (port
->p_id_subtype
!= LLDP_PORTID_SUBTYPE_LOCAL
) {
584 log_debug("interfaces", "use ifname for %s",
586 port
->p_id_subtype
= LLDP_PORTID_SUBTYPE_IFNAME
;
587 port
->p_id_len
= strlen(hardware
->h_ifname
);
589 if ((port
->p_id
= calloc(1, port
->p_id_len
)) == NULL
)
590 fatal("interfaces", NULL
);
591 memcpy(port
->p_id
, hardware
->h_ifname
, port
->p_id_len
);
594 if (port
->p_descr_force
== 0) {
595 /* use the actual alias in the port description */
596 log_debug("interfaces", "using alias in description for %s",
600 port
->p_descr
= strdup(iface
->alias
);
602 /* We don't have anything else to put here and for CDP
603 * with need something non-NULL */
604 port
->p_descr
= strdup(hardware
->h_ifname
);
608 if (port
->p_id_subtype
!= LLDP_PORTID_SUBTYPE_LOCAL
) {
609 log_debug("interfaces", "use MAC address for %s",
611 port
->p_id_subtype
= LLDP_PORTID_SUBTYPE_LLADDR
;
613 if ((port
->p_id
= calloc(1, ETHER_ADDR_LEN
)) == NULL
)
614 fatal("interfaces", NULL
);
615 memcpy(port
->p_id
, hardware
->h_lladdr
, ETHER_ADDR_LEN
);
616 port
->p_id_len
= ETHER_ADDR_LEN
;
619 if (port
->p_descr_force
== 0) {
620 /* use the ifname in the port description until alias is set */
621 log_debug("interfaces", "using ifname in description for %s",
624 port
->p_descr
= strdup(hardware
->h_ifname
);
630 interfaces_helper_add_hardware(struct lldpd
*cfg
,
631 struct lldpd_hardware
*hardware
)
633 TRACE(LLDPD_INTERFACES_NEW(hardware
->h_ifname
));
634 TAILQ_INSERT_TAIL(&cfg
->g_hardware
, hardware
, h_entries
);
638 interfaces_helper_physical(struct lldpd
*cfg
,
639 struct interfaces_device_list
*interfaces
,
640 struct lldpd_ops
*ops
,
641 int(*init
)(struct lldpd
*, struct lldpd_hardware
*))
643 struct interfaces_device
*iface
;
644 struct lldpd_hardware
*hardware
;
647 TAILQ_FOREACH(iface
, interfaces
, next
) {
648 if (!(iface
->type
& IFACE_PHYSICAL_T
)) continue;
649 if (iface
->ignore
) continue;
651 log_debug("interfaces", "%s is an acceptable ethernet device",
654 if ((hardware
= lldpd_get_hardware(cfg
,
656 iface
->index
)) == NULL
) {
657 if ((hardware
= lldpd_alloc_hardware(cfg
,
659 iface
->index
)) == NULL
) {
660 log_warnx("interfaces", "Unable to allocate space for %s",
666 if (hardware
->h_flags
)
668 if (hardware
->h_ops
!= ops
) {
670 log_debug("interfaces",
671 "interface %s is converted from another type of interface",
673 if (hardware
->h_ops
&& hardware
->h_ops
->cleanup
) {
674 hardware
->h_ops
->cleanup(cfg
, hardware
);
675 levent_hardware_release(hardware
);
676 levent_hardware_init(hardware
);
679 if (init(cfg
, hardware
) != 0) {
680 log_warnx("interfaces",
681 "unable to initialize %s",
683 lldpd_hardware_cleanup(cfg
, hardware
);
686 hardware
->h_ops
= ops
;
687 hardware
->h_mangle
= (iface
->upper
&&
688 iface
->upper
->type
& IFACE_BOND_T
);
691 interfaces_helper_add_hardware(cfg
, hardware
);
693 lldpd_port_cleanup(&hardware
->h_lport
, 0);
695 hardware
->h_flags
= iface
->flags
; /* Should be non-zero */
696 iface
->ignore
= 1; /* Future handlers
701 /* Get local address */
702 memcpy(&hardware
->h_lladdr
, iface
->address
, ETHER_ADDR_LEN
);
704 /* Fill information about port */
705 interfaces_helper_port_name_desc(cfg
, hardware
, iface
);
707 /* Fill additional info */
708 hardware
->h_mtu
= iface
->mtu
? iface
->mtu
: 1500;
711 if (iface
->upper
&& iface
->upper
->type
& IFACE_BOND_T
)
712 hardware
->h_lport
.p_aggregid
= iface
->upper
->index
;
714 hardware
->h_lport
.p_aggregid
= 0;
720 interfaces_helper_promisc(struct lldpd
*cfg
,
721 struct lldpd_hardware
*hardware
)
723 if (!cfg
->g_config
.c_promisc
) return;
724 if (priv_iface_promisc(hardware
->h_ifname
) != 0) {
725 log_warnx("interfaces",
726 "unable to enable promiscuous mode for %s",
732 * Send the packet using the hardware function. Optionnaly mangle the MAC address.
734 * With bonds, we have duplicate MAC address on different physical
735 * interfaces. We need to alter the source MAC address when we send on an
736 * inactive slave. The `h_mangle` flah is used to know if we need to do
737 * something like that.
740 interfaces_send_helper(struct lldpd
*cfg
,
741 struct lldpd_hardware
*hardware
,
742 char *buffer
, size_t size
)
744 if (size
< 2 * ETHER_ADDR_LEN
) {
745 log_warnx("interfaces",
746 "packet to send on %s is too small!",
750 if (hardware
->h_mangle
) {
751 #define MAC_UL_ADMINISTERED_BIT_MASK 0x02
752 char *src_mac
= buffer
+ ETHER_ADDR_LEN
;
753 char arbitrary
[] = { 0x00, 0x60, 0x08, 0x69, 0x97, 0xef};
755 switch (cfg
->g_config
.c_bond_slave_src_mac_type
) {
756 case LLDP_BOND_SLAVE_SRC_MAC_TYPE_LOCALLY_ADMINISTERED
:
757 if (!(*src_mac
& MAC_UL_ADMINISTERED_BIT_MASK
)) {
758 *src_mac
|= MAC_UL_ADMINISTERED_BIT_MASK
;
761 /* Fallback to fixed value */
763 case LLDP_BOND_SLAVE_SRC_MAC_TYPE_FIXED
:
764 memcpy(src_mac
, arbitrary
, ETHER_ADDR_LEN
);
766 case LLDP_BOND_SLAVE_SRC_MAC_TYPE_ZERO
:
767 memset(src_mac
, 0, ETHER_ADDR_LEN
);
771 return hardware
->h_ops
->send(cfg
, hardware
, buffer
, size
);