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