1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <arpa/inet.h>
4 #include <linux/sockios.h>
5 #include <sys/ioctl.h>
6
7 #include "sd-event.h"
8 #include "sd-id128.h"
9 #include "sd-lldp-tx.h"
10
11 #include "alloc-util.h"
12 #include "ether-addr-util.h"
13 #include "fd-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"
21 #include "web-util.h"
22
23 /* The LLDP spec calls this "txFastInit", see 9.2.5.19 */
24 #define LLDP_FAST_TX_INIT 4U
25
26 /* The LLDP spec calls this "msgTxHold", see 9.2.5.6 */
27 #define LLDP_TX_HOLD 4U
28
29 /* The jitter range to add, see 9.2.2. */
30 #define LLDP_TX_JITTER_USEC (400U * USEC_PER_MSEC)
31
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)
34
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)
37
38 #define LLDP_TX_TTL ((uint16_t) DIV_ROUND_UP(LLDP_TX_INTERVAL_USEC * LLDP_TX_HOLD + 1, USEC_PER_SEC))
39
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 }},
44 };
45
46 struct sd_lldp_tx {
47 unsigned n_ref;
48
49 int ifindex;
50 char *ifname;
51
52 sd_event *event;
53 int64_t event_priority;
54 sd_event_source *timer_event_source;
55
56 unsigned fast_tx;
57
58 sd_lldp_multicast_mode_t mode;
59 struct ether_addr hwaddr;
60
61 char *port_description;
62 char *hostname;
63 char *pretty_hostname;
64 char *mud_url;
65 uint16_t supported_capabilities;
66 uint16_t enabled_capabilities;
67 };
68
69 #define log_lldp_tx_errno(lldp_tx, error, fmt, ...) \
70 log_interface_prefix_full_errno( \
71 "LLDP Tx: ", \
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( \
76 "LLDP Tx: ", \
77 sd_lldp_tx, lldp_tx, \
78 0, fmt, ##__VA_ARGS__)
79
lldp_tx_free(sd_lldp_tx * lldp_tx)80 static sd_lldp_tx *lldp_tx_free(sd_lldp_tx *lldp_tx) {
81 if (!lldp_tx)
82 return NULL;
83
84 sd_lldp_tx_detach_event(lldp_tx);
85
86 free(lldp_tx->port_description);
87 free(lldp_tx->hostname);
88 free(lldp_tx->pretty_hostname);
89 free(lldp_tx->mud_url);
90
91 free(lldp_tx->ifname);
92 return mfree(lldp_tx);
93 }
94
95 DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_lldp_tx, sd_lldp_tx, lldp_tx_free);
96
sd_lldp_tx_new(sd_lldp_tx ** ret)97 int sd_lldp_tx_new(sd_lldp_tx **ret) {
98 _cleanup_(sd_lldp_tx_unrefp) sd_lldp_tx *lldp_tx = NULL;
99
100 assert_return(ret, -EINVAL);
101
102 lldp_tx = new(sd_lldp_tx, 1);
103 if (!lldp_tx)
104 return -ENOMEM;
105
106 *lldp_tx = (sd_lldp_tx) {
107 .n_ref = 1,
108 .mode = _SD_LLDP_MULTICAST_MODE_INVALID,
109 };
110
111 *ret = TAKE_PTR(lldp_tx);
112 return 0;
113 }
114
sd_lldp_tx_set_ifindex(sd_lldp_tx * lldp_tx,int ifindex)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);
118
119 lldp_tx->ifindex = ifindex;
120 return 0;
121 }
122
sd_lldp_tx_set_ifname(sd_lldp_tx * lldp_tx,const char * ifname)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);
126
127 if (!ifname_valid_full(ifname, IFNAME_VALID_ALTERNATIVE))
128 return -EINVAL;
129
130 return free_and_strdup(&lldp_tx->ifname, ifname);
131 }
132
sd_lldp_tx_get_ifname(sd_lldp_tx * lldp_tx,const char ** ret)133 int sd_lldp_tx_get_ifname(sd_lldp_tx *lldp_tx, const char **ret) {
134 int r;
135
136 assert_return(lldp_tx, -EINVAL);
137
138 r = get_ifname(lldp_tx->ifindex, &lldp_tx->ifname);
139 if (r < 0)
140 return r;
141
142 if (ret)
143 *ret = lldp_tx->ifname;
144
145 return 0;
146 }
147
sd_lldp_tx_set_multicast_mode(sd_lldp_tx * lldp_tx,sd_lldp_multicast_mode_t mode)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);
151
152 lldp_tx->mode = mode;
153 return 0;
154 }
155
sd_lldp_tx_set_hwaddr(sd_lldp_tx * lldp_tx,const struct ether_addr * hwaddr)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);
159
160 lldp_tx->hwaddr = *hwaddr;
161 return 0;
162 }
163
sd_lldp_tx_set_capabilities(sd_lldp_tx * lldp_tx,uint16_t supported,uint16_t enabled)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);
167
168 lldp_tx->supported_capabilities = supported;
169 lldp_tx->enabled_capabilities = enabled;
170 return 0;
171 }
172
sd_lldp_tx_set_port_description(sd_lldp_tx * lldp_tx,const char * port_description)173 int sd_lldp_tx_set_port_description(sd_lldp_tx *lldp_tx, const char *port_description) {
174 assert_return(lldp_tx, -EINVAL);
175
176 /* An empty string unset the previously set hostname. */
177 if (strlen_ptr(port_description) >= 512)
178 return -EINVAL;
179
180 return free_and_strdup(&lldp_tx->port_description, empty_to_null(port_description));
181 }
182
sd_lldp_tx_set_hostname(sd_lldp_tx * lldp_tx,const char * hostname)183 int sd_lldp_tx_set_hostname(sd_lldp_tx *lldp_tx, const char *hostname) {
184 assert_return(lldp_tx, -EINVAL);
185
186 /* An empty string unset the previously set hostname. */
187 if (!isempty(hostname)) {
188 assert_cc(HOST_NAME_MAX < 512);
189
190 if (!hostname_is_valid(hostname, 0))
191 return -EINVAL;
192 }
193
194 return free_and_strdup(&lldp_tx->hostname, empty_to_null(hostname));
195 }
196
sd_lldp_tx_set_pretty_hostname(sd_lldp_tx * lldp_tx,const char * pretty_hostname)197 int sd_lldp_tx_set_pretty_hostname(sd_lldp_tx *lldp_tx, const char *pretty_hostname) {
198 assert_return(lldp_tx, -EINVAL);
199
200 /* An empty string unset the previously set hostname. */
201 if (strlen_ptr(pretty_hostname) >= 512)
202 return -EINVAL;
203
204 return free_and_strdup(&lldp_tx->pretty_hostname, empty_to_null(pretty_hostname));
205 }
206
sd_lldp_tx_set_mud_url(sd_lldp_tx * lldp_tx,const char * mud_url)207 int sd_lldp_tx_set_mud_url(sd_lldp_tx *lldp_tx, const char *mud_url) {
208 assert_return(lldp_tx, -EINVAL);
209
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.
213 * See RFC 8520. */
214 if (strlen(mud_url) >= 256)
215 return -EINVAL;
216
217 if (!http_url_is_valid(mud_url))
218 return -EINVAL;
219 }
220
221 return free_and_strdup(&lldp_tx->mud_url, empty_to_null(mud_url));
222 }
223
lldp_tx_calculate_maximum_packet_size(sd_lldp_tx * lldp_tx,const char * hostname,const char * pretty_hostname)224 static size_t lldp_tx_calculate_maximum_packet_size(sd_lldp_tx *lldp_tx, const char *hostname, const char *pretty_hostname) {
225 assert(lldp_tx);
226 assert(lldp_tx->ifindex > 0);
227
228 return sizeof(struct ether_header) +
229 /* Chassis ID */
230 2 + 1 + (SD_ID128_STRING_MAX - 1) +
231 /* Port ID */
232 2 + 1 + strlen_ptr(lldp_tx->ifname) +
233 /* TTL */
234 2 + 2 +
235 /* Port description */
236 2 + strlen_ptr(lldp_tx->port_description) +
237 /* System name */
238 2 + strlen_ptr(hostname) +
239 /* System description */
240 2 + strlen_ptr(pretty_hostname) +
241 /* MUD URL */
242 2 + sizeof(SD_LLDP_OUI_IANA_MUD) + strlen_ptr(lldp_tx->mud_url) +
243 /* System Capabilities */
244 2 + 4 +
245 /* End */
246 2;
247 }
248
packet_append_tlv_header(uint8_t * packet,size_t packet_size,size_t * offset,uint8_t type,size_t data_len)249 static int packet_append_tlv_header(uint8_t *packet, size_t packet_size, size_t *offset, uint8_t type, size_t data_len) {
250 assert(packet);
251 assert(offset);
252
253 /*
254 * +--------+--------+--------------
255 * |TLV Type| len | value
256 * |(7 bits)|(9 bits)|(0-511 octets)
257 * +--------+--------+--------------
258 * where:
259 *
260 * len = indicates the length of value
261 */
262
263 /* The type field is 7-bits. */
264 if (type >= 128)
265 return -EINVAL;
266
267 /* The data length field is 9-bits. */
268 if (data_len >= 512)
269 return -EINVAL;
270
271 if (packet_size < 2 + data_len)
272 return -ENOBUFS;
273
274 if (*offset > packet_size - 2 - data_len)
275 return -ENOBUFS;
276
277 packet[(*offset)++] = (type << 1) | !!(data_len >> 8);
278 packet[(*offset)++] = data_len & (size_t) UINT8_MAX;
279
280 return 0;
281 }
282
packet_append_prefixed_string(uint8_t * packet,size_t packet_size,size_t * offset,uint8_t type,size_t prefix_len,const void * prefix,const char * str)283 static int packet_append_prefixed_string(
284 uint8_t *packet,
285 size_t packet_size,
286 size_t *offset,
287 uint8_t type,
288 size_t prefix_len,
289 const void *prefix,
290 const char *str) {
291
292 size_t len;
293 int r;
294
295 assert(packet);
296 assert(offset);
297 assert(prefix_len == 0 || prefix);
298
299 if (isempty(str))
300 return 0;
301
302 len = strlen(str);
303
304 /* Check for overflow */
305 if (len > SIZE_MAX - prefix_len)
306 return -ENOBUFS;
307
308 r = packet_append_tlv_header(packet, packet_size, offset, type, prefix_len + len);
309 if (r < 0)
310 return r;
311
312 memcpy_safe(packet + *offset, prefix, prefix_len);
313 *offset += prefix_len;
314
315 memcpy(packet + *offset, str, len);
316 *offset += len;
317
318 return 0;
319 }
320
packet_append_string(uint8_t * packet,size_t packet_size,size_t * offset,uint8_t type,const char * str)321 static int packet_append_string(
322 uint8_t *packet,
323 size_t packet_size,
324 size_t *offset,
325 uint8_t type,
326 const char *str) {
327
328 return packet_append_prefixed_string(packet, packet_size, offset, type, 0, NULL, str);
329 }
330
lldp_tx_create_packet(sd_lldp_tx * lldp_tx,size_t * ret_packet_size,uint8_t ** ret_packet)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;
337 int r;
338
339 assert(lldp_tx);
340 assert(lldp_tx->ifindex > 0);
341 assert(ret_packet_size);
342 assert(ret_packet);
343
344 /* If ifname is not set yet, set ifname from ifindex. */
345 r = sd_lldp_tx_get_ifname(lldp_tx, NULL);
346 if (r < 0)
347 return r;
348
349 r = sd_id128_get_machine(&machine_id);
350 if (r < 0)
351 return r;
352
353 if (!lldp_tx->hostname)
354 (void) gethostname_strict(&hostname);
355 if (!lldp_tx->pretty_hostname)
356 (void) get_pretty_hostname(&pretty_hostname);
357
358 packet_size = lldp_tx_calculate_maximum_packet_size(lldp_tx,
359 lldp_tx->hostname ?: hostname,
360 lldp_tx->pretty_hostname ?: pretty_hostname);
361
362 packet = new(uint8_t, packet_size);
363 if (!packet)
364 return -ENOMEM;
365
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);
370
371 offset = sizeof(struct ether_header);
372
373 /* The three mandatory TLVs must appear first, in this specific order:
374 * 1. Chassis ID
375 * 2. Port ID
376 * 3. Time To Live
377 */
378
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));
382 if (r < 0)
383 return r;
384
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 },
387 lldp_tx->ifname);
388 if (r < 0)
389 return r;
390
391 r = packet_append_tlv_header(packet, packet_size, &offset, SD_LLDP_TYPE_TTL, 2);
392 if (r < 0)
393 return r;
394
395 unaligned_write_be16(packet + offset, LLDP_TX_TTL);
396 offset += 2;
397
398 /* Optional TLVs follow, in no specific order: */
399
400 r = packet_append_string(packet, packet_size, &offset, SD_LLDP_TYPE_PORT_DESCRIPTION,
401 lldp_tx->port_description);
402 if (r < 0)
403 return r;
404
405 r = packet_append_string(packet, packet_size, &offset, SD_LLDP_TYPE_SYSTEM_NAME,
406 lldp_tx->hostname ?: hostname);
407 if (r < 0)
408 return r;
409
410 r = packet_append_string(packet, packet_size, &offset, SD_LLDP_TYPE_SYSTEM_DESCRIPTION,
411 lldp_tx->pretty_hostname ?: pretty_hostname);
412 if (r < 0)
413 return r;
414
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 * +--------+--------+----------+---------+--------------
421 * where:
422 *
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
428 */
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,
431 lldp_tx->mud_url);
432 if (r < 0)
433 return r;
434
435 r = packet_append_tlv_header(packet, packet_size, &offset, SD_LLDP_TYPE_SYSTEM_CAPABILITIES, 4);
436 if (r < 0)
437 return r;
438
439 unaligned_write_be16(packet + offset, lldp_tx->supported_capabilities);
440 offset += 2;
441 unaligned_write_be16(packet + offset, lldp_tx->enabled_capabilities);
442 offset += 2;
443
444 r = packet_append_tlv_header(packet, packet_size, &offset, SD_LLDP_TYPE_END, 0);
445 if (r < 0)
446 return r;
447
448 *ret_packet_size = offset;
449 *ret_packet = TAKE_PTR(packet);
450 return 0;
451 }
452
lldp_tx_send_packet(sd_lldp_tx * lldp_tx,size_t packet_size,const uint8_t * 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;
456 ssize_t l;
457
458 assert(lldp_tx);
459 assert(lldp_tx->ifindex > 0);
460 assert(packet_size > sizeof(struct ether_header));
461 assert(packet);
462
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,
468 };
469 memcpy(sa.ll.sll_addr, lldp_multicast_addr + lldp_tx->mode, ETH_ALEN);
470
471 fd = socket(AF_PACKET, SOCK_RAW | SOCK_CLOEXEC, IPPROTO_RAW);
472 if (fd < 0)
473 return -errno;
474
475 l = sendto(fd, packet, packet_size, MSG_NOSIGNAL, &sa.sa, sizeof(sa.ll));
476 if (l < 0)
477 return -errno;
478
479 if ((size_t) l != packet_size)
480 return -EIO;
481
482 return 0;
483 }
484
lldp_tx_send(sd_lldp_tx * lldp_tx)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 */
488 int r;
489
490 assert(lldp_tx);
491
492 r = lldp_tx_create_packet(lldp_tx, &packet_size, &packet);
493 if (r < 0)
494 return r;
495
496 return lldp_tx_send_packet(lldp_tx, packet_size, packet);
497 }
498
sd_lldp_tx_attach_event(sd_lldp_tx * lldp_tx,sd_event * event,int64_t priority)499 int sd_lldp_tx_attach_event(sd_lldp_tx *lldp_tx, sd_event *event, int64_t priority) {
500 int r;
501
502 assert_return(lldp_tx, -EINVAL);
503 assert_return(!lldp_tx->event, -EBUSY);
504
505 if (event)
506 lldp_tx->event = sd_event_ref(event);
507 else {
508 r = sd_event_default(&lldp_tx->event);
509 if (r < 0)
510 return r;
511 }
512
513 lldp_tx->event_priority = priority;
514
515 return 0;
516 }
517
sd_lldp_tx_detach_event(sd_lldp_tx * lldp_tx)518 int sd_lldp_tx_detach_event(sd_lldp_tx *lldp_tx) {
519 assert_return(lldp_tx, -EINVAL);
520
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);
523 return 0;
524 }
525
lldp_tx_get_delay(sd_lldp_tx * lldp_tx)526 static usec_t lldp_tx_get_delay(sd_lldp_tx *lldp_tx) {
527 assert(lldp_tx);
528
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);
531 }
532
lldp_tx_reset_timer(sd_lldp_tx * lldp_tx)533 static int lldp_tx_reset_timer(sd_lldp_tx *lldp_tx) {
534 usec_t delay;
535 int r;
536
537 assert(lldp_tx);
538 assert(lldp_tx->timer_event_source);
539
540 delay = lldp_tx_get_delay(lldp_tx);
541
542 r = sd_event_source_set_time_relative(lldp_tx->timer_event_source, delay);
543 if (r < 0)
544 return r;
545
546 return sd_event_source_set_enabled(lldp_tx->timer_event_source, SD_EVENT_ONESHOT);
547 }
548
on_timer_event(sd_event_source * s,uint64_t usec,void * userdata)549 static int on_timer_event(sd_event_source *s, uint64_t usec, void *userdata) {
550 sd_lldp_tx *lldp_tx = userdata;
551 int r;
552
553 assert(lldp_tx);
554
555 r = lldp_tx_send(lldp_tx);
556 if (r < 0)
557 log_lldp_tx_errno(lldp_tx, r, "Failed to send packet, ignoring: %m");
558
559 if (lldp_tx->fast_tx > 0)
560 lldp_tx->fast_tx--;
561
562 r = lldp_tx_reset_timer(lldp_tx);
563 if (r < 0)
564 log_lldp_tx_errno(lldp_tx, r, "Failed to reset timer: %m");
565
566 return 0;
567 }
568
sd_lldp_tx_is_running(sd_lldp_tx * lldp_tx)569 int sd_lldp_tx_is_running(sd_lldp_tx *lldp_tx) {
570 int enabled;
571
572 if (!lldp_tx)
573 return 0;
574
575 if (!lldp_tx->timer_event_source)
576 return 0;
577
578 if (sd_event_source_get_enabled(lldp_tx->timer_event_source, &enabled) < 0)
579 return 0;
580
581 return enabled == SD_EVENT_ONESHOT;
582 }
583
sd_lldp_tx_stop(sd_lldp_tx * lldp_tx)584 int sd_lldp_tx_stop(sd_lldp_tx *lldp_tx) {
585 if (!lldp_tx)
586 return 0;
587
588 if (!lldp_tx->timer_event_source)
589 return 0;
590
591 (void) sd_event_source_set_enabled(lldp_tx->timer_event_source, SD_EVENT_OFF);
592
593 return 1;
594 }
sd_lldp_tx_start(sd_lldp_tx * lldp_tx)595 int sd_lldp_tx_start(sd_lldp_tx *lldp_tx) {
596 usec_t delay;
597 int r;
598
599 assert_return(lldp_tx, -EINVAL);
600 assert_return(lldp_tx->event, -EINVAL);
601 assert_return(lldp_tx->ifindex > 0, -EINVAL);
602 assert_return(lldp_tx->mode >= 0 && lldp_tx->mode < _SD_LLDP_MULTICAST_MODE_MAX, -EINVAL);
603 assert_return(!ether_addr_is_null(&lldp_tx->hwaddr), -EINVAL);
604
605 if (sd_lldp_tx_is_running(lldp_tx))
606 return 0;
607
608 lldp_tx->fast_tx = LLDP_FAST_TX_INIT;
609
610 if (lldp_tx->timer_event_source) {
611 r = lldp_tx_reset_timer(lldp_tx);
612 if (r < 0)
613 return log_lldp_tx_errno(lldp_tx, r, "Failed to re-enable timer: %m");
614
615 return 0;
616 }
617
618 delay = lldp_tx_get_delay(lldp_tx);
619
620 r = sd_event_add_time_relative(lldp_tx->event, &lldp_tx->timer_event_source,
621 CLOCK_BOOTTIME, delay, 0,
622 on_timer_event, lldp_tx);
623 if (r < 0)
624 return r;
625
626 (void) sd_event_source_set_description(lldp_tx->timer_event_source, "lldp-tx-timer");
627 (void) sd_event_source_set_priority(lldp_tx->timer_event_source, lldp_tx->event_priority);
628
629 return 0;
630 }
631