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