Bug Summary

File:build-scan/../src/libsystemd-network/sd-dhcp-client.c
Warning:line 1981, column 25
Potential leak of memory pointed to by 'client'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name sd-dhcp-client.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -menable-no-infs -menable-no-nans -menable-unsafe-fp-math -fno-signed-zeros -mreassociate -freciprocal-math -fdenormal-fp-math=preserve-sign,preserve-sign -ffp-contract=fast -fno-rounding-math -ffast-math -ffinite-math-only -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.0.0 -include config.h -I src/libsystemd-network/libsystemd-network.a.p -I src/libsystemd-network -I ../src/libsystemd-network -I src/basic -I ../src/basic -I src/shared -I ../src/shared -I src/systemd -I ../src/systemd -I src/journal -I ../src/journal -I src/journal-remote -I ../src/journal-remote -I src/nspawn -I ../src/nspawn -I src/resolve -I ../src/resolve -I src/timesync -I ../src/timesync -I ../src/time-wait-sync -I src/login -I ../src/login -I src/udev -I ../src/udev -I src/libudev -I ../src/libudev -I src/core -I ../src/core -I ../src/libsystemd/sd-bus -I ../src/libsystemd/sd-device -I ../src/libsystemd/sd-hwdb -I ../src/libsystemd/sd-id128 -I ../src/libsystemd/sd-netlink -I ../src/libsystemd/sd-network -I . -I .. -D _FILE_OFFSET_BITS=64 -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wwrite-strings -Wno-unused-parameter -Wno-missing-field-initializers -Wno-unused-result -Wno-format-signedness -Wno-error=nonnull -std=gnu99 -fconst-strings -fdebug-compilation-dir /home/mrc0mmand/repos/@redhat-plumbers/systemd-rhel8/build-scan -ferror-limit 19 -fvisibility hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcolor-diagnostics -analyzer-output=html -faddrsig -o /tmp/scan-build-2021-07-16-221226-1465241-1 -x c ../src/libsystemd-network/sd-dhcp-client.c
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
36struct 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
100static 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 */
118static 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
134static int client_receive_message_raw(
135 sd_event_source *s,
136 int fd,
137 uint32_t revents,
138 void *userdata);
139static int client_receive_message_udp(
140 sd_event_source *s,
141 int fd,
142 uint32_t revents,
143 void *userdata);
144static void client_stop(sd_dhcp_client *client, int error);
145
146int 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
159int 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
167int 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
199int 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
214int 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
224int 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
265int 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
288int 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 */
344static 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
403int 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
412int 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
420int 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
434int 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
443int 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
463int 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
474int 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
483int 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
495static 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
502static 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
525static 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
540static 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
697static 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
719static 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
731static 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
813static 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
950static int client_start(sd_dhcp_client *client);
951
952static 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
1093error:
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
1101static 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
1125error:
1126 if (r < 0)
1127 client_stop(client, r);
1128
1129 return 0;
1130}
1131
1132static 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
1163error:
1164 if (r < 0)
1165 client_stop(client, r);
1166
1167 return 0;
1168
1169}
1170
1171static 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
1178static 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
1205static int client_start(sd_dhcp_client *client) {
1206 client->start_delay = 0;
1207 return client_start_delayed(client);
1208}
1209
1210static 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
1227static 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
1253static 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
1263static 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
1313static 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
1325static 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
1394static 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
1408static 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
1552static 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
1690error:
1691 if (r < 0)
1692 client_stop(client, r);
1693
1694 return r;
1695}
1696
1697static 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
1780static 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
1845int 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
1871int 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
1882int 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
1901int 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
1909sd_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
1915sd_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
1926sd_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
1954int 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)
;
1
Assuming 'ret' is non-null
2
'?' condition is true
3
Taking false branch
4
Loop condition is false. Exiting loop
1958
1959 client = new0(sd_dhcp_client, 1)((sd_dhcp_client*) calloc((1), sizeof(sd_dhcp_client)));
5
Memory is allocated
1960 if (!client)
6
Assuming 'client' is non-null
7
Taking false branch
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;
8
Assuming 'anonymize' is not equal to 0
1972 /* NOTE: this could be moved to a function. */
1973 if (anonymize
8.1
'anonymize' is not equal to 0
) {
9
Taking true branch
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)
10
Assuming field 'req_opts' is null
11
Taking true branch
1981 return -ENOMEM12;
12
Potential leak of memory pointed to by 'client'
1982
1983 *ret = TAKE_PTR(client)({ typeof(client) _ptr_ = (client); (client) = ((void*)0); _ptr_
; })
;
1984
1985 return 0;
1986}