]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-link-bus.c
shared: split out polkit stuff from bus-util.c → bus-polkit.c
[thirdparty/systemd.git] / src / network / networkd-link-bus.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
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"
269e4d2d 9#include "bus-polkit.h"
cf0fbc49 10#include "bus-util.h"
15761549 11#include "dns-domain.h"
6a1af3d4 12#include "networkd-link-bus.h"
e331e246 13#include "networkd-link.h"
23f53b99 14#include "networkd-manager.h"
6bedfcbb 15#include "parse-util.h"
15761549 16#include "resolve-util.h"
cf0fbc49 17#include "strv.h"
15761549 18#include "user-util.h"
e331e246 19
35c5a9ca
YW
20BUS_DEFINE_PROPERTY_GET_ENUM(property_get_operational_state, link_operstate, LinkOperationalState);
21BUS_DEFINE_PROPERTY_GET_ENUM(property_get_carrier_state, link_carrier_state, LinkCarrierState);
22BUS_DEFINE_PROPERTY_GET_ENUM(property_get_address_state, link_address_state, LinkAddressState);
e331e246
TG
23static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_administrative_state, link_state, LinkState);
24
a879e1a4
YW
25static int property_get_bit_rates(
26 sd_bus *bus,
27 const char *path,
28 const char *interface,
29 const char *property,
30 sd_bus_message *reply,
31 void *userdata,
32 sd_bus_error *error) {
33
34 Link *link = userdata;
35 Manager *manager;
42a63431
YW
36 double interval_sec;
37 uint64_t tx, rx;
a879e1a4
YW
38
39 assert(bus);
40 assert(reply);
41 assert(userdata);
42
43 manager = link->manager;
44
e813de54
YW
45 if (!manager->use_speed_meter ||
46 manager->speed_meter_usec_old == 0 ||
47 !link->stats_updated)
48 return sd_bus_message_append(reply, "(tt)", UINT64_MAX, UINT64_MAX);
a879e1a4
YW
49
50 assert(manager->speed_meter_usec_new > manager->speed_meter_usec_old);
42a63431 51 interval_sec = (manager->speed_meter_usec_new - manager->speed_meter_usec_old) / USEC_PER_SEC;
a879e1a4
YW
52
53 if (link->stats_new.tx_bytes > link->stats_old.tx_bytes)
42a63431 54 tx = (uint64_t) ((link->stats_new.tx_bytes - link->stats_old.tx_bytes) / interval_sec);
a879e1a4 55 else
42a63431 56 tx = (uint64_t) ((UINT64_MAX - (link->stats_old.tx_bytes - link->stats_new.tx_bytes)) / interval_sec);
a879e1a4
YW
57
58 if (link->stats_new.rx_bytes > link->stats_old.rx_bytes)
42a63431 59 rx = (uint64_t) ((link->stats_new.rx_bytes - link->stats_old.rx_bytes) / interval_sec);
a879e1a4 60 else
42a63431 61 rx = (uint64_t) ((UINT64_MAX - (link->stats_old.rx_bytes - link->stats_new.rx_bytes)) / interval_sec);
a879e1a4 62
42a63431 63 return sd_bus_message_append(reply, "(tt)", tx, rx);
a879e1a4
YW
64}
65
15761549
YW
66static int verify_managed_link(Link *l, sd_bus_error *error) {
67 assert(l);
68
69 if (l->flags & IFF_LOOPBACK)
70 return sd_bus_error_setf(error, BUS_ERROR_LINK_BUSY, "Link %s is loopback device.", l->ifname);
71
72 return 0;
73}
74
75int bus_link_method_set_ntp_servers(sd_bus_message *message, void *userdata, sd_bus_error *error) {
76 _cleanup_strv_free_ char **ntp = NULL;
77 Link *l = userdata;
78 int r;
79 char **i;
80
81 assert(message);
82 assert(l);
83
84 r = verify_managed_link(l, error);
85 if (r < 0)
86 return r;
87
88 r = sd_bus_message_read_strv(message, &ntp);
89 if (r < 0)
90 return r;
91
92 STRV_FOREACH(i, ntp) {
93 r = dns_name_is_valid_or_address(*i);
94 if (r < 0)
95 return r;
96 if (r == 0)
97 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid NTP server: %s", *i);
98 }
99
100 r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
101 "org.freedesktop.network1.set-ntp-servers",
102 NULL, true, UID_INVALID,
103 &l->manager->polkit_registry, error);
104 if (r < 0)
105 return r;
106 if (r == 0)
107 return 1; /* Polkit will call us back */
108
109 strv_free_and_replace(l->ntp, ntp);
110
111 (void) link_dirty(l);
112
113 return sd_bus_reply_method_return(message, NULL);
114}
115
116int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_bus_error *error) {
117 _cleanup_free_ struct in_addr_data *dns = NULL;
118 size_t allocated = 0, n = 0;
119 Link *l = userdata;
120 int r;
121
122 assert(message);
123 assert(l);
124
125 r = verify_managed_link(l, error);
126 if (r < 0)
127 return r;
128
129 r = sd_bus_message_enter_container(message, 'a', "(iay)");
130 if (r < 0)
131 return r;
132
133 for (;;) {
134 int family;
135 size_t sz;
136 const void *d;
137
138 assert_cc(sizeof(int) == sizeof(int32_t));
139
140 r = sd_bus_message_enter_container(message, 'r', "iay");
141 if (r < 0)
142 return r;
143 if (r == 0)
144 break;
145
146 r = sd_bus_message_read(message, "i", &family);
147 if (r < 0)
148 return r;
149
150 if (!IN_SET(family, AF_INET, AF_INET6))
151 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family);
152
153 r = sd_bus_message_read_array(message, 'y', &d, &sz);
154 if (r < 0)
155 return r;
156 if (sz != FAMILY_ADDRESS_SIZE(family))
157 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid address size");
158
159 if (!dns_server_address_valid(family, d))
160 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid DNS server address");
161
162 r = sd_bus_message_exit_container(message);
163 if (r < 0)
164 return r;
165
166 if (!GREEDY_REALLOC(dns, allocated, n+1))
167 return -ENOMEM;
168
169 dns[n].family = family;
170 memcpy(&dns[n].address, d, sz);
171 n++;
172 }
173
174 r = sd_bus_message_exit_container(message);
175 if (r < 0)
176 return r;
177
178 r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
179 "org.freedesktop.network1.set-dns-servers",
180 NULL, true, UID_INVALID,
181 &l->manager->polkit_registry, error);
182 if (r < 0)
183 return r;
184 if (r == 0)
185 return 1; /* Polkit will call us back */
186
187 free_and_replace(l->dns, dns);
188 l->n_dns = n;
189
190 (void) link_dirty(l);
191
192 return sd_bus_reply_method_return(message, NULL);
193}
194
195int bus_link_method_set_domains(sd_bus_message *message, void *userdata, sd_bus_error *error) {
196 _cleanup_(ordered_set_freep) OrderedSet *search_domains = NULL, *route_domains = NULL;
197 Link *l = userdata;
198 int r;
199
200 assert(message);
201 assert(l);
202
203 r = verify_managed_link(l, error);
204 if (r < 0)
205 return r;
206
207 r = sd_bus_message_enter_container(message, 'a', "(sb)");
208 if (r < 0)
209 return r;
210
211 for (;;) {
212 _cleanup_free_ char *str = NULL;
213 OrderedSet **domains;
214 const char *name;
215 int route_only;
216
217 r = sd_bus_message_read(message, "(sb)", &name, &route_only);
218 if (r < 0)
219 return r;
220 if (r == 0)
221 break;
222
223 r = dns_name_is_valid(name);
224 if (r < 0)
225 return r;
226 if (r == 0)
227 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid search domain %s", name);
228 if (!route_only && dns_name_is_root(name))
229 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Root domain is not suitable as search domain");
230
231 r = dns_name_normalize(name, 0, &str);
232 if (r < 0)
233 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid search domain %s", name);
234
235 domains = route_only ? &route_domains : &search_domains;
236 r = ordered_set_ensure_allocated(domains, &string_hash_ops);
237 if (r < 0)
238 return r;
239
240 r = ordered_set_put(*domains, str);
241 if (r < 0)
242 return r;
243
244 TAKE_PTR(str);
245 }
246
247 r = sd_bus_message_exit_container(message);
248 if (r < 0)
249 return r;
250
251 r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
252 "org.freedesktop.network1.set-domains",
253 NULL, true, UID_INVALID,
254 &l->manager->polkit_registry, error);
255 if (r < 0)
256 return r;
257 if (r == 0)
258 return 1; /* Polkit will call us back */
259
260 ordered_set_free_free(l->search_domains);
261 ordered_set_free_free(l->route_domains);
262 l->search_domains = TAKE_PTR(search_domains);
263 l->route_domains = TAKE_PTR(route_domains);
264
265 (void) link_dirty(l);
266
267 return sd_bus_reply_method_return(message, NULL);
268}
269
270int bus_link_method_set_default_route(sd_bus_message *message, void *userdata, sd_bus_error *error) {
271 Link *l = userdata;
272 int r, b;
273
274 assert(message);
275 assert(l);
276
277 r = verify_managed_link(l, error);
278 if (r < 0)
279 return r;
280
281 r = sd_bus_message_read(message, "b", &b);
282 if (r < 0)
283 return r;
284
285 r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
286 "org.freedesktop.network1.set-default-route",
287 NULL, true, UID_INVALID,
288 &l->manager->polkit_registry, error);
289 if (r < 0)
290 return r;
291 if (r == 0)
292 return 1; /* Polkit will call us back */
293
294 if (l->dns_default_route != b) {
295 l->dns_default_route = b;
296 (void) link_dirty(l);
297 }
298
299 return sd_bus_reply_method_return(message, NULL);
300}
301
302int bus_link_method_set_llmnr(sd_bus_message *message, void *userdata, sd_bus_error *error) {
303 Link *l = userdata;
304 ResolveSupport mode;
305 const char *llmnr;
306 int r;
307
308 assert(message);
309 assert(l);
310
311 r = verify_managed_link(l, error);
312 if (r < 0)
313 return r;
314
315 r = sd_bus_message_read(message, "s", &llmnr);
316 if (r < 0)
317 return r;
318
319 if (isempty(llmnr))
320 mode = RESOLVE_SUPPORT_YES;
321 else {
322 mode = resolve_support_from_string(llmnr);
323 if (mode < 0)
324 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid LLMNR setting: %s", llmnr);
325 }
326
327 r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
328 "org.freedesktop.network1.set-llmnr",
329 NULL, true, UID_INVALID,
330 &l->manager->polkit_registry, error);
331 if (r < 0)
332 return r;
333 if (r == 0)
334 return 1; /* Polkit will call us back */
335
336 if (l->llmnr != mode) {
337 l->llmnr = mode;
338 (void) link_dirty(l);
339 }
340
341 return sd_bus_reply_method_return(message, NULL);
342}
343
344int 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 (void) link_dirty(l);
381 }
382
383 return sd_bus_reply_method_return(message, NULL);
384}
385
386int bus_link_method_set_dns_over_tls(sd_bus_message *message, void *userdata, sd_bus_error *error) {
387 Link *l = userdata;
388 const char *dns_over_tls;
389 DnsOverTlsMode mode;
390 int r;
391
392 assert(message);
393 assert(l);
394
395 r = verify_managed_link(l, error);
396 if (r < 0)
397 return r;
398
399 r = sd_bus_message_read(message, "s", &dns_over_tls);
400 if (r < 0)
401 return r;
402
403 if (isempty(dns_over_tls))
404 mode = _DNS_OVER_TLS_MODE_INVALID;
405 else {
406 mode = dns_over_tls_mode_from_string(dns_over_tls);
407 if (mode < 0)
408 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid DNSOverTLS setting: %s", dns_over_tls);
409 }
410
411 r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
412 "org.freedesktop.network1.set-dns-over-tls",
413 NULL, true, UID_INVALID,
414 &l->manager->polkit_registry, error);
415 if (r < 0)
416 return r;
417 if (r == 0)
418 return 1; /* Polkit will call us back */
419
420 if (l->dns_over_tls_mode != mode) {
421 l->dns_over_tls_mode = mode;
422 (void) link_dirty(l);
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) {
429 Link *l = userdata;
430 const char *dnssec;
431 DnssecMode mode;
432 int r;
433
434 assert(message);
435 assert(l);
436
437 r = verify_managed_link(l, error);
438 if (r < 0)
439 return r;
440
441 r = sd_bus_message_read(message, "s", &dnssec);
442 if (r < 0)
443 return r;
444
445 if (isempty(dnssec))
446 mode = _DNSSEC_MODE_INVALID;
447 else {
448 mode = dnssec_mode_from_string(dnssec);
449 if (mode < 0)
450 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid DNSSEC setting: %s", dnssec);
451 }
452
453 r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
454 "org.freedesktop.network1.set-dnssec",
455 NULL, true, UID_INVALID,
456 &l->manager->polkit_registry, error);
457 if (r < 0)
458 return r;
459 if (r == 0)
460 return 1; /* Polkit will call us back */
461
462 if (l->dnssec_mode != mode) {
463 l->dnssec_mode = mode;
464 (void) link_dirty(l);
465 }
466
467 return sd_bus_reply_method_return(message, NULL);
468}
469
470int bus_link_method_set_dnssec_negative_trust_anchors(sd_bus_message *message, void *userdata, sd_bus_error *error) {
471 _cleanup_set_free_free_ Set *ns = NULL;
472 _cleanup_strv_free_ char **ntas = NULL;
473 Link *l = userdata;
474 int r;
475 char **i;
476
477 assert(message);
478 assert(l);
479
480 r = verify_managed_link(l, error);
481 if (r < 0)
482 return r;
483
484 r = sd_bus_message_read_strv(message, &ntas);
485 if (r < 0)
486 return r;
487
488 STRV_FOREACH(i, ntas) {
489 r = dns_name_is_valid(*i);
490 if (r < 0)
491 return r;
492 if (r == 0)
493 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid negative trust anchor domain: %s", *i);
494 }
495
496 ns = set_new(&dns_name_hash_ops);
497 if (!ns)
498 return -ENOMEM;
499
500 STRV_FOREACH(i, ntas) {
501 r = set_put_strdup(ns, *i);
502 if (r < 0)
503 return r;
504 }
505
506 r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
507 "org.freedesktop.network1.set-dnssec-negative-trust-anchors",
508 NULL, true, UID_INVALID,
509 &l->manager->polkit_registry, error);
510 if (r < 0)
511 return r;
512 if (r == 0)
513 return 1; /* Polkit will call us back */
514
515 set_free_free(l->dnssec_negative_trust_anchors);
516 l->dnssec_negative_trust_anchors = TAKE_PTR(ns);
517
518 (void) link_dirty(l);
519
520 return sd_bus_reply_method_return(message, NULL);
521}
522
523int bus_link_method_revert_ntp(sd_bus_message *message, void *userdata, sd_bus_error *error) {
524 Link *l = userdata;
525 int r;
526
527 assert(message);
528 assert(l);
529
530 r = verify_managed_link(l, error);
531 if (r < 0)
532 return r;
533
534 r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
535 "org.freedesktop.network1.revert-ntp",
536 NULL, true, UID_INVALID,
537 &l->manager->polkit_registry, error);
538 if (r < 0)
539 return r;
540 if (r == 0)
541 return 1; /* Polkit will call us back */
542
543 link_ntp_settings_clear(l);
544 (void) link_dirty(l);
545
546 return sd_bus_reply_method_return(message, NULL);
547}
548
549int bus_link_method_revert_dns(sd_bus_message *message, void *userdata, sd_bus_error *error) {
550 Link *l = userdata;
551 int r;
552
553 assert(message);
554 assert(l);
555
556 r = verify_managed_link(l, error);
557 if (r < 0)
558 return r;
559
560 r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
561 "org.freedesktop.network1.revert-dns",
562 NULL, true, UID_INVALID,
563 &l->manager->polkit_registry, error);
564 if (r < 0)
565 return r;
566 if (r == 0)
567 return 1; /* Polkit will call us back */
568
569 link_dns_settings_clear(l);
570 (void) link_dirty(l);
571
572 return sd_bus_reply_method_return(message, NULL);
573}
574
ae65d7db
YW
575int bus_link_method_renew(sd_bus_message *message, void *userdata, sd_bus_error *error) {
576 Link *l = userdata;
577 int r;
578
579 assert(l);
580
581 if (!l->network)
582 return sd_bus_error_setf(error, BUS_ERROR_UNMANAGED_INTERFACE,
583 "Interface %s is not managed by systemd-networkd",
584 l->ifname);
585
586 r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
587 "org.freedesktop.network1.renew",
588 NULL, true, UID_INVALID,
589 &l->manager->polkit_registry, error);
590 if (r < 0)
591 return r;
592 if (r == 0)
593 return 1; /* Polkit will call us back */
594
595 if (l->dhcp_client) {
596 r = sd_dhcp_client_send_renew(l->dhcp_client);
597 if (r < 0)
598 return r;
599 }
600
601 return sd_bus_reply_method_return(message, NULL);
602}
603
99b8517c
YW
604int bus_link_method_reconfigure(sd_bus_message *message, void *userdata, sd_bus_error *error) {
605 Link *l = userdata;
606 int r;
607
608 assert(message);
609 assert(l);
610
611 r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
612 "org.freedesktop.network1.reconfigure",
613 NULL, true, UID_INVALID,
614 &l->manager->polkit_registry, error);
615 if (r < 0)
616 return r;
617 if (r == 0)
618 return 1; /* Polkit will call us back */
619
620 r = link_reconfigure(l, true);
621 if (r < 0)
622 return r;
623
624 return sd_bus_reply_method_return(message, NULL);
625}
626
e331e246
TG
627const sd_bus_vtable link_vtable[] = {
628 SD_BUS_VTABLE_START(0),
629
630 SD_BUS_PROPERTY("OperationalState", "s", property_get_operational_state, offsetof(Link, operstate), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
35c5a9ca
YW
631 SD_BUS_PROPERTY("CarrierState", "s", property_get_carrier_state, offsetof(Link, carrier_state), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
632 SD_BUS_PROPERTY("AddressState", "s", property_get_address_state, offsetof(Link, address_state), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
e331e246 633 SD_BUS_PROPERTY("AdministrativeState", "s", property_get_administrative_state, offsetof(Link, state), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
42a63431 634 SD_BUS_PROPERTY("BitRates", "(tt)", property_get_bit_rates, 0, 0),
e331e246 635
15761549
YW
636 SD_BUS_METHOD("SetNTP", "as", NULL, bus_link_method_set_ntp_servers, SD_BUS_VTABLE_UNPRIVILEGED),
637 SD_BUS_METHOD("SetDNS", "a(iay)", NULL, bus_link_method_set_dns_servers, SD_BUS_VTABLE_UNPRIVILEGED),
638 SD_BUS_METHOD("SetDomains", "a(sb)", NULL, bus_link_method_set_domains, SD_BUS_VTABLE_UNPRIVILEGED),
639 SD_BUS_METHOD("SetDefaultRoute", "b", NULL, bus_link_method_set_default_route, SD_BUS_VTABLE_UNPRIVILEGED),
640 SD_BUS_METHOD("SetLLMNR", "s", NULL, bus_link_method_set_llmnr, SD_BUS_VTABLE_UNPRIVILEGED),
641 SD_BUS_METHOD("SetMulticastDNS", "s", NULL, bus_link_method_set_mdns, SD_BUS_VTABLE_UNPRIVILEGED),
642 SD_BUS_METHOD("SetDNSOverTLS", "s", NULL, bus_link_method_set_dns_over_tls, SD_BUS_VTABLE_UNPRIVILEGED),
643 SD_BUS_METHOD("SetDNSSEC", "s", NULL, bus_link_method_set_dnssec, SD_BUS_VTABLE_UNPRIVILEGED),
644 SD_BUS_METHOD("SetDNSSECNegativeTrustAnchors", "as", NULL, bus_link_method_set_dnssec_negative_trust_anchors, SD_BUS_VTABLE_UNPRIVILEGED),
645 SD_BUS_METHOD("RevertNTP", NULL, NULL, bus_link_method_revert_ntp, SD_BUS_VTABLE_UNPRIVILEGED),
646 SD_BUS_METHOD("RevertDNS", NULL, NULL, bus_link_method_revert_dns, SD_BUS_VTABLE_UNPRIVILEGED),
ae65d7db 647 SD_BUS_METHOD("Renew", NULL, NULL, bus_link_method_renew, SD_BUS_VTABLE_UNPRIVILEGED),
99b8517c 648 SD_BUS_METHOD("Reconfigure", NULL, NULL, bus_link_method_reconfigure, SD_BUS_VTABLE_UNPRIVILEGED),
15761549 649
e331e246
TG
650 SD_BUS_VTABLE_END
651};
652
6a1af3d4 653char *link_bus_path(Link *link) {
c8f5edea 654 _cleanup_free_ char *ifindex = NULL;
e331e246 655 char *p;
c8f5edea 656 int r;
e331e246
TG
657
658 assert(link);
659 assert(link->ifindex > 0);
660
c8f5edea
TG
661 if (asprintf(&ifindex, "%d", link->ifindex) < 0)
662 return NULL;
663
664 r = sd_bus_path_encode("/org/freedesktop/network1/link", ifindex, &p);
665 if (r < 0)
02f50053 666 return NULL;
e331e246
TG
667
668 return p;
669}
670
671int link_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
672 _cleanup_strv_free_ char **l = NULL;
673 Manager *m = userdata;
fdb90ac6 674 unsigned c = 0;
e331e246
TG
675 Link *link;
676 Iterator i;
e331e246
TG
677
678 assert(bus);
679 assert(path);
680 assert(m);
681 assert(nodes);
682
fdb90ac6
LP
683 l = new0(char*, hashmap_size(m->links) + 1);
684 if (!l)
685 return -ENOMEM;
686
e331e246
TG
687 HASHMAP_FOREACH(link, m->links, i) {
688 char *p;
689
690 p = link_bus_path(link);
691 if (!p)
692 return -ENOMEM;
693
fdb90ac6 694 l[c++] = p;
e331e246
TG
695 }
696
fdb90ac6 697 l[c] = NULL;
ae2a15bc 698 *nodes = TAKE_PTR(l);
e331e246
TG
699
700 return 1;
701}
702
703int link_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
c8f5edea 704 _cleanup_free_ char *identifier = NULL;
e331e246
TG
705 Manager *m = userdata;
706 Link *link;
707 int ifindex, r;
708
709 assert(bus);
710 assert(path);
711 assert(interface);
712 assert(m);
713 assert(found);
714
c8f5edea 715 r = sd_bus_path_decode(path, "/org/freedesktop/network1/link", &identifier);
a7f6e7e8 716 if (r <= 0)
c8f5edea
TG
717 return 0;
718
597da51b
ZJS
719 ifindex = parse_ifindex(identifier);
720 if (ifindex < 0)
e331e246
TG
721 return 0;
722
723 r = link_get(m, ifindex, &link);
724 if (r < 0)
725 return 0;
726
727 *found = link;
728
729 return 1;
730}
731
aa3108f6 732int link_send_changed_strv(Link *link, char **properties) {
e331e246 733 _cleanup_free_ char *p = NULL;
e331e246
TG
734
735 assert(link);
736 assert(link->manager);
aa3108f6 737 assert(properties);
e331e246 738
4852e159 739 if (!link->manager->bus)
aa3108f6 740 return 0;
e331e246
TG
741
742 p = link_bus_path(link);
743 if (!p)
744 return -ENOMEM;
745
746 return sd_bus_emit_properties_changed_strv(
747 link->manager->bus,
748 p,
749 "org.freedesktop.network1.Link",
aa3108f6
YW
750 properties);
751}
752
753int link_send_changed(Link *link, const char *property, ...) {
754 char **properties;
755
756 properties = strv_from_stdarg_alloca(property);
757
758 return link_send_changed_strv(link, properties);
e331e246 759}