]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-radv.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / network / networkd-radv.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
091214b6
PF
2/***
3 This file is part of systemd.
4
5 Copyright (C) 2017 Intel Corporation. All rights reserved.
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19***/
20
21#include <netinet/icmp6.h>
22#include <arpa/inet.h>
23
24#include "networkd-address.h"
c555a358 25#include "networkd-manager.h"
091214b6
PF
26#include "networkd-radv.h"
27#include "sd-radv.h"
28
c555a358
PF
29static int radv_get_ip6dns(Network *network, struct in6_addr **dns,
30 size_t *n_dns) {
31 _cleanup_free_ struct in6_addr *addresses = NULL;
32 size_t i, n_addresses = 0, n_allocated = 0;
33
34 assert(network);
35 assert(dns);
36 assert(n_dns);
37
38 for (i = 0; i < network->n_dns; i++) {
39 union in_addr_union *addr;
40
41 if (network->dns[i].family != AF_INET6)
42 continue;
43
44 addr = &network->dns[i].address;
45
46 if (in_addr_is_null(AF_INET6, addr) ||
47 in_addr_is_link_local(AF_INET6, addr) ||
48 in_addr_is_localhost(AF_INET6, addr))
49 continue;
50
51 if (!GREEDY_REALLOC(addresses, n_allocated, n_addresses + 1))
52 return -ENOMEM;
53
54 addresses[n_addresses++] = addr->in6;
55 }
56
57 if (addresses) {
58 *dns = addresses;
59 addresses = NULL;
60
61 *n_dns = n_addresses;
62 }
63
64 return n_addresses;
65}
66
67static int radv_set_dns(Link *link, Link *uplink) {
68 _cleanup_free_ struct in6_addr *dns = NULL;
69 size_t n_dns;
70 usec_t lifetime_usec;
71 int r;
72
73 if (!link->network->router_emit_dns)
74 return 0;
75
76 if (link->network->router_dns) {
77 dns = newdup(struct in6_addr, link->network->router_dns,
78 link->network->n_router_dns);
79 if (dns == NULL)
80 return -ENOMEM;
81
82 n_dns = link->network->n_router_dns;
83 lifetime_usec = link->network->router_dns_lifetime_usec;
84
85 goto set_dns;
86 }
87
88 lifetime_usec = SD_RADV_DEFAULT_DNS_LIFETIME_USEC;
89
90 r = radv_get_ip6dns(link->network, &dns, &n_dns);
91 if (r > 0)
92 goto set_dns;
93
94 if (uplink) {
95 r = radv_get_ip6dns(uplink->network, &dns, &n_dns);
96 if (r > 0)
97 goto set_dns;
98 }
99
100 return 0;
101
102 set_dns:
103 return sd_radv_set_rdnss(link->radv,
104 DIV_ROUND_UP(lifetime_usec, USEC_PER_SEC),
105 dns, n_dns);
106}
107
108static int radv_set_domains(Link *link, Link *uplink) {
109 char **search_domains;
110 usec_t lifetime_usec;
111
112 if (!link->network->router_emit_domains)
113 return 0;
114
115 search_domains = link->network->router_search_domains;
116 lifetime_usec = link->network->router_dns_lifetime_usec;
117
118 if (search_domains)
119 goto set_domains;
120
121 lifetime_usec = SD_RADV_DEFAULT_DNS_LIFETIME_USEC;
122
123 search_domains = link->network->search_domains;
124 if (search_domains)
125 goto set_domains;
126
127 if (uplink) {
128 search_domains = uplink->network->search_domains;
129 if (search_domains)
130 goto set_domains;
131 }
132
133 return 0;
134
135 set_domains:
136 return sd_radv_set_dnssl(link->radv,
137 DIV_ROUND_UP(lifetime_usec, USEC_PER_SEC),
138 search_domains);
139
140}
141
142int radv_emit_dns(Link *link) {
143 Link *uplink;
144 int r;
145
146 uplink = manager_find_uplink(link->manager, link);
147
148 r = radv_set_dns(link, uplink);
149 if (r < 0)
150 log_link_warning_errno(link, r, "Could not set RA DNS: %m");
151
152 r = radv_set_domains(link, uplink);
153 if (r < 0)
154 log_link_warning_errno(link, r, "Could not set RA Domains: %m");
155
156 return 0;
157}
158
091214b6
PF
159int radv_configure(Link *link) {
160 int r;
161 Prefix *p;
162
163 assert(link);
164 assert(link->network);
165
166 r = sd_radv_new(&link->radv);
167 if (r < 0)
168 return r;
169
170 r = sd_radv_attach_event(link->radv, NULL, 0);
171 if (r < 0)
172 return r;
173
174 r = sd_radv_set_mac(link->radv, &link->mac);
175 if (r < 0)
176 return r;
177
178 r = sd_radv_set_ifindex(link->radv, link->ifindex);
179 if (r < 0)
180 return r;
181
182 r = sd_radv_set_managed_information(link->radv, link->network->router_managed);
183 if (r < 0)
184 return r;
185
186 r = sd_radv_set_other_information(link->radv, link->network->router_other_information);
187 if (r < 0)
188 return r;
189
301a2fb9
PF
190 /* a value of 0xffffffff represents infinity, 0x0 means this host is
191 not a router */
091214b6 192 r = sd_radv_set_router_lifetime(link->radv,
945e3225 193 DIV_ROUND_UP(link->network->router_lifetime_usec, USEC_PER_SEC));
091214b6
PF
194 if (r < 0)
195 return r;
196
197 if (link->network->router_lifetime_usec > 0) {
198 r = sd_radv_set_preference(link->radv,
199 link->network->router_preference);
200 if (r < 0)
201 return r;
202 }
203
204 LIST_FOREACH(prefixes, p, link->network->static_prefixes) {
205 r = sd_radv_add_prefix(link->radv, p->radv_prefix);
206 if (r != -EEXIST && r < 0)
207 return r;
208 }
209
c555a358 210 return radv_emit_dns(link);
091214b6 211}