File: | build-scan/../src/libsystemd-network/sd-dhcp-client.c |
Warning: | line 1981, column 25 Potential leak of memory pointed to by 'client' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* SPDX-License-Identifier: LGPL-2.1+ */ | |||
2 | /*** | |||
3 | Copyright © 2013 Intel Corporation. All rights reserved. | |||
4 | ***/ | |||
5 | ||||
6 | #include <errno(*__errno_location ()).h> | |||
7 | #include <net/ethernet.h> | |||
8 | #include <net/if_arp.h> | |||
9 | #include <stdio.h> | |||
10 | #include <stdlib.h> | |||
11 | #include <string.h> | |||
12 | #include <sys/ioctl.h> | |||
13 | #include <linux1/if_infiniband.h> | |||
14 | ||||
15 | #include "sd-dhcp-client.h" | |||
16 | ||||
17 | #include "alloc-util.h" | |||
18 | #include "async.h" | |||
19 | #include "dhcp-identifier.h" | |||
20 | #include "dhcp-internal.h" | |||
21 | #include "dhcp-lease-internal.h" | |||
22 | #include "dhcp-protocol.h" | |||
23 | #include "dns-domain.h" | |||
24 | #include "hostname-util.h" | |||
25 | #include "random-util.h" | |||
26 | #include "string-util.h" | |||
27 | #include "util.h" | |||
28 | #include "strv.h" | |||
29 | ||||
30 | #define MAX_CLIENT_ID_LEN(sizeof(uint32_t) + 128) (sizeof(uint32_t) + MAX_DUID_LEN128) /* Arbitrary limit */ | |||
31 | #define MAX_MAC_ADDR_LEN__extension__ (__builtin_choose_expr( __builtin_constant_p(20 ) && __builtin_constant_p(6) && __builtin_types_compatible_p (typeof(20), typeof(6)), ((20) > (6)) ? (20) : (6), ((void )0))) CONST_MAX(INFINIBAND_ALEN, ETH_ALEN)__extension__ (__builtin_choose_expr( __builtin_constant_p(20 ) && __builtin_constant_p(6) && __builtin_types_compatible_p (typeof(20), typeof(6)), ((20) > (6)) ? (20) : (6), ((void )0))) | |||
32 | ||||
33 | #define RESTART_AFTER_NAK_MIN_USEC(1 * ((usec_t) 1000000ULL)) (1 * USEC_PER_SEC((usec_t) 1000000ULL)) | |||
34 | #define RESTART_AFTER_NAK_MAX_USEC(30 * ((usec_t) (60ULL*((usec_t) 1000000ULL)))) (30 * USEC_PER_MINUTE((usec_t) (60ULL*((usec_t) 1000000ULL)))) | |||
35 | ||||
36 | struct sd_dhcp_client { | |||
37 | unsigned n_ref; | |||
38 | ||||
39 | DHCPState state; | |||
40 | sd_event *event; | |||
41 | int event_priority; | |||
42 | sd_event_source *timeout_resend; | |||
43 | int ifindex; | |||
44 | int fd; | |||
45 | uint16_t port; | |||
46 | union sockaddr_union link; | |||
47 | sd_event_source *receive_message; | |||
48 | bool_Bool request_broadcast; | |||
49 | uint8_t *req_opts; | |||
50 | size_t req_opts_allocated; | |||
51 | size_t req_opts_size; | |||
52 | bool_Bool anonymize; | |||
53 | be32_t last_addr; | |||
54 | uint8_t mac_addr[MAX_MAC_ADDR_LEN__extension__ (__builtin_choose_expr( __builtin_constant_p(20 ) && __builtin_constant_p(6) && __builtin_types_compatible_p (typeof(20), typeof(6)), ((20) > (6)) ? (20) : (6), ((void )0)))]; | |||
55 | size_t mac_addr_len; | |||
56 | uint16_t arp_type; | |||
57 | struct { | |||
58 | uint8_t type; | |||
59 | union { | |||
60 | struct { | |||
61 | /* 0: Generic (non-LL) (RFC 2132) */ | |||
62 | uint8_t data[MAX_CLIENT_ID_LEN(sizeof(uint32_t) + 128)]; | |||
63 | } _packed___attribute__ ((packed)) gen; | |||
64 | struct { | |||
65 | /* 1: Ethernet Link-Layer (RFC 2132) */ | |||
66 | uint8_t haddr[ETH_ALEN6]; | |||
67 | } _packed___attribute__ ((packed)) eth; | |||
68 | struct { | |||
69 | /* 2 - 254: ARP/Link-Layer (RFC 2132) */ | |||
70 | uint8_t haddr[0]; | |||
71 | } _packed___attribute__ ((packed)) ll; | |||
72 | struct { | |||
73 | /* 255: Node-specific (RFC 4361) */ | |||
74 | be32_t iaid; | |||
75 | struct duid duid; | |||
76 | } _packed___attribute__ ((packed)) ns; | |||
77 | struct { | |||
78 | uint8_t data[MAX_CLIENT_ID_LEN(sizeof(uint32_t) + 128)]; | |||
79 | } _packed___attribute__ ((packed)) raw; | |||
80 | }; | |||
81 | } _packed___attribute__ ((packed)) client_id; | |||
82 | size_t client_id_len; | |||
83 | char *hostname; | |||
84 | char *vendor_class_identifier; | |||
85 | char **user_class; | |||
86 | uint32_t mtu; | |||
87 | uint32_t xid; | |||
88 | usec_t start_time; | |||
89 | unsigned int attempt; | |||
90 | usec_t request_sent; | |||
91 | sd_event_source *timeout_t1; | |||
92 | sd_event_source *timeout_t2; | |||
93 | sd_event_source *timeout_expire; | |||
94 | sd_dhcp_client_callback_t callback; | |||
95 | void *userdata; | |||
96 | sd_dhcp_lease *lease; | |||
97 | usec_t start_delay; | |||
98 | }; | |||
99 | ||||
100 | static const uint8_t default_req_opts[] = { | |||
101 | SD_DHCP_OPTION_SUBNET_MASK, | |||
102 | SD_DHCP_OPTION_ROUTER, | |||
103 | SD_DHCP_OPTION_HOST_NAME, | |||
104 | SD_DHCP_OPTION_DOMAIN_NAME, | |||
105 | SD_DHCP_OPTION_DOMAIN_NAME_SERVER, | |||
106 | }; | |||
107 | ||||
108 | /* RFC7844 section 3: | |||
109 | MAY contain the Parameter Request List option. | |||
110 | RFC7844 section 3.6: | |||
111 | The client intending to protect its privacy SHOULD only request a | |||
112 | minimal number of options in the PRL and SHOULD also randomly shuffle | |||
113 | the ordering of option codes in the PRL. If this random ordering | |||
114 | cannot be implemented, the client MAY order the option codes in the | |||
115 | PRL by option code number (lowest to highest). | |||
116 | */ | |||
117 | /* NOTE: using PRL options that Windows 10 RFC7844 implementation uses */ | |||
118 | static const uint8_t default_req_opts_anonymize[] = { | |||
119 | SD_DHCP_OPTION_SUBNET_MASK, /* 1 */ | |||
120 | SD_DHCP_OPTION_ROUTER, /* 3 */ | |||
121 | SD_DHCP_OPTION_DOMAIN_NAME_SERVER, /* 6 */ | |||
122 | SD_DHCP_OPTION_DOMAIN_NAME, /* 15 */ | |||
123 | SD_DHCP_OPTION_ROUTER_DISCOVER, /* 31 */ | |||
124 | SD_DHCP_OPTION_STATIC_ROUTE, /* 33 */ | |||
125 | SD_DHCP_OPTION_VENDOR_SPECIFIC, /* 43 */ | |||
126 | SD_DHCP_OPTION_NETBIOS_NAMESERVER, /* 44 */ | |||
127 | SD_DHCP_OPTION_NETBIOS_NODETYPE, /* 46 */ | |||
128 | SD_DHCP_OPTION_NETBIOS_SCOPE, /* 47 */ | |||
129 | SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE, /* 121 */ | |||
130 | SD_DHCP_OPTION_PRIVATE_CLASSLESS_STATIC_ROUTE, /* 249 */ | |||
131 | SD_DHCP_OPTION_PRIVATE_PROXY_AUTODISCOVERY, /* 252 */ | |||
132 | }; | |||
133 | ||||
134 | static int client_receive_message_raw( | |||
135 | sd_event_source *s, | |||
136 | int fd, | |||
137 | uint32_t revents, | |||
138 | void *userdata); | |||
139 | static int client_receive_message_udp( | |||
140 | sd_event_source *s, | |||
141 | int fd, | |||
142 | uint32_t revents, | |||
143 | void *userdata); | |||
144 | static void client_stop(sd_dhcp_client *client, int error); | |||
145 | ||||
146 | int sd_dhcp_client_set_callback( | |||
147 | sd_dhcp_client *client, | |||
148 | sd_dhcp_client_callback_t cb, | |||
149 | void *userdata) { | |||
150 | ||||
151 | assert_return(client, -EINVAL)do { if (!(((__builtin_expect(!!(client),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("client"), "../src/libsystemd-network/sd-dhcp-client.c" , 151, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
152 | ||||
153 | client->callback = cb; | |||
154 | client->userdata = userdata; | |||
155 | ||||
156 | return 0; | |||
157 | } | |||
158 | ||||
159 | int sd_dhcp_client_set_request_broadcast(sd_dhcp_client *client, int broadcast) { | |||
160 | assert_return(client, -EINVAL)do { if (!(((__builtin_expect(!!(client),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("client"), "../src/libsystemd-network/sd-dhcp-client.c" , 160, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
161 | ||||
162 | client->request_broadcast = !!broadcast; | |||
163 | ||||
164 | return 0; | |||
165 | } | |||
166 | ||||
167 | int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option) { | |||
168 | size_t i; | |||
169 | ||||
170 | assert_return(client, -EINVAL)do { if (!(((__builtin_expect(!!(client),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("client"), "../src/libsystemd-network/sd-dhcp-client.c" , 170, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
171 | assert_return(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED), -EBUSY)do { if (!(((__builtin_expect(!!(({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended[20 - sizeof((int[]){DHCP_STATE_INIT, DHCP_STATE_STOPPED})/sizeof (int)]; switch(client->state) { case DHCP_STATE_INIT: case DHCP_STATE_STOPPED: _found = 1; break; default: break; } _found ; })),1))) ? (1) : (log_assert_failed_return_realm(LOG_REALM_SYSTEMD , ("IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)" ), "../src/libsystemd-network/sd-dhcp-client.c", 171, __PRETTY_FUNCTION__ ), 0))) return (-16); } while (0); | |||
172 | ||||
173 | switch(option) { | |||
174 | ||||
175 | case SD_DHCP_OPTION_PAD: | |||
176 | case SD_DHCP_OPTION_OVERLOAD: | |||
177 | case SD_DHCP_OPTION_MESSAGE_TYPE: | |||
178 | case SD_DHCP_OPTION_PARAMETER_REQUEST_LIST: | |||
179 | case SD_DHCP_OPTION_END: | |||
180 | return -EINVAL22; | |||
181 | ||||
182 | default: | |||
183 | break; | |||
184 | } | |||
185 | ||||
186 | for (i = 0; i < client->req_opts_size; i++) | |||
187 | if (client->req_opts[i] == option) | |||
188 | return -EEXIST17; | |||
189 | ||||
190 | if (!GREEDY_REALLOC(client->req_opts, client->req_opts_allocated,greedy_realloc((void**) &(client->req_opts), &(client ->req_opts_allocated), (client->req_opts_size + 1), sizeof ((client->req_opts)[0])) | |||
191 | client->req_opts_size + 1)greedy_realloc((void**) &(client->req_opts), &(client ->req_opts_allocated), (client->req_opts_size + 1), sizeof ((client->req_opts)[0]))) | |||
192 | return -ENOMEM12; | |||
193 | ||||
194 | client->req_opts[client->req_opts_size++] = option; | |||
195 | ||||
196 | return 0; | |||
197 | } | |||
198 | ||||
199 | int sd_dhcp_client_set_request_address( | |||
200 | sd_dhcp_client *client, | |||
201 | const struct in_addr *last_addr) { | |||
202 | ||||
203 | assert_return(client, -EINVAL)do { if (!(((__builtin_expect(!!(client),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("client"), "../src/libsystemd-network/sd-dhcp-client.c" , 203, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
204 | assert_return(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED), -EBUSY)do { if (!(((__builtin_expect(!!(({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended[20 - sizeof((int[]){DHCP_STATE_INIT, DHCP_STATE_STOPPED})/sizeof (int)]; switch(client->state) { case DHCP_STATE_INIT: case DHCP_STATE_STOPPED: _found = 1; break; default: break; } _found ; })),1))) ? (1) : (log_assert_failed_return_realm(LOG_REALM_SYSTEMD , ("IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)" ), "../src/libsystemd-network/sd-dhcp-client.c", 204, __PRETTY_FUNCTION__ ), 0))) return (-16); } while (0); | |||
205 | ||||
206 | if (last_addr) | |||
207 | client->last_addr = last_addr->s_addr; | |||
208 | else | |||
209 | client->last_addr = INADDR_ANY((in_addr_t) 0x00000000); | |||
210 | ||||
211 | return 0; | |||
212 | } | |||
213 | ||||
214 | int sd_dhcp_client_set_ifindex(sd_dhcp_client *client, int ifindex) { | |||
215 | ||||
216 | assert_return(client, -EINVAL)do { if (!(((__builtin_expect(!!(client),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("client"), "../src/libsystemd-network/sd-dhcp-client.c" , 216, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
217 | assert_return(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED), -EBUSY)do { if (!(((__builtin_expect(!!(({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended[20 - sizeof((int[]){DHCP_STATE_INIT, DHCP_STATE_STOPPED})/sizeof (int)]; switch(client->state) { case DHCP_STATE_INIT: case DHCP_STATE_STOPPED: _found = 1; break; default: break; } _found ; })),1))) ? (1) : (log_assert_failed_return_realm(LOG_REALM_SYSTEMD , ("IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)" ), "../src/libsystemd-network/sd-dhcp-client.c", 217, __PRETTY_FUNCTION__ ), 0))) return (-16); } while (0); | |||
218 | assert_return(ifindex > 0, -EINVAL)do { if (!(((__builtin_expect(!!(ifindex > 0),1))) ? (1) : (log_assert_failed_return_realm(LOG_REALM_SYSTEMD, ("ifindex > 0" ), "../src/libsystemd-network/sd-dhcp-client.c", 218, __PRETTY_FUNCTION__ ), 0))) return (-22); } while (0); | |||
219 | ||||
220 | client->ifindex = ifindex; | |||
221 | return 0; | |||
222 | } | |||
223 | ||||
224 | int sd_dhcp_client_set_mac( | |||
225 | sd_dhcp_client *client, | |||
226 | const uint8_t *addr, | |||
227 | size_t addr_len, | |||
228 | uint16_t arp_type) { | |||
229 | ||||
230 | DHCP_CLIENT_DONT_DESTROY(client)__attribute__((cleanup(sd_dhcp_client_unrefp))) __attribute__ ((unused)) sd_dhcp_client *_dont_destroy_client = sd_dhcp_client_ref (client); | |||
231 | bool_Bool need_restart = false0; | |||
232 | ||||
233 | assert_return(client, -EINVAL)do { if (!(((__builtin_expect(!!(client),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("client"), "../src/libsystemd-network/sd-dhcp-client.c" , 233, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
234 | assert_return(addr, -EINVAL)do { if (!(((__builtin_expect(!!(addr),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("addr"), "../src/libsystemd-network/sd-dhcp-client.c" , 234, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
235 | assert_return(addr_len > 0 && addr_len <= MAX_MAC_ADDR_LEN, -EINVAL)do { if (!(((__builtin_expect(!!(addr_len > 0 && addr_len <= __extension__ (__builtin_choose_expr( __builtin_constant_p (20) && __builtin_constant_p(6) && __builtin_types_compatible_p (typeof(20), typeof(6)), ((20) > (6)) ? (20) : (6), ((void )0)))),1))) ? (1) : (log_assert_failed_return_realm(LOG_REALM_SYSTEMD , ("addr_len > 0 && addr_len <= MAX_MAC_ADDR_LEN" ), "../src/libsystemd-network/sd-dhcp-client.c", 235, __PRETTY_FUNCTION__ ), 0))) return (-22); } while (0); | |||
236 | assert_return(arp_type > 0, -EINVAL)do { if (!(((__builtin_expect(!!(arp_type > 0),1))) ? (1) : (log_assert_failed_return_realm(LOG_REALM_SYSTEMD, ("arp_type > 0" ), "../src/libsystemd-network/sd-dhcp-client.c", 236, __PRETTY_FUNCTION__ ), 0))) return (-22); } while (0); | |||
237 | ||||
238 | if (arp_type == ARPHRD_ETHER1) | |||
239 | assert_return(addr_len == ETH_ALEN, -EINVAL)do { if (!(((__builtin_expect(!!(addr_len == 6),1))) ? (1) : ( log_assert_failed_return_realm(LOG_REALM_SYSTEMD, ("addr_len == ETH_ALEN" ), "../src/libsystemd-network/sd-dhcp-client.c", 239, __PRETTY_FUNCTION__ ), 0))) return (-22); } while (0); | |||
240 | else if (arp_type == ARPHRD_INFINIBAND32) | |||
241 | assert_return(addr_len == INFINIBAND_ALEN, -EINVAL)do { if (!(((__builtin_expect(!!(addr_len == 20),1))) ? (1) : (log_assert_failed_return_realm(LOG_REALM_SYSTEMD, ("addr_len == INFINIBAND_ALEN" ), "../src/libsystemd-network/sd-dhcp-client.c", 241, __PRETTY_FUNCTION__ ), 0))) return (-22); } while (0); | |||
242 | else | |||
243 | return -EINVAL22; | |||
244 | ||||
245 | if (client->mac_addr_len == addr_len && | |||
246 | memcmp(&client->mac_addr, addr, addr_len) == 0) | |||
247 | return 0; | |||
248 | ||||
249 | if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){DHCP_STATE_INIT, DHCP_STATE_STOPPED})/sizeof (int)]; switch(client->state) { case DHCP_STATE_INIT: case DHCP_STATE_STOPPED: _found = 1; break; default: break; } _found ; })) { | |||
250 | log_dhcp_client(client, "Changing MAC address on running DHCP client, restarting")log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/libsystemd-network/sd-dhcp-client.c", 250, __func__ , "DHCP CLIENT (0x%x): " "Changing MAC address on running DHCP client, restarting" , client->xid); | |||
251 | need_restart = true1; | |||
252 | client_stop(client, SD_DHCP_CLIENT_EVENT_STOP); | |||
253 | } | |||
254 | ||||
255 | memcpy(&client->mac_addr, addr, addr_len); | |||
256 | client->mac_addr_len = addr_len; | |||
257 | client->arp_type = arp_type; | |||
258 | ||||
259 | if (need_restart && client->state != DHCP_STATE_STOPPED) | |||
260 | sd_dhcp_client_start(client); | |||
261 | ||||
262 | return 0; | |||
263 | } | |||
264 | ||||
265 | int sd_dhcp_client_get_client_id( | |||
266 | sd_dhcp_client *client, | |||
267 | uint8_t *type, | |||
268 | const uint8_t **data, | |||
269 | size_t *data_len) { | |||
270 | ||||
271 | assert_return(client, -EINVAL)do { if (!(((__builtin_expect(!!(client),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("client"), "../src/libsystemd-network/sd-dhcp-client.c" , 271, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
272 | assert_return(type, -EINVAL)do { if (!(((__builtin_expect(!!(type),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("type"), "../src/libsystemd-network/sd-dhcp-client.c" , 272, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
273 | assert_return(data, -EINVAL)do { if (!(((__builtin_expect(!!(data),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("data"), "../src/libsystemd-network/sd-dhcp-client.c" , 273, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
274 | assert_return(data_len, -EINVAL)do { if (!(((__builtin_expect(!!(data_len),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("data_len"), "../src/libsystemd-network/sd-dhcp-client.c" , 274, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
275 | ||||
276 | *type = 0; | |||
277 | *data = NULL((void*)0); | |||
278 | *data_len = 0; | |||
279 | if (client->client_id_len) { | |||
280 | *type = client->client_id.type; | |||
281 | *data = client->client_id.raw.data; | |||
282 | *data_len = client->client_id_len - sizeof(client->client_id.type); | |||
283 | } | |||
284 | ||||
285 | return 0; | |||
286 | } | |||
287 | ||||
288 | int sd_dhcp_client_set_client_id( | |||
289 | sd_dhcp_client *client, | |||
290 | uint8_t type, | |||
291 | const uint8_t *data, | |||
292 | size_t data_len) { | |||
293 | ||||
294 | DHCP_CLIENT_DONT_DESTROY(client)__attribute__((cleanup(sd_dhcp_client_unrefp))) __attribute__ ((unused)) sd_dhcp_client *_dont_destroy_client = sd_dhcp_client_ref (client); | |||
295 | bool_Bool need_restart = false0; | |||
296 | ||||
297 | assert_return(client, -EINVAL)do { if (!(((__builtin_expect(!!(client),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("client"), "../src/libsystemd-network/sd-dhcp-client.c" , 297, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
298 | assert_return(data, -EINVAL)do { if (!(((__builtin_expect(!!(data),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("data"), "../src/libsystemd-network/sd-dhcp-client.c" , 298, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
299 | assert_return(data_len > 0 && data_len <= MAX_CLIENT_ID_LEN, -EINVAL)do { if (!(((__builtin_expect(!!(data_len > 0 && data_len <= (sizeof(uint32_t) + 128)),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("data_len > 0 && data_len <= MAX_CLIENT_ID_LEN" ), "../src/libsystemd-network/sd-dhcp-client.c", 299, __PRETTY_FUNCTION__ ), 0))) return (-22); } while (0); | |||
300 | ||||
301 | switch (type) { | |||
302 | ||||
303 | case ARPHRD_ETHER1: | |||
304 | if (data_len != ETH_ALEN6) | |||
305 | return -EINVAL22; | |||
306 | break; | |||
307 | ||||
308 | case ARPHRD_INFINIBAND32: | |||
309 | if (data_len != INFINIBAND_ALEN20) | |||
310 | return -EINVAL22; | |||
311 | break; | |||
312 | ||||
313 | default: | |||
314 | break; | |||
315 | } | |||
316 | ||||
317 | if (client->client_id_len == data_len + sizeof(client->client_id.type) && | |||
318 | client->client_id.type == type && | |||
319 | memcmp(&client->client_id.raw.data, data, data_len) == 0) | |||
320 | return 0; | |||
321 | ||||
322 | if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){DHCP_STATE_INIT, DHCP_STATE_STOPPED})/sizeof (int)]; switch(client->state) { case DHCP_STATE_INIT: case DHCP_STATE_STOPPED: _found = 1; break; default: break; } _found ; })) { | |||
323 | log_dhcp_client(client, "Changing client ID on running DHCP "log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/libsystemd-network/sd-dhcp-client.c", 324, __func__ , "DHCP CLIENT (0x%x): " "Changing client ID on running DHCP " "client, restarting", client->xid) | |||
324 | "client, restarting")log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/libsystemd-network/sd-dhcp-client.c", 324, __func__ , "DHCP CLIENT (0x%x): " "Changing client ID on running DHCP " "client, restarting", client->xid); | |||
325 | need_restart = true1; | |||
326 | client_stop(client, SD_DHCP_CLIENT_EVENT_STOP); | |||
327 | } | |||
328 | ||||
329 | client->client_id.type = type; | |||
330 | memcpy(&client->client_id.raw.data, data, data_len); | |||
331 | client->client_id_len = data_len + sizeof (client->client_id.type); | |||
332 | ||||
333 | if (need_restart && client->state != DHCP_STATE_STOPPED) | |||
334 | sd_dhcp_client_start(client); | |||
335 | ||||
336 | return 0; | |||
337 | } | |||
338 | ||||
339 | /** | |||
340 | * Sets IAID and DUID. If duid is non-null, the DUID is set to duid_type + duid | |||
341 | * without further modification. Otherwise, if duid_type is supported, DUID | |||
342 | * is set based on that type. Otherwise, an error is returned. | |||
343 | */ | |||
344 | static int dhcp_client_set_iaid_duid( | |||
345 | sd_dhcp_client *client, | |||
346 | uint32_t iaid, | |||
347 | bool_Bool append_iaid, | |||
348 | uint16_t duid_type, | |||
349 | const void *duid, | |||
350 | size_t duid_len) { | |||
351 | ||||
352 | DHCP_CLIENT_DONT_DESTROY(client)__attribute__((cleanup(sd_dhcp_client_unrefp))) __attribute__ ((unused)) sd_dhcp_client *_dont_destroy_client = sd_dhcp_client_ref (client); | |||
353 | int r; | |||
354 | size_t len; | |||
355 | ||||
356 | assert_return(client, -EINVAL)do { if (!(((__builtin_expect(!!(client),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("client"), "../src/libsystemd-network/sd-dhcp-client.c" , 356, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
357 | assert_return(duid_len == 0 || duid != NULL, -EINVAL)do { if (!(((__builtin_expect(!!(duid_len == 0 || duid != ((void *)0)),1))) ? (1) : (log_assert_failed_return_realm(LOG_REALM_SYSTEMD , ("duid_len == 0 || duid != NULL"), "../src/libsystemd-network/sd-dhcp-client.c" , 357, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
358 | ||||
359 | if (duid != NULL((void*)0)) { | |||
360 | r = dhcp_validate_duid_len(duid_type, duid_len); | |||
361 | if (r < 0) | |||
362 | return r; | |||
363 | } | |||
364 | ||||
365 | zero(client->client_id)(({ size_t _l_ = (sizeof(client->client_id)); void *_x_ = ( &(client->client_id)); _l_ == 0 ? _x_ : memset(_x_, 0, _l_); })); | |||
366 | client->client_id.type = 255; | |||
367 | ||||
368 | if (append_iaid) { | |||
369 | /* If IAID is not configured, generate it. */ | |||
370 | if (iaid == 0) { | |||
371 | r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr, | |||
372 | client->mac_addr_len, | |||
373 | &client->client_id.ns.iaid); | |||
374 | if (r < 0) | |||
375 | return r; | |||
376 | } else | |||
377 | client->client_id.ns.iaid = htobe32(iaid); | |||
378 | } | |||
379 | ||||
380 | if (duid != NULL((void*)0)) { | |||
381 | client->client_id.ns.duid.type = htobe16(duid_type); | |||
382 | memcpy(&client->client_id.ns.duid.raw.data, duid, duid_len); | |||
383 | len = sizeof(client->client_id.ns.duid.type) + duid_len; | |||
384 | } else if (duid_type == DUID_TYPE_EN) { | |||
385 | r = dhcp_identifier_set_duid_en(&client->client_id.ns.duid, &len); | |||
386 | if (r < 0) | |||
387 | return r; | |||
388 | } else | |||
389 | return -EOPNOTSUPP95; | |||
390 | ||||
391 | client->client_id_len = sizeof(client->client_id.type) + len + | |||
392 | (append_iaid ? sizeof(client->client_id.ns.iaid) : 0); | |||
393 | ||||
394 | if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){DHCP_STATE_INIT, DHCP_STATE_STOPPED})/sizeof (int)]; switch(client->state) { case DHCP_STATE_INIT: case DHCP_STATE_STOPPED: _found = 1; break; default: break; } _found ; })) { | |||
395 | log_dhcp_client(client, "Configured IAID+DUID, restarting.")log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/libsystemd-network/sd-dhcp-client.c", 395, __func__ , "DHCP CLIENT (0x%x): " "Configured IAID+DUID, restarting.", client->xid); | |||
396 | client_stop(client, SD_DHCP_CLIENT_EVENT_STOP); | |||
397 | sd_dhcp_client_start(client); | |||
398 | } | |||
399 | ||||
400 | return 0; | |||
401 | } | |||
402 | ||||
403 | int sd_dhcp_client_set_iaid_duid( | |||
404 | sd_dhcp_client *client, | |||
405 | uint32_t iaid, | |||
406 | uint16_t duid_type, | |||
407 | const void *duid, | |||
408 | size_t duid_len) { | |||
409 | return dhcp_client_set_iaid_duid(client, iaid, true1, duid_type, duid, duid_len); | |||
410 | } | |||
411 | ||||
412 | int sd_dhcp_client_set_duid( | |||
413 | sd_dhcp_client *client, | |||
414 | uint16_t duid_type, | |||
415 | const void *duid, | |||
416 | size_t duid_len) { | |||
417 | return dhcp_client_set_iaid_duid(client, 0, false0, duid_type, duid, duid_len); | |||
418 | } | |||
419 | ||||
420 | int sd_dhcp_client_set_hostname( | |||
421 | sd_dhcp_client *client, | |||
422 | const char *hostname) { | |||
423 | ||||
424 | assert_return(client, -EINVAL)do { if (!(((__builtin_expect(!!(client),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("client"), "../src/libsystemd-network/sd-dhcp-client.c" , 424, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
425 | ||||
426 | /* Make sure hostnames qualify as DNS and as Linux hostnames */ | |||
427 | if (hostname && | |||
428 | !(hostname_is_valid(hostname, false0) && dns_name_is_valid(hostname) > 0)) | |||
429 | return -EINVAL22; | |||
430 | ||||
431 | return free_and_strdup(&client->hostname, hostname); | |||
432 | } | |||
433 | ||||
434 | int sd_dhcp_client_set_vendor_class_identifier( | |||
435 | sd_dhcp_client *client, | |||
436 | const char *vci) { | |||
437 | ||||
438 | assert_return(client, -EINVAL)do { if (!(((__builtin_expect(!!(client),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("client"), "../src/libsystemd-network/sd-dhcp-client.c" , 438, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
439 | ||||
440 | return free_and_strdup(&client->vendor_class_identifier, vci); | |||
441 | } | |||
442 | ||||
443 | int sd_dhcp_client_set_user_class( | |||
444 | sd_dhcp_client *client, | |||
445 | const char* const* user_class) { | |||
446 | ||||
447 | _cleanup_strv_free___attribute__((cleanup(strv_freep))) char **s = NULL((void*)0); | |||
448 | char **p; | |||
449 | ||||
450 | STRV_FOREACH(p, (char **) user_class)for ((p) = ((char **) user_class); (p) && *(p); (p)++ ) | |||
451 | if (strlen(*p) > 255) | |||
452 | return -ENAMETOOLONG36; | |||
453 | ||||
454 | s = strv_copy((char **) user_class); | |||
455 | if (!s) | |||
456 | return -ENOMEM12; | |||
457 | ||||
458 | client->user_class = TAKE_PTR(s)({ typeof(s) _ptr_ = (s); (s) = ((void*)0); _ptr_; }); | |||
459 | ||||
460 | return 0; | |||
461 | } | |||
462 | ||||
463 | int sd_dhcp_client_set_client_port( | |||
464 | sd_dhcp_client *client, | |||
465 | uint16_t port) { | |||
466 | ||||
467 | assert_return(client, -EINVAL)do { if (!(((__builtin_expect(!!(client),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("client"), "../src/libsystemd-network/sd-dhcp-client.c" , 467, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
468 | ||||
469 | client->port = port; | |||
470 | ||||
471 | return 0; | |||
472 | } | |||
473 | ||||
474 | int sd_dhcp_client_set_mtu(sd_dhcp_client *client, uint32_t mtu) { | |||
475 | assert_return(client, -EINVAL)do { if (!(((__builtin_expect(!!(client),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("client"), "../src/libsystemd-network/sd-dhcp-client.c" , 475, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
476 | assert_return(mtu >= DHCP_DEFAULT_MIN_SIZE, -ERANGE)do { if (!(((__builtin_expect(!!(mtu >= 576),1))) ? (1) : ( log_assert_failed_return_realm(LOG_REALM_SYSTEMD, ("mtu >= DHCP_DEFAULT_MIN_SIZE" ), "../src/libsystemd-network/sd-dhcp-client.c", 476, __PRETTY_FUNCTION__ ), 0))) return (-34); } while (0); | |||
477 | ||||
478 | client->mtu = mtu; | |||
479 | ||||
480 | return 0; | |||
481 | } | |||
482 | ||||
483 | int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret) { | |||
484 | assert_return(client, -EINVAL)do { if (!(((__builtin_expect(!!(client),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("client"), "../src/libsystemd-network/sd-dhcp-client.c" , 484, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
485 | ||||
486 | if (!IN_SET(client->state, DHCP_STATE_BOUND, DHCP_STATE_RENEWING, DHCP_STATE_REBINDING)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){DHCP_STATE_BOUND, DHCP_STATE_RENEWING, DHCP_STATE_REBINDING })/sizeof(int)]; switch(client->state) { case DHCP_STATE_BOUND : case DHCP_STATE_RENEWING: case DHCP_STATE_REBINDING: _found = 1; break; default: break; } _found; })) | |||
487 | return -EADDRNOTAVAIL99; | |||
488 | ||||
489 | if (ret) | |||
490 | *ret = client->lease; | |||
491 | ||||
492 | return 0; | |||
493 | } | |||
494 | ||||
495 | static void client_notify(sd_dhcp_client *client, int event) { | |||
496 | assert(client)do { if ((__builtin_expect(!!(!(client)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("client"), "../src/libsystemd-network/sd-dhcp-client.c" , 496, __PRETTY_FUNCTION__); } while (0); | |||
497 | ||||
498 | if (client->callback) | |||
499 | client->callback(client, event, client->userdata); | |||
500 | } | |||
501 | ||||
502 | static int client_initialize(sd_dhcp_client *client) { | |||
503 | assert_return(client, -EINVAL)do { if (!(((__builtin_expect(!!(client),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("client"), "../src/libsystemd-network/sd-dhcp-client.c" , 503, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
504 | ||||
505 | client->receive_message = sd_event_source_unref(client->receive_message); | |||
506 | ||||
507 | client->fd = asynchronous_close(client->fd); | |||
508 | ||||
509 | client->timeout_resend = sd_event_source_unref(client->timeout_resend); | |||
510 | ||||
511 | client->timeout_t1 = sd_event_source_unref(client->timeout_t1); | |||
512 | client->timeout_t2 = sd_event_source_unref(client->timeout_t2); | |||
513 | client->timeout_expire = sd_event_source_unref(client->timeout_expire); | |||
514 | ||||
515 | client->attempt = 1; | |||
516 | ||||
517 | client->state = DHCP_STATE_INIT; | |||
518 | client->xid = 0; | |||
519 | ||||
520 | client->lease = sd_dhcp_lease_unref(client->lease); | |||
521 | ||||
522 | return 0; | |||
523 | } | |||
524 | ||||
525 | static void client_stop(sd_dhcp_client *client, int error) { | |||
526 | assert(client)do { if ((__builtin_expect(!!(!(client)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("client"), "../src/libsystemd-network/sd-dhcp-client.c" , 526, __PRETTY_FUNCTION__); } while (0); | |||
527 | ||||
528 | if (error < 0) | |||
529 | log_dhcp_client(client, "STOPPED: %s", strerror(-error))log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/libsystemd-network/sd-dhcp-client.c", 529, __func__ , "DHCP CLIENT (0x%x): " "STOPPED: %s", client->xid, strerror (-error)); | |||
530 | else if (error == SD_DHCP_CLIENT_EVENT_STOP) | |||
531 | log_dhcp_client(client, "STOPPED")log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/libsystemd-network/sd-dhcp-client.c", 531, __func__ , "DHCP CLIENT (0x%x): " "STOPPED", client->xid); | |||
532 | else | |||
533 | log_dhcp_client(client, "STOPPED: Unknown event")log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/libsystemd-network/sd-dhcp-client.c", 533, __func__ , "DHCP CLIENT (0x%x): " "STOPPED: Unknown event", client-> xid); | |||
534 | ||||
535 | client_notify(client, error); | |||
536 | ||||
537 | client_initialize(client); | |||
538 | } | |||
539 | ||||
540 | static int client_message_init( | |||
541 | sd_dhcp_client *client, | |||
542 | DHCPPacket **ret, | |||
543 | uint8_t type, | |||
544 | size_t *_optlen, | |||
545 | size_t *_optoffset) { | |||
546 | ||||
547 | _cleanup_free___attribute__((cleanup(freep))) DHCPPacket *packet = NULL((void*)0); | |||
548 | size_t optlen, optoffset, size; | |||
549 | be16_t max_size; | |||
550 | usec_t time_now; | |||
551 | uint16_t secs; | |||
552 | int r; | |||
553 | ||||
554 | assert(client)do { if ((__builtin_expect(!!(!(client)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("client"), "../src/libsystemd-network/sd-dhcp-client.c" , 554, __PRETTY_FUNCTION__); } while (0); | |||
555 | assert(client->start_time)do { if ((__builtin_expect(!!(!(client->start_time)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("client->start_time"), "../src/libsystemd-network/sd-dhcp-client.c" , 555, __PRETTY_FUNCTION__); } while (0); | |||
556 | assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("ret"), "../src/libsystemd-network/sd-dhcp-client.c" , 556, __PRETTY_FUNCTION__); } while (0); | |||
557 | assert(_optlen)do { if ((__builtin_expect(!!(!(_optlen)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("_optlen"), "../src/libsystemd-network/sd-dhcp-client.c" , 557, __PRETTY_FUNCTION__); } while (0); | |||
558 | assert(_optoffset)do { if ((__builtin_expect(!!(!(_optoffset)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("_optoffset"), "../src/libsystemd-network/sd-dhcp-client.c" , 558, __PRETTY_FUNCTION__); } while (0); | |||
559 | assert(IN_SET(type, DHCP_DISCOVER, DHCP_REQUEST))do { if ((__builtin_expect(!!(!(({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended[20 - sizeof((int[]){DHCP_DISCOVER, DHCP_REQUEST})/sizeof(int)]; switch(type) { case DHCP_DISCOVER: case DHCP_REQUEST: _found = 1; break; default: break; } _found; }))),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("IN_SET(type, DHCP_DISCOVER, DHCP_REQUEST)" ), "../src/libsystemd-network/sd-dhcp-client.c", 559, __PRETTY_FUNCTION__ ); } while (0); | |||
560 | ||||
561 | optlen = DHCP_MIN_OPTIONS_SIZE(576 - (int32_t)(sizeof(struct udphdr) + (int32_t)(sizeof(struct iphdr))) - (int32_t)(sizeof(DHCPMessage))); | |||
562 | size = sizeof(DHCPPacket) + optlen; | |||
563 | ||||
564 | packet = malloc0(size)(calloc(1, (size))); | |||
565 | if (!packet) | |||
566 | return -ENOMEM12; | |||
567 | ||||
568 | r = dhcp_message_init(&packet->dhcp, BOOTREQUEST, client->xid, type, | |||
569 | client->arp_type, optlen, &optoffset); | |||
570 | if (r < 0) | |||
571 | return r; | |||
572 | ||||
573 | /* Although 'secs' field is a SHOULD in RFC 2131, certain DHCP servers | |||
574 | refuse to issue an DHCP lease if 'secs' is set to zero */ | |||
575 | r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now); | |||
576 | if (r < 0) | |||
577 | return r; | |||
578 | assert(time_now >= client->start_time)do { if ((__builtin_expect(!!(!(time_now >= client->start_time )),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("time_now >= client->start_time" ), "../src/libsystemd-network/sd-dhcp-client.c", 578, __PRETTY_FUNCTION__ ); } while (0); | |||
579 | ||||
580 | /* seconds between sending first and last DISCOVER | |||
581 | * must always be strictly positive to deal with broken servers */ | |||
582 | secs = ((time_now - client->start_time) / USEC_PER_SEC((usec_t) 1000000ULL)) ? : 1; | |||
583 | packet->dhcp.secs = htobe16(secs); | |||
584 | ||||
585 | /* RFC2132 section 4.1 | |||
586 | A client that cannot receive unicast IP datagrams until its protocol | |||
587 | software has been configured with an IP address SHOULD set the | |||
588 | BROADCAST bit in the 'flags' field to 1 in any DHCPDISCOVER or | |||
589 | DHCPREQUEST messages that client sends. The BROADCAST bit will | |||
590 | provide a hint to the DHCP server and BOOTP relay agent to broadcast | |||
591 | any messages to the client on the client's subnet. | |||
592 | ||||
593 | Note: some interfaces needs this to be enabled, but some networks | |||
594 | needs this to be disabled as broadcasts are filteretd, so this | |||
595 | needs to be configurable */ | |||
596 | if (client->request_broadcast || client->arp_type != ARPHRD_ETHER1) | |||
597 | packet->dhcp.flags = htobe16(0x8000); | |||
598 | ||||
599 | /* RFC2132 section 4.1.1: | |||
600 | The client MUST include its hardware address in the ’chaddr’ field, if | |||
601 | necessary for delivery of DHCP reply messages. Non-Ethernet | |||
602 | interfaces will leave 'chaddr' empty and use the client identifier | |||
603 | instead (eg, RFC 4390 section 2.1). | |||
604 | */ | |||
605 | if (client->arp_type == ARPHRD_ETHER1) | |||
606 | memcpy(&packet->dhcp.chaddr, &client->mac_addr, ETH_ALEN6); | |||
607 | ||||
608 | /* If no client identifier exists, construct an RFC 4361-compliant one */ | |||
609 | if (client->client_id_len == 0) { | |||
610 | size_t duid_len; | |||
611 | ||||
612 | client->client_id.type = 255; | |||
613 | ||||
614 | r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr, client->mac_addr_len, &client->client_id.ns.iaid); | |||
615 | if (r < 0) | |||
616 | return r; | |||
617 | ||||
618 | r = dhcp_identifier_set_duid_en(&client->client_id.ns.duid, &duid_len); | |||
619 | if (r < 0) | |||
620 | return r; | |||
621 | ||||
622 | client->client_id_len = sizeof(client->client_id.type) + sizeof(client->client_id.ns.iaid) + duid_len; | |||
623 | } | |||
624 | ||||
625 | /* Some DHCP servers will refuse to issue an DHCP lease if the Client | |||
626 | Identifier option is not set */ | |||
627 | if (client->client_id_len) { | |||
628 | r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0, | |||
629 | SD_DHCP_OPTION_CLIENT_IDENTIFIER, | |||
630 | client->client_id_len, | |||
631 | &client->client_id); | |||
632 | if (r < 0) | |||
633 | return r; | |||
634 | } | |||
635 | ||||
636 | /* RFC2131 section 3.5: | |||
637 | in its initial DHCPDISCOVER or DHCPREQUEST message, a | |||
638 | client may provide the server with a list of specific | |||
639 | parameters the client is interested in. If the client | |||
640 | includes a list of parameters in a DHCPDISCOVER message, | |||
641 | it MUST include that list in any subsequent DHCPREQUEST | |||
642 | messages. | |||
643 | */ | |||
644 | ||||
645 | /* RFC7844 section 3: | |||
646 | MAY contain the Parameter Request List option. */ | |||
647 | /* NOTE: in case that there would be an option to do not send | |||
648 | * any PRL at all, the size should be checked before sending */ | |||
649 | if (client->req_opts_size > 0) { | |||
650 | r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0, | |||
651 | SD_DHCP_OPTION_PARAMETER_REQUEST_LIST, | |||
652 | client->req_opts_size, client->req_opts); | |||
653 | if (r < 0) | |||
654 | return r; | |||
655 | } | |||
656 | ||||
657 | /* RFC2131 section 3.5: | |||
658 | The client SHOULD include the ’maximum DHCP message size’ option to | |||
659 | let the server know how large the server may make its DHCP messages. | |||
660 | ||||
661 | Note (from ConnMan): Some DHCP servers will send bigger DHCP packets | |||
662 | than the defined default size unless the Maximum Messge Size option | |||
663 | is explicitly set | |||
664 | ||||
665 | RFC3442 "Requirements to Avoid Sizing Constraints": | |||
666 | Because a full routing table can be quite large, the standard 576 | |||
667 | octet maximum size for a DHCP message may be too short to contain | |||
668 | some legitimate Classless Static Route options. Because of this, | |||
669 | clients implementing the Classless Static Route option SHOULD send a | |||
670 | Maximum DHCP Message Size [4] option if the DHCP client's TCP/IP | |||
671 | stack is capable of receiving larger IP datagrams. In this case, the | |||
672 | client SHOULD set the value of this option to at least the MTU of the | |||
673 | interface that the client is configuring. The client MAY set the | |||
674 | value of this option higher, up to the size of the largest UDP packet | |||
675 | it is prepared to accept. (Note that the value specified in the | |||
676 | Maximum DHCP Message Size option is the total maximum packet size, | |||
677 | including IP and UDP headers.) | |||
678 | */ | |||
679 | /* RFC7844 section 3: | |||
680 | SHOULD NOT contain any other option. */ | |||
681 | if (!client->anonymize) { | |||
682 | max_size = htobe16(size); | |||
683 | r = dhcp_option_append(&packet->dhcp, client->mtu, &optoffset, 0, | |||
684 | SD_DHCP_OPTION_MAXIMUM_MESSAGE_SIZE, | |||
685 | 2, &max_size); | |||
686 | if (r < 0) | |||
687 | return r; | |||
688 | } | |||
689 | ||||
690 | *_optlen = optlen; | |||
691 | *_optoffset = optoffset; | |||
692 | *ret = TAKE_PTR(packet)({ typeof(packet) _ptr_ = (packet); (packet) = ((void*)0); _ptr_ ; }); | |||
693 | ||||
694 | return 0; | |||
695 | } | |||
696 | ||||
697 | static int client_append_fqdn_option( | |||
698 | DHCPMessage *message, | |||
699 | size_t optlen, | |||
700 | size_t *optoffset, | |||
701 | const char *fqdn) { | |||
702 | ||||
703 | uint8_t buffer[3 + DHCP_MAX_FQDN_LENGTH255]; | |||
704 | int r; | |||
705 | ||||
706 | buffer[0] = DHCP_FQDN_FLAG_S | /* Request server to perform A RR DNS updates */ | |||
707 | DHCP_FQDN_FLAG_E; /* Canonical wire format */ | |||
708 | buffer[1] = 0; /* RCODE1 (deprecated) */ | |||
709 | buffer[2] = 0; /* RCODE2 (deprecated) */ | |||
710 | ||||
711 | r = dns_name_to_wire_format(fqdn, buffer + 3, sizeof(buffer) - 3, false0); | |||
712 | if (r > 0) | |||
713 | r = dhcp_option_append(message, optlen, optoffset, 0, | |||
714 | SD_DHCP_OPTION_FQDN, 3 + r, buffer); | |||
715 | ||||
716 | return r; | |||
717 | } | |||
718 | ||||
719 | static int dhcp_client_send_raw( | |||
720 | sd_dhcp_client *client, | |||
721 | DHCPPacket *packet, | |||
722 | size_t len) { | |||
723 | ||||
724 | dhcp_packet_append_ip_headers(packet, INADDR_ANY((in_addr_t) 0x00000000), client->port, | |||
725 | INADDR_BROADCAST((in_addr_t) 0xffffffff), DHCP_PORT_SERVER, len); | |||
726 | ||||
727 | return dhcp_network_send_raw_socket(client->fd, &client->link, | |||
728 | packet, len); | |||
729 | } | |||
730 | ||||
731 | static int client_send_discover(sd_dhcp_client *client) { | |||
732 | _cleanup_free___attribute__((cleanup(freep))) DHCPPacket *discover = NULL((void*)0); | |||
733 | size_t optoffset, optlen; | |||
734 | int r; | |||
735 | ||||
736 | assert(client)do { if ((__builtin_expect(!!(!(client)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("client"), "../src/libsystemd-network/sd-dhcp-client.c" , 736, __PRETTY_FUNCTION__); } while (0); | |||
737 | assert(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_SELECTING))do { if ((__builtin_expect(!!(!(({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended[20 - sizeof((int[]){DHCP_STATE_INIT, DHCP_STATE_SELECTING})/sizeof (int)]; switch(client->state) { case DHCP_STATE_INIT: case DHCP_STATE_SELECTING: _found = 1; break; default: break; } _found ; }))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_SELECTING)" ), "../src/libsystemd-network/sd-dhcp-client.c", 737, __PRETTY_FUNCTION__ ); } while (0); | |||
738 | ||||
739 | r = client_message_init(client, &discover, DHCP_DISCOVER, | |||
740 | &optlen, &optoffset); | |||
741 | if (r < 0) | |||
742 | return r; | |||
743 | ||||
744 | /* the client may suggest values for the network address | |||
745 | and lease time in the DHCPDISCOVER message. The client may include | |||
746 | the ’requested IP address’ option to suggest that a particular IP | |||
747 | address be assigned, and may include the ’IP address lease time’ | |||
748 | option to suggest the lease time it would like. | |||
749 | */ | |||
750 | if (client->last_addr != INADDR_ANY((in_addr_t) 0x00000000)) { | |||
751 | r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0, | |||
752 | SD_DHCP_OPTION_REQUESTED_IP_ADDRESS, | |||
753 | 4, &client->last_addr); | |||
754 | if (r < 0) | |||
755 | return r; | |||
756 | } | |||
757 | ||||
758 | if (client->hostname) { | |||
759 | /* According to RFC 4702 "clients that send the Client FQDN option in | |||
760 | their messages MUST NOT also send the Host Name option". Just send | |||
761 | one of the two depending on the hostname type. | |||
762 | */ | |||
763 | if (dns_name_is_single_label(client->hostname)) { | |||
764 | /* it is unclear from RFC 2131 if client should send hostname in | |||
765 | DHCPDISCOVER but dhclient does and so we do as well | |||
766 | */ | |||
767 | r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0, | |||
768 | SD_DHCP_OPTION_HOST_NAME, | |||
769 | strlen(client->hostname), client->hostname); | |||
770 | } else | |||
771 | r = client_append_fqdn_option(&discover->dhcp, optlen, &optoffset, | |||
772 | client->hostname); | |||
773 | if (r < 0) | |||
774 | return r; | |||
775 | } | |||
776 | ||||
777 | if (client->vendor_class_identifier) { | |||
778 | r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0, | |||
779 | SD_DHCP_OPTION_VENDOR_CLASS_IDENTIFIER, | |||
780 | strlen(client->vendor_class_identifier), | |||
781 | client->vendor_class_identifier); | |||
782 | if (r < 0) | |||
783 | return r; | |||
784 | } | |||
785 | ||||
786 | if (client->user_class) { | |||
787 | r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0, | |||
788 | SD_DHCP_OPTION_USER_CLASS, | |||
789 | strv_length(client->user_class), | |||
790 | client->user_class); | |||
791 | if (r < 0) | |||
792 | return r; | |||
793 | } | |||
794 | ||||
795 | r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0, | |||
796 | SD_DHCP_OPTION_END, 0, NULL((void*)0)); | |||
797 | if (r < 0) | |||
798 | return r; | |||
799 | ||||
800 | /* We currently ignore: | |||
801 | The client SHOULD wait a random time between one and ten seconds to | |||
802 | desynchronize the use of DHCP at startup. | |||
803 | */ | |||
804 | r = dhcp_client_send_raw(client, discover, sizeof(DHCPPacket) + optoffset); | |||
805 | if (r < 0) | |||
806 | return r; | |||
807 | ||||
808 | log_dhcp_client(client, "DISCOVER")log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/libsystemd-network/sd-dhcp-client.c", 808, __func__ , "DHCP CLIENT (0x%x): " "DISCOVER", client->xid); | |||
809 | ||||
810 | return 0; | |||
811 | } | |||
812 | ||||
813 | static int client_send_request(sd_dhcp_client *client) { | |||
814 | _cleanup_free___attribute__((cleanup(freep))) DHCPPacket *request = NULL((void*)0); | |||
815 | size_t optoffset, optlen; | |||
816 | int r; | |||
817 | ||||
818 | assert(client)do { if ((__builtin_expect(!!(!(client)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("client"), "../src/libsystemd-network/sd-dhcp-client.c" , 818, __PRETTY_FUNCTION__); } while (0); | |||
819 | ||||
820 | r = client_message_init(client, &request, DHCP_REQUEST, &optlen, &optoffset); | |||
821 | if (r < 0) | |||
822 | return r; | |||
823 | ||||
824 | switch (client->state) { | |||
825 | /* See RFC2131 section 4.3.2 (note that there is a typo in the RFC, | |||
826 | SELECTING should be REQUESTING) | |||
827 | */ | |||
828 | ||||
829 | case DHCP_STATE_REQUESTING: | |||
830 | /* Client inserts the address of the selected server in ’server | |||
831 | identifier’, ’ciaddr’ MUST be zero, ’requested IP address’ MUST be | |||
832 | filled in with the yiaddr value from the chosen DHCPOFFER. | |||
833 | */ | |||
834 | ||||
835 | r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0, | |||
836 | SD_DHCP_OPTION_SERVER_IDENTIFIER, | |||
837 | 4, &client->lease->server_address); | |||
838 | if (r < 0) | |||
839 | return r; | |||
840 | ||||
841 | r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0, | |||
842 | SD_DHCP_OPTION_REQUESTED_IP_ADDRESS, | |||
843 | 4, &client->lease->address); | |||
844 | if (r < 0) | |||
845 | return r; | |||
846 | ||||
847 | break; | |||
848 | ||||
849 | case DHCP_STATE_INIT_REBOOT: | |||
850 | /* ’server identifier’ MUST NOT be filled in, ’requested IP address’ | |||
851 | option MUST be filled in with client’s notion of its previously | |||
852 | assigned address. ’ciaddr’ MUST be zero. | |||
853 | */ | |||
854 | r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0, | |||
855 | SD_DHCP_OPTION_REQUESTED_IP_ADDRESS, | |||
856 | 4, &client->last_addr); | |||
857 | if (r < 0) | |||
858 | return r; | |||
859 | break; | |||
860 | ||||
861 | case DHCP_STATE_RENEWING: | |||
862 | /* ’server identifier’ MUST NOT be filled in, ’requested IP address’ | |||
863 | option MUST NOT be filled in, ’ciaddr’ MUST be filled in with | |||
864 | client’s IP address. | |||
865 | */ | |||
866 | ||||
867 | case DHCP_STATE_REBINDING: | |||
868 | /* ’server identifier’ MUST NOT be filled in, ’requested IP address’ | |||
869 | option MUST NOT be filled in, ’ciaddr’ MUST be filled in with | |||
870 | client’s IP address. | |||
871 | ||||
872 | This message MUST be broadcast to the 0xffffffff IP broadcast address. | |||
873 | */ | |||
874 | request->dhcp.ciaddr = client->lease->address; | |||
875 | ||||
876 | break; | |||
877 | ||||
878 | case DHCP_STATE_INIT: | |||
879 | case DHCP_STATE_SELECTING: | |||
880 | case DHCP_STATE_REBOOTING: | |||
881 | case DHCP_STATE_BOUND: | |||
882 | case DHCP_STATE_STOPPED: | |||
883 | return -EINVAL22; | |||
884 | } | |||
885 | ||||
886 | if (client->hostname) { | |||
887 | if (dns_name_is_single_label(client->hostname)) | |||
888 | r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0, | |||
889 | SD_DHCP_OPTION_HOST_NAME, | |||
890 | strlen(client->hostname), client->hostname); | |||
891 | else | |||
892 | r = client_append_fqdn_option(&request->dhcp, optlen, &optoffset, | |||
893 | client->hostname); | |||
894 | if (r < 0) | |||
895 | return r; | |||
896 | } | |||
897 | ||||
898 | if (client->vendor_class_identifier) { | |||
899 | r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0, | |||
900 | SD_DHCP_OPTION_VENDOR_CLASS_IDENTIFIER, | |||
901 | strlen(client->vendor_class_identifier), | |||
902 | client->vendor_class_identifier); | |||
903 | if (r < 0) | |||
904 | return r; | |||
905 | } | |||
906 | ||||
907 | r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0, | |||
908 | SD_DHCP_OPTION_END, 0, NULL((void*)0)); | |||
909 | if (r < 0) | |||
910 | return r; | |||
911 | ||||
912 | if (client->state == DHCP_STATE_RENEWING) { | |||
913 | r = dhcp_network_send_udp_socket(client->fd, | |||
914 | client->lease->server_address, | |||
915 | DHCP_PORT_SERVER, | |||
916 | &request->dhcp, | |||
917 | sizeof(DHCPMessage) + optoffset); | |||
918 | } else { | |||
919 | r = dhcp_client_send_raw(client, request, sizeof(DHCPPacket) + optoffset); | |||
920 | } | |||
921 | if (r < 0) | |||
922 | return r; | |||
923 | ||||
924 | switch (client->state) { | |||
925 | ||||
926 | case DHCP_STATE_REQUESTING: | |||
927 | log_dhcp_client(client, "REQUEST (requesting)")log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/libsystemd-network/sd-dhcp-client.c", 927, __func__ , "DHCP CLIENT (0x%x): " "REQUEST (requesting)", client->xid ); | |||
928 | break; | |||
929 | ||||
930 | case DHCP_STATE_INIT_REBOOT: | |||
931 | log_dhcp_client(client, "REQUEST (init-reboot)")log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/libsystemd-network/sd-dhcp-client.c", 931, __func__ , "DHCP CLIENT (0x%x): " "REQUEST (init-reboot)", client-> xid); | |||
932 | break; | |||
933 | ||||
934 | case DHCP_STATE_RENEWING: | |||
935 | log_dhcp_client(client, "REQUEST (renewing)")log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/libsystemd-network/sd-dhcp-client.c", 935, __func__ , "DHCP CLIENT (0x%x): " "REQUEST (renewing)", client->xid ); | |||
936 | break; | |||
937 | ||||
938 | case DHCP_STATE_REBINDING: | |||
939 | log_dhcp_client(client, "REQUEST (rebinding)")log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/libsystemd-network/sd-dhcp-client.c", 939, __func__ , "DHCP CLIENT (0x%x): " "REQUEST (rebinding)", client->xid ); | |||
940 | break; | |||
941 | ||||
942 | default: | |||
943 | log_dhcp_client(client, "REQUEST (invalid)")log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/libsystemd-network/sd-dhcp-client.c", 943, __func__ , "DHCP CLIENT (0x%x): " "REQUEST (invalid)", client->xid); | |||
944 | break; | |||
945 | } | |||
946 | ||||
947 | return 0; | |||
948 | } | |||
949 | ||||
950 | static int client_start(sd_dhcp_client *client); | |||
951 | ||||
952 | static int client_timeout_resend( | |||
953 | sd_event_source *s, | |||
954 | uint64_t usec, | |||
955 | void *userdata) { | |||
956 | ||||
957 | sd_dhcp_client *client = userdata; | |||
958 | DHCP_CLIENT_DONT_DESTROY(client)__attribute__((cleanup(sd_dhcp_client_unrefp))) __attribute__ ((unused)) sd_dhcp_client *_dont_destroy_client = sd_dhcp_client_ref (client); | |||
959 | usec_t next_timeout = 0; | |||
960 | uint64_t time_now; | |||
961 | uint32_t time_left; | |||
962 | int r; | |||
963 | ||||
964 | assert(s)do { if ((__builtin_expect(!!(!(s)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("s"), "../src/libsystemd-network/sd-dhcp-client.c" , 964, __PRETTY_FUNCTION__); } while (0); | |||
965 | assert(client)do { if ((__builtin_expect(!!(!(client)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("client"), "../src/libsystemd-network/sd-dhcp-client.c" , 965, __PRETTY_FUNCTION__); } while (0); | |||
966 | assert(client->event)do { if ((__builtin_expect(!!(!(client->event)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("client->event"), "../src/libsystemd-network/sd-dhcp-client.c" , 966, __PRETTY_FUNCTION__); } while (0); | |||
967 | ||||
968 | r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now); | |||
969 | if (r < 0) | |||
970 | goto error; | |||
971 | ||||
972 | switch (client->state) { | |||
973 | ||||
974 | case DHCP_STATE_RENEWING: | |||
975 | ||||
976 | time_left = (client->lease->t2 - client->lease->t1) / 2; | |||
977 | if (time_left < 60) | |||
978 | time_left = 60; | |||
979 | ||||
980 | next_timeout = time_now + time_left * USEC_PER_SEC((usec_t) 1000000ULL); | |||
981 | ||||
982 | break; | |||
983 | ||||
984 | case DHCP_STATE_REBINDING: | |||
985 | ||||
986 | time_left = (client->lease->lifetime - client->lease->t2) / 2; | |||
987 | if (time_left < 60) | |||
988 | time_left = 60; | |||
989 | ||||
990 | next_timeout = time_now + time_left * USEC_PER_SEC((usec_t) 1000000ULL); | |||
991 | break; | |||
992 | ||||
993 | case DHCP_STATE_REBOOTING: | |||
994 | /* start over as we did not receive a timely ack or nak */ | |||
995 | r = client_initialize(client); | |||
996 | if (r < 0) | |||
997 | goto error; | |||
998 | ||||
999 | r = client_start(client); | |||
1000 | if (r < 0) | |||
1001 | goto error; | |||
1002 | else { | |||
1003 | log_dhcp_client(client, "REBOOTED")log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/libsystemd-network/sd-dhcp-client.c", 1003, __func__ , "DHCP CLIENT (0x%x): " "REBOOTED", client->xid); | |||
1004 | return 0; | |||
1005 | } | |||
1006 | ||||
1007 | case DHCP_STATE_INIT: | |||
1008 | case DHCP_STATE_INIT_REBOOT: | |||
1009 | case DHCP_STATE_SELECTING: | |||
1010 | case DHCP_STATE_REQUESTING: | |||
1011 | case DHCP_STATE_BOUND: | |||
1012 | ||||
1013 | if (client->attempt < 64) | |||
1014 | client->attempt *= 2; | |||
1015 | ||||
1016 | next_timeout = time_now + (client->attempt - 1) * USEC_PER_SEC((usec_t) 1000000ULL); | |||
1017 | ||||
1018 | break; | |||
1019 | ||||
1020 | case DHCP_STATE_STOPPED: | |||
1021 | r = -EINVAL22; | |||
1022 | goto error; | |||
1023 | } | |||
1024 | ||||
1025 | next_timeout += (random_u32() & 0x1fffff); | |||
1026 | ||||
1027 | client->timeout_resend = sd_event_source_unref(client->timeout_resend); | |||
1028 | ||||
1029 | r = sd_event_add_time(client->event, | |||
1030 | &client->timeout_resend, | |||
1031 | clock_boottime_or_monotonic(), | |||
1032 | next_timeout, 10 * USEC_PER_MSEC((usec_t) 1000ULL), | |||
1033 | client_timeout_resend, client); | |||
1034 | if (r < 0) | |||
1035 | goto error; | |||
1036 | ||||
1037 | r = sd_event_source_set_priority(client->timeout_resend, | |||
1038 | client->event_priority); | |||
1039 | if (r < 0) | |||
1040 | goto error; | |||
1041 | ||||
1042 | r = sd_event_source_set_description(client->timeout_resend, "dhcp4-resend-timer"); | |||
1043 | if (r < 0) | |||
1044 | goto error; | |||
1045 | ||||
1046 | switch (client->state) { | |||
1047 | case DHCP_STATE_INIT: | |||
1048 | r = client_send_discover(client); | |||
1049 | if (r >= 0) { | |||
1050 | client->state = DHCP_STATE_SELECTING; | |||
1051 | client->attempt = 1; | |||
1052 | } else { | |||
1053 | if (client->attempt >= 64) | |||
1054 | goto error; | |||
1055 | } | |||
1056 | ||||
1057 | break; | |||
1058 | ||||
1059 | case DHCP_STATE_SELECTING: | |||
1060 | r = client_send_discover(client); | |||
1061 | if (r < 0 && client->attempt >= 64) | |||
1062 | goto error; | |||
1063 | ||||
1064 | break; | |||
1065 | ||||
1066 | case DHCP_STATE_INIT_REBOOT: | |||
1067 | case DHCP_STATE_REQUESTING: | |||
1068 | case DHCP_STATE_RENEWING: | |||
1069 | case DHCP_STATE_REBINDING: | |||
1070 | r = client_send_request(client); | |||
1071 | if (r < 0 && client->attempt >= 64) | |||
1072 | goto error; | |||
1073 | ||||
1074 | if (client->state == DHCP_STATE_INIT_REBOOT) | |||
1075 | client->state = DHCP_STATE_REBOOTING; | |||
1076 | ||||
1077 | client->request_sent = time_now; | |||
1078 | ||||
1079 | break; | |||
1080 | ||||
1081 | case DHCP_STATE_REBOOTING: | |||
1082 | case DHCP_STATE_BOUND: | |||
1083 | ||||
1084 | break; | |||
1085 | ||||
1086 | case DHCP_STATE_STOPPED: | |||
1087 | r = -EINVAL22; | |||
1088 | goto error; | |||
1089 | } | |||
1090 | ||||
1091 | return 0; | |||
1092 | ||||
1093 | error: | |||
1094 | client_stop(client, r); | |||
1095 | ||||
1096 | /* Errors were dealt with when stopping the client, don't spill | |||
1097 | errors into the event loop handler */ | |||
1098 | return 0; | |||
1099 | } | |||
1100 | ||||
1101 | static int client_initialize_io_events( | |||
1102 | sd_dhcp_client *client, | |||
1103 | sd_event_io_handler_t io_callback) { | |||
1104 | ||||
1105 | int r; | |||
1106 | ||||
1107 | assert(client)do { if ((__builtin_expect(!!(!(client)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("client"), "../src/libsystemd-network/sd-dhcp-client.c" , 1107, __PRETTY_FUNCTION__); } while (0); | |||
1108 | assert(client->event)do { if ((__builtin_expect(!!(!(client->event)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("client->event"), "../src/libsystemd-network/sd-dhcp-client.c" , 1108, __PRETTY_FUNCTION__); } while (0); | |||
1109 | ||||
1110 | r = sd_event_add_io(client->event, &client->receive_message, | |||
1111 | client->fd, EPOLLINEPOLLIN, io_callback, | |||
1112 | client); | |||
1113 | if (r < 0) | |||
1114 | goto error; | |||
1115 | ||||
1116 | r = sd_event_source_set_priority(client->receive_message, | |||
1117 | client->event_priority); | |||
1118 | if (r < 0) | |||
1119 | goto error; | |||
1120 | ||||
1121 | r = sd_event_source_set_description(client->receive_message, "dhcp4-receive-message"); | |||
1122 | if (r < 0) | |||
1123 | goto error; | |||
1124 | ||||
1125 | error: | |||
1126 | if (r < 0) | |||
1127 | client_stop(client, r); | |||
1128 | ||||
1129 | return 0; | |||
1130 | } | |||
1131 | ||||
1132 | static int client_initialize_time_events(sd_dhcp_client *client) { | |||
1133 | uint64_t usec = 0; | |||
1134 | int r; | |||
1135 | ||||
1136 | assert(client)do { if ((__builtin_expect(!!(!(client)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("client"), "../src/libsystemd-network/sd-dhcp-client.c" , 1136, __PRETTY_FUNCTION__); } while (0); | |||
1137 | assert(client->event)do { if ((__builtin_expect(!!(!(client->event)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("client->event"), "../src/libsystemd-network/sd-dhcp-client.c" , 1137, __PRETTY_FUNCTION__); } while (0); | |||
1138 | ||||
1139 | client->timeout_resend = sd_event_source_unref(client->timeout_resend); | |||
1140 | ||||
1141 | if (client->start_delay) { | |||
1142 | assert_se(sd_event_now(client->event, clock_boottime_or_monotonic(), &usec) >= 0)do { if ((__builtin_expect(!!(!(sd_event_now(client->event , clock_boottime_or_monotonic(), &usec) >= 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("sd_event_now(client->event, clock_boottime_or_monotonic(), &usec) >= 0" ), "../src/libsystemd-network/sd-dhcp-client.c", 1142, __PRETTY_FUNCTION__ ); } while (0); | |||
1143 | usec += client->start_delay; | |||
1144 | } | |||
1145 | ||||
1146 | r = sd_event_add_time(client->event, | |||
1147 | &client->timeout_resend, | |||
1148 | clock_boottime_or_monotonic(), | |||
1149 | usec, 0, | |||
1150 | client_timeout_resend, client); | |||
1151 | if (r < 0) | |||
1152 | goto error; | |||
1153 | ||||
1154 | r = sd_event_source_set_priority(client->timeout_resend, | |||
1155 | client->event_priority); | |||
1156 | if (r < 0) | |||
1157 | goto error; | |||
1158 | ||||
1159 | r = sd_event_source_set_description(client->timeout_resend, "dhcp4-resend-timer"); | |||
1160 | if (r < 0) | |||
1161 | goto error; | |||
1162 | ||||
1163 | error: | |||
1164 | if (r < 0) | |||
1165 | client_stop(client, r); | |||
1166 | ||||
1167 | return 0; | |||
1168 | ||||
1169 | } | |||
1170 | ||||
1171 | static int client_initialize_events(sd_dhcp_client *client, sd_event_io_handler_t io_callback) { | |||
1172 | client_initialize_io_events(client, io_callback); | |||
1173 | client_initialize_time_events(client); | |||
1174 | ||||
1175 | return 0; | |||
1176 | } | |||
1177 | ||||
1178 | static int client_start_delayed(sd_dhcp_client *client) { | |||
1179 | int r; | |||
1180 | ||||
1181 | assert_return(client, -EINVAL)do { if (!(((__builtin_expect(!!(client),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("client"), "../src/libsystemd-network/sd-dhcp-client.c" , 1181, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
1182 | assert_return(client->event, -EINVAL)do { if (!(((__builtin_expect(!!(client->event),1))) ? (1) : (log_assert_failed_return_realm(LOG_REALM_SYSTEMD, ("client->event" ), "../src/libsystemd-network/sd-dhcp-client.c", 1182, __PRETTY_FUNCTION__ ), 0))) return (-22); } while (0); | |||
1183 | assert_return(client->ifindex > 0, -EINVAL)do { if (!(((__builtin_expect(!!(client->ifindex > 0),1 ))) ? (1) : (log_assert_failed_return_realm(LOG_REALM_SYSTEMD , ("client->ifindex > 0"), "../src/libsystemd-network/sd-dhcp-client.c" , 1183, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
1184 | assert_return(client->fd < 0, -EBUSY)do { if (!(((__builtin_expect(!!(client->fd < 0),1))) ? (1) : (log_assert_failed_return_realm(LOG_REALM_SYSTEMD, ("client->fd < 0" ), "../src/libsystemd-network/sd-dhcp-client.c", 1184, __PRETTY_FUNCTION__ ), 0))) return (-16); } while (0); | |||
1185 | assert_return(client->xid == 0, -EINVAL)do { if (!(((__builtin_expect(!!(client->xid == 0),1))) ? ( 1) : (log_assert_failed_return_realm(LOG_REALM_SYSTEMD, ("client->xid == 0" ), "../src/libsystemd-network/sd-dhcp-client.c", 1185, __PRETTY_FUNCTION__ ), 0))) return (-22); } while (0); | |||
1186 | assert_return(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_INIT_REBOOT), -EBUSY)do { if (!(((__builtin_expect(!!(({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended[20 - sizeof((int[]){DHCP_STATE_INIT, DHCP_STATE_INIT_REBOOT})/sizeof (int)]; switch(client->state) { case DHCP_STATE_INIT: case DHCP_STATE_INIT_REBOOT: _found = 1; break; default: break; } _found; })),1))) ? (1) : (log_assert_failed_return_realm(LOG_REALM_SYSTEMD , ("IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_INIT_REBOOT)" ), "../src/libsystemd-network/sd-dhcp-client.c", 1186, __PRETTY_FUNCTION__ ), 0))) return (-16); } while (0); | |||
1187 | ||||
1188 | client->xid = random_u32(); | |||
1189 | ||||
1190 | r = dhcp_network_bind_raw_socket(client->ifindex, &client->link, | |||
1191 | client->xid, client->mac_addr, | |||
1192 | client->mac_addr_len, client->arp_type, client->port); | |||
1193 | if (r < 0) { | |||
1194 | client_stop(client, r); | |||
1195 | return r; | |||
1196 | } | |||
1197 | client->fd = r; | |||
1198 | ||||
1199 | if (IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_INIT_REBOOT)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){DHCP_STATE_INIT, DHCP_STATE_INIT_REBOOT} )/sizeof(int)]; switch(client->state) { case DHCP_STATE_INIT : case DHCP_STATE_INIT_REBOOT: _found = 1; break; default: break ; } _found; })) | |||
1200 | client->start_time = now(clock_boottime_or_monotonic()); | |||
1201 | ||||
1202 | return client_initialize_events(client, client_receive_message_raw); | |||
1203 | } | |||
1204 | ||||
1205 | static int client_start(sd_dhcp_client *client) { | |||
1206 | client->start_delay = 0; | |||
1207 | return client_start_delayed(client); | |||
1208 | } | |||
1209 | ||||
1210 | static int client_timeout_expire(sd_event_source *s, uint64_t usec, void *userdata) { | |||
1211 | sd_dhcp_client *client = userdata; | |||
1212 | DHCP_CLIENT_DONT_DESTROY(client)__attribute__((cleanup(sd_dhcp_client_unrefp))) __attribute__ ((unused)) sd_dhcp_client *_dont_destroy_client = sd_dhcp_client_ref (client); | |||
1213 | ||||
1214 | log_dhcp_client(client, "EXPIRED")log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/libsystemd-network/sd-dhcp-client.c", 1214, __func__ , "DHCP CLIENT (0x%x): " "EXPIRED", client->xid); | |||
1215 | ||||
1216 | client_notify(client, SD_DHCP_CLIENT_EVENT_EXPIRED); | |||
1217 | ||||
1218 | /* lease was lost, start over if not freed or stopped in callback */ | |||
1219 | if (client->state != DHCP_STATE_STOPPED) { | |||
1220 | client_initialize(client); | |||
1221 | client_start(client); | |||
1222 | } | |||
1223 | ||||
1224 | return 0; | |||
1225 | } | |||
1226 | ||||
1227 | static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata) { | |||
1228 | sd_dhcp_client *client = userdata; | |||
1229 | DHCP_CLIENT_DONT_DESTROY(client)__attribute__((cleanup(sd_dhcp_client_unrefp))) __attribute__ ((unused)) sd_dhcp_client *_dont_destroy_client = sd_dhcp_client_ref (client); | |||
1230 | int r; | |||
1231 | ||||
1232 | assert(client)do { if ((__builtin_expect(!!(!(client)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("client"), "../src/libsystemd-network/sd-dhcp-client.c" , 1232, __PRETTY_FUNCTION__); } while (0); | |||
1233 | ||||
1234 | client->receive_message = sd_event_source_unref(client->receive_message); | |||
1235 | client->fd = asynchronous_close(client->fd); | |||
1236 | ||||
1237 | client->state = DHCP_STATE_REBINDING; | |||
1238 | client->attempt = 1; | |||
1239 | ||||
1240 | r = dhcp_network_bind_raw_socket(client->ifindex, &client->link, | |||
1241 | client->xid, client->mac_addr, | |||
1242 | client->mac_addr_len, client->arp_type, | |||
1243 | client->port); | |||
1244 | if (r < 0) { | |||
1245 | client_stop(client, r); | |||
1246 | return 0; | |||
1247 | } | |||
1248 | client->fd = r; | |||
1249 | ||||
1250 | return client_initialize_events(client, client_receive_message_raw); | |||
1251 | } | |||
1252 | ||||
1253 | static int client_timeout_t1(sd_event_source *s, uint64_t usec, void *userdata) { | |||
1254 | sd_dhcp_client *client = userdata; | |||
1255 | DHCP_CLIENT_DONT_DESTROY(client)__attribute__((cleanup(sd_dhcp_client_unrefp))) __attribute__ ((unused)) sd_dhcp_client *_dont_destroy_client = sd_dhcp_client_ref (client); | |||
1256 | ||||
1257 | client->state = DHCP_STATE_RENEWING; | |||
1258 | client->attempt = 1; | |||
1259 | ||||
1260 | return client_initialize_time_events(client); | |||
1261 | } | |||
1262 | ||||
1263 | static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer, size_t len) { | |||
1264 | _cleanup_(sd_dhcp_lease_unrefp)__attribute__((cleanup(sd_dhcp_lease_unrefp))) sd_dhcp_lease *lease = NULL((void*)0); | |||
1265 | int r; | |||
1266 | ||||
1267 | r = dhcp_lease_new(&lease); | |||
1268 | if (r < 0) | |||
1269 | return r; | |||
1270 | ||||
1271 | if (client->client_id_len) { | |||
1272 | r = dhcp_lease_set_client_id(lease, | |||
1273 | (uint8_t *) &client->client_id, | |||
1274 | client->client_id_len); | |||
1275 | if (r < 0) | |||
1276 | return r; | |||
1277 | } | |||
1278 | ||||
1279 | r = dhcp_option_parse(offer, len, dhcp_lease_parse_options, lease, NULL((void*)0)); | |||
1280 | if (r != DHCP_OFFER) { | |||
1281 | log_dhcp_client(client, "received message was not an OFFER, ignoring")log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/libsystemd-network/sd-dhcp-client.c", 1281, __func__ , "DHCP CLIENT (0x%x): " "received message was not an OFFER, ignoring" , client->xid); | |||
1282 | return -ENOMSG42; | |||
1283 | } | |||
1284 | ||||
1285 | lease->next_server = offer->siaddr; | |||
1286 | lease->address = offer->yiaddr; | |||
1287 | ||||
1288 | if (lease->address == 0 || | |||
1289 | lease->server_address == 0 || | |||
1290 | lease->lifetime == 0) { | |||
1291 | log_dhcp_client(client, "received lease lacks address, server address or lease lifetime, ignoring")log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/libsystemd-network/sd-dhcp-client.c", 1291, __func__ , "DHCP CLIENT (0x%x): " "received lease lacks address, server address or lease lifetime, ignoring" , client->xid); | |||
1292 | return -ENOMSG42; | |||
1293 | } | |||
1294 | ||||
1295 | if (!lease->have_subnet_mask) { | |||
1296 | r = dhcp_lease_set_default_subnet_mask(lease); | |||
1297 | if (r < 0) { | |||
1298 | log_dhcp_client(client,log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/libsystemd-network/sd-dhcp-client.c", 1300, __func__ , "DHCP CLIENT (0x%x): " "received lease lacks subnet mask, " "and a fallback one cannot be generated, ignoring", client-> xid) | |||
1299 | "received lease lacks subnet mask, "log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/libsystemd-network/sd-dhcp-client.c", 1300, __func__ , "DHCP CLIENT (0x%x): " "received lease lacks subnet mask, " "and a fallback one cannot be generated, ignoring", client-> xid) | |||
1300 | "and a fallback one cannot be generated, ignoring")log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/libsystemd-network/sd-dhcp-client.c", 1300, __func__ , "DHCP CLIENT (0x%x): " "received lease lacks subnet mask, " "and a fallback one cannot be generated, ignoring", client-> xid); | |||
1301 | return -ENOMSG42; | |||
1302 | } | |||
1303 | } | |||
1304 | ||||
1305 | sd_dhcp_lease_unref(client->lease); | |||
1306 | client->lease = TAKE_PTR(lease)({ typeof(lease) _ptr_ = (lease); (lease) = ((void*)0); _ptr_ ; }); | |||
1307 | ||||
1308 | log_dhcp_client(client, "OFFER")log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/libsystemd-network/sd-dhcp-client.c", 1308, __func__ , "DHCP CLIENT (0x%x): " "OFFER", client->xid); | |||
1309 | ||||
1310 | return 0; | |||
1311 | } | |||
1312 | ||||
1313 | static int client_handle_forcerenew(sd_dhcp_client *client, DHCPMessage *force, size_t len) { | |||
1314 | int r; | |||
1315 | ||||
1316 | r = dhcp_option_parse(force, len, NULL((void*)0), NULL((void*)0), NULL((void*)0)); | |||
1317 | if (r != DHCP_FORCERENEW) | |||
1318 | return -ENOMSG42; | |||
1319 | ||||
1320 | log_dhcp_client(client, "FORCERENEW")log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/libsystemd-network/sd-dhcp-client.c", 1320, __func__ , "DHCP CLIENT (0x%x): " "FORCERENEW", client->xid); | |||
1321 | ||||
1322 | return 0; | |||
1323 | } | |||
1324 | ||||
1325 | static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack, size_t len) { | |||
1326 | _cleanup_(sd_dhcp_lease_unrefp)__attribute__((cleanup(sd_dhcp_lease_unrefp))) sd_dhcp_lease *lease = NULL((void*)0); | |||
1327 | _cleanup_free___attribute__((cleanup(freep))) char *error_message = NULL((void*)0); | |||
1328 | int r; | |||
1329 | ||||
1330 | r = dhcp_lease_new(&lease); | |||
1331 | if (r < 0) | |||
1332 | return r; | |||
1333 | ||||
1334 | if (client->client_id_len) { | |||
1335 | r = dhcp_lease_set_client_id(lease, | |||
1336 | (uint8_t *) &client->client_id, | |||
1337 | client->client_id_len); | |||
1338 | if (r < 0) | |||
1339 | return r; | |||
1340 | } | |||
1341 | ||||
1342 | r = dhcp_option_parse(ack, len, dhcp_lease_parse_options, lease, &error_message); | |||
1343 | if (r == DHCP_NAK) { | |||
1344 | log_dhcp_client(client, "NAK: %s", strna(error_message))log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/libsystemd-network/sd-dhcp-client.c", 1344, __func__ , "DHCP CLIENT (0x%x): " "NAK: %s", client->xid, strna(error_message )); | |||
1345 | return -EADDRNOTAVAIL99; | |||
1346 | } | |||
1347 | ||||
1348 | if (r != DHCP_ACK) { | |||
1349 | log_dhcp_client(client, "received message was not an ACK, ignoring")log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/libsystemd-network/sd-dhcp-client.c", 1349, __func__ , "DHCP CLIENT (0x%x): " "received message was not an ACK, ignoring" , client->xid); | |||
1350 | return -ENOMSG42; | |||
1351 | } | |||
1352 | ||||
1353 | lease->next_server = ack->siaddr; | |||
1354 | ||||
1355 | lease->address = ack->yiaddr; | |||
1356 | ||||
1357 | if (lease->address == INADDR_ANY((in_addr_t) 0x00000000) || | |||
1358 | lease->server_address == INADDR_ANY((in_addr_t) 0x00000000) || | |||
1359 | lease->lifetime == 0) { | |||
1360 | log_dhcp_client(client, "received lease lacks address, server "log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/libsystemd-network/sd-dhcp-client.c", 1361, __func__ , "DHCP CLIENT (0x%x): " "received lease lacks address, server " "address or lease lifetime, ignoring", client->xid) | |||
1361 | "address or lease lifetime, ignoring")log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/libsystemd-network/sd-dhcp-client.c", 1361, __func__ , "DHCP CLIENT (0x%x): " "received lease lacks address, server " "address or lease lifetime, ignoring", client->xid); | |||
1362 | return -ENOMSG42; | |||
1363 | } | |||
1364 | ||||
1365 | if (lease->subnet_mask == INADDR_ANY((in_addr_t) 0x00000000)) { | |||
1366 | r = dhcp_lease_set_default_subnet_mask(lease); | |||
1367 | if (r < 0) { | |||
1368 | log_dhcp_client(client,log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/libsystemd-network/sd-dhcp-client.c", 1370, __func__ , "DHCP CLIENT (0x%x): " "received lease lacks subnet mask, " "and a fallback one cannot be generated, ignoring", client-> xid) | |||
1369 | "received lease lacks subnet mask, "log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/libsystemd-network/sd-dhcp-client.c", 1370, __func__ , "DHCP CLIENT (0x%x): " "received lease lacks subnet mask, " "and a fallback one cannot be generated, ignoring", client-> xid) | |||
1370 | "and a fallback one cannot be generated, ignoring")log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/libsystemd-network/sd-dhcp-client.c", 1370, __func__ , "DHCP CLIENT (0x%x): " "received lease lacks subnet mask, " "and a fallback one cannot be generated, ignoring", client-> xid); | |||
1371 | return -ENOMSG42; | |||
1372 | } | |||
1373 | } | |||
1374 | ||||
1375 | r = SD_DHCP_CLIENT_EVENT_IP_ACQUIRE; | |||
1376 | if (client->lease) { | |||
1377 | if (client->lease->address != lease->address || | |||
1378 | client->lease->subnet_mask != lease->subnet_mask || | |||
1379 | client->lease->router != lease->router) { | |||
1380 | r = SD_DHCP_CLIENT_EVENT_IP_CHANGE; | |||
1381 | } else | |||
1382 | r = SD_DHCP_CLIENT_EVENT_RENEW; | |||
1383 | ||||
1384 | client->lease = sd_dhcp_lease_unref(client->lease); | |||
1385 | } | |||
1386 | ||||
1387 | client->lease = TAKE_PTR(lease)({ typeof(lease) _ptr_ = (lease); (lease) = ((void*)0); _ptr_ ; }); | |||
1388 | ||||
1389 | log_dhcp_client(client, "ACK")log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/libsystemd-network/sd-dhcp-client.c", 1389, __func__ , "DHCP CLIENT (0x%x): " "ACK", client->xid); | |||
1390 | ||||
1391 | return r; | |||
1392 | } | |||
1393 | ||||
1394 | static uint64_t client_compute_timeout(sd_dhcp_client *client, uint32_t lifetime, double factor) { | |||
1395 | assert(client)do { if ((__builtin_expect(!!(!(client)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("client"), "../src/libsystemd-network/sd-dhcp-client.c" , 1395, __PRETTY_FUNCTION__); } while (0); | |||
1396 | assert(client->request_sent)do { if ((__builtin_expect(!!(!(client->request_sent)),0)) ) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("client->request_sent" ), "../src/libsystemd-network/sd-dhcp-client.c", 1396, __PRETTY_FUNCTION__ ); } while (0); | |||
1397 | assert(lifetime > 0)do { if ((__builtin_expect(!!(!(lifetime > 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("lifetime > 0"), "../src/libsystemd-network/sd-dhcp-client.c" , 1397, __PRETTY_FUNCTION__); } while (0); | |||
1398 | ||||
1399 | if (lifetime > 3) | |||
1400 | lifetime -= 3; | |||
1401 | else | |||
1402 | lifetime = 0; | |||
1403 | ||||
1404 | return client->request_sent + (lifetime * USEC_PER_SEC((usec_t) 1000000ULL) * factor) + | |||
1405 | + (random_u32() & 0x1fffff); | |||
1406 | } | |||
1407 | ||||
1408 | static int client_set_lease_timeouts(sd_dhcp_client *client) { | |||
1409 | usec_t time_now; | |||
1410 | uint64_t lifetime_timeout; | |||
1411 | uint64_t t2_timeout; | |||
1412 | uint64_t t1_timeout; | |||
1413 | char time_string[FORMAT_TIMESPAN_MAX64]; | |||
1414 | int r; | |||
1415 | ||||
1416 | assert(client)do { if ((__builtin_expect(!!(!(client)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("client"), "../src/libsystemd-network/sd-dhcp-client.c" , 1416, __PRETTY_FUNCTION__); } while (0); | |||
1417 | assert(client->event)do { if ((__builtin_expect(!!(!(client->event)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("client->event"), "../src/libsystemd-network/sd-dhcp-client.c" , 1417, __PRETTY_FUNCTION__); } while (0); | |||
1418 | assert(client->lease)do { if ((__builtin_expect(!!(!(client->lease)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("client->lease"), "../src/libsystemd-network/sd-dhcp-client.c" , 1418, __PRETTY_FUNCTION__); } while (0); | |||
1419 | assert(client->lease->lifetime)do { if ((__builtin_expect(!!(!(client->lease->lifetime )),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("client->lease->lifetime" ), "../src/libsystemd-network/sd-dhcp-client.c", 1419, __PRETTY_FUNCTION__ ); } while (0); | |||
1420 | ||||
1421 | client->timeout_t1 = sd_event_source_unref(client->timeout_t1); | |||
1422 | client->timeout_t2 = sd_event_source_unref(client->timeout_t2); | |||
1423 | client->timeout_expire = sd_event_source_unref(client->timeout_expire); | |||
1424 | ||||
1425 | /* don't set timers for infinite leases */ | |||
1426 | if (client->lease->lifetime == 0xffffffff) | |||
1427 | return 0; | |||
1428 | ||||
1429 | r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now); | |||
1430 | if (r < 0) | |||
1431 | return r; | |||
1432 | assert(client->request_sent <= time_now)do { if ((__builtin_expect(!!(!(client->request_sent <= time_now)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ( "client->request_sent <= time_now"), "../src/libsystemd-network/sd-dhcp-client.c" , 1432, __PRETTY_FUNCTION__); } while (0); | |||
1433 | ||||
1434 | /* convert the various timeouts from relative (secs) to absolute (usecs) */ | |||
1435 | lifetime_timeout = client_compute_timeout(client, client->lease->lifetime, 1); | |||
1436 | if (client->lease->t1 > 0 && client->lease->t2 > 0) { | |||
1437 | /* both T1 and T2 are given */ | |||
1438 | if (client->lease->t1 < client->lease->t2 && | |||
1439 | client->lease->t2 < client->lease->lifetime) { | |||
1440 | /* they are both valid */ | |||
1441 | t2_timeout = client_compute_timeout(client, client->lease->t2, 1); | |||
1442 | t1_timeout = client_compute_timeout(client, client->lease->t1, 1); | |||
1443 | } else { | |||
1444 | /* discard both */ | |||
1445 | t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0); | |||
1446 | client->lease->t2 = (client->lease->lifetime * 7) / 8; | |||
1447 | t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5); | |||
1448 | client->lease->t1 = client->lease->lifetime / 2; | |||
1449 | } | |||
1450 | } else if (client->lease->t2 > 0 && client->lease->t2 < client->lease->lifetime) { | |||
1451 | /* only T2 is given, and it is valid */ | |||
1452 | t2_timeout = client_compute_timeout(client, client->lease->t2, 1); | |||
1453 | t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5); | |||
1454 | client->lease->t1 = client->lease->lifetime / 2; | |||
1455 | if (t2_timeout <= t1_timeout) { | |||
1456 | /* the computed T1 would be invalid, so discard T2 */ | |||
1457 | t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0); | |||
1458 | client->lease->t2 = (client->lease->lifetime * 7) / 8; | |||
1459 | } | |||
1460 | } else if (client->lease->t1 > 0 && client->lease->t1 < client->lease->lifetime) { | |||
1461 | /* only T1 is given, and it is valid */ | |||
1462 | t1_timeout = client_compute_timeout(client, client->lease->t1, 1); | |||
1463 | t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0); | |||
1464 | client->lease->t2 = (client->lease->lifetime * 7) / 8; | |||
1465 | if (t2_timeout <= t1_timeout) { | |||
1466 | /* the computed T2 would be invalid, so discard T1 */ | |||
1467 | t2_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5); | |||
1468 | client->lease->t2 = client->lease->lifetime / 2; | |||
1469 | } | |||
1470 | } else { | |||
1471 | /* fall back to the default timeouts */ | |||
1472 | t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5); | |||
1473 | client->lease->t1 = client->lease->lifetime / 2; | |||
1474 | t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0); | |||
1475 | client->lease->t2 = (client->lease->lifetime * 7) / 8; | |||
1476 | } | |||
1477 | ||||
1478 | /* arm lifetime timeout */ | |||
1479 | r = sd_event_add_time(client->event, &client->timeout_expire, | |||
1480 | clock_boottime_or_monotonic(), | |||
1481 | lifetime_timeout, 10 * USEC_PER_MSEC((usec_t) 1000ULL), | |||
1482 | client_timeout_expire, client); | |||
1483 | if (r < 0) | |||
1484 | return r; | |||
1485 | ||||
1486 | r = sd_event_source_set_priority(client->timeout_expire, | |||
1487 | client->event_priority); | |||
1488 | if (r < 0) | |||
1489 | return r; | |||
1490 | ||||
1491 | r = sd_event_source_set_description(client->timeout_expire, "dhcp4-lifetime"); | |||
1492 | if (r < 0) | |||
1493 | return r; | |||
1494 | ||||
1495 | log_dhcp_client(client, "lease expires in %s",log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/libsystemd-network/sd-dhcp-client.c", 1496, __func__ , "DHCP CLIENT (0x%x): " "lease expires in %s", client->xid , format_timespan(time_string, 64, lifetime_timeout - time_now , ((usec_t) 1000000ULL))) | |||
1496 | format_timespan(time_string, FORMAT_TIMESPAN_MAX, lifetime_timeout - time_now, USEC_PER_SEC))log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/libsystemd-network/sd-dhcp-client.c", 1496, __func__ , "DHCP CLIENT (0x%x): " "lease expires in %s", client->xid , format_timespan(time_string, 64, lifetime_timeout - time_now , ((usec_t) 1000000ULL))); | |||
1497 | ||||
1498 | /* don't arm earlier timeouts if this has already expired */ | |||
1499 | if (lifetime_timeout <= time_now) | |||
1500 | return 0; | |||
1501 | ||||
1502 | /* arm T2 timeout */ | |||
1503 | r = sd_event_add_time(client->event, | |||
1504 | &client->timeout_t2, | |||
1505 | clock_boottime_or_monotonic(), | |||
1506 | t2_timeout, | |||
1507 | 10 * USEC_PER_MSEC((usec_t) 1000ULL), | |||
1508 | client_timeout_t2, client); | |||
1509 | if (r < 0) | |||
1510 | return r; | |||
1511 | ||||
1512 | r = sd_event_source_set_priority(client->timeout_t2, | |||
1513 | client->event_priority); | |||
1514 | if (r < 0) | |||
1515 | return r; | |||
1516 | ||||
1517 | r = sd_event_source_set_description(client->timeout_t2, "dhcp4-t2-timeout"); | |||
1518 | if (r < 0) | |||
1519 | return r; | |||
1520 | ||||
1521 | log_dhcp_client(client, "T2 expires in %s",log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/libsystemd-network/sd-dhcp-client.c", 1522, __func__ , "DHCP CLIENT (0x%x): " "T2 expires in %s", client->xid, format_timespan (time_string, 64, t2_timeout - time_now, ((usec_t) 1000000ULL ))) | |||
1522 | format_timespan(time_string, FORMAT_TIMESPAN_MAX, t2_timeout - time_now, USEC_PER_SEC))log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/libsystemd-network/sd-dhcp-client.c", 1522, __func__ , "DHCP CLIENT (0x%x): " "T2 expires in %s", client->xid, format_timespan (time_string, 64, t2_timeout - time_now, ((usec_t) 1000000ULL ))); | |||
1523 | ||||
1524 | /* don't arm earlier timeout if this has already expired */ | |||
1525 | if (t2_timeout <= time_now) | |||
1526 | return 0; | |||
1527 | ||||
1528 | /* arm T1 timeout */ | |||
1529 | r = sd_event_add_time(client->event, | |||
1530 | &client->timeout_t1, | |||
1531 | clock_boottime_or_monotonic(), | |||
1532 | t1_timeout, 10 * USEC_PER_MSEC((usec_t) 1000ULL), | |||
1533 | client_timeout_t1, client); | |||
1534 | if (r < 0) | |||
1535 | return r; | |||
1536 | ||||
1537 | r = sd_event_source_set_priority(client->timeout_t1, | |||
1538 | client->event_priority); | |||
1539 | if (r < 0) | |||
1540 | return r; | |||
1541 | ||||
1542 | r = sd_event_source_set_description(client->timeout_t1, "dhcp4-t1-timer"); | |||
1543 | if (r < 0) | |||
1544 | return r; | |||
1545 | ||||
1546 | log_dhcp_client(client, "T1 expires in %s",log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/libsystemd-network/sd-dhcp-client.c", 1547, __func__ , "DHCP CLIENT (0x%x): " "T1 expires in %s", client->xid, format_timespan (time_string, 64, t1_timeout - time_now, ((usec_t) 1000000ULL ))) | |||
1547 | format_timespan(time_string, FORMAT_TIMESPAN_MAX, t1_timeout - time_now, USEC_PER_SEC))log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/libsystemd-network/sd-dhcp-client.c", 1547, __func__ , "DHCP CLIENT (0x%x): " "T1 expires in %s", client->xid, format_timespan (time_string, 64, t1_timeout - time_now, ((usec_t) 1000000ULL ))); | |||
1548 | ||||
1549 | return 0; | |||
1550 | } | |||
1551 | ||||
1552 | static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, int len) { | |||
1553 | DHCP_CLIENT_DONT_DESTROY(client)__attribute__((cleanup(sd_dhcp_client_unrefp))) __attribute__ ((unused)) sd_dhcp_client *_dont_destroy_client = sd_dhcp_client_ref (client); | |||
1554 | char time_string[FORMAT_TIMESPAN_MAX64]; | |||
1555 | int r = 0, notify_event = 0; | |||
1556 | ||||
1557 | assert(client)do { if ((__builtin_expect(!!(!(client)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("client"), "../src/libsystemd-network/sd-dhcp-client.c" , 1557, __PRETTY_FUNCTION__); } while (0); | |||
1558 | assert(client->event)do { if ((__builtin_expect(!!(!(client->event)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("client->event"), "../src/libsystemd-network/sd-dhcp-client.c" , 1558, __PRETTY_FUNCTION__); } while (0); | |||
1559 | assert(message)do { if ((__builtin_expect(!!(!(message)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("message"), "../src/libsystemd-network/sd-dhcp-client.c" , 1559, __PRETTY_FUNCTION__); } while (0); | |||
1560 | ||||
1561 | switch (client->state) { | |||
1562 | case DHCP_STATE_SELECTING: | |||
1563 | ||||
1564 | r = client_handle_offer(client, message, len); | |||
1565 | if (r >= 0) { | |||
1566 | ||||
1567 | client->timeout_resend = | |||
1568 | sd_event_source_unref(client->timeout_resend); | |||
1569 | ||||
1570 | client->state = DHCP_STATE_REQUESTING; | |||
1571 | client->attempt = 1; | |||
1572 | ||||
1573 | r = sd_event_add_time(client->event, | |||
1574 | &client->timeout_resend, | |||
1575 | clock_boottime_or_monotonic(), | |||
1576 | 0, 0, | |||
1577 | client_timeout_resend, client); | |||
1578 | if (r < 0) | |||
1579 | goto error; | |||
1580 | ||||
1581 | r = sd_event_source_set_priority(client->timeout_resend, | |||
1582 | client->event_priority); | |||
1583 | if (r < 0) | |||
1584 | goto error; | |||
1585 | ||||
1586 | r = sd_event_source_set_description(client->timeout_resend, "dhcp4-resend-timer"); | |||
1587 | if (r < 0) | |||
1588 | goto error; | |||
1589 | } else if (r == -ENOMSG42) | |||
1590 | /* invalid message, let's ignore it */ | |||
1591 | return 0; | |||
1592 | ||||
1593 | break; | |||
1594 | ||||
1595 | case DHCP_STATE_REBOOTING: | |||
1596 | case DHCP_STATE_REQUESTING: | |||
1597 | case DHCP_STATE_RENEWING: | |||
1598 | case DHCP_STATE_REBINDING: | |||
1599 | ||||
1600 | r = client_handle_ack(client, message, len); | |||
1601 | if (r >= 0) { | |||
1602 | client->start_delay = 0; | |||
1603 | client->timeout_resend = | |||
1604 | sd_event_source_unref(client->timeout_resend); | |||
1605 | client->receive_message = | |||
1606 | sd_event_source_unref(client->receive_message); | |||
1607 | client->fd = asynchronous_close(client->fd); | |||
1608 | ||||
1609 | if (IN_SET(client->state, DHCP_STATE_REQUESTING,({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){DHCP_STATE_REQUESTING, DHCP_STATE_REBOOTING })/sizeof(int)]; switch(client->state) { case DHCP_STATE_REQUESTING : case DHCP_STATE_REBOOTING: _found = 1; break; default: break ; } _found; }) | |||
1610 | DHCP_STATE_REBOOTING)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){DHCP_STATE_REQUESTING, DHCP_STATE_REBOOTING })/sizeof(int)]; switch(client->state) { case DHCP_STATE_REQUESTING : case DHCP_STATE_REBOOTING: _found = 1; break; default: break ; } _found; })) | |||
1611 | notify_event = SD_DHCP_CLIENT_EVENT_IP_ACQUIRE; | |||
1612 | else if (r != SD_DHCP_CLIENT_EVENT_IP_ACQUIRE) | |||
1613 | notify_event = r; | |||
1614 | ||||
1615 | client->state = DHCP_STATE_BOUND; | |||
1616 | client->attempt = 1; | |||
1617 | ||||
1618 | client->last_addr = client->lease->address; | |||
1619 | ||||
1620 | r = client_set_lease_timeouts(client); | |||
1621 | if (r < 0) { | |||
1622 | log_dhcp_client(client, "could not set lease timeouts")log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/libsystemd-network/sd-dhcp-client.c", 1622, __func__ , "DHCP CLIENT (0x%x): " "could not set lease timeouts", client ->xid); | |||
1623 | goto error; | |||
1624 | } | |||
1625 | ||||
1626 | r = dhcp_network_bind_udp_socket(client->ifindex, client->lease->address, client->port); | |||
1627 | if (r < 0) { | |||
1628 | log_dhcp_client(client, "could not bind UDP socket")log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/libsystemd-network/sd-dhcp-client.c", 1628, __func__ , "DHCP CLIENT (0x%x): " "could not bind UDP socket", client-> xid); | |||
1629 | goto error; | |||
1630 | } | |||
1631 | ||||
1632 | client->fd = r; | |||
1633 | ||||
1634 | client_initialize_io_events(client, client_receive_message_udp); | |||
1635 | ||||
1636 | if (notify_event) { | |||
1637 | client_notify(client, notify_event); | |||
1638 | if (client->state == DHCP_STATE_STOPPED) | |||
1639 | return 0; | |||
1640 | } | |||
1641 | ||||
1642 | } else if (r == -EADDRNOTAVAIL99) { | |||
1643 | /* got a NAK, let's restart the client */ | |||
1644 | client->timeout_resend = | |||
1645 | sd_event_source_unref(client->timeout_resend); | |||
1646 | ||||
1647 | r = client_initialize(client); | |||
1648 | if (r < 0) | |||
1649 | goto error; | |||
1650 | ||||
1651 | r = client_start_delayed(client); | |||
1652 | if (r < 0) | |||
1653 | goto error; | |||
1654 | ||||
1655 | log_dhcp_client(client, "REBOOT in %s", format_timespan(time_string, FORMAT_TIMESPAN_MAX,log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/libsystemd-network/sd-dhcp-client.c", 1656, __func__ , "DHCP CLIENT (0x%x): " "REBOOT in %s", client->xid, format_timespan (time_string, 64, client->start_delay, ((usec_t) 1000000ULL ))) | |||
1656 | client->start_delay, USEC_PER_SEC))log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/libsystemd-network/sd-dhcp-client.c", 1656, __func__ , "DHCP CLIENT (0x%x): " "REBOOT in %s", client->xid, format_timespan (time_string, 64, client->start_delay, ((usec_t) 1000000ULL ))); | |||
1657 | ||||
1658 | client->start_delay = CLAMP(client->start_delay * 2,__extension__ ({ const typeof((client->start_delay * 2)) __unique_prefix_X3 = ((client->start_delay * 2)); const typeof(((1 * ((usec_t ) 1000000ULL)))) __unique_prefix_LOW4 = (((1 * ((usec_t) 1000000ULL )))); const typeof(((30 * ((usec_t) (60ULL*((usec_t) 1000000ULL )))))) __unique_prefix_HIGH5 = (((30 * ((usec_t) (60ULL*((usec_t ) 1000000ULL)))))); __unique_prefix_X3 > __unique_prefix_HIGH5 ? __unique_prefix_HIGH5 : __unique_prefix_X3 < __unique_prefix_LOW4 ? __unique_prefix_LOW4 : __unique_prefix_X3; }) | |||
1659 | RESTART_AFTER_NAK_MIN_USEC, RESTART_AFTER_NAK_MAX_USEC)__extension__ ({ const typeof((client->start_delay * 2)) __unique_prefix_X3 = ((client->start_delay * 2)); const typeof(((1 * ((usec_t ) 1000000ULL)))) __unique_prefix_LOW4 = (((1 * ((usec_t) 1000000ULL )))); const typeof(((30 * ((usec_t) (60ULL*((usec_t) 1000000ULL )))))) __unique_prefix_HIGH5 = (((30 * ((usec_t) (60ULL*((usec_t ) 1000000ULL)))))); __unique_prefix_X3 > __unique_prefix_HIGH5 ? __unique_prefix_HIGH5 : __unique_prefix_X3 < __unique_prefix_LOW4 ? __unique_prefix_LOW4 : __unique_prefix_X3; }); | |||
1660 | ||||
1661 | return 0; | |||
1662 | } else if (r == -ENOMSG42) | |||
1663 | /* invalid message, let's ignore it */ | |||
1664 | return 0; | |||
1665 | ||||
1666 | break; | |||
1667 | ||||
1668 | case DHCP_STATE_BOUND: | |||
1669 | r = client_handle_forcerenew(client, message, len); | |||
1670 | if (r >= 0) { | |||
1671 | r = client_timeout_t1(NULL((void*)0), 0, client); | |||
1672 | if (r < 0) | |||
1673 | goto error; | |||
1674 | } else if (r == -ENOMSG42) | |||
1675 | /* invalid message, let's ignore it */ | |||
1676 | return 0; | |||
1677 | ||||
1678 | break; | |||
1679 | ||||
1680 | case DHCP_STATE_INIT: | |||
1681 | case DHCP_STATE_INIT_REBOOT: | |||
1682 | ||||
1683 | break; | |||
1684 | ||||
1685 | case DHCP_STATE_STOPPED: | |||
1686 | r = -EINVAL22; | |||
1687 | goto error; | |||
1688 | } | |||
1689 | ||||
1690 | error: | |||
1691 | if (r < 0) | |||
1692 | client_stop(client, r); | |||
1693 | ||||
1694 | return r; | |||
1695 | } | |||
1696 | ||||
1697 | static int client_receive_message_udp( | |||
1698 | sd_event_source *s, | |||
1699 | int fd, | |||
1700 | uint32_t revents, | |||
1701 | void *userdata) { | |||
1702 | ||||
1703 | sd_dhcp_client *client = userdata; | |||
1704 | _cleanup_free___attribute__((cleanup(freep))) DHCPMessage *message = NULL((void*)0); | |||
1705 | const struct ether_addr zero_mac = {}; | |||
1706 | const struct ether_addr *expected_chaddr = NULL((void*)0); | |||
1707 | uint8_t expected_hlen = 0; | |||
1708 | ssize_t len, buflen; | |||
1709 | ||||
1710 | assert(s)do { if ((__builtin_expect(!!(!(s)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("s"), "../src/libsystemd-network/sd-dhcp-client.c" , 1710, __PRETTY_FUNCTION__); } while (0); | |||
1711 | assert(client)do { if ((__builtin_expect(!!(!(client)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("client"), "../src/libsystemd-network/sd-dhcp-client.c" , 1711, __PRETTY_FUNCTION__); } while (0); | |||
1712 | ||||
1713 | buflen = next_datagram_size_fd(fd); | |||
1714 | if (buflen < 0) | |||
1715 | return buflen; | |||
1716 | ||||
1717 | message = malloc0(buflen)(calloc(1, (buflen))); | |||
1718 | if (!message) | |||
1719 | return -ENOMEM12; | |||
1720 | ||||
1721 | len = recv(fd, message, buflen, 0); | |||
1722 | if (len < 0) { | |||
1723 | if (IN_SET(errno, EAGAIN, EINTR)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){11, 4})/sizeof(int)]; switch((*__errno_location ())) { case 11: case 4: _found = 1; break; default: break; } _found; })) | |||
1724 | return 0; | |||
1725 | ||||
1726 | return log_dhcp_client_errno(client, errno,log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), (*__errno_location ()), "../src/libsystemd-network/sd-dhcp-client.c" , 1727, __func__, "DHCP CLIENT (0x%x): " "Could not receive message from UDP socket: %m" , client->xid) | |||
1727 | "Could not receive message from UDP socket: %m")log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), (*__errno_location ()), "../src/libsystemd-network/sd-dhcp-client.c" , 1727, __func__, "DHCP CLIENT (0x%x): " "Could not receive message from UDP socket: %m" , client->xid); | |||
1728 | } | |||
1729 | if ((size_t) len < sizeof(DHCPMessage)) { | |||
1730 | log_dhcp_client(client, "Too small to be a DHCP message: ignoring")log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/libsystemd-network/sd-dhcp-client.c", 1730, __func__ , "DHCP CLIENT (0x%x): " "Too small to be a DHCP message: ignoring" , client->xid); | |||
1731 | return 0; | |||
1732 | } | |||
1733 | ||||
1734 | if (be32toh(message->magic) != DHCP_MAGIC_COOKIE(uint32_t)(0x63825363)) { | |||
1735 | log_dhcp_client(client, "Not a DHCP message: ignoring")log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/libsystemd-network/sd-dhcp-client.c", 1735, __func__ , "DHCP CLIENT (0x%x): " "Not a DHCP message: ignoring", client ->xid); | |||
1736 | return 0; | |||
1737 | } | |||
1738 | ||||
1739 | if (message->op != BOOTREPLY) { | |||
1740 | log_dhcp_client(client, "Not a BOOTREPLY message: ignoring")log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/libsystemd-network/sd-dhcp-client.c", 1740, __func__ , "DHCP CLIENT (0x%x): " "Not a BOOTREPLY message: ignoring", client->xid); | |||
1741 | return 0; | |||
1742 | } | |||
1743 | ||||
1744 | if (message->htype != client->arp_type) { | |||
1745 | log_dhcp_client(client, "Packet type does not match client type")log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/libsystemd-network/sd-dhcp-client.c", 1745, __func__ , "DHCP CLIENT (0x%x): " "Packet type does not match client type" , client->xid); | |||
1746 | return 0; | |||
1747 | } | |||
1748 | ||||
1749 | if (client->arp_type == ARPHRD_ETHER1) { | |||
1750 | expected_hlen = ETH_ALEN6; | |||
1751 | expected_chaddr = (const struct ether_addr *) &client->mac_addr; | |||
1752 | } else { | |||
1753 | /* Non-Ethernet links expect zero chaddr */ | |||
1754 | expected_hlen = 0; | |||
1755 | expected_chaddr = &zero_mac; | |||
1756 | } | |||
1757 | ||||
1758 | if (message->hlen != expected_hlen) { | |||
1759 | log_dhcp_client(client, "Unexpected packet hlen %d", message->hlen)log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/libsystemd-network/sd-dhcp-client.c", 1759, __func__ , "DHCP CLIENT (0x%x): " "Unexpected packet hlen %d", client-> xid, message->hlen); | |||
1760 | return 0; | |||
1761 | } | |||
1762 | ||||
1763 | if (memcmp(&message->chaddr[0], expected_chaddr, ETH_ALEN6)) { | |||
1764 | log_dhcp_client(client, "Received chaddr does not match expected: ignoring")log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/libsystemd-network/sd-dhcp-client.c", 1764, __func__ , "DHCP CLIENT (0x%x): " "Received chaddr does not match expected: ignoring" , client->xid); | |||
1765 | return 0; | |||
1766 | } | |||
1767 | ||||
1768 | if (client->state != DHCP_STATE_BOUND && | |||
1769 | be32toh(message->xid) != client->xid) { | |||
1770 | /* in BOUND state, we may receive FORCERENEW with xid set by server, | |||
1771 | so ignore the xid in this case */ | |||
1772 | log_dhcp_client(client, "Received xid (%u) does not match expected (%u): ignoring",log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/libsystemd-network/sd-dhcp-client.c", 1773, __func__ , "DHCP CLIENT (0x%x): " "Received xid (%u) does not match expected (%u): ignoring" , client->xid, be32toh(message->xid), client->xid) | |||
1773 | be32toh(message->xid), client->xid)log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/libsystemd-network/sd-dhcp-client.c", 1773, __func__ , "DHCP CLIENT (0x%x): " "Received xid (%u) does not match expected (%u): ignoring" , client->xid, be32toh(message->xid), client->xid); | |||
1774 | return 0; | |||
1775 | } | |||
1776 | ||||
1777 | return client_handle_message(client, message, len); | |||
1778 | } | |||
1779 | ||||
1780 | static int client_receive_message_raw( | |||
1781 | sd_event_source *s, | |||
1782 | int fd, | |||
1783 | uint32_t revents, | |||
1784 | void *userdata) { | |||
1785 | ||||
1786 | sd_dhcp_client *client = userdata; | |||
1787 | _cleanup_free___attribute__((cleanup(freep))) DHCPPacket *packet = NULL((void*)0); | |||
1788 | uint8_t cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))((((sizeof (struct cmsghdr)) + sizeof (size_t) - 1) & (size_t ) ~(sizeof (size_t) - 1)) + (sizeof(struct tpacket_auxdata)))]; | |||
1789 | struct iovec iov = {}; | |||
1790 | struct msghdr msg = { | |||
1791 | .msg_iov = &iov, | |||
1792 | .msg_iovlen = 1, | |||
1793 | .msg_control = cmsgbuf, | |||
1794 | .msg_controllen = sizeof(cmsgbuf), | |||
1795 | }; | |||
1796 | struct cmsghdr *cmsg; | |||
1797 | bool_Bool checksum = true1; | |||
1798 | ssize_t buflen, len; | |||
1799 | int r; | |||
1800 | ||||
1801 | assert(s)do { if ((__builtin_expect(!!(!(s)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("s"), "../src/libsystemd-network/sd-dhcp-client.c" , 1801, __PRETTY_FUNCTION__); } while (0); | |||
1802 | assert(client)do { if ((__builtin_expect(!!(!(client)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("client"), "../src/libsystemd-network/sd-dhcp-client.c" , 1802, __PRETTY_FUNCTION__); } while (0); | |||
1803 | ||||
1804 | buflen = next_datagram_size_fd(fd); | |||
1805 | if (buflen < 0) | |||
1806 | return buflen; | |||
1807 | ||||
1808 | packet = malloc0(buflen)(calloc(1, (buflen))); | |||
1809 | if (!packet) | |||
1810 | return -ENOMEM12; | |||
1811 | ||||
1812 | iov.iov_base = packet; | |||
1813 | iov.iov_len = buflen; | |||
1814 | ||||
1815 | len = recvmsg(fd, &msg, 0); | |||
1816 | if (len < 0) { | |||
1817 | if (IN_SET(errno, EAGAIN, EINTR)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){11, 4})/sizeof(int)]; switch((*__errno_location ())) { case 11: case 4: _found = 1; break; default: break; } _found; })) | |||
1818 | return 0; | |||
1819 | ||||
1820 | return log_dhcp_client_errno(client, errno,log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), (*__errno_location ()), "../src/libsystemd-network/sd-dhcp-client.c" , 1821, __func__, "DHCP CLIENT (0x%x): " "Could not receive message from raw socket: %m" , client->xid) | |||
1821 | "Could not receive message from raw socket: %m")log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), (*__errno_location ()), "../src/libsystemd-network/sd-dhcp-client.c" , 1821, __func__, "DHCP CLIENT (0x%x): " "Could not receive message from raw socket: %m" , client->xid); | |||
1822 | } else if ((size_t)len < sizeof(DHCPPacket)) | |||
1823 | return 0; | |||
1824 | ||||
1825 | CMSG_FOREACH(cmsg, &msg)for ((cmsg) = ((size_t) (&msg)->msg_controllen >= sizeof (struct cmsghdr) ? (struct cmsghdr *) (&msg)->msg_control : (struct cmsghdr *) 0); (cmsg); (cmsg) = __cmsg_nxthdr ((& msg), (cmsg))) { | |||
1826 | if (cmsg->cmsg_level == SOL_PACKET263 && | |||
1827 | cmsg->cmsg_type == PACKET_AUXDATA8 && | |||
1828 | cmsg->cmsg_len == CMSG_LEN(sizeof(struct tpacket_auxdata))((((sizeof (struct cmsghdr)) + sizeof (size_t) - 1) & (size_t ) ~(sizeof (size_t) - 1)) + (sizeof(struct tpacket_auxdata)))) { | |||
1829 | struct tpacket_auxdata *aux = (struct tpacket_auxdata*)CMSG_DATA(cmsg)((cmsg)->__cmsg_data); | |||
1830 | ||||
1831 | checksum = !(aux->tp_status & TP_STATUS_CSUMNOTREADY(1 << 3)); | |||
1832 | break; | |||
1833 | } | |||
1834 | } | |||
1835 | ||||
1836 | r = dhcp_packet_verify_headers(packet, len, checksum, client->port); | |||
1837 | if (r < 0) | |||
1838 | return 0; | |||
1839 | ||||
1840 | len -= DHCP_IP_UDP_SIZE(int32_t)(sizeof(struct udphdr) + (int32_t)(sizeof(struct iphdr ))); | |||
1841 | ||||
1842 | return client_handle_message(client, &packet->dhcp, len); | |||
1843 | } | |||
1844 | ||||
1845 | int sd_dhcp_client_start(sd_dhcp_client *client) { | |||
1846 | int r; | |||
1847 | ||||
1848 | assert_return(client, -EINVAL)do { if (!(((__builtin_expect(!!(client),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("client"), "../src/libsystemd-network/sd-dhcp-client.c" , 1848, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
1849 | ||||
1850 | r = client_initialize(client); | |||
1851 | if (r < 0) | |||
1852 | return r; | |||
1853 | ||||
1854 | /* RFC7844 section 3.3: | |||
1855 | SHOULD perform a complete four-way handshake, starting with a | |||
1856 | DHCPDISCOVER, to obtain a new address lease. If the client can | |||
1857 | ascertain that this is exactly the same network to which it was | |||
1858 | previously connected, and if the link-layer address did not change, | |||
1859 | the client MAY issue a DHCPREQUEST to try to reclaim the current | |||
1860 | address. */ | |||
1861 | if (client->last_addr && !client->anonymize) | |||
1862 | client->state = DHCP_STATE_INIT_REBOOT; | |||
1863 | ||||
1864 | r = client_start(client); | |||
1865 | if (r >= 0) | |||
1866 | log_dhcp_client(client, "STARTED on ifindex %i", client->ifindex)log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/libsystemd-network/sd-dhcp-client.c", 1866, __func__ , "DHCP CLIENT (0x%x): " "STARTED on ifindex %i", client-> xid, client->ifindex); | |||
1867 | ||||
1868 | return r; | |||
1869 | } | |||
1870 | ||||
1871 | int sd_dhcp_client_stop(sd_dhcp_client *client) { | |||
1872 | DHCP_CLIENT_DONT_DESTROY(client)__attribute__((cleanup(sd_dhcp_client_unrefp))) __attribute__ ((unused)) sd_dhcp_client *_dont_destroy_client = sd_dhcp_client_ref (client); | |||
1873 | ||||
1874 | assert_return(client, -EINVAL)do { if (!(((__builtin_expect(!!(client),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("client"), "../src/libsystemd-network/sd-dhcp-client.c" , 1874, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
1875 | ||||
1876 | client_stop(client, SD_DHCP_CLIENT_EVENT_STOP); | |||
1877 | client->state = DHCP_STATE_STOPPED; | |||
1878 | ||||
1879 | return 0; | |||
1880 | } | |||
1881 | ||||
1882 | int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event, int64_t priority) { | |||
1883 | int r; | |||
1884 | ||||
1885 | assert_return(client, -EINVAL)do { if (!(((__builtin_expect(!!(client),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("client"), "../src/libsystemd-network/sd-dhcp-client.c" , 1885, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
1886 | assert_return(!client->event, -EBUSY)do { if (!(((__builtin_expect(!!(!client->event),1))) ? (1 ) : (log_assert_failed_return_realm(LOG_REALM_SYSTEMD, ("!client->event" ), "../src/libsystemd-network/sd-dhcp-client.c", 1886, __PRETTY_FUNCTION__ ), 0))) return (-16); } while (0); | |||
1887 | ||||
1888 | if (event) | |||
1889 | client->event = sd_event_ref(event); | |||
1890 | else { | |||
1891 | r = sd_event_default(&client->event); | |||
1892 | if (r < 0) | |||
1893 | return 0; | |||
1894 | } | |||
1895 | ||||
1896 | client->event_priority = priority; | |||
1897 | ||||
1898 | return 0; | |||
1899 | } | |||
1900 | ||||
1901 | int sd_dhcp_client_detach_event(sd_dhcp_client *client) { | |||
1902 | assert_return(client, -EINVAL)do { if (!(((__builtin_expect(!!(client),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("client"), "../src/libsystemd-network/sd-dhcp-client.c" , 1902, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
1903 | ||||
1904 | client->event = sd_event_unref(client->event); | |||
1905 | ||||
1906 | return 0; | |||
1907 | } | |||
1908 | ||||
1909 | sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client) { | |||
1910 | assert_return(client, NULL)do { if (!(((__builtin_expect(!!(client),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("client"), "../src/libsystemd-network/sd-dhcp-client.c" , 1910, __PRETTY_FUNCTION__), 0))) return (((void*)0)); } while (0); | |||
1911 | ||||
1912 | return client->event; | |||
1913 | } | |||
1914 | ||||
1915 | sd_dhcp_client *sd_dhcp_client_ref(sd_dhcp_client *client) { | |||
1916 | ||||
1917 | if (!client) | |||
1918 | return NULL((void*)0); | |||
1919 | ||||
1920 | assert(client->n_ref >= 1)do { if ((__builtin_expect(!!(!(client->n_ref >= 1)),0) )) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("client->n_ref >= 1" ), "../src/libsystemd-network/sd-dhcp-client.c", 1920, __PRETTY_FUNCTION__ ); } while (0); | |||
1921 | client->n_ref++; | |||
1922 | ||||
1923 | return client; | |||
1924 | } | |||
1925 | ||||
1926 | sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client) { | |||
1927 | ||||
1928 | if (!client) | |||
1929 | return NULL((void*)0); | |||
1930 | ||||
1931 | assert(client->n_ref >= 1)do { if ((__builtin_expect(!!(!(client->n_ref >= 1)),0) )) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("client->n_ref >= 1" ), "../src/libsystemd-network/sd-dhcp-client.c", 1931, __PRETTY_FUNCTION__ ); } while (0); | |||
1932 | client->n_ref--; | |||
1933 | ||||
1934 | if (client->n_ref > 0) | |||
1935 | return NULL((void*)0); | |||
1936 | ||||
1937 | log_dhcp_client(client, "FREE")log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/libsystemd-network/sd-dhcp-client.c", 1937, __func__ , "DHCP CLIENT (0x%x): " "FREE", client->xid); | |||
1938 | ||||
1939 | client_initialize(client); | |||
1940 | ||||
1941 | client->receive_message = sd_event_source_unref(client->receive_message); | |||
1942 | ||||
1943 | sd_dhcp_client_detach_event(client); | |||
1944 | ||||
1945 | sd_dhcp_lease_unref(client->lease); | |||
1946 | ||||
1947 | free(client->req_opts); | |||
1948 | free(client->hostname); | |||
1949 | free(client->vendor_class_identifier); | |||
1950 | client->user_class = strv_free(client->user_class); | |||
1951 | return mfree(client); | |||
1952 | } | |||
1953 | ||||
1954 | int sd_dhcp_client_new(sd_dhcp_client **ret, int anonymize) { | |||
1955 | _cleanup_(sd_dhcp_client_unrefp)__attribute__((cleanup(sd_dhcp_client_unrefp))) sd_dhcp_client *client = NULL((void*)0); | |||
1956 | ||||
1957 | assert_return(ret, -EINVAL)do { if (!(((__builtin_expect(!!(ret),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("ret"), "../src/libsystemd-network/sd-dhcp-client.c" , 1957, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
| ||||
1958 | ||||
1959 | client = new0(sd_dhcp_client, 1)((sd_dhcp_client*) calloc((1), sizeof(sd_dhcp_client))); | |||
1960 | if (!client) | |||
1961 | return -ENOMEM12; | |||
1962 | ||||
1963 | client->n_ref = 1; | |||
1964 | client->state = DHCP_STATE_INIT; | |||
1965 | client->ifindex = -1; | |||
1966 | client->fd = -1; | |||
1967 | client->attempt = 1; | |||
1968 | client->mtu = DHCP_DEFAULT_MIN_SIZE576; | |||
1969 | client->port = DHCP_PORT_CLIENT; | |||
1970 | ||||
1971 | client->anonymize = !!anonymize; | |||
1972 | /* NOTE: this could be moved to a function. */ | |||
1973 | if (anonymize
| |||
1974 | client->req_opts_size = ELEMENTSOF(default_req_opts_anonymize)__extension__ (__builtin_choose_expr( !__builtin_types_compatible_p (typeof(default_req_opts_anonymize), typeof(&*(default_req_opts_anonymize ))), sizeof(default_req_opts_anonymize)/sizeof((default_req_opts_anonymize )[0]), ((void)0))); | |||
1975 | client->req_opts = memdup(default_req_opts_anonymize, client->req_opts_size); | |||
1976 | } else { | |||
1977 | client->req_opts_size = ELEMENTSOF(default_req_opts)__extension__ (__builtin_choose_expr( !__builtin_types_compatible_p (typeof(default_req_opts), typeof(&*(default_req_opts))), sizeof(default_req_opts)/sizeof((default_req_opts)[0]), ((void )0))); | |||
1978 | client->req_opts = memdup(default_req_opts, client->req_opts_size); | |||
1979 | } | |||
1980 | if (!client->req_opts) | |||
1981 | return -ENOMEM12; | |||
| ||||
1982 | ||||
1983 | *ret = TAKE_PTR(client)({ typeof(client) _ptr_ = (client); (client) = ((void*)0); _ptr_ ; }); | |||
1984 | ||||
1985 | return 0; | |||
1986 | } |