1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
4 #include <linux/sockios.h>
9 #include "sd-lldp-tx.h"
11 #include "alloc-util.h"
12 #include "ether-addr-util.h"
14 #include "hostname-util.h"
15 #include "network-common.h"
16 #include "random-util.h"
17 #include "socket-util.h"
18 #include "string-util.h"
19 #include "time-util.h"
20 #include "unaligned.h"
23 /* The LLDP spec calls this "txFastInit", see 9.2.5.19 */
24 #define LLDP_FAST_TX_INIT 4U
26 /* The LLDP spec calls this "msgTxHold", see 9.2.5.6 */
27 #define LLDP_TX_HOLD 4U
29 /* The jitter range to add, see 9.2.2. */
30 #define LLDP_TX_JITTER_USEC (400U * USEC_PER_MSEC)
32 /* The LLDP spec calls this msgTxInterval, but we subtract half the jitter off it. */
33 #define LLDP_TX_INTERVAL_USEC (30U * USEC_PER_SEC - LLDP_TX_JITTER_USEC / 2)
35 /* The LLDP spec calls this msgFastTx, but we subtract half the jitter off it. */
36 #define LLDP_FAST_TX_INTERVAL_USEC (1U * USEC_PER_SEC - LLDP_TX_JITTER_USEC / 2)
38 #define LLDP_TX_TTL ((uint16_t) DIV_ROUND_UP(LLDP_TX_INTERVAL_USEC * LLDP_TX_HOLD + 1, USEC_PER_SEC))
40 static const struct ether_addr lldp_multicast_addr
[_SD_LLDP_MULTICAST_MODE_MAX
] = {
41 [SD_LLDP_MULTICAST_MODE_NEAREST_BRIDGE
] = {{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e }},
42 [SD_LLDP_MULTICAST_MODE_NON_TPMR_BRIDGE
] = {{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 }},
43 [SD_LLDP_MULTICAST_MODE_CUSTOMER_BRIDGE
] = {{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 }},
53 int64_t event_priority
;
54 sd_event_source
*timer_event_source
;
58 sd_lldp_multicast_mode_t mode
;
59 struct ether_addr hwaddr
;
61 char *port_description
;
63 char *pretty_hostname
;
65 uint16_t supported_capabilities
;
66 uint16_t enabled_capabilities
;
69 #define log_lldp_tx_errno(lldp_tx, error, fmt, ...) \
70 log_interface_prefix_full_errno( \
72 sd_lldp_tx, lldp_tx, \
73 error, fmt, ##__VA_ARGS__)
74 #define log_lldp_tx(lldp_tx, fmt, ...) \
75 log_interface_prefix_full_errno_zerook( \
77 sd_lldp_tx, lldp_tx, \
78 0, fmt, ##__VA_ARGS__)
80 static sd_lldp_tx
*lldp_tx_free(sd_lldp_tx
*lldp_tx
) {
84 sd_lldp_tx_detach_event(lldp_tx
);
86 free(lldp_tx
->port_description
);
87 free(lldp_tx
->hostname
);
88 free(lldp_tx
->pretty_hostname
);
89 free(lldp_tx
->mud_url
);
91 free(lldp_tx
->ifname
);
92 return mfree(lldp_tx
);
95 DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_lldp_tx
, sd_lldp_tx
, lldp_tx_free
);
97 int sd_lldp_tx_new(sd_lldp_tx
**ret
) {
98 _cleanup_(sd_lldp_tx_unrefp
) sd_lldp_tx
*lldp_tx
= NULL
;
100 assert_return(ret
, -EINVAL
);
102 lldp_tx
= new(sd_lldp_tx
, 1);
106 *lldp_tx
= (sd_lldp_tx
) {
108 .mode
= _SD_LLDP_MULTICAST_MODE_INVALID
,
111 *ret
= TAKE_PTR(lldp_tx
);
115 int sd_lldp_tx_set_ifindex(sd_lldp_tx
*lldp_tx
, int ifindex
) {
116 assert_return(lldp_tx
, -EINVAL
);
117 assert_return(ifindex
> 0, -EINVAL
);
119 lldp_tx
->ifindex
= ifindex
;
123 int sd_lldp_tx_set_ifname(sd_lldp_tx
*lldp_tx
, const char *ifname
) {
124 assert_return(lldp_tx
, -EINVAL
);
125 assert_return(ifname
, -EINVAL
);
127 if (!ifname_valid_full(ifname
, IFNAME_VALID_ALTERNATIVE
))
130 return free_and_strdup(&lldp_tx
->ifname
, ifname
);
133 int sd_lldp_tx_get_ifname(sd_lldp_tx
*lldp_tx
, const char **ret
) {
136 assert_return(lldp_tx
, -EINVAL
);
138 r
= get_ifname(lldp_tx
->ifindex
, &lldp_tx
->ifname
);
143 *ret
= lldp_tx
->ifname
;
148 int sd_lldp_tx_set_multicast_mode(sd_lldp_tx
*lldp_tx
, sd_lldp_multicast_mode_t mode
) {
149 assert_return(lldp_tx
, -EINVAL
);
150 assert_return(mode
>= 0 && mode
< _SD_LLDP_MULTICAST_MODE_MAX
, -EINVAL
);
152 lldp_tx
->mode
= mode
;
156 int sd_lldp_tx_set_hwaddr(sd_lldp_tx
*lldp_tx
, const struct ether_addr
*hwaddr
) {
157 assert_return(lldp_tx
, -EINVAL
);
158 assert_return(!ether_addr_is_null(hwaddr
), -EINVAL
);
160 lldp_tx
->hwaddr
= *hwaddr
;
164 int sd_lldp_tx_set_capabilities(sd_lldp_tx
*lldp_tx
, uint16_t supported
, uint16_t enabled
) {
165 assert_return(lldp_tx
, -EINVAL
);
166 assert_return((enabled
& ~supported
) == 0, -EINVAL
);
168 lldp_tx
->supported_capabilities
= supported
;
169 lldp_tx
->enabled_capabilities
= enabled
;
173 int sd_lldp_tx_set_port_description(sd_lldp_tx
*lldp_tx
, const char *port_description
) {
174 assert_return(lldp_tx
, -EINVAL
);
176 /* An empty string unset the previously set hostname. */
177 if (strlen_ptr(port_description
) >= 512)
180 return free_and_strdup(&lldp_tx
->port_description
, empty_to_null(port_description
));
183 int sd_lldp_tx_set_hostname(sd_lldp_tx
*lldp_tx
, const char *hostname
) {
184 assert_return(lldp_tx
, -EINVAL
);
186 /* An empty string unset the previously set hostname. */
187 if (!isempty(hostname
)) {
188 assert_cc(HOST_NAME_MAX
< 512);
190 if (!hostname_is_valid(hostname
, 0))
194 return free_and_strdup(&lldp_tx
->hostname
, empty_to_null(hostname
));
197 int sd_lldp_tx_set_pretty_hostname(sd_lldp_tx
*lldp_tx
, const char *pretty_hostname
) {
198 assert_return(lldp_tx
, -EINVAL
);
200 /* An empty string unset the previously set hostname. */
201 if (strlen_ptr(pretty_hostname
) >= 512)
204 return free_and_strdup(&lldp_tx
->pretty_hostname
, empty_to_null(pretty_hostname
));
207 int sd_lldp_tx_set_mud_url(sd_lldp_tx
*lldp_tx
, const char *mud_url
) {
208 assert_return(lldp_tx
, -EINVAL
);
210 /* An empty string unset the previously set hostname. */
211 if (!isempty(mud_url
)) {
212 /* Unless the maximum length of each value is 511, the MUD url must be smaller than 256.
214 if (strlen(mud_url
) >= 256)
217 if (!http_url_is_valid(mud_url
))
221 return free_and_strdup(&lldp_tx
->mud_url
, empty_to_null(mud_url
));
224 static size_t lldp_tx_calculate_maximum_packet_size(sd_lldp_tx
*lldp_tx
, const char *hostname
, const char *pretty_hostname
) {
226 assert(lldp_tx
->ifindex
> 0);
228 return sizeof(struct ether_header
) +
230 2 + 1 + (SD_ID128_STRING_MAX
- 1) +
232 2 + 1 + strlen_ptr(lldp_tx
->ifname
) +
235 /* Port description */
236 2 + strlen_ptr(lldp_tx
->port_description
) +
238 2 + strlen_ptr(hostname
) +
239 /* System description */
240 2 + strlen_ptr(pretty_hostname
) +
242 2 + sizeof(SD_LLDP_OUI_IANA_MUD
) + strlen_ptr(lldp_tx
->mud_url
) +
243 /* System Capabilities */
249 static int packet_append_tlv_header(uint8_t *packet
, size_t packet_size
, size_t *offset
, uint8_t type
, size_t data_len
) {
254 * +--------+--------+--------------
255 * |TLV Type| len | value
256 * |(7 bits)|(9 bits)|(0-511 octets)
257 * +--------+--------+--------------
260 * len = indicates the length of value
263 /* The type field is 7-bits. */
267 /* The data length field is 9-bits. */
271 if (packet_size
< 2 + data_len
)
274 if (*offset
> packet_size
- 2 - data_len
)
277 packet
[(*offset
)++] = (type
<< 1) | !!(data_len
>> 8);
278 packet
[(*offset
)++] = data_len
& (size_t) UINT8_MAX
;
283 static int packet_append_prefixed_string(
297 assert(prefix_len
== 0 || prefix
);
304 /* Check for overflow */
305 if (len
> SIZE_MAX
- prefix_len
)
308 r
= packet_append_tlv_header(packet
, packet_size
, offset
, type
, prefix_len
+ len
);
312 memcpy_safe(packet
+ *offset
, prefix
, prefix_len
);
313 *offset
+= prefix_len
;
315 memcpy(packet
+ *offset
, str
, len
);
321 static int packet_append_string(
328 return packet_append_prefixed_string(packet
, packet_size
, offset
, type
, 0, NULL
, str
);
331 static int lldp_tx_create_packet(sd_lldp_tx
*lldp_tx
, size_t *ret_packet_size
, uint8_t **ret_packet
) {
332 _cleanup_free_
char *hostname
= NULL
, *pretty_hostname
= NULL
;
333 _cleanup_free_
uint8_t *packet
= NULL
;
334 struct ether_header
*header
;
335 size_t packet_size
, offset
;
336 sd_id128_t machine_id
;
340 assert(lldp_tx
->ifindex
> 0);
341 assert(ret_packet_size
);
344 /* If ifname is not set yet, set ifname from ifindex. */
345 r
= sd_lldp_tx_get_ifname(lldp_tx
, NULL
);
349 r
= sd_id128_get_machine(&machine_id
);
353 if (!lldp_tx
->hostname
)
354 (void) gethostname_strict(&hostname
);
355 if (!lldp_tx
->pretty_hostname
)
356 (void) get_pretty_hostname(&pretty_hostname
);
358 packet_size
= lldp_tx_calculate_maximum_packet_size(lldp_tx
,
359 lldp_tx
->hostname
?: hostname
,
360 lldp_tx
->pretty_hostname
?: pretty_hostname
);
362 packet
= new(uint8_t, packet_size
);
366 header
= (struct ether_header
*) packet
;
367 header
->ether_type
= htobe16(ETHERTYPE_LLDP
);
368 memcpy(header
->ether_dhost
, lldp_multicast_addr
+ lldp_tx
->mode
, ETH_ALEN
);
369 memcpy(header
->ether_shost
, &lldp_tx
->hwaddr
, ETH_ALEN
);
371 offset
= sizeof(struct ether_header
);
373 /* The three mandatory TLVs must appear first, in this specific order:
379 r
= packet_append_prefixed_string(packet
, packet_size
, &offset
, SD_LLDP_TYPE_CHASSIS_ID
,
380 1, (const uint8_t[]) { SD_LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED
},
381 SD_ID128_TO_STRING(machine_id
));
385 r
= packet_append_prefixed_string(packet
, packet_size
, &offset
, SD_LLDP_TYPE_PORT_ID
,
386 1, (const uint8_t[]) { SD_LLDP_PORT_SUBTYPE_INTERFACE_NAME
},
391 r
= packet_append_tlv_header(packet
, packet_size
, &offset
, SD_LLDP_TYPE_TTL
, 2);
395 unaligned_write_be16(packet
+ offset
, LLDP_TX_TTL
);
398 /* Optional TLVs follow, in no specific order: */
400 r
= packet_append_string(packet
, packet_size
, &offset
, SD_LLDP_TYPE_PORT_DESCRIPTION
,
401 lldp_tx
->port_description
);
405 r
= packet_append_string(packet
, packet_size
, &offset
, SD_LLDP_TYPE_SYSTEM_NAME
,
406 lldp_tx
->hostname
?: hostname
);
410 r
= packet_append_string(packet
, packet_size
, &offset
, SD_LLDP_TYPE_SYSTEM_DESCRIPTION
,
411 lldp_tx
->pretty_hostname
?: pretty_hostname
);
415 /* See section 12 of RFC 8520.
416 * +--------+--------+----------+---------+--------------
417 * |TLV Type| len | OUI |subtype | MUDString
418 * | =127 | |= 00 00 5E| = 1 |
419 * |(7 bits)|(9 bits)|(3 octets)|(1 octet)|(1-255 octets)
420 * +--------+--------+----------+---------+--------------
423 * o TLV Type = 127 indicates a vendor-specific TLV
424 * o len = indicates the TLV string length
425 * o OUI = 00 00 5E is the organizationally unique identifier of IANA
426 * o subtype = 1 (as assigned by IANA for the MUDstring)
427 * o MUDstring = the length MUST NOT exceed 255 octets
429 r
= packet_append_prefixed_string(packet
, packet_size
, &offset
, SD_LLDP_TYPE_PRIVATE
,
430 sizeof(SD_LLDP_OUI_IANA_MUD
), SD_LLDP_OUI_IANA_MUD
,
435 r
= packet_append_tlv_header(packet
, packet_size
, &offset
, SD_LLDP_TYPE_SYSTEM_CAPABILITIES
, 4);
439 unaligned_write_be16(packet
+ offset
, lldp_tx
->supported_capabilities
);
441 unaligned_write_be16(packet
+ offset
, lldp_tx
->enabled_capabilities
);
444 r
= packet_append_tlv_header(packet
, packet_size
, &offset
, SD_LLDP_TYPE_END
, 0);
448 *ret_packet_size
= offset
;
449 *ret_packet
= TAKE_PTR(packet
);
453 static int lldp_tx_send_packet(sd_lldp_tx
*lldp_tx
, size_t packet_size
, const uint8_t *packet
) {
454 _cleanup_close_
int fd
= -1;
455 union sockaddr_union sa
;
459 assert(lldp_tx
->ifindex
> 0);
460 assert(packet_size
> sizeof(struct ether_header
));
463 sa
= (union sockaddr_union
) {
464 .ll
.sll_family
= AF_PACKET
,
465 .ll
.sll_protocol
= htobe16(ETHERTYPE_LLDP
),
466 .ll
.sll_ifindex
= lldp_tx
->ifindex
,
467 .ll
.sll_halen
= ETH_ALEN
,
469 memcpy(sa
.ll
.sll_addr
, lldp_multicast_addr
+ lldp_tx
->mode
, ETH_ALEN
);
471 fd
= socket(AF_PACKET
, SOCK_RAW
| SOCK_CLOEXEC
, IPPROTO_RAW
);
475 l
= sendto(fd
, packet
, packet_size
, MSG_NOSIGNAL
, &sa
.sa
, sizeof(sa
.ll
));
479 if ((size_t) l
!= packet_size
)
485 static int lldp_tx_send(sd_lldp_tx
*lldp_tx
) {
486 _cleanup_free_
uint8_t *packet
= NULL
;
487 size_t packet_size
= 0; /* avoid false maybe-uninitialized warning */
492 r
= lldp_tx_create_packet(lldp_tx
, &packet_size
, &packet
);
496 return lldp_tx_send_packet(lldp_tx
, packet_size
, packet
);
499 int sd_lldp_tx_attach_event(sd_lldp_tx
*lldp_tx
, sd_event
*event
, int64_t priority
) {
502 assert_return(lldp_tx
, -EINVAL
);
503 assert_return(!lldp_tx
->event
, -EBUSY
);
506 lldp_tx
->event
= sd_event_ref(event
);
508 r
= sd_event_default(&lldp_tx
->event
);
513 lldp_tx
->event_priority
= priority
;
518 int sd_lldp_tx_detach_event(sd_lldp_tx
*lldp_tx
) {
519 assert_return(lldp_tx
, -EINVAL
);
521 lldp_tx
->timer_event_source
= sd_event_source_disable_unref(lldp_tx
->timer_event_source
);
522 lldp_tx
->event
= sd_event_unref(lldp_tx
->event
);
526 static usec_t
lldp_tx_get_delay(sd_lldp_tx
*lldp_tx
) {
529 return usec_add(lldp_tx
->fast_tx
> 0 ? LLDP_FAST_TX_INTERVAL_USEC
: LLDP_TX_INTERVAL_USEC
,
530 (usec_t
) random_u64() % LLDP_TX_JITTER_USEC
);
533 static int lldp_tx_reset_timer(sd_lldp_tx
*lldp_tx
) {
538 assert(lldp_tx
->timer_event_source
);
540 delay
= lldp_tx_get_delay(lldp_tx
);
542 r
= sd_event_source_set_time_relative(lldp_tx
->timer_event_source
, delay
);
546 return sd_event_source_set_enabled(lldp_tx
->timer_event_source
, SD_EVENT_ONESHOT
);
549 static int on_timer_event(sd_event_source
*s
, uint64_t usec
, void *userdata
) {
550 sd_lldp_tx
*lldp_tx
= ASSERT_PTR(userdata
);
553 r
= lldp_tx_send(lldp_tx
);
555 log_lldp_tx_errno(lldp_tx
, r
, "Failed to send packet, ignoring: %m");
557 if (lldp_tx
->fast_tx
> 0)
560 r
= lldp_tx_reset_timer(lldp_tx
);
562 log_lldp_tx_errno(lldp_tx
, r
, "Failed to reset timer: %m");
567 int sd_lldp_tx_is_running(sd_lldp_tx
*lldp_tx
) {
573 if (!lldp_tx
->timer_event_source
)
576 if (sd_event_source_get_enabled(lldp_tx
->timer_event_source
, &enabled
) < 0)
579 return enabled
== SD_EVENT_ONESHOT
;
582 int sd_lldp_tx_stop(sd_lldp_tx
*lldp_tx
) {
586 if (!lldp_tx
->timer_event_source
)
589 (void) sd_event_source_set_enabled(lldp_tx
->timer_event_source
, SD_EVENT_OFF
);
593 int sd_lldp_tx_start(sd_lldp_tx
*lldp_tx
) {
597 assert_return(lldp_tx
, -EINVAL
);
598 assert_return(lldp_tx
->event
, -EINVAL
);
599 assert_return(lldp_tx
->ifindex
> 0, -EINVAL
);
600 assert_return(lldp_tx
->mode
>= 0 && lldp_tx
->mode
< _SD_LLDP_MULTICAST_MODE_MAX
, -EINVAL
);
601 assert_return(!ether_addr_is_null(&lldp_tx
->hwaddr
), -EINVAL
);
603 if (sd_lldp_tx_is_running(lldp_tx
))
606 lldp_tx
->fast_tx
= LLDP_FAST_TX_INIT
;
608 if (lldp_tx
->timer_event_source
) {
609 r
= lldp_tx_reset_timer(lldp_tx
);
611 return log_lldp_tx_errno(lldp_tx
, r
, "Failed to re-enable timer: %m");
616 delay
= lldp_tx_get_delay(lldp_tx
);
618 r
= sd_event_add_time_relative(lldp_tx
->event
, &lldp_tx
->timer_event_source
,
619 CLOCK_BOOTTIME
, delay
, 0,
620 on_timer_event
, lldp_tx
);
624 (void) sd_event_source_set_description(lldp_tx
->timer_event_source
, "lldp-tx-timer");
625 (void) sd_event_source_set_priority(lldp_tx
->timer_event_source
, lldp_tx
->event_priority
);