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