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