]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-dhcp6.c
Merge pull request #4538 from fbuihuu/confirm-spawn-fixes
[thirdparty/systemd.git] / src / network / networkd-dhcp6.c
1 /***
2 This file is part of systemd.
3
4 Copyright (C) 2014 Intel Corporation. All rights reserved.
5
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #include <netinet/ether.h>
21 #include <linux/if.h>
22
23 #include "sd-dhcp6-client.h"
24
25 #include "network-internal.h"
26 #include "networkd-link.h"
27 #include "networkd-manager.h"
28
29 static int dhcp6_lease_address_acquired(sd_dhcp6_client *client, Link *link);
30
31 static int dhcp6_lease_information_acquired(sd_dhcp6_client *client,
32 Link *link) {
33 return 0;
34 }
35
36 static int dhcp6_address_handler(sd_netlink *rtnl, sd_netlink_message *m,
37 void *userdata) {
38 _cleanup_link_unref_ Link *link = userdata;
39 int r;
40
41 assert(link);
42
43 r = sd_netlink_message_get_errno(m);
44 if (r < 0 && r != -EEXIST) {
45 if (link->rtnl_extended_attrs) {
46 log_link_warning(link, "Could not set extended netlink attributes, reverting to fallback mechanism");
47
48 link->rtnl_extended_attrs = false;
49 dhcp6_lease_address_acquired(link->dhcp6_client, link);
50
51 return 1;
52 }
53
54 log_link_error_errno(link, r, "Could not set DHCPv6 address: %m");
55
56 link_enter_failed(link);
57
58 } else if (r >= 0)
59 manager_rtnl_process_address(rtnl, m, link->manager);
60
61 return 1;
62 }
63
64 static int dhcp6_address_change(
65 Link *link,
66 struct in6_addr *ip6_addr,
67 uint32_t lifetime_preferred,
68 uint32_t lifetime_valid) {
69
70 _cleanup_address_free_ Address *addr = NULL;
71 char buffer[INET6_ADDRSTRLEN];
72 int r;
73
74 r = address_new(&addr);
75 if (r < 0)
76 return r;
77
78 addr->family = AF_INET6;
79 memcpy(&addr->in_addr.in6, ip6_addr, sizeof(*ip6_addr));
80
81 addr->flags = IFA_F_NOPREFIXROUTE;
82 addr->prefixlen = 128;
83
84 addr->cinfo.ifa_prefered = lifetime_preferred;
85 addr->cinfo.ifa_valid = lifetime_valid;
86
87 log_link_info(link,
88 "DHCPv6 address %s/%d timeout preferred %d valid %d",
89 inet_ntop(AF_INET6, &addr->in_addr.in6, buffer, sizeof(buffer)),
90 addr->prefixlen, lifetime_preferred, lifetime_valid);
91
92 r = address_configure(addr, link, dhcp6_address_handler, true);
93 if (r < 0)
94 log_link_warning_errno(link, r, "Could not assign DHCPv6 address: %m");
95
96 return r;
97 }
98
99 static int dhcp6_lease_address_acquired(sd_dhcp6_client *client, Link *link) {
100 int r;
101 sd_dhcp6_lease *lease;
102 struct in6_addr ip6_addr;
103 uint32_t lifetime_preferred, lifetime_valid;
104
105 r = sd_dhcp6_client_get_lease(client, &lease);
106 if (r < 0)
107 return r;
108
109 sd_dhcp6_lease_reset_address_iter(lease);
110
111 while (sd_dhcp6_lease_get_address(lease, &ip6_addr,
112 &lifetime_preferred,
113 &lifetime_valid) >= 0) {
114
115 r = dhcp6_address_change(link, &ip6_addr, lifetime_preferred, lifetime_valid);
116 if (r < 0)
117 return r;
118 }
119
120 return 0;
121 }
122
123 static void dhcp6_handler(sd_dhcp6_client *client, int event, void *userdata) {
124 int r;
125 Link *link = userdata;
126
127 assert(link);
128 assert(link->network);
129
130 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
131 return;
132
133 switch(event) {
134 case SD_DHCP6_CLIENT_EVENT_STOP:
135 case SD_DHCP6_CLIENT_EVENT_RESEND_EXPIRE:
136 case SD_DHCP6_CLIENT_EVENT_RETRANS_MAX:
137 if (sd_dhcp6_client_get_lease(client, NULL) >= 0)
138 log_link_warning(link, "DHCPv6 lease lost");
139
140 link->dhcp6_configured = false;
141 break;
142
143 case SD_DHCP6_CLIENT_EVENT_IP_ACQUIRE:
144 r = dhcp6_lease_address_acquired(client, link);
145 if (r < 0) {
146 link_enter_failed(link);
147 return;
148 }
149
150 /* fall through */
151 case SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST:
152 r = dhcp6_lease_information_acquired(client, link);
153 if (r < 0) {
154 link_enter_failed(link);
155 return;
156 }
157
158 link->dhcp6_configured = true;
159 break;
160
161 default:
162 if (event < 0)
163 log_link_warning_errno(link, event, "DHCPv6 error: %m");
164 else
165 log_link_warning(link, "DHCPv6 unknown event: %d", event);
166 return;
167 }
168
169 link_check_ready(link);
170 }
171
172 int dhcp6_request_address(Link *link, int ir) {
173 int r, inf_req;
174 bool running;
175
176 assert(link);
177 assert(link->dhcp6_client);
178 assert(in_addr_is_link_local(AF_INET6, (const union in_addr_union*)&link->ipv6ll_address) > 0);
179
180 r = sd_dhcp6_client_is_running(link->dhcp6_client);
181 if (r < 0)
182 return r;
183 else
184 running = !!r;
185
186 if (running) {
187 r = sd_dhcp6_client_get_information_request(link->dhcp6_client, &inf_req);
188 if (r < 0)
189 return r;
190
191 if (inf_req == ir)
192 return 0;
193
194 r = sd_dhcp6_client_stop(link->dhcp6_client);
195 if (r < 0)
196 return r;
197 } else {
198 r = sd_dhcp6_client_set_local_address(link->dhcp6_client, &link->ipv6ll_address);
199 if (r < 0)
200 return r;
201 }
202
203 r = sd_dhcp6_client_set_information_request(link->dhcp6_client, ir);
204 if (r < 0)
205 return r;
206
207 r = sd_dhcp6_client_start(link->dhcp6_client);
208 if (r < 0)
209 return r;
210
211 return 0;
212 }
213
214 int dhcp6_configure(Link *link) {
215 sd_dhcp6_client *client = NULL;
216 int r;
217 const DUID *duid;
218
219 assert(link);
220
221 if (link->dhcp6_client)
222 return 0;
223
224 r = sd_dhcp6_client_new(&client);
225 if (r < 0)
226 return r;
227
228 r = sd_dhcp6_client_attach_event(client, NULL, 0);
229 if (r < 0)
230 goto error;
231
232 r = sd_dhcp6_client_set_mac(client,
233 (const uint8_t *) &link->mac,
234 sizeof (link->mac), ARPHRD_ETHER);
235 if (r < 0)
236 goto error;
237
238 r = sd_dhcp6_client_set_iaid(client, link->network->iaid);
239 if (r < 0)
240 goto error;
241
242 duid = link_duid(link);
243 r = sd_dhcp6_client_set_duid(client,
244 duid->type,
245 duid->raw_data_len > 0 ? duid->raw_data : NULL,
246 duid->raw_data_len);
247 if (r < 0)
248 goto error;
249
250 r = sd_dhcp6_client_set_ifindex(client, link->ifindex);
251 if (r < 0)
252 goto error;
253
254 r = sd_dhcp6_client_set_callback(client, dhcp6_handler, link);
255 if (r < 0)
256 goto error;
257
258 link->dhcp6_client = client;
259
260 return 0;
261
262 error:
263 sd_dhcp6_client_unref(client);
264 return r;
265 }