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