1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include <linux/nexthop.h>
5 #include "dhcp-server-internal.h"
6 #include "dhcp6-internal.h"
7 #include "dhcp6-lease-internal.h"
8 #include "dns-domain.h"
9 #include "ip-protocol-list.h"
10 #include "netif-util.h"
11 #include "networkd-address.h"
12 #include "networkd-dhcp-common.h"
13 #include "networkd-json.h"
14 #include "networkd-link.h"
15 #include "networkd-manager.h"
16 #include "networkd-neighbor.h"
17 #include "networkd-network.h"
18 #include "networkd-nexthop.h"
19 #include "networkd-route-util.h"
20 #include "networkd-route.h"
21 #include "networkd-routing-policy-rule.h"
22 #include "sort-util.h"
23 #include "udev-util.h"
24 #include "user-util.h"
25 #include "wifi-util.h"
27 static int address_build_json(Address
*address
, JsonVariant
**ret
) {
28 _cleanup_free_
char *scope
= NULL
, *flags
= NULL
, *state
= NULL
;
34 r
= route_scope_to_string_alloc(address
->scope
, &scope
);
38 r
= address_flags_to_string_alloc(address
->flags
, address
->family
, &flags
);
42 r
= network_config_state_to_string_alloc(address
->state
, &state
);
46 return json_build(ret
, JSON_BUILD_OBJECT(
47 JSON_BUILD_PAIR_INTEGER("Family", address
->family
),
48 JSON_BUILD_PAIR_IN_ADDR("Address", &address
->in_addr
, address
->family
),
49 JSON_BUILD_PAIR_IN_ADDR_NON_NULL("Peer", &address
->in_addr_peer
, address
->family
),
50 JSON_BUILD_PAIR_IN4_ADDR_NON_NULL("Broadcast", &address
->broadcast
),
51 JSON_BUILD_PAIR_UNSIGNED("PrefixLength", address
->prefixlen
),
52 JSON_BUILD_PAIR_UNSIGNED("Scope", address
->scope
),
53 JSON_BUILD_PAIR_STRING("ScopeString", scope
),
54 JSON_BUILD_PAIR_UNSIGNED("Flags", address
->flags
),
55 JSON_BUILD_PAIR_STRING("FlagsString", flags
),
56 JSON_BUILD_PAIR_STRING_NON_EMPTY("Label", address
->label
),
57 JSON_BUILD_PAIR_FINITE_USEC("PreferredLifetimeUSec", address
->lifetime_preferred_usec
),
58 JSON_BUILD_PAIR_FINITE_USEC("PreferredLifetimeUsec", address
->lifetime_preferred_usec
), /* for backward compat */
59 JSON_BUILD_PAIR_FINITE_USEC("ValidLifetimeUSec", address
->lifetime_valid_usec
),
60 JSON_BUILD_PAIR_FINITE_USEC("ValidLifetimeUsec", address
->lifetime_valid_usec
), /* for backward compat */
61 JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(address
->source
)),
62 JSON_BUILD_PAIR_STRING("ConfigState", state
),
63 JSON_BUILD_PAIR_IN_ADDR_NON_NULL("ConfigProvider", &address
->provider
, address
->family
)));
66 static int addresses_append_json(Set
*addresses
, JsonVariant
**v
) {
67 _cleanup_(json_variant_unrefp
) JsonVariant
*array
= NULL
;
73 SET_FOREACH(address
, addresses
) {
74 _cleanup_(json_variant_unrefp
) JsonVariant
*e
= NULL
;
76 r
= address_build_json(address
, &e
);
80 r
= json_variant_append_array(&array
, e
);
85 return json_variant_set_field_non_null(v
, "Addresses", array
);
88 static int neighbor_build_json(Neighbor
*n
, JsonVariant
**ret
) {
89 _cleanup_free_
char *state
= NULL
;
95 r
= network_config_state_to_string_alloc(n
->state
, &state
);
99 return json_build(ret
, JSON_BUILD_OBJECT(
100 JSON_BUILD_PAIR_INTEGER("Family", n
->family
),
101 JSON_BUILD_PAIR_IN_ADDR("Destination", &n
->in_addr
, n
->family
),
102 JSON_BUILD_PAIR_HW_ADDR("LinkLayerAddress", &n
->ll_addr
),
103 JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(n
->source
)),
104 JSON_BUILD_PAIR_STRING("ConfigState", state
)));
107 static int neighbors_append_json(Set
*neighbors
, JsonVariant
**v
) {
108 _cleanup_(json_variant_unrefp
) JsonVariant
*array
= NULL
;
114 SET_FOREACH(neighbor
, neighbors
) {
115 _cleanup_(json_variant_unrefp
) JsonVariant
*e
= NULL
;
117 r
= neighbor_build_json(neighbor
, &e
);
121 r
= json_variant_append_array(&array
, e
);
126 return json_variant_set_field_non_null(v
, "Neighbors", array
);
129 static int nexthop_group_build_json(NextHop
*nexthop
, JsonVariant
**ret
) {
130 _cleanup_(json_variant_unrefp
) JsonVariant
*array
= NULL
;
131 struct nexthop_grp
*g
;
137 HASHMAP_FOREACH(g
, nexthop
->group
) {
138 r
= json_variant_append_arrayb(
141 JSON_BUILD_PAIR_UNSIGNED("ID", g
->id
),
142 JSON_BUILD_PAIR_UNSIGNED("Weight", g
->weight
+1)));
147 *ret
= TAKE_PTR(array
);
151 static int nexthop_build_json(NextHop
*n
, JsonVariant
**ret
) {
152 _cleanup_(json_variant_unrefp
) JsonVariant
*group
= NULL
;
153 _cleanup_free_
char *flags
= NULL
, *protocol
= NULL
, *state
= NULL
;
159 r
= route_flags_to_string_alloc(n
->flags
, &flags
);
163 r
= route_protocol_to_string_alloc(n
->protocol
, &protocol
);
167 r
= network_config_state_to_string_alloc(n
->state
, &state
);
171 r
= nexthop_group_build_json(n
, &group
);
175 return json_build(ret
, JSON_BUILD_OBJECT(
176 JSON_BUILD_PAIR_UNSIGNED("ID", n
->id
),
177 JSON_BUILD_PAIR_IN_ADDR_NON_NULL("Gateway", &n
->gw
, n
->family
),
178 JSON_BUILD_PAIR_UNSIGNED("Flags", n
->flags
),
179 JSON_BUILD_PAIR_STRING("FlagsString", strempty(flags
)),
180 JSON_BUILD_PAIR_UNSIGNED("Protocol", n
->protocol
),
181 JSON_BUILD_PAIR_STRING("ProtocolString", protocol
),
182 JSON_BUILD_PAIR_BOOLEAN("Blackhole", n
->blackhole
),
183 JSON_BUILD_PAIR_VARIANT_NON_NULL("Group", group
),
184 JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(n
->source
)),
185 JSON_BUILD_PAIR_STRING("ConfigState", state
)));
188 static int nexthops_append_json(Set
*nexthops
, JsonVariant
**v
) {
189 _cleanup_(json_variant_unrefp
) JsonVariant
*array
= NULL
;
195 SET_FOREACH(nexthop
, nexthops
) {
196 _cleanup_(json_variant_unrefp
) JsonVariant
*e
= NULL
;
198 r
= nexthop_build_json(nexthop
, &e
);
202 r
= json_variant_append_array(&array
, e
);
207 return json_variant_set_field_non_null(v
, "NextHops", array
);
210 static int route_build_json(Route
*route
, JsonVariant
**ret
) {
211 _cleanup_free_
char *scope
= NULL
, *protocol
= NULL
, *table
= NULL
, *flags
= NULL
, *state
= NULL
;
218 manager
= route
->link
? route
->link
->manager
: route
->manager
;
222 r
= route_scope_to_string_alloc(route
->scope
, &scope
);
226 r
= route_protocol_to_string_alloc(route
->protocol
, &protocol
);
230 r
= manager_get_route_table_to_string(manager
, route
->table
, /* append_num = */ false, &table
);
234 r
= route_flags_to_string_alloc(route
->flags
, &flags
);
238 r
= network_config_state_to_string_alloc(route
->state
, &state
);
242 return json_build(ret
, JSON_BUILD_OBJECT(
243 JSON_BUILD_PAIR_INTEGER("Family", route
->family
),
244 JSON_BUILD_PAIR_IN_ADDR("Destination", &route
->dst
, route
->family
),
245 JSON_BUILD_PAIR_UNSIGNED("DestinationPrefixLength", route
->dst_prefixlen
),
246 JSON_BUILD_PAIR_IN_ADDR_NON_NULL("Gateway", &route
->gw
, route
->gw_family
),
247 JSON_BUILD_PAIR_CONDITION(route
->src_prefixlen
> 0,
248 "Source", JSON_BUILD_IN_ADDR(&route
->src
, route
->family
)),
249 JSON_BUILD_PAIR_UNSIGNED_NON_ZERO("SourcePrefixLength", route
->src_prefixlen
),
250 JSON_BUILD_PAIR_IN_ADDR_NON_NULL("PreferredSource", &route
->prefsrc
, route
->family
),
251 JSON_BUILD_PAIR_UNSIGNED("Scope", route
->scope
),
252 JSON_BUILD_PAIR_STRING("ScopeString", scope
),
253 JSON_BUILD_PAIR_UNSIGNED("Protocol", route
->protocol
),
254 JSON_BUILD_PAIR_STRING("ProtocolString", protocol
),
255 JSON_BUILD_PAIR_UNSIGNED("Type", route
->type
),
256 JSON_BUILD_PAIR_STRING("TypeString", route_type_to_string(route
->type
)),
257 JSON_BUILD_PAIR_UNSIGNED("Priority", route
->priority
),
258 JSON_BUILD_PAIR_UNSIGNED("Table", route
->table
),
259 JSON_BUILD_PAIR_STRING("TableString", table
),
260 JSON_BUILD_PAIR_UNSIGNED_NON_ZERO("MTU", route
->mtu
),
261 JSON_BUILD_PAIR_UNSIGNED("Preference", route
->pref
),
262 JSON_BUILD_PAIR_UNSIGNED("Flags", route
->flags
),
263 JSON_BUILD_PAIR_STRING("FlagsString", strempty(flags
)),
264 JSON_BUILD_PAIR_FINITE_USEC("LifetimeUSec", route
->lifetime_usec
),
265 JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(route
->source
)),
266 JSON_BUILD_PAIR_STRING("ConfigState", state
),
267 JSON_BUILD_PAIR_IN_ADDR_NON_NULL("ConfigProvider", &route
->provider
, route
->family
)));
270 static int routes_append_json(Set
*routes
, JsonVariant
**v
) {
271 _cleanup_(json_variant_unrefp
) JsonVariant
*array
= NULL
;
277 SET_FOREACH(route
, routes
) {
278 _cleanup_(json_variant_unrefp
) JsonVariant
*e
= NULL
;
280 r
= route_build_json(route
, &e
);
284 r
= json_variant_append_array(&array
, e
);
289 return json_variant_set_field_non_null(v
, "Routes", array
);
292 static int routing_policy_rule_build_json(RoutingPolicyRule
*rule
, JsonVariant
**ret
) {
293 _cleanup_free_
char *table
= NULL
, *protocol
= NULL
, *state
= NULL
;
297 assert(rule
->manager
);
300 r
= manager_get_route_table_to_string(rule
->manager
, rule
->table
, /* append_num = */ false, &table
);
301 if (r
< 0 && r
!= -EINVAL
)
304 r
= route_protocol_to_string_alloc(rule
->protocol
, &protocol
);
308 r
= network_config_state_to_string_alloc(rule
->state
, &state
);
312 return json_build(ret
, JSON_BUILD_OBJECT(
313 JSON_BUILD_PAIR_INTEGER("Family", rule
->family
),
314 JSON_BUILD_PAIR_IN_ADDR_NON_NULL("FromPrefix", &rule
->from
, rule
->family
),
315 JSON_BUILD_PAIR_CONDITION(in_addr_is_set(rule
->family
, &rule
->from
),
316 "FromPrefixLength", JSON_BUILD_UNSIGNED(rule
->from_prefixlen
)),
317 JSON_BUILD_PAIR_IN_ADDR_NON_NULL("ToPrefix", &rule
->to
, rule
->family
),
318 JSON_BUILD_PAIR_CONDITION(in_addr_is_set(rule
->family
, &rule
->to
),
319 "ToPrefixLength", JSON_BUILD_UNSIGNED(rule
->to_prefixlen
)),
320 JSON_BUILD_PAIR_UNSIGNED("Protocol", rule
->protocol
),
321 JSON_BUILD_PAIR_STRING("ProtocolString", protocol
),
322 JSON_BUILD_PAIR_UNSIGNED("TOS", rule
->tos
),
323 JSON_BUILD_PAIR_UNSIGNED("Type", rule
->type
),
324 JSON_BUILD_PAIR_STRING("TypeString", fr_act_type_full_to_string(rule
->type
)),
325 JSON_BUILD_PAIR_UNSIGNED("IPProtocol", rule
->ipproto
),
326 JSON_BUILD_PAIR_STRING("IPProtocolString", ip_protocol_to_name(rule
->ipproto
)),
327 JSON_BUILD_PAIR_UNSIGNED("Priority", rule
->priority
),
328 JSON_BUILD_PAIR_UNSIGNED("FirewallMark", rule
->fwmark
),
329 JSON_BUILD_PAIR_UNSIGNED("FirewallMask", rule
->fwmask
),
330 JSON_BUILD_PAIR_UNSIGNED_NON_ZERO("Table", rule
->table
),
331 JSON_BUILD_PAIR_STRING_NON_EMPTY("TableString", table
),
332 JSON_BUILD_PAIR_BOOLEAN("Invert", rule
->invert_rule
),
333 JSON_BUILD_PAIR_CONDITION(rule
->suppress_prefixlen
>= 0,
334 "SuppressPrefixLength", JSON_BUILD_UNSIGNED(rule
->suppress_prefixlen
)),
335 JSON_BUILD_PAIR_CONDITION(rule
->suppress_ifgroup
>= 0,
336 "SuppressInterfaceGroup", JSON_BUILD_UNSIGNED(rule
->suppress_ifgroup
)),
337 JSON_BUILD_PAIR_CONDITION(rule
->sport
.start
!= 0 || rule
->sport
.end
!= 0, "SourcePort",
338 JSON_BUILD_ARRAY(JSON_BUILD_UNSIGNED(rule
->sport
.start
), JSON_BUILD_UNSIGNED(rule
->sport
.end
))),
339 JSON_BUILD_PAIR_CONDITION(rule
->dport
.start
!= 0 || rule
->dport
.end
!= 0, "DestinationPort",
340 JSON_BUILD_ARRAY(JSON_BUILD_UNSIGNED(rule
->dport
.start
), JSON_BUILD_UNSIGNED(rule
->dport
.end
))),
341 JSON_BUILD_PAIR_CONDITION(rule
->uid_range
.start
!= UID_INVALID
&& rule
->uid_range
.end
!= UID_INVALID
, "User",
342 JSON_BUILD_ARRAY(JSON_BUILD_UNSIGNED(rule
->uid_range
.start
), JSON_BUILD_UNSIGNED(rule
->uid_range
.end
))),
343 JSON_BUILD_PAIR_STRING_NON_EMPTY("IncomingInterface", rule
->iif
),
344 JSON_BUILD_PAIR_STRING_NON_EMPTY("OutgoingInterface", rule
->oif
),
345 JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(rule
->source
)),
346 JSON_BUILD_PAIR_STRING("ConfigState", state
)));
349 static int routing_policy_rules_append_json(Set
*rules
, JsonVariant
**v
) {
350 _cleanup_(json_variant_unrefp
) JsonVariant
*array
= NULL
;
351 RoutingPolicyRule
*rule
;
356 SET_FOREACH(rule
, rules
) {
357 _cleanup_(json_variant_unrefp
) JsonVariant
*e
= NULL
;
359 r
= routing_policy_rule_build_json(rule
, &e
);
363 r
= json_variant_append_array(&array
, e
);
368 return json_variant_set_field_non_null(v
, "RoutingPolicyRules", array
);
371 static int network_append_json(Network
*network
, JsonVariant
**v
) {
377 return json_variant_merge_objectb(
378 v
, JSON_BUILD_OBJECT(
379 JSON_BUILD_PAIR_STRING("NetworkFile", network
->filename
),
380 JSON_BUILD_PAIR_STRV("NetworkFileDropins", network
->dropins
),
381 JSON_BUILD_PAIR_BOOLEAN("RequiredForOnline", network
->required_for_online
),
382 JSON_BUILD_PAIR("RequiredOperationalStateForOnline",
383 JSON_BUILD_ARRAY(JSON_BUILD_STRING(link_operstate_to_string(network
->required_operstate_for_online
.min
)),
384 JSON_BUILD_STRING(link_operstate_to_string(network
->required_operstate_for_online
.max
)))),
385 JSON_BUILD_PAIR_STRING("RequiredFamilyForOnline",
386 link_required_address_family_to_string(network
->required_family_for_online
)),
387 JSON_BUILD_PAIR_STRING("ActivationPolicy",
388 activation_policy_to_string(network
->activation_policy
))));
391 static int device_append_json(sd_device
*device
, JsonVariant
**v
) {
392 _cleanup_strv_free_
char **link_dropins
= NULL
;
393 const char *link
= NULL
, *path
= NULL
, *vendor
= NULL
, *model
= NULL
, *joined
;
401 (void) sd_device_get_property_value(device
, "ID_NET_LINK_FILE", &link
);
403 if (sd_device_get_property_value(device
, "ID_NET_LINK_FILE_DROPINS", &joined
) >= 0) {
404 r
= strv_split_full(&link_dropins
, joined
, ":", EXTRACT_CUNESCAPE
);
409 (void) sd_device_get_property_value(device
, "ID_PATH", &path
);
411 (void) device_get_vendor_string(device
, &vendor
);
412 (void) device_get_model_string(device
, &model
);
414 return json_variant_merge_objectb(
417 JSON_BUILD_PAIR_STRING_NON_EMPTY("LinkFile", link
),
418 JSON_BUILD_PAIR_STRV_NON_EMPTY("LinkFileDropins", link_dropins
),
419 JSON_BUILD_PAIR_STRING_NON_EMPTY("Path", path
),
420 JSON_BUILD_PAIR_STRING_NON_EMPTY("Vendor", vendor
),
421 JSON_BUILD_PAIR_STRING_NON_EMPTY("Model", model
)));
424 static int dns_append_json_one(Link
*link
, const struct in_addr_full
*a
, NetworkConfigSource s
, const union in_addr_union
*p
, JsonVariant
**array
) {
429 if (a
->ifindex
!= 0 && a
->ifindex
!= link
->ifindex
)
432 return json_variant_append_arrayb(
435 JSON_BUILD_PAIR_INTEGER("Family", a
->family
),
436 JSON_BUILD_PAIR_IN_ADDR("Address", &a
->address
, a
->family
),
437 JSON_BUILD_PAIR_UNSIGNED_NON_ZERO("Port", a
->port
),
438 JSON_BUILD_PAIR_CONDITION(a
->ifindex
!= 0, "InterfaceIndex", JSON_BUILD_INTEGER(a
->ifindex
)),
439 JSON_BUILD_PAIR_STRING_NON_EMPTY("ServerName", a
->server_name
),
440 JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(s
)),
441 JSON_BUILD_PAIR_IN_ADDR_NON_NULL("ConfigProvider", p
, a
->family
)));
444 static int dns_append_json(Link
*link
, JsonVariant
**v
) {
445 _cleanup_(json_variant_unrefp
) JsonVariant
*array
= NULL
;
454 if (link
->n_dns
!= UINT_MAX
)
455 for (unsigned i
= 0; i
< link
->n_dns
; i
++) {
456 r
= dns_append_json_one(link
, link
->dns
[i
], NETWORK_CONFIG_SOURCE_RUNTIME
, NULL
, &array
);
461 for (unsigned i
= 0; i
< link
->network
->n_dns
; i
++) {
462 r
= dns_append_json_one(link
, link
->network
->dns
[i
], NETWORK_CONFIG_SOURCE_STATIC
, NULL
, &array
);
467 if (link
->dhcp_lease
&& link
->network
->dhcp_use_dns
) {
468 const struct in_addr
*dns
;
469 union in_addr_union s
;
472 r
= sd_dhcp_lease_get_server_identifier(link
->dhcp_lease
, &s
.in
);
476 n_dns
= sd_dhcp_lease_get_dns(link
->dhcp_lease
, &dns
);
477 for (int i
= 0; i
< n_dns
; i
++) {
478 r
= dns_append_json_one(link
,
479 &(struct in_addr_full
) { .family
= AF_INET
, .address
.in
= dns
[i
], },
480 NETWORK_CONFIG_SOURCE_DHCP4
,
488 if (link
->dhcp6_lease
&& link
->network
->dhcp6_use_dns
) {
489 const struct in6_addr
*dns
;
490 union in_addr_union s
;
493 r
= sd_dhcp6_lease_get_server_address(link
->dhcp6_lease
, &s
.in6
);
497 n_dns
= sd_dhcp6_lease_get_dns(link
->dhcp6_lease
, &dns
);
498 for (int i
= 0; i
< n_dns
; i
++) {
499 r
= dns_append_json_one(link
,
500 &(struct in_addr_full
) { .family
= AF_INET6
, .address
.in6
= dns
[i
], },
501 NETWORK_CONFIG_SOURCE_DHCP6
,
509 if (link
->network
->ipv6_accept_ra_use_dns
) {
512 SET_FOREACH(a
, link
->ndisc_rdnss
) {
513 r
= dns_append_json_one(link
,
514 &(struct in_addr_full
) { .family
= AF_INET6
, .address
.in6
= a
->address
, },
515 NETWORK_CONFIG_SOURCE_NDISC
,
516 &(union in_addr_union
) { .in6
= a
->router
},
524 return json_variant_set_field_non_null(v
, "DNS", array
);
527 static int server_append_json_one_addr(int family
, const union in_addr_union
*a
, NetworkConfigSource s
, const union in_addr_union
*p
, JsonVariant
**array
) {
528 _cleanup_(json_variant_unrefp
) JsonVariant
*v
= NULL
;
531 assert(IN_SET(family
, AF_INET
, AF_INET6
));
535 r
= json_build(&v
, JSON_BUILD_OBJECT(
536 JSON_BUILD_PAIR_INTEGER("Family", family
),
537 JSON_BUILD_PAIR_IN_ADDR("Address", a
, family
),
538 JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(s
)),
539 JSON_BUILD_PAIR_IN_ADDR_NON_NULL("ConfigProvider", p
, family
)));
543 return json_variant_append_array(array
, v
);
546 static int server_append_json_one_fqdn(int family
, const char *fqdn
, NetworkConfigSource s
, const union in_addr_union
*p
, JsonVariant
**array
) {
547 _cleanup_(json_variant_unrefp
) JsonVariant
*v
= NULL
;
550 assert(IN_SET(family
, AF_UNSPEC
, AF_INET
, AF_INET6
));
554 r
= json_build(&v
, JSON_BUILD_OBJECT(
555 JSON_BUILD_PAIR_STRING("Server", fqdn
),
556 JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(s
)),
557 JSON_BUILD_PAIR_IN_ADDR_NON_NULL("ConfigProvider", p
, family
)));
561 return json_variant_append_array(array
, v
);
564 static int server_append_json_one_string(const char *str
, NetworkConfigSource s
, JsonVariant
**array
) {
565 union in_addr_union a
;
570 if (in_addr_from_string_auto(str
, &family
, &a
) >= 0)
571 return server_append_json_one_addr(family
, &a
, s
, NULL
, array
);
573 return server_append_json_one_fqdn(AF_UNSPEC
, str
, s
, NULL
, array
);
576 static int ntp_append_json(Link
*link
, JsonVariant
**v
) {
577 _cleanup_(json_variant_unrefp
) JsonVariant
*array
= NULL
;
586 STRV_FOREACH(p
, link
->ntp
?: link
->network
->ntp
) {
587 r
= server_append_json_one_string(*p
, NETWORK_CONFIG_SOURCE_RUNTIME
, &array
);
593 if (link
->dhcp_lease
&& link
->network
->dhcp_use_ntp
) {
594 const struct in_addr
*ntp
;
595 union in_addr_union s
;
598 r
= sd_dhcp_lease_get_server_identifier(link
->dhcp_lease
, &s
.in
);
602 n_ntp
= sd_dhcp_lease_get_ntp(link
->dhcp_lease
, &ntp
);
603 for (int i
= 0; i
< n_ntp
; i
++) {
604 r
= server_append_json_one_addr(AF_INET
,
605 &(union in_addr_union
) { .in
= ntp
[i
], },
606 NETWORK_CONFIG_SOURCE_DHCP4
,
614 if (link
->dhcp6_lease
&& link
->network
->dhcp6_use_ntp
) {
615 const struct in6_addr
*ntp_addr
;
616 union in_addr_union s
;
620 r
= sd_dhcp6_lease_get_server_address(link
->dhcp6_lease
, &s
.in6
);
624 n_ntp
= sd_dhcp6_lease_get_ntp_addrs(link
->dhcp6_lease
, &ntp_addr
);
625 for (int i
= 0; i
< n_ntp
; i
++) {
626 r
= server_append_json_one_addr(AF_INET6
,
627 &(union in_addr_union
) { .in6
= ntp_addr
[i
], },
628 NETWORK_CONFIG_SOURCE_DHCP6
,
635 n_ntp
= sd_dhcp6_lease_get_ntp_fqdn(link
->dhcp6_lease
, &ntp_fqdn
);
636 for (int i
= 0; i
< n_ntp
; i
++) {
637 r
= server_append_json_one_fqdn(AF_INET6
,
639 NETWORK_CONFIG_SOURCE_DHCP6
,
648 return json_variant_set_field_non_null(v
, "NTP", array
);
651 static int sip_append_json(Link
*link
, JsonVariant
**v
) {
652 _cleanup_(json_variant_unrefp
) JsonVariant
*array
= NULL
;
653 const struct in_addr
*sip
;
654 union in_addr_union s
;
660 if (!link
->network
|| !link
->network
->dhcp_use_sip
|| !link
->dhcp_lease
)
663 n_sip
= sd_dhcp_lease_get_sip(link
->dhcp_lease
, &sip
);
667 r
= sd_dhcp_lease_get_server_identifier(link
->dhcp_lease
, &s
.in
);
671 for (int i
= 0; i
< n_sip
; i
++) {
672 r
= server_append_json_one_addr(AF_INET
,
673 &(union in_addr_union
) { .in
= sip
[i
], },
674 NETWORK_CONFIG_SOURCE_DHCP4
,
681 return json_variant_set_field_non_null(v
, "SIP", array
);
684 static int domain_append_json(int family
, const char *domain
, NetworkConfigSource s
, const union in_addr_union
*p
, JsonVariant
**array
) {
685 _cleanup_(json_variant_unrefp
) JsonVariant
*v
= NULL
;
688 assert(IN_SET(family
, AF_UNSPEC
, AF_INET
, AF_INET6
));
692 r
= json_build(&v
, JSON_BUILD_OBJECT(
693 JSON_BUILD_PAIR_STRING("Domain", domain
),
694 JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(s
)),
695 JSON_BUILD_PAIR_IN_ADDR_NON_NULL("ConfigProvider", p
, family
)));
699 return json_variant_append_array(array
, v
);
702 static int domains_append_json(Link
*link
, bool is_route
, JsonVariant
**v
) {
703 _cleanup_(json_variant_unrefp
) JsonVariant
*array
= NULL
;
704 OrderedSet
*link_domains
, *network_domains
;
705 DHCPUseDomains use_domains
;
706 union in_addr_union s
;
717 link_domains
= is_route
? link
->route_domains
: link
->search_domains
;
718 network_domains
= is_route
? link
->network
->route_domains
: link
->network
->search_domains
;
719 use_domains
= is_route
? DHCP_USE_DOMAINS_ROUTE
: DHCP_USE_DOMAINS_YES
;
721 ORDERED_SET_FOREACH(domain
, link_domains
?: network_domains
) {
722 r
= domain_append_json(AF_UNSPEC
, domain
,
723 link_domains
? NETWORK_CONFIG_SOURCE_RUNTIME
: NETWORK_CONFIG_SOURCE_STATIC
,
730 if (link
->dhcp_lease
&&
731 link
->network
->dhcp_use_domains
== use_domains
) {
732 r
= sd_dhcp_lease_get_server_identifier(link
->dhcp_lease
, &s
.in
);
736 if (sd_dhcp_lease_get_domainname(link
->dhcp_lease
, &domain
) >= 0) {
737 r
= domain_append_json(AF_INET
, domain
, NETWORK_CONFIG_SOURCE_DHCP4
, &s
, &array
);
742 if (sd_dhcp_lease_get_search_domains(link
->dhcp_lease
, &domains
) >= 0)
743 STRV_FOREACH(p
, domains
) {
744 r
= domain_append_json(AF_INET
, *p
, NETWORK_CONFIG_SOURCE_DHCP4
, &s
, &array
);
750 if (link
->dhcp6_lease
&&
751 link
->network
->dhcp6_use_domains
== use_domains
) {
752 r
= sd_dhcp6_lease_get_server_address(link
->dhcp6_lease
, &s
.in6
);
756 if (sd_dhcp6_lease_get_domains(link
->dhcp6_lease
, &domains
) >= 0)
757 STRV_FOREACH(p
, domains
) {
758 r
= domain_append_json(AF_INET6
, *p
, NETWORK_CONFIG_SOURCE_DHCP6
, &s
, &array
);
764 if (link
->network
->ipv6_accept_ra_use_domains
== use_domains
) {
767 SET_FOREACH(a
, link
->ndisc_dnssl
) {
768 r
= domain_append_json(AF_INET6
, NDISC_DNSSL_DOMAIN(a
), NETWORK_CONFIG_SOURCE_NDISC
,
769 &(union in_addr_union
) { .in6
= a
->router
},
777 return json_variant_set_field_non_null(v
, is_route
? "RouteDomains" : "SearchDomains", array
);
780 static int nta_append_json(const char *nta
, NetworkConfigSource s
, JsonVariant
**array
) {
781 _cleanup_(json_variant_unrefp
) JsonVariant
*v
= NULL
;
787 r
= json_build(&v
, JSON_BUILD_OBJECT(
788 JSON_BUILD_PAIR_STRING("DNSSECNegativeTrustAnchor", nta
),
789 JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(s
))));
793 return json_variant_append_array(array
, v
);
796 static int ntas_append_json(Link
*link
, JsonVariant
**v
) {
797 _cleanup_(json_variant_unrefp
) JsonVariant
*array
= NULL
;
807 SET_FOREACH(nta
, link
->dnssec_negative_trust_anchors
?: link
->network
->dnssec_negative_trust_anchors
) {
808 r
= nta_append_json(nta
,
809 link
->dnssec_negative_trust_anchors
? NETWORK_CONFIG_SOURCE_RUNTIME
: NETWORK_CONFIG_SOURCE_STATIC
,
815 return json_variant_set_field_non_null(v
, "DNSSECNegativeTrustAnchors", array
);
818 static int dns_misc_append_json(Link
*link
, JsonVariant
**v
) {
819 _cleanup_(json_variant_unrefp
) JsonVariant
*array
= NULL
;
820 ResolveSupport resolve_support
;
821 NetworkConfigSource source
;
831 resolve_support
= link
->llmnr
>= 0 ? link
->llmnr
: link
->network
->llmnr
;
832 if (resolve_support
>= 0) {
833 _cleanup_(json_variant_unrefp
) JsonVariant
*e
= NULL
;
835 source
= link
->llmnr
>= 0 ? NETWORK_CONFIG_SOURCE_RUNTIME
: NETWORK_CONFIG_SOURCE_STATIC
;
837 r
= json_build(&e
, JSON_BUILD_OBJECT(
838 JSON_BUILD_PAIR_STRING("LLMNR", resolve_support_to_string(resolve_support
)),
839 JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(source
))));
843 r
= json_variant_append_array(&array
, e
);
848 resolve_support
= link
->mdns
>= 0 ? link
->mdns
: link
->network
->mdns
;
849 if (resolve_support
>= 0) {
850 _cleanup_(json_variant_unrefp
) JsonVariant
*e
= NULL
;
852 source
= link
->mdns
>= 0 ? NETWORK_CONFIG_SOURCE_RUNTIME
: NETWORK_CONFIG_SOURCE_STATIC
;
854 r
= json_build(&e
, JSON_BUILD_OBJECT(
855 JSON_BUILD_PAIR_STRING("MDNS", resolve_support_to_string(resolve_support
)),
856 JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(source
))));
860 r
= json_variant_append_array(&array
, e
);
865 t
= link
->dns_default_route
>= 0 ? link
->dns_default_route
: link
->network
->dns_default_route
;
867 _cleanup_(json_variant_unrefp
) JsonVariant
*e
= NULL
;
869 source
= link
->dns_default_route
>= 0 ? NETWORK_CONFIG_SOURCE_RUNTIME
: NETWORK_CONFIG_SOURCE_STATIC
;
871 r
= json_build(&e
, JSON_BUILD_OBJECT(
872 JSON_BUILD_PAIR_BOOLEAN("DNSDefaultRoute", t
),
873 JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(source
))));
877 r
= json_variant_append_array(&array
, e
);
882 mode
= link
->dns_over_tls_mode
>= 0 ? link
->dns_over_tls_mode
: link
->network
->dns_over_tls_mode
;
884 _cleanup_(json_variant_unrefp
) JsonVariant
*e
= NULL
;
886 source
= link
->dns_over_tls_mode
>= 0 ? NETWORK_CONFIG_SOURCE_RUNTIME
: NETWORK_CONFIG_SOURCE_STATIC
;
888 r
= json_build(&e
, JSON_BUILD_OBJECT(
889 JSON_BUILD_PAIR_STRING("DNSOverTLS", dns_over_tls_mode_to_string(mode
)),
890 JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(source
))));
894 r
= json_variant_append_array(&array
, e
);
899 return json_variant_set_field_non_null(v
, "DNSSettings", array
);
902 static int captive_portal_append_json(Link
*link
, JsonVariant
**v
) {
903 const char *captive_portal
;
909 r
= link_get_captive_portal(link
, &captive_portal
);
913 return json_variant_merge_objectb(v
, JSON_BUILD_OBJECT(JSON_BUILD_PAIR_STRING("CaptivePortal", captive_portal
)));
916 static int pref64_append_json(Link
*link
, JsonVariant
**v
) {
917 _cleanup_(json_variant_unrefp
) JsonVariant
*array
= NULL
, *w
= NULL
;
924 if (!link
->network
|| !link
->network
->ipv6_accept_ra_use_pref64
)
927 SET_FOREACH(i
, link
->ndisc_pref64
) {
928 r
= json_variant_append_arrayb(&array
,
930 JSON_BUILD_PAIR_IN6_ADDR_NON_NULL("Prefix", &i
->prefix
),
931 JSON_BUILD_PAIR_UNSIGNED("PrefixLength", i
->prefix_len
),
932 JSON_BUILD_PAIR_FINITE_USEC("LifetimeUSec", i
->lifetime_usec
),
933 JSON_BUILD_PAIR_IN6_ADDR_NON_NULL("ConfigProvider", &i
->router
)));
938 r
= json_variant_set_field_non_null(&w
, "PREF64", array
);
942 return json_variant_set_field_non_null(v
, "NDisc", w
);
945 static int dhcp_server_offered_leases_append_json(Link
*link
, JsonVariant
**v
) {
946 _cleanup_(json_variant_unrefp
) JsonVariant
*array
= NULL
;
953 if (!link
->dhcp_server
)
956 HASHMAP_FOREACH(lease
, link
->dhcp_server
->bound_leases_by_client_id
) {
957 struct in_addr address
= { .s_addr
= lease
->address
};
959 r
= json_variant_append_arrayb(
962 JSON_BUILD_PAIR_BYTE_ARRAY(
964 lease
->client_id
.data
,
965 lease
->client_id
.length
),
966 JSON_BUILD_PAIR_IN4_ADDR_NON_NULL("Address", &address
),
967 JSON_BUILD_PAIR_STRING_NON_EMPTY("Hostname", lease
->hostname
),
968 JSON_BUILD_PAIR_FINITE_USEC(
969 "ExpirationUSec", lease
->expiration
)));
974 return json_variant_set_field_non_null(v
, "Leases", array
);
977 static int dhcp_server_static_leases_append_json(Link
*link
, JsonVariant
**v
) {
978 _cleanup_(json_variant_unrefp
) JsonVariant
*array
= NULL
;
985 if (!link
->dhcp_server
)
988 HASHMAP_FOREACH(lease
, link
->dhcp_server
->static_leases_by_client_id
) {
989 _cleanup_(json_variant_unrefp
) JsonVariant
*e
= NULL
;
990 struct in_addr address
= { .s_addr
= lease
->address
};
994 JSON_BUILD_PAIR_BYTE_ARRAY(
996 lease
->client_id
.data
,
997 lease
->client_id
.length
),
998 JSON_BUILD_PAIR_IN4_ADDR_NON_NULL("Address", &address
)));
1002 r
= json_variant_append_array(&array
, e
);
1007 return json_variant_set_field_non_null(v
, "StaticLeases", array
);
1010 static int dhcp_server_append_json(Link
*link
, JsonVariant
**v
) {
1011 _cleanup_(json_variant_unrefp
) JsonVariant
*w
= NULL
;
1017 if (!link
->dhcp_server
)
1022 JSON_BUILD_PAIR_UNSIGNED("PoolOffset", link
->dhcp_server
->pool_offset
),
1023 JSON_BUILD_PAIR_UNSIGNED("PoolSize", link
->dhcp_server
->pool_size
)));
1027 r
= dhcp_server_offered_leases_append_json(link
, &w
);
1031 r
= dhcp_server_static_leases_append_json(link
, &w
);
1035 return json_variant_set_field_non_null(v
, "DHCPServer", w
);
1038 static int dhcp6_client_vendor_options_append_json(Link
*link
, JsonVariant
**v
) {
1039 _cleanup_(json_variant_unrefp
) JsonVariant
*array
= NULL
;
1040 sd_dhcp6_option
**options
= NULL
;
1041 int r
, n_vendor_options
;
1046 if (!link
->dhcp6_lease
)
1049 n_vendor_options
= sd_dhcp6_lease_get_vendor_options(link
->dhcp6_lease
, &options
);
1051 FOREACH_ARRAY(option
, options
, n_vendor_options
) {
1052 r
= json_variant_append_arrayb(&array
,
1054 JSON_BUILD_PAIR_UNSIGNED("EnterpriseId", (*option
)->enterprise_identifier
),
1055 JSON_BUILD_PAIR_UNSIGNED("SubOptionCode", (*option
)->option
),
1056 JSON_BUILD_PAIR_HEX("SubOptionData", (*option
)->data
, (*option
)->length
)));
1061 return json_variant_set_field_non_null(v
, "VendorSpecificOptions", array
);
1064 static int dhcp6_client_lease_append_json(Link
*link
, JsonVariant
**v
) {
1065 _cleanup_(json_variant_unrefp
) JsonVariant
*w
= NULL
;
1066 usec_t ts
= USEC_INFINITY
, t1
= USEC_INFINITY
, t2
= USEC_INFINITY
;
1072 if (!link
->dhcp6_lease
)
1075 r
= sd_dhcp6_lease_get_timestamp(link
->dhcp6_lease
, CLOCK_BOOTTIME
, &ts
);
1076 if (r
< 0 && r
!= -ENODATA
)
1079 r
= sd_dhcp6_lease_get_t1_timestamp(link
->dhcp6_lease
, CLOCK_BOOTTIME
, &t1
);
1080 if (r
< 0 && r
!= -ENODATA
)
1083 r
= sd_dhcp6_lease_get_t2_timestamp(link
->dhcp6_lease
, CLOCK_BOOTTIME
, &t2
);
1084 if (r
< 0 && r
!= -ENODATA
)
1087 r
= json_build(&w
, JSON_BUILD_OBJECT(
1088 JSON_BUILD_PAIR_FINITE_USEC("Timeout1USec", t1
),
1089 JSON_BUILD_PAIR_FINITE_USEC("Timeout2USec", t2
),
1090 JSON_BUILD_PAIR_FINITE_USEC("LeaseTimestampUSec", ts
)));
1094 return json_variant_set_field_non_null(v
, "Lease", w
);
1097 static int dhcp6_client_pd_append_json(Link
*link
, JsonVariant
**v
) {
1098 _cleanup_(json_variant_unrefp
) JsonVariant
*array
= NULL
;
1102 assert(link
->network
);
1105 if (!link
->network
->dhcp6_use_pd_prefix
||
1106 !sd_dhcp6_lease_has_pd_prefix(link
->dhcp6_lease
))
1109 FOREACH_DHCP6_PD_PREFIX(link
->dhcp6_lease
) {
1110 usec_t lifetime_preferred_usec
, lifetime_valid_usec
;
1111 struct in6_addr prefix
;
1114 r
= sd_dhcp6_lease_get_pd_prefix(link
->dhcp6_lease
, &prefix
, &prefix_len
);
1118 r
= sd_dhcp6_lease_get_pd_lifetime_timestamp(link
->dhcp6_lease
, CLOCK_BOOTTIME
,
1119 &lifetime_preferred_usec
, &lifetime_valid_usec
);
1123 r
= json_variant_append_arrayb(&array
, JSON_BUILD_OBJECT(
1124 JSON_BUILD_PAIR_IN6_ADDR("Prefix", &prefix
),
1125 JSON_BUILD_PAIR_UNSIGNED("PrefixLength", prefix_len
),
1126 JSON_BUILD_PAIR_FINITE_USEC("PreferredLifetimeUSec", lifetime_preferred_usec
),
1127 JSON_BUILD_PAIR_FINITE_USEC("ValidLifetimeUSec", lifetime_valid_usec
)));
1132 return json_variant_set_field_non_null(v
, "Prefixes", array
);
1135 static int dhcp6_client_append_json(Link
*link
, JsonVariant
**v
) {
1136 _cleanup_(json_variant_unrefp
) JsonVariant
*w
= NULL
;
1142 if (!link
->dhcp6_client
)
1145 r
= dhcp6_client_lease_append_json(link
, &w
);
1149 r
= dhcp6_client_pd_append_json(link
, &w
);
1153 r
= dhcp6_client_vendor_options_append_json(link
, &w
);
1157 return json_variant_set_field_non_null(v
, "DHCPv6Client", w
);
1160 static int dhcp_client_lease_append_json(Link
*link
, JsonVariant
**v
) {
1161 _cleanup_(json_variant_unrefp
) JsonVariant
*w
= NULL
;
1162 usec_t lease_timestamp_usec
= USEC_INFINITY
, t1
= USEC_INFINITY
, t2
= USEC_INFINITY
;
1168 if (!link
->dhcp_client
|| !link
->dhcp_lease
)
1171 r
= sd_dhcp_lease_get_timestamp(link
->dhcp_lease
, CLOCK_BOOTTIME
, &lease_timestamp_usec
);
1172 if (r
< 0 && r
!= -ENODATA
)
1175 r
= sd_dhcp_lease_get_t1_timestamp(link
->dhcp_lease
, CLOCK_BOOTTIME
, &t1
);
1176 if (r
< 0 && r
!= -ENODATA
)
1179 r
= sd_dhcp_lease_get_t2_timestamp(link
->dhcp_lease
, CLOCK_BOOTTIME
, &t2
);
1180 if (r
< 0 && r
!= -ENODATA
)
1183 r
= json_build(&w
, JSON_BUILD_OBJECT(
1184 JSON_BUILD_PAIR_FINITE_USEC("LeaseTimestampUSec", lease_timestamp_usec
),
1185 JSON_BUILD_PAIR_FINITE_USEC("Timeout1USec", t1
),
1186 JSON_BUILD_PAIR_FINITE_USEC("Timeout2USec", t2
)));
1190 return json_variant_set_field_non_null(v
, "Lease", w
);
1193 static int dhcp_client_pd_append_json(Link
*link
, JsonVariant
**v
) {
1194 _cleanup_(json_variant_unrefp
) JsonVariant
*addresses
= NULL
, *array
= NULL
;
1195 uint8_t ipv4masklen
, sixrd_prefixlen
;
1196 struct in6_addr sixrd_prefix
;
1197 const struct in_addr
*br_addresses
;
1198 size_t n_br_addresses
= 0;
1202 assert(link
->network
);
1205 if (!link
->network
->dhcp_use_6rd
|| !sd_dhcp_lease_has_6rd(link
->dhcp_lease
))
1208 r
= sd_dhcp_lease_get_6rd(link
->dhcp_lease
, &ipv4masklen
, &sixrd_prefixlen
, &sixrd_prefix
, &br_addresses
, &n_br_addresses
);
1212 FOREACH_ARRAY(br_address
, br_addresses
, n_br_addresses
) {
1213 r
= json_variant_append_arrayb(&addresses
, JSON_BUILD_IN4_ADDR(br_address
));
1218 r
= json_build(&array
, JSON_BUILD_OBJECT(
1219 JSON_BUILD_PAIR_IN6_ADDR("Prefix", &sixrd_prefix
),
1220 JSON_BUILD_PAIR_UNSIGNED("PrefixLength", sixrd_prefixlen
),
1221 JSON_BUILD_PAIR_UNSIGNED("IPv4MaskLength", ipv4masklen
),
1222 JSON_BUILD_PAIR_VARIANT_NON_NULL("BorderRouters", addresses
)));
1226 return json_variant_set_field_non_null(v
, "6rdPrefix", array
);
1229 static int dhcp_client_append_json(Link
*link
, JsonVariant
**v
) {
1230 _cleanup_(json_variant_unrefp
) JsonVariant
*w
= NULL
;
1236 if (!link
->dhcp_client
)
1239 r
= dhcp_client_lease_append_json(link
, &w
);
1243 r
= dhcp_client_pd_append_json(link
, &w
);
1247 return json_variant_set_field_non_null(v
, "DHCPv4Client", w
);
1250 int link_build_json(Link
*link
, JsonVariant
**ret
) {
1251 _cleanup_(json_variant_unrefp
) JsonVariant
*v
= NULL
;
1252 _cleanup_free_
char *type
= NULL
, *flags
= NULL
;
1258 r
= net_get_type_string(link
->dev
, link
->iftype
, &type
);
1262 r
= link_flags_to_string_alloc(link
->flags
, &flags
);
1266 r
= json_build(&v
, JSON_BUILD_OBJECT(
1267 /* basic information */
1268 JSON_BUILD_PAIR_INTEGER("Index", link
->ifindex
),
1269 JSON_BUILD_PAIR_STRING("Name", link
->ifname
),
1270 JSON_BUILD_PAIR_STRV_NON_EMPTY("AlternativeNames", link
->alternative_names
),
1271 JSON_BUILD_PAIR_CONDITION(link
->master_ifindex
> 0,
1272 "MasterInterfaceIndex", JSON_BUILD_INTEGER(link
->master_ifindex
)),
1273 JSON_BUILD_PAIR_STRING_NON_EMPTY("Kind", link
->kind
),
1274 JSON_BUILD_PAIR_STRING("Type", type
),
1275 JSON_BUILD_PAIR_STRING_NON_EMPTY("Driver", link
->driver
),
1276 JSON_BUILD_PAIR_UNSIGNED("Flags", link
->flags
),
1277 JSON_BUILD_PAIR_STRING("FlagsString", flags
),
1278 JSON_BUILD_PAIR_UNSIGNED("KernelOperationalState", link
->kernel_operstate
),
1279 JSON_BUILD_PAIR_STRING("KernelOperationalStateString", kernel_operstate_to_string(link
->kernel_operstate
)),
1280 JSON_BUILD_PAIR_UNSIGNED("MTU", link
->mtu
),
1281 JSON_BUILD_PAIR_UNSIGNED("MinimumMTU", link
->min_mtu
),
1282 JSON_BUILD_PAIR_UNSIGNED("MaximumMTU", link
->max_mtu
),
1283 JSON_BUILD_PAIR_HW_ADDR_NON_NULL("HardwareAddress", &link
->hw_addr
),
1284 JSON_BUILD_PAIR_HW_ADDR_NON_NULL("PermanentHardwareAddress", &link
->permanent_hw_addr
),
1285 JSON_BUILD_PAIR_HW_ADDR_NON_NULL("BroadcastAddress", &link
->bcast_addr
),
1286 JSON_BUILD_PAIR_IN6_ADDR_NON_NULL("IPv6LinkLocalAddress", &link
->ipv6ll_address
),
1287 /* wlan information */
1288 JSON_BUILD_PAIR_CONDITION(link
->wlan_iftype
> 0, "WirelessLanInterfaceType",
1289 JSON_BUILD_UNSIGNED(link
->wlan_iftype
)),
1290 JSON_BUILD_PAIR_CONDITION(link
->wlan_iftype
> 0, "WirelessLanInterfaceTypeString",
1291 JSON_BUILD_STRING(nl80211_iftype_to_string(link
->wlan_iftype
))),
1292 JSON_BUILD_PAIR_STRING_NON_EMPTY("SSID", link
->ssid
),
1293 JSON_BUILD_PAIR_ETHER_ADDR_NON_NULL("BSSID", &link
->bssid
),
1295 JSON_BUILD_PAIR_STRING("AdministrativeState", link_state_to_string(link
->state
)),
1296 JSON_BUILD_PAIR_STRING("OperationalState", link_operstate_to_string(link
->operstate
)),
1297 JSON_BUILD_PAIR_STRING("CarrierState", link_carrier_state_to_string(link
->carrier_state
)),
1298 JSON_BUILD_PAIR_STRING("AddressState", link_address_state_to_string(link
->address_state
)),
1299 JSON_BUILD_PAIR_STRING("IPv4AddressState", link_address_state_to_string(link
->ipv4_address_state
)),
1300 JSON_BUILD_PAIR_STRING("IPv6AddressState", link_address_state_to_string(link
->ipv6_address_state
)),
1301 JSON_BUILD_PAIR_STRING("OnlineState", link_online_state_to_string(link
->online_state
))));
1305 r
= network_append_json(link
->network
, &v
);
1309 r
= device_append_json(link
->dev
, &v
);
1313 r
= dns_append_json(link
, &v
);
1317 r
= ntp_append_json(link
, &v
);
1321 r
= sip_append_json(link
, &v
);
1325 r
= domains_append_json(link
, /* is_route = */ false, &v
);
1329 r
= domains_append_json(link
, /* is_route = */ true, &v
);
1333 r
= ntas_append_json(link
, &v
);
1337 r
= dns_misc_append_json(link
, &v
);
1341 r
= captive_portal_append_json(link
, &v
);
1345 r
= pref64_append_json(link
, &v
);
1349 r
= addresses_append_json(link
->addresses
, &v
);
1353 r
= neighbors_append_json(link
->neighbors
, &v
);
1357 r
= nexthops_append_json(link
->nexthops
, &v
);
1361 r
= routes_append_json(link
->routes
, &v
);
1365 r
= dhcp_server_append_json(link
, &v
);
1369 r
= dhcp_client_append_json(link
, &v
);
1373 r
= dhcp6_client_append_json(link
, &v
);
1381 static int links_append_json(Manager
*manager
, JsonVariant
**v
) {
1382 _cleanup_(json_variant_unrefp
) JsonVariant
*array
= NULL
;
1383 _cleanup_free_ Link
**links
= NULL
;
1390 r
= hashmap_dump_sorted(manager
->links_by_index
, (void***) &links
, &n_links
);
1394 FOREACH_ARRAY(link
, links
, n_links
) {
1395 _cleanup_(json_variant_unrefp
) JsonVariant
*e
= NULL
;
1397 r
= link_build_json(*link
, &e
);
1401 r
= json_variant_append_array(&array
, e
);
1406 return json_variant_set_field_non_null(v
, "Interfaces", array
);
1409 int manager_build_json(Manager
*manager
, JsonVariant
**ret
) {
1410 _cleanup_(json_variant_unrefp
) JsonVariant
*v
= NULL
;
1416 r
= links_append_json(manager
, &v
);
1420 r
= nexthops_append_json(manager
->nexthops
, &v
);
1424 r
= routes_append_json(manager
->routes
, &v
);
1428 r
= routing_policy_rules_append_json(manager
->rules
, &v
);