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