]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-link-bus.c
Merge pull request #16496 from DaanDeMeyer/firstboot-shell
[thirdparty/systemd.git] / src / network / networkd-link-bus.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #include <net/if.h>
4 #include <netinet/in.h>
5 #include <sys/capability.h>
6
7 #include "alloc-util.h"
8 #include "bus-common-errors.h"
9 #include "bus-get-properties.h"
10 #include "bus-message-util.h"
11 #include "bus-polkit.h"
12 #include "dns-domain.h"
13 #include "networkd-link-bus.h"
14 #include "networkd-link.h"
15 #include "networkd-manager.h"
16 #include "parse-util.h"
17 #include "resolve-util.h"
18 #include "socket-netlink.h"
19 #include "strv.h"
20 #include "user-util.h"
21
22 BUS_DEFINE_PROPERTY_GET_ENUM(property_get_operational_state, link_operstate, LinkOperationalState);
23 BUS_DEFINE_PROPERTY_GET_ENUM(property_get_carrier_state, link_carrier_state, LinkCarrierState);
24 BUS_DEFINE_PROPERTY_GET_ENUM(property_get_address_state, link_address_state, LinkAddressState);
25 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_administrative_state, link_state, LinkState);
26
27 static int property_get_bit_rates(
28 sd_bus *bus,
29 const char *path,
30 const char *interface,
31 const char *property,
32 sd_bus_message *reply,
33 void *userdata,
34 sd_bus_error *error) {
35
36 Link *link = userdata;
37 Manager *manager;
38 double interval_sec;
39 uint64_t tx, rx;
40
41 assert(bus);
42 assert(reply);
43 assert(userdata);
44
45 manager = link->manager;
46
47 if (!manager->use_speed_meter ||
48 manager->speed_meter_usec_old == 0 ||
49 !link->stats_updated)
50 return sd_bus_message_append(reply, "(tt)", UINT64_MAX, UINT64_MAX);
51
52 assert(manager->speed_meter_usec_new > manager->speed_meter_usec_old);
53 interval_sec = (manager->speed_meter_usec_new - manager->speed_meter_usec_old) / USEC_PER_SEC;
54
55 if (link->stats_new.tx_bytes > link->stats_old.tx_bytes)
56 tx = (uint64_t) ((link->stats_new.tx_bytes - link->stats_old.tx_bytes) / interval_sec);
57 else
58 tx = (uint64_t) ((UINT64_MAX - (link->stats_old.tx_bytes - link->stats_new.tx_bytes)) / interval_sec);
59
60 if (link->stats_new.rx_bytes > link->stats_old.rx_bytes)
61 rx = (uint64_t) ((link->stats_new.rx_bytes - link->stats_old.rx_bytes) / interval_sec);
62 else
63 rx = (uint64_t) ((UINT64_MAX - (link->stats_old.rx_bytes - link->stats_new.rx_bytes)) / interval_sec);
64
65 return sd_bus_message_append(reply, "(tt)", tx, rx);
66 }
67
68 static int verify_managed_link(Link *l, sd_bus_error *error) {
69 assert(l);
70
71 if (l->flags & IFF_LOOPBACK)
72 return sd_bus_error_setf(error, BUS_ERROR_LINK_BUSY, "Link %s is loopback device.", l->ifname);
73
74 return 0;
75 }
76
77 int bus_link_method_set_ntp_servers(sd_bus_message *message, void *userdata, sd_bus_error *error) {
78 _cleanup_strv_free_ char **ntp = NULL;
79 Link *l = userdata;
80 int r;
81 char **i;
82
83 assert(message);
84 assert(l);
85
86 r = verify_managed_link(l, error);
87 if (r < 0)
88 return r;
89
90 r = sd_bus_message_read_strv(message, &ntp);
91 if (r < 0)
92 return r;
93
94 STRV_FOREACH(i, ntp) {
95 r = dns_name_is_valid_or_address(*i);
96 if (r < 0)
97 return r;
98 if (r == 0)
99 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid NTP server: %s", *i);
100 }
101
102 r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
103 "org.freedesktop.network1.set-ntp-servers",
104 NULL, true, UID_INVALID,
105 &l->manager->polkit_registry, error);
106 if (r < 0)
107 return r;
108 if (r == 0)
109 return 1; /* Polkit will call us back */
110
111 strv_free_and_replace(l->ntp, ntp);
112
113 (void) link_dirty(l);
114
115 return sd_bus_reply_method_return(message, NULL);
116 }
117
118 static int bus_link_method_set_dns_servers_internal(sd_bus_message *message, void *userdata, sd_bus_error *error, bool extended) {
119 struct in_addr_full **dns;
120 Link *l = userdata;
121 size_t n;
122 int r;
123
124 assert(message);
125 assert(l);
126
127 r = verify_managed_link(l, error);
128 if (r < 0)
129 return r;
130
131 r = bus_message_read_dns_servers(message, error, extended, &dns, &n);
132 if (r < 0)
133 return r;
134
135 r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
136 "org.freedesktop.network1.set-dns-servers",
137 NULL, true, UID_INVALID,
138 &l->manager->polkit_registry, error);
139 if (r < 0)
140 goto finalize;
141 if (r == 0) {
142 r = 1; /* Polkit will call us back */
143 goto finalize;
144 }
145
146 if (l->n_dns != (unsigned) -1)
147 for (unsigned i = 0; i < l->n_dns; i++)
148 in_addr_full_free(l->dns[i]);
149
150 free_and_replace(l->dns, dns);
151 l->n_dns = n;
152
153 (void) link_dirty(l);
154
155 return sd_bus_reply_method_return(message, NULL);
156
157 finalize:
158 for (size_t i = 0; i < n; i++)
159 in_addr_full_free(dns[i]);
160 free(dns);
161
162 return r;
163 }
164
165 int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_bus_error *error) {
166 return bus_link_method_set_dns_servers_internal(message, userdata, error, false);
167 }
168
169 int bus_link_method_set_dns_servers_ex(sd_bus_message *message, void *userdata, sd_bus_error *error) {
170 return bus_link_method_set_dns_servers_internal(message, userdata, error, true);
171 }
172
173 int bus_link_method_set_domains(sd_bus_message *message, void *userdata, sd_bus_error *error) {
174 _cleanup_(ordered_set_freep) OrderedSet *search_domains = NULL, *route_domains = NULL;
175 Link *l = userdata;
176 int r;
177
178 assert(message);
179 assert(l);
180
181 r = verify_managed_link(l, error);
182 if (r < 0)
183 return r;
184
185 r = sd_bus_message_enter_container(message, 'a', "(sb)");
186 if (r < 0)
187 return r;
188
189 for (;;) {
190 _cleanup_free_ char *str = NULL;
191 OrderedSet **domains;
192 const char *name;
193 int route_only;
194
195 r = sd_bus_message_read(message, "(sb)", &name, &route_only);
196 if (r < 0)
197 return r;
198 if (r == 0)
199 break;
200
201 r = dns_name_is_valid(name);
202 if (r < 0)
203 return r;
204 if (r == 0)
205 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid search domain %s", name);
206 if (!route_only && dns_name_is_root(name))
207 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Root domain is not suitable as search domain");
208
209 r = dns_name_normalize(name, 0, &str);
210 if (r < 0)
211 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid search domain %s", name);
212
213 domains = route_only ? &route_domains : &search_domains;
214 r = ordered_set_ensure_allocated(domains, &string_hash_ops);
215 if (r < 0)
216 return r;
217
218 r = ordered_set_put(*domains, str);
219 if (r < 0)
220 return r;
221
222 TAKE_PTR(str);
223 }
224
225 r = sd_bus_message_exit_container(message);
226 if (r < 0)
227 return r;
228
229 r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
230 "org.freedesktop.network1.set-domains",
231 NULL, true, UID_INVALID,
232 &l->manager->polkit_registry, error);
233 if (r < 0)
234 return r;
235 if (r == 0)
236 return 1; /* Polkit will call us back */
237
238 ordered_set_free_free(l->search_domains);
239 ordered_set_free_free(l->route_domains);
240 l->search_domains = TAKE_PTR(search_domains);
241 l->route_domains = TAKE_PTR(route_domains);
242
243 (void) link_dirty(l);
244
245 return sd_bus_reply_method_return(message, NULL);
246 }
247
248 int bus_link_method_set_default_route(sd_bus_message *message, void *userdata, sd_bus_error *error) {
249 Link *l = userdata;
250 int r, b;
251
252 assert(message);
253 assert(l);
254
255 r = verify_managed_link(l, error);
256 if (r < 0)
257 return r;
258
259 r = sd_bus_message_read(message, "b", &b);
260 if (r < 0)
261 return r;
262
263 r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
264 "org.freedesktop.network1.set-default-route",
265 NULL, true, UID_INVALID,
266 &l->manager->polkit_registry, error);
267 if (r < 0)
268 return r;
269 if (r == 0)
270 return 1; /* Polkit will call us back */
271
272 if (l->dns_default_route != b) {
273 l->dns_default_route = b;
274 (void) link_dirty(l);
275 }
276
277 return sd_bus_reply_method_return(message, NULL);
278 }
279
280 int bus_link_method_set_llmnr(sd_bus_message *message, void *userdata, sd_bus_error *error) {
281 Link *l = userdata;
282 ResolveSupport mode;
283 const char *llmnr;
284 int r;
285
286 assert(message);
287 assert(l);
288
289 r = verify_managed_link(l, error);
290 if (r < 0)
291 return r;
292
293 r = sd_bus_message_read(message, "s", &llmnr);
294 if (r < 0)
295 return r;
296
297 if (isempty(llmnr))
298 mode = RESOLVE_SUPPORT_YES;
299 else {
300 mode = resolve_support_from_string(llmnr);
301 if (mode < 0)
302 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid LLMNR setting: %s", llmnr);
303 }
304
305 r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
306 "org.freedesktop.network1.set-llmnr",
307 NULL, true, UID_INVALID,
308 &l->manager->polkit_registry, error);
309 if (r < 0)
310 return r;
311 if (r == 0)
312 return 1; /* Polkit will call us back */
313
314 if (l->llmnr != mode) {
315 l->llmnr = mode;
316 (void) link_dirty(l);
317 }
318
319 return sd_bus_reply_method_return(message, NULL);
320 }
321
322 int bus_link_method_set_mdns(sd_bus_message *message, void *userdata, sd_bus_error *error) {
323 Link *l = userdata;
324 ResolveSupport mode;
325 const char *mdns;
326 int r;
327
328 assert(message);
329 assert(l);
330
331 r = verify_managed_link(l, error);
332 if (r < 0)
333 return r;
334
335 r = sd_bus_message_read(message, "s", &mdns);
336 if (r < 0)
337 return r;
338
339 if (isempty(mdns))
340 mode = RESOLVE_SUPPORT_NO;
341 else {
342 mode = resolve_support_from_string(mdns);
343 if (mode < 0)
344 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid MulticastDNS setting: %s", mdns);
345 }
346
347 r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
348 "org.freedesktop.network1.set-mdns",
349 NULL, true, UID_INVALID,
350 &l->manager->polkit_registry, error);
351 if (r < 0)
352 return r;
353 if (r == 0)
354 return 1; /* Polkit will call us back */
355
356 if (l->mdns != mode) {
357 l->mdns = mode;
358 (void) link_dirty(l);
359 }
360
361 return sd_bus_reply_method_return(message, NULL);
362 }
363
364 int bus_link_method_set_dns_over_tls(sd_bus_message *message, void *userdata, sd_bus_error *error) {
365 Link *l = userdata;
366 const char *dns_over_tls;
367 DnsOverTlsMode mode;
368 int r;
369
370 assert(message);
371 assert(l);
372
373 r = verify_managed_link(l, error);
374 if (r < 0)
375 return r;
376
377 r = sd_bus_message_read(message, "s", &dns_over_tls);
378 if (r < 0)
379 return r;
380
381 if (isempty(dns_over_tls))
382 mode = _DNS_OVER_TLS_MODE_INVALID;
383 else {
384 mode = dns_over_tls_mode_from_string(dns_over_tls);
385 if (mode < 0)
386 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid DNSOverTLS setting: %s", dns_over_tls);
387 }
388
389 r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
390 "org.freedesktop.network1.set-dns-over-tls",
391 NULL, true, UID_INVALID,
392 &l->manager->polkit_registry, error);
393 if (r < 0)
394 return r;
395 if (r == 0)
396 return 1; /* Polkit will call us back */
397
398 if (l->dns_over_tls_mode != mode) {
399 l->dns_over_tls_mode = mode;
400 (void) link_dirty(l);
401 }
402
403 return sd_bus_reply_method_return(message, NULL);
404 }
405
406 int bus_link_method_set_dnssec(sd_bus_message *message, void *userdata, sd_bus_error *error) {
407 Link *l = userdata;
408 const char *dnssec;
409 DnssecMode mode;
410 int r;
411
412 assert(message);
413 assert(l);
414
415 r = verify_managed_link(l, error);
416 if (r < 0)
417 return r;
418
419 r = sd_bus_message_read(message, "s", &dnssec);
420 if (r < 0)
421 return r;
422
423 if (isempty(dnssec))
424 mode = _DNSSEC_MODE_INVALID;
425 else {
426 mode = dnssec_mode_from_string(dnssec);
427 if (mode < 0)
428 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid DNSSEC setting: %s", dnssec);
429 }
430
431 r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
432 "org.freedesktop.network1.set-dnssec",
433 NULL, true, UID_INVALID,
434 &l->manager->polkit_registry, error);
435 if (r < 0)
436 return r;
437 if (r == 0)
438 return 1; /* Polkit will call us back */
439
440 if (l->dnssec_mode != mode) {
441 l->dnssec_mode = mode;
442 (void) link_dirty(l);
443 }
444
445 return sd_bus_reply_method_return(message, NULL);
446 }
447
448 int bus_link_method_set_dnssec_negative_trust_anchors(sd_bus_message *message, void *userdata, sd_bus_error *error) {
449 _cleanup_set_free_free_ Set *ns = NULL;
450 _cleanup_strv_free_ char **ntas = NULL;
451 Link *l = userdata;
452 int r;
453 char **i;
454
455 assert(message);
456 assert(l);
457
458 r = verify_managed_link(l, error);
459 if (r < 0)
460 return r;
461
462 r = sd_bus_message_read_strv(message, &ntas);
463 if (r < 0)
464 return r;
465
466 STRV_FOREACH(i, ntas) {
467 r = dns_name_is_valid(*i);
468 if (r < 0)
469 return r;
470 if (r == 0)
471 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid negative trust anchor domain: %s", *i);
472 }
473
474 ns = set_new(&dns_name_hash_ops);
475 if (!ns)
476 return -ENOMEM;
477
478 STRV_FOREACH(i, ntas) {
479 r = set_put_strdup(&ns, *i);
480 if (r < 0)
481 return r;
482 }
483
484 r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
485 "org.freedesktop.network1.set-dnssec-negative-trust-anchors",
486 NULL, true, UID_INVALID,
487 &l->manager->polkit_registry, error);
488 if (r < 0)
489 return r;
490 if (r == 0)
491 return 1; /* Polkit will call us back */
492
493 set_free_free(l->dnssec_negative_trust_anchors);
494 l->dnssec_negative_trust_anchors = TAKE_PTR(ns);
495
496 (void) link_dirty(l);
497
498 return sd_bus_reply_method_return(message, NULL);
499 }
500
501 int bus_link_method_revert_ntp(sd_bus_message *message, void *userdata, sd_bus_error *error) {
502 Link *l = userdata;
503 int r;
504
505 assert(message);
506 assert(l);
507
508 r = verify_managed_link(l, error);
509 if (r < 0)
510 return r;
511
512 r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
513 "org.freedesktop.network1.revert-ntp",
514 NULL, true, UID_INVALID,
515 &l->manager->polkit_registry, error);
516 if (r < 0)
517 return r;
518 if (r == 0)
519 return 1; /* Polkit will call us back */
520
521 link_ntp_settings_clear(l);
522 (void) link_dirty(l);
523
524 return sd_bus_reply_method_return(message, NULL);
525 }
526
527 int bus_link_method_revert_dns(sd_bus_message *message, void *userdata, sd_bus_error *error) {
528 Link *l = userdata;
529 int r;
530
531 assert(message);
532 assert(l);
533
534 r = verify_managed_link(l, error);
535 if (r < 0)
536 return r;
537
538 r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
539 "org.freedesktop.network1.revert-dns",
540 NULL, true, UID_INVALID,
541 &l->manager->polkit_registry, error);
542 if (r < 0)
543 return r;
544 if (r == 0)
545 return 1; /* Polkit will call us back */
546
547 link_dns_settings_clear(l);
548 (void) link_dirty(l);
549
550 return sd_bus_reply_method_return(message, NULL);
551 }
552
553 int bus_link_method_force_renew(sd_bus_message *message, void *userdata, sd_bus_error *error) {
554 Link *l = userdata;
555 int r;
556
557 assert(l);
558
559 if (!l->network)
560 return sd_bus_error_setf(error, BUS_ERROR_UNMANAGED_INTERFACE,
561 "Interface %s is not managed by systemd-networkd",
562 l->ifname);
563
564 r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
565 "org.freedesktop.network1.forcerenew",
566 NULL, true, UID_INVALID,
567 &l->manager->polkit_registry, error);
568 if (r < 0)
569 return r;
570 if (r == 0)
571 return 1; /* Polkit will call us back */
572
573 if (l->dhcp_server) {
574 r = sd_dhcp_server_forcerenew(l->dhcp_server);
575 if (r < 0)
576 return r;
577 }
578
579 return sd_bus_reply_method_return(message, NULL);
580 }
581
582 int bus_link_method_renew(sd_bus_message *message, void *userdata, sd_bus_error *error) {
583 Link *l = userdata;
584 int r;
585
586 assert(l);
587
588 if (!l->network)
589 return sd_bus_error_setf(error, BUS_ERROR_UNMANAGED_INTERFACE,
590 "Interface %s is not managed by systemd-networkd",
591 l->ifname);
592
593 r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
594 "org.freedesktop.network1.renew",
595 NULL, true, UID_INVALID,
596 &l->manager->polkit_registry, error);
597 if (r < 0)
598 return r;
599 if (r == 0)
600 return 1; /* Polkit will call us back */
601
602 if (l->dhcp_client) {
603 r = sd_dhcp_client_send_renew(l->dhcp_client);
604 if (r < 0)
605 return r;
606 }
607
608 return sd_bus_reply_method_return(message, NULL);
609 }
610
611 int bus_link_method_reconfigure(sd_bus_message *message, void *userdata, sd_bus_error *error) {
612 Link *l = userdata;
613 int r;
614
615 assert(message);
616 assert(l);
617
618 r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
619 "org.freedesktop.network1.reconfigure",
620 NULL, true, UID_INVALID,
621 &l->manager->polkit_registry, error);
622 if (r < 0)
623 return r;
624 if (r == 0)
625 return 1; /* Polkit will call us back */
626
627 r = link_reconfigure(l, true);
628 if (r < 0)
629 return r;
630
631 link_set_state(l, LINK_STATE_INITIALIZED);
632 r = link_save(l);
633 if (r < 0)
634 return r;
635 link_clean(l);
636
637 return sd_bus_reply_method_return(message, NULL);
638 }
639
640 const sd_bus_vtable link_vtable[] = {
641 SD_BUS_VTABLE_START(0),
642
643 SD_BUS_PROPERTY("OperationalState", "s", property_get_operational_state, offsetof(Link, operstate), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
644 SD_BUS_PROPERTY("CarrierState", "s", property_get_carrier_state, offsetof(Link, carrier_state), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
645 SD_BUS_PROPERTY("AddressState", "s", property_get_address_state, offsetof(Link, address_state), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
646 SD_BUS_PROPERTY("AdministrativeState", "s", property_get_administrative_state, offsetof(Link, state), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
647 SD_BUS_PROPERTY("BitRates", "(tt)", property_get_bit_rates, 0, 0),
648
649 SD_BUS_METHOD("SetNTP", "as", NULL, bus_link_method_set_ntp_servers, SD_BUS_VTABLE_UNPRIVILEGED),
650 SD_BUS_METHOD("SetDNS", "a(iay)", NULL, bus_link_method_set_dns_servers, SD_BUS_VTABLE_UNPRIVILEGED),
651 SD_BUS_METHOD("SetDNSEx", "a(iayqs)", NULL, bus_link_method_set_dns_servers_ex, SD_BUS_VTABLE_UNPRIVILEGED),
652 SD_BUS_METHOD("SetDomains", "a(sb)", NULL, bus_link_method_set_domains, SD_BUS_VTABLE_UNPRIVILEGED),
653 SD_BUS_METHOD("SetDefaultRoute", "b", NULL, bus_link_method_set_default_route, SD_BUS_VTABLE_UNPRIVILEGED),
654 SD_BUS_METHOD("SetLLMNR", "s", NULL, bus_link_method_set_llmnr, SD_BUS_VTABLE_UNPRIVILEGED),
655 SD_BUS_METHOD("SetMulticastDNS", "s", NULL, bus_link_method_set_mdns, SD_BUS_VTABLE_UNPRIVILEGED),
656 SD_BUS_METHOD("SetDNSOverTLS", "s", NULL, bus_link_method_set_dns_over_tls, SD_BUS_VTABLE_UNPRIVILEGED),
657 SD_BUS_METHOD("SetDNSSEC", "s", NULL, bus_link_method_set_dnssec, SD_BUS_VTABLE_UNPRIVILEGED),
658 SD_BUS_METHOD("SetDNSSECNegativeTrustAnchors", "as", NULL, bus_link_method_set_dnssec_negative_trust_anchors, SD_BUS_VTABLE_UNPRIVILEGED),
659 SD_BUS_METHOD("RevertNTP", NULL, NULL, bus_link_method_revert_ntp, SD_BUS_VTABLE_UNPRIVILEGED),
660 SD_BUS_METHOD("RevertDNS", NULL, NULL, bus_link_method_revert_dns, SD_BUS_VTABLE_UNPRIVILEGED),
661 SD_BUS_METHOD("Renew", NULL, NULL, bus_link_method_renew, SD_BUS_VTABLE_UNPRIVILEGED),
662 SD_BUS_METHOD("ForceRenew", NULL, NULL, bus_link_method_force_renew, SD_BUS_VTABLE_UNPRIVILEGED),
663 SD_BUS_METHOD("Reconfigure", NULL, NULL, bus_link_method_reconfigure, SD_BUS_VTABLE_UNPRIVILEGED),
664
665 SD_BUS_VTABLE_END
666 };
667
668 char *link_bus_path(Link *link) {
669 _cleanup_free_ char *ifindex = NULL;
670 char *p;
671 int r;
672
673 assert(link);
674 assert(link->ifindex > 0);
675
676 if (asprintf(&ifindex, "%d", link->ifindex) < 0)
677 return NULL;
678
679 r = sd_bus_path_encode("/org/freedesktop/network1/link", ifindex, &p);
680 if (r < 0)
681 return NULL;
682
683 return p;
684 }
685
686 int link_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
687 _cleanup_strv_free_ char **l = NULL;
688 Manager *m = userdata;
689 unsigned c = 0;
690 Link *link;
691 Iterator i;
692
693 assert(bus);
694 assert(path);
695 assert(m);
696 assert(nodes);
697
698 l = new0(char*, hashmap_size(m->links) + 1);
699 if (!l)
700 return -ENOMEM;
701
702 HASHMAP_FOREACH(link, m->links, i) {
703 char *p;
704
705 p = link_bus_path(link);
706 if (!p)
707 return -ENOMEM;
708
709 l[c++] = p;
710 }
711
712 l[c] = NULL;
713 *nodes = TAKE_PTR(l);
714
715 return 1;
716 }
717
718 int link_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
719 _cleanup_free_ char *identifier = NULL;
720 Manager *m = userdata;
721 Link *link;
722 int ifindex, r;
723
724 assert(bus);
725 assert(path);
726 assert(interface);
727 assert(m);
728 assert(found);
729
730 r = sd_bus_path_decode(path, "/org/freedesktop/network1/link", &identifier);
731 if (r <= 0)
732 return 0;
733
734 ifindex = parse_ifindex(identifier);
735 if (ifindex < 0)
736 return 0;
737
738 r = link_get(m, ifindex, &link);
739 if (r < 0)
740 return 0;
741
742 if (streq(interface, "org.freedesktop.network1.DHCPServer") && !link->dhcp_server)
743 return 0;
744
745 *found = link;
746
747 return 1;
748 }
749
750 int link_send_changed_strv(Link *link, char **properties) {
751 _cleanup_free_ char *p = NULL;
752
753 assert(link);
754 assert(link->manager);
755 assert(properties);
756
757 if (!link->manager->bus)
758 return 0;
759
760 p = link_bus_path(link);
761 if (!p)
762 return -ENOMEM;
763
764 return sd_bus_emit_properties_changed_strv(
765 link->manager->bus,
766 p,
767 "org.freedesktop.network1.Link",
768 properties);
769 }
770
771 int link_send_changed(Link *link, const char *property, ...) {
772 char **properties;
773
774 properties = strv_from_stdarg_alloca(property);
775
776 return link_send_changed_strv(link, properties);
777 }