Bug Summary

File:build-scan/../src/libsystemd-network/sd-dhcp6-client.c
Warning:line 1449, 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-dhcp6-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-dhcp6-client.c
1/* SPDX-License-Identifier: LGPL-2.1+ */
2/***
3 Copyright © 2014-2015 Intel Corporation. All rights reserved.
4***/
5
6#include <errno(*__errno_location ()).h>
7#include <string.h>
8#include <sys/ioctl.h>
9#include <linux1/if_infiniband.h>
10
11#include "sd-dhcp6-client.h"
12
13#include "alloc-util.h"
14#include "dhcp-identifier.h"
15#include "dhcp6-internal.h"
16#include "dhcp6-lease-internal.h"
17#include "dhcp6-protocol.h"
18#include "dns-domain.h"
19#include "fd-util.h"
20#include "hostname-util.h"
21#include "in-addr-util.h"
22#include "network-internal.h"
23#include "random-util.h"
24#include "socket-util.h"
25#include "string-table.h"
26#include "util.h"
27
28#define MAX_MAC_ADDR_LEN20 INFINIBAND_ALEN20
29
30struct sd_dhcp6_client {
31 unsigned n_ref;
32
33 enum DHCP6State state;
34 sd_event *event;
35 int event_priority;
36 int ifindex;
37 struct in6_addr local_address;
38 uint8_t mac_addr[MAX_MAC_ADDR_LEN20];
39 size_t mac_addr_len;
40 uint16_t arp_type;
41 DHCP6IA ia_na;
42 DHCP6IA ia_pd;
43 bool_Bool prefix_delegation;
44 be32_t transaction_id;
45 usec_t transaction_start;
46 struct sd_dhcp6_lease *lease;
47 int fd;
48 bool_Bool information_request;
49 be16_t *req_opts;
50 size_t req_opts_allocated;
51 size_t req_opts_len;
52 char *fqdn;
53 sd_event_source *receive_message;
54 usec_t retransmit_time;
55 uint8_t retransmit_count;
56 sd_event_source *timeout_resend;
57 sd_event_source *timeout_resend_expire;
58 sd_dhcp6_client_callback_t callback;
59 void *userdata;
60 struct duid duid;
61 size_t duid_len;
62};
63
64static const uint16_t default_req_opts[] = {
65 SD_DHCP6_OPTION_DNS_SERVERS,
66 SD_DHCP6_OPTION_DOMAIN_LIST,
67 SD_DHCP6_OPTION_NTP_SERVER,
68 SD_DHCP6_OPTION_SNTP_SERVERS,
69};
70
71const char * dhcp6_message_type_table[_DHCP6_MESSAGE_MAX] = {
72 [DHCP6_SOLICIT] = "SOLICIT",
73 [DHCP6_ADVERTISE] = "ADVERTISE",
74 [DHCP6_REQUEST] = "REQUEST",
75 [DHCP6_CONFIRM] = "CONFIRM",
76 [DHCP6_RENEW] = "RENEW",
77 [DHCP6_REBIND] = "REBIND",
78 [DHCP6_REPLY] = "REPLY",
79 [DHCP6_RELEASE] = "RELEASE",
80 [DHCP6_DECLINE] = "DECLINE",
81 [DHCP6_RECONFIGURE] = "RECONFIGURE",
82 [DHCP6_INFORMATION_REQUEST] = "INFORMATION-REQUEST",
83 [DHCP6_RELAY_FORW] = "RELAY-FORW",
84 [DHCP6_RELAY_REPL] = "RELAY-REPL",
85};
86
87DEFINE_STRING_TABLE_LOOKUP(dhcp6_message_type, int)const char *dhcp6_message_type_to_string(int i) { if (i < 0
|| i >= (int) __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p
(typeof(dhcp6_message_type_table), typeof(&*(dhcp6_message_type_table
))), sizeof(dhcp6_message_type_table)/sizeof((dhcp6_message_type_table
)[0]), ((void)0)))) return ((void*)0); return dhcp6_message_type_table
[i]; } int dhcp6_message_type_from_string(const char *s) { return
(int) string_table_lookup(dhcp6_message_type_table, __extension__
(__builtin_choose_expr( !__builtin_types_compatible_p(typeof
(dhcp6_message_type_table), typeof(&*(dhcp6_message_type_table
))), sizeof(dhcp6_message_type_table)/sizeof((dhcp6_message_type_table
)[0]), ((void)0))), s); }
;
88
89const char * dhcp6_message_status_table[_DHCP6_STATUS_MAX] = {
90 [DHCP6_STATUS_SUCCESS] = "Success",
91 [DHCP6_STATUS_UNSPEC_FAIL] = "Unspecified failure",
92 [DHCP6_STATUS_NO_ADDRS_AVAIL] = "No addresses available",
93 [DHCP6_STATUS_NO_BINDING] = "Binding unavailable",
94 [DHCP6_STATUS_NOT_ON_LINK] = "Not on link",
95 [DHCP6_STATUS_USE_MULTICAST] = "Use multicast",
96};
97
98DEFINE_STRING_TABLE_LOOKUP(dhcp6_message_status, int)const char *dhcp6_message_status_to_string(int i) { if (i <
0 || i >= (int) __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p
(typeof(dhcp6_message_status_table), typeof(&*(dhcp6_message_status_table
))), sizeof(dhcp6_message_status_table)/sizeof((dhcp6_message_status_table
)[0]), ((void)0)))) return ((void*)0); return dhcp6_message_status_table
[i]; } int dhcp6_message_status_from_string(const char *s) { return
(int) string_table_lookup(dhcp6_message_status_table, __extension__
(__builtin_choose_expr( !__builtin_types_compatible_p(typeof
(dhcp6_message_status_table), typeof(&*(dhcp6_message_status_table
))), sizeof(dhcp6_message_status_table)/sizeof((dhcp6_message_status_table
)[0]), ((void)0))), s); }
;
99
100#define DHCP6_CLIENT_DONT_DESTROY(client)__attribute__((cleanup(sd_dhcp6_client_unrefp))) __attribute__
((unused)) sd_dhcp6_client *_dont_destroy_client = sd_dhcp6_client_ref
(client)
\
101 _cleanup_(sd_dhcp6_client_unrefp)__attribute__((cleanup(sd_dhcp6_client_unrefp))) _unused___attribute__ ((unused)) sd_dhcp6_client *_dont_destroy_##client = sd_dhcp6_client_ref(client)
102
103static int client_start(sd_dhcp6_client *client, enum DHCP6State state);
104
105int sd_dhcp6_client_set_callback(
106 sd_dhcp6_client *client,
107 sd_dhcp6_client_callback_t cb,
108 void *userdata) {
109
110 assert_return(client, -EINVAL)do { if (!(((__builtin_expect(!!(client),1))) ? (1) : (log_assert_failed_return_realm
(LOG_REALM_SYSTEMD, ("client"), "../src/libsystemd-network/sd-dhcp6-client.c"
, 110, __PRETTY_FUNCTION__), 0))) return (-22); } while (0)
;
111
112 client->callback = cb;
113 client->userdata = userdata;
114
115 return 0;
116}
117
118int sd_dhcp6_client_set_ifindex(sd_dhcp6_client *client, int ifindex) {
119
120 assert_return(client, -EINVAL)do { if (!(((__builtin_expect(!!(client),1))) ? (1) : (log_assert_failed_return_realm
(LOG_REALM_SYSTEMD, ("client"), "../src/libsystemd-network/sd-dhcp6-client.c"
, 120, __PRETTY_FUNCTION__), 0))) return (-22); } while (0)
;
121 assert_return(ifindex >= -1, -EINVAL)do { if (!(((__builtin_expect(!!(ifindex >= -1),1))) ? (1)
: (log_assert_failed_return_realm(LOG_REALM_SYSTEMD, ("ifindex >= -1"
), "../src/libsystemd-network/sd-dhcp6-client.c", 121, __PRETTY_FUNCTION__
), 0))) return (-22); } while (0)
;
122 assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY)do { if (!(((__builtin_expect(!!(({ _Bool _found = 0; static __attribute__
((unused)) char _static_assert__macros_need_to_be_extended[20
- sizeof((int[]){DHCP6_STATE_STOPPED})/sizeof(int)]; switch(
client->state) { case DHCP6_STATE_STOPPED: _found = 1; break
; default: break; } _found; })),1))) ? (1) : (log_assert_failed_return_realm
(LOG_REALM_SYSTEMD, ("IN_SET(client->state, DHCP6_STATE_STOPPED)"
), "../src/libsystemd-network/sd-dhcp6-client.c", 122, __PRETTY_FUNCTION__
), 0))) return (-16); } while (0)
;
123
124 client->ifindex = ifindex;
125 return 0;
126}
127
128int sd_dhcp6_client_set_local_address(
129 sd_dhcp6_client *client,
130 const struct in6_addr *local_address) {
131
132 assert_return(client, -EINVAL)do { if (!(((__builtin_expect(!!(client),1))) ? (1) : (log_assert_failed_return_realm
(LOG_REALM_SYSTEMD, ("client"), "../src/libsystemd-network/sd-dhcp6-client.c"
, 132, __PRETTY_FUNCTION__), 0))) return (-22); } while (0)
;
133 assert_return(local_address, -EINVAL)do { if (!(((__builtin_expect(!!(local_address),1))) ? (1) : (
log_assert_failed_return_realm(LOG_REALM_SYSTEMD, ("local_address"
), "../src/libsystemd-network/sd-dhcp6-client.c", 133, __PRETTY_FUNCTION__
), 0))) return (-22); } while (0)
;
134 assert_return(in_addr_is_link_local(AF_INET6, (const union in_addr_union *) local_address) > 0, -EINVAL)do { if (!(((__builtin_expect(!!(in_addr_is_link_local(10, (const
union in_addr_union *) local_address) > 0),1))) ? (1) : (
log_assert_failed_return_realm(LOG_REALM_SYSTEMD, ("in_addr_is_link_local(AF_INET6, (const union in_addr_union *) local_address) > 0"
), "../src/libsystemd-network/sd-dhcp6-client.c", 134, __PRETTY_FUNCTION__
), 0))) return (-22); } while (0)
;
135
136 assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY)do { if (!(((__builtin_expect(!!(({ _Bool _found = 0; static __attribute__
((unused)) char _static_assert__macros_need_to_be_extended[20
- sizeof((int[]){DHCP6_STATE_STOPPED})/sizeof(int)]; switch(
client->state) { case DHCP6_STATE_STOPPED: _found = 1; break
; default: break; } _found; })),1))) ? (1) : (log_assert_failed_return_realm
(LOG_REALM_SYSTEMD, ("IN_SET(client->state, DHCP6_STATE_STOPPED)"
), "../src/libsystemd-network/sd-dhcp6-client.c", 136, __PRETTY_FUNCTION__
), 0))) return (-16); } while (0)
;
137
138 client->local_address = *local_address;
139
140 return 0;
141}
142
143int sd_dhcp6_client_set_mac(
144 sd_dhcp6_client *client,
145 const uint8_t *addr, size_t addr_len,
146 uint16_t arp_type) {
147
148 assert_return(client, -EINVAL)do { if (!(((__builtin_expect(!!(client),1))) ? (1) : (log_assert_failed_return_realm
(LOG_REALM_SYSTEMD, ("client"), "../src/libsystemd-network/sd-dhcp6-client.c"
, 148, __PRETTY_FUNCTION__), 0))) return (-22); } while (0)
;
149 assert_return(addr, -EINVAL)do { if (!(((__builtin_expect(!!(addr),1))) ? (1) : (log_assert_failed_return_realm
(LOG_REALM_SYSTEMD, ("addr"), "../src/libsystemd-network/sd-dhcp6-client.c"
, 149, __PRETTY_FUNCTION__), 0))) return (-22); } while (0)
;
150 assert_return(addr_len > 0 && addr_len <= MAX_MAC_ADDR_LEN, -EINVAL)do { if (!(((__builtin_expect(!!(addr_len > 0 && addr_len
<= 20),1))) ? (1) : (log_assert_failed_return_realm(LOG_REALM_SYSTEMD
, ("addr_len > 0 && addr_len <= MAX_MAC_ADDR_LEN"
), "../src/libsystemd-network/sd-dhcp6-client.c", 150, __PRETTY_FUNCTION__
), 0))) return (-22); } while (0)
;
151 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-dhcp6-client.c", 151, __PRETTY_FUNCTION__
), 0))) return (-22); } while (0)
;
152
153 assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY)do { if (!(((__builtin_expect(!!(({ _Bool _found = 0; static __attribute__
((unused)) char _static_assert__macros_need_to_be_extended[20
- sizeof((int[]){DHCP6_STATE_STOPPED})/sizeof(int)]; switch(
client->state) { case DHCP6_STATE_STOPPED: _found = 1; break
; default: break; } _found; })),1))) ? (1) : (log_assert_failed_return_realm
(LOG_REALM_SYSTEMD, ("IN_SET(client->state, DHCP6_STATE_STOPPED)"
), "../src/libsystemd-network/sd-dhcp6-client.c", 153, __PRETTY_FUNCTION__
), 0))) return (-16); } while (0)
;
154
155 if (arp_type == ARPHRD_ETHER1)
156 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-dhcp6-client.c", 156, __PRETTY_FUNCTION__
), 0))) return (-22); } while (0)
;
157 else if (arp_type == ARPHRD_INFINIBAND32)
158 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-dhcp6-client.c", 158, __PRETTY_FUNCTION__
), 0))) return (-22); } while (0)
;
159 else
160 return -EINVAL22;
161
162 if (client->mac_addr_len == addr_len &&
163 memcmp(&client->mac_addr, addr, addr_len) == 0)
164 return 0;
165
166 memcpy(&client->mac_addr, addr, addr_len);
167 client->mac_addr_len = addr_len;
168 client->arp_type = arp_type;
169
170 return 0;
171}
172
173static int client_ensure_duid(sd_dhcp6_client *client) {
174 if (client->duid_len != 0)
175 return 0;
176
177 return dhcp_identifier_set_duid_en(&client->duid, &client->duid_len);
178}
179
180/**
181 * Sets DUID. If duid is non-null, the DUID is set to duid_type + duid
182 * without further modification. Otherwise, if duid_type is supported, DUID
183 * is set based on that type. Otherwise, an error is returned.
184 */
185int sd_dhcp6_client_set_duid(
186 sd_dhcp6_client *client,
187 uint16_t duid_type,
188 const void *duid,
189 size_t duid_len) {
190
191 int r;
192 assert_return(client, -EINVAL)do { if (!(((__builtin_expect(!!(client),1))) ? (1) : (log_assert_failed_return_realm
(LOG_REALM_SYSTEMD, ("client"), "../src/libsystemd-network/sd-dhcp6-client.c"
, 192, __PRETTY_FUNCTION__), 0))) return (-22); } while (0)
;
193 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-dhcp6-client.c"
, 193, __PRETTY_FUNCTION__), 0))) return (-22); } while (0)
;
194 assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY)do { if (!(((__builtin_expect(!!(({ _Bool _found = 0; static __attribute__
((unused)) char _static_assert__macros_need_to_be_extended[20
- sizeof((int[]){DHCP6_STATE_STOPPED})/sizeof(int)]; switch(
client->state) { case DHCP6_STATE_STOPPED: _found = 1; break
; default: break; } _found; })),1))) ? (1) : (log_assert_failed_return_realm
(LOG_REALM_SYSTEMD, ("IN_SET(client->state, DHCP6_STATE_STOPPED)"
), "../src/libsystemd-network/sd-dhcp6-client.c", 194, __PRETTY_FUNCTION__
), 0))) return (-16); } while (0)
;
195
196 if (duid != NULL((void*)0)) {
197 r = dhcp_validate_duid_len(duid_type, duid_len);
198 if (r < 0)
199 return r;
200 }
201
202 if (duid != NULL((void*)0)) {
203 client->duid.type = htobe16(duid_type);
204 memcpy(&client->duid.raw.data, duid, duid_len);
205 client->duid_len = sizeof(client->duid.type) + duid_len;
206 } else if (duid_type == DUID_TYPE_EN) {
207 r = dhcp_identifier_set_duid_en(&client->duid, &client->duid_len);
208 if (r < 0)
209 return r;
210 } else
211 return -EOPNOTSUPP95;
212
213 return 0;
214}
215
216int sd_dhcp6_client_set_iaid(sd_dhcp6_client *client, uint32_t iaid) {
217 assert_return(client, -EINVAL)do { if (!(((__builtin_expect(!!(client),1))) ? (1) : (log_assert_failed_return_realm
(LOG_REALM_SYSTEMD, ("client"), "../src/libsystemd-network/sd-dhcp6-client.c"
, 217, __PRETTY_FUNCTION__), 0))) return (-22); } while (0)
;
218 assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY)do { if (!(((__builtin_expect(!!(({ _Bool _found = 0; static __attribute__
((unused)) char _static_assert__macros_need_to_be_extended[20
- sizeof((int[]){DHCP6_STATE_STOPPED})/sizeof(int)]; switch(
client->state) { case DHCP6_STATE_STOPPED: _found = 1; break
; default: break; } _found; })),1))) ? (1) : (log_assert_failed_return_realm
(LOG_REALM_SYSTEMD, ("IN_SET(client->state, DHCP6_STATE_STOPPED)"
), "../src/libsystemd-network/sd-dhcp6-client.c", 218, __PRETTY_FUNCTION__
), 0))) return (-16); } while (0)
;
219
220 client->ia_na.ia_na.id = htobe32(iaid);
221 client->ia_pd.ia_pd.id = htobe32(iaid);
222
223 return 0;
224}
225
226int sd_dhcp6_client_set_fqdn(
227 sd_dhcp6_client *client,
228 const char *fqdn) {
229
230 assert_return(client, -EINVAL)do { if (!(((__builtin_expect(!!(client),1))) ? (1) : (log_assert_failed_return_realm
(LOG_REALM_SYSTEMD, ("client"), "../src/libsystemd-network/sd-dhcp6-client.c"
, 230, __PRETTY_FUNCTION__), 0))) return (-22); } while (0)
;
231
232 /* Make sure FQDN qualifies as DNS and as Linux hostname */
233 if (fqdn &&
234 !(hostname_is_valid(fqdn, false0) && dns_name_is_valid(fqdn) > 0))
235 return -EINVAL22;
236
237 return free_and_strdup(&client->fqdn, fqdn);
238}
239
240int sd_dhcp6_client_set_information_request(sd_dhcp6_client *client, int enabled) {
241 assert_return(client, -EINVAL)do { if (!(((__builtin_expect(!!(client),1))) ? (1) : (log_assert_failed_return_realm
(LOG_REALM_SYSTEMD, ("client"), "../src/libsystemd-network/sd-dhcp6-client.c"
, 241, __PRETTY_FUNCTION__), 0))) return (-22); } while (0)
;
242 assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY)do { if (!(((__builtin_expect(!!(({ _Bool _found = 0; static __attribute__
((unused)) char _static_assert__macros_need_to_be_extended[20
- sizeof((int[]){DHCP6_STATE_STOPPED})/sizeof(int)]; switch(
client->state) { case DHCP6_STATE_STOPPED: _found = 1; break
; default: break; } _found; })),1))) ? (1) : (log_assert_failed_return_realm
(LOG_REALM_SYSTEMD, ("IN_SET(client->state, DHCP6_STATE_STOPPED)"
), "../src/libsystemd-network/sd-dhcp6-client.c", 242, __PRETTY_FUNCTION__
), 0))) return (-16); } while (0)
;
243
244 client->information_request = enabled;
245
246 return 0;
247}
248
249int sd_dhcp6_client_get_information_request(sd_dhcp6_client *client, int *enabled) {
250 assert_return(client, -EINVAL)do { if (!(((__builtin_expect(!!(client),1))) ? (1) : (log_assert_failed_return_realm
(LOG_REALM_SYSTEMD, ("client"), "../src/libsystemd-network/sd-dhcp6-client.c"
, 250, __PRETTY_FUNCTION__), 0))) return (-22); } while (0)
;
251 assert_return(enabled, -EINVAL)do { if (!(((__builtin_expect(!!(enabled),1))) ? (1) : (log_assert_failed_return_realm
(LOG_REALM_SYSTEMD, ("enabled"), "../src/libsystemd-network/sd-dhcp6-client.c"
, 251, __PRETTY_FUNCTION__), 0))) return (-22); } while (0)
;
252
253 *enabled = client->information_request;
254
255 return 0;
256}
257
258int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client, uint16_t option) {
259 size_t t;
260
261 assert_return(client, -EINVAL)do { if (!(((__builtin_expect(!!(client),1))) ? (1) : (log_assert_failed_return_realm
(LOG_REALM_SYSTEMD, ("client"), "../src/libsystemd-network/sd-dhcp6-client.c"
, 261, __PRETTY_FUNCTION__), 0))) return (-22); } while (0)
;
262 assert_return(client->state == DHCP6_STATE_STOPPED, -EBUSY)do { if (!(((__builtin_expect(!!(client->state == DHCP6_STATE_STOPPED
),1))) ? (1) : (log_assert_failed_return_realm(LOG_REALM_SYSTEMD
, ("client->state == DHCP6_STATE_STOPPED"), "../src/libsystemd-network/sd-dhcp6-client.c"
, 262, __PRETTY_FUNCTION__), 0))) return (-16); } while (0)
;
263
264 switch(option) {
265
266 case SD_DHCP6_OPTION_DNS_SERVERS:
267 case SD_DHCP6_OPTION_DOMAIN_LIST:
268 case SD_DHCP6_OPTION_SNTP_SERVERS:
269 case SD_DHCP6_OPTION_NTP_SERVER:
270 case SD_DHCP6_OPTION_RAPID_COMMIT:
271 break;
272
273 default:
274 return -EINVAL22;
275 }
276
277 for (t = 0; t < client->req_opts_len; t++)
278 if (client->req_opts[t] == htobe16(option))
279 return -EEXIST17;
280
281 if (!GREEDY_REALLOC(client->req_opts, client->req_opts_allocated,greedy_realloc((void**) &(client->req_opts), &(client
->req_opts_allocated), (client->req_opts_len + 1), sizeof
((client->req_opts)[0]))
282 client->req_opts_len + 1)greedy_realloc((void**) &(client->req_opts), &(client
->req_opts_allocated), (client->req_opts_len + 1), sizeof
((client->req_opts)[0]))
)
283 return -ENOMEM12;
284
285 client->req_opts[client->req_opts_len++] = htobe16(option);
286
287 return 0;
288}
289
290int sd_dhcp6_client_set_prefix_delegation(sd_dhcp6_client *client, bool_Bool delegation) {
291 assert_return(client, -EINVAL)do { if (!(((__builtin_expect(!!(client),1))) ? (1) : (log_assert_failed_return_realm
(LOG_REALM_SYSTEMD, ("client"), "../src/libsystemd-network/sd-dhcp6-client.c"
, 291, __PRETTY_FUNCTION__), 0))) return (-22); } while (0)
;
292
293 client->prefix_delegation = delegation;
294
295 return 0;
296}
297
298int sd_dhcp6_client_get_lease(sd_dhcp6_client *client, sd_dhcp6_lease **ret) {
299 assert_return(client, -EINVAL)do { if (!(((__builtin_expect(!!(client),1))) ? (1) : (log_assert_failed_return_realm
(LOG_REALM_SYSTEMD, ("client"), "../src/libsystemd-network/sd-dhcp6-client.c"
, 299, __PRETTY_FUNCTION__), 0))) return (-22); } while (0)
;
300
301 if (!client->lease)
302 return -ENOMSG42;
303
304 if (ret)
305 *ret = client->lease;
306
307 return 0;
308}
309
310static void client_notify(sd_dhcp6_client *client, int event) {
311 assert(client)do { if ((__builtin_expect(!!(!(client)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("client"), "../src/libsystemd-network/sd-dhcp6-client.c"
, 311, __PRETTY_FUNCTION__); } while (0)
;
312
313 if (client->callback)
314 client->callback(client, event, client->userdata);
315}
316
317static void client_set_lease(sd_dhcp6_client *client, sd_dhcp6_lease *lease) {
318 assert(client)do { if ((__builtin_expect(!!(!(client)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("client"), "../src/libsystemd-network/sd-dhcp6-client.c"
, 318, __PRETTY_FUNCTION__); } while (0)
;
319
320 if (client->lease) {
321 dhcp6_lease_clear_timers(&client->lease->ia);
322 sd_dhcp6_lease_unref(client->lease);
323 }
324
325 client->lease = lease;
326}
327
328static int client_reset(sd_dhcp6_client *client) {
329 assert(client)do { if ((__builtin_expect(!!(!(client)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("client"), "../src/libsystemd-network/sd-dhcp6-client.c"
, 329, __PRETTY_FUNCTION__); } while (0)
;
330
331 client_set_lease(client, NULL((void*)0));
332
333 client->receive_message =
334 sd_event_source_unref(client->receive_message);
335
336 client->transaction_id = 0;
337 client->transaction_start = 0;
338
339 client->ia_na.timeout_t1 =
340 sd_event_source_unref(client->ia_na.timeout_t1);
341 client->ia_na.timeout_t2 =
342 sd_event_source_unref(client->ia_na.timeout_t2);
343
344 client->retransmit_time = 0;
345 client->retransmit_count = 0;
346 client->timeout_resend = sd_event_source_unref(client->timeout_resend);
347 client->timeout_resend_expire =
348 sd_event_source_unref(client->timeout_resend_expire);
349
350 client->state = DHCP6_STATE_STOPPED;
351
352 return 0;
353}
354
355static void client_stop(sd_dhcp6_client *client, int error) {
356 DHCP6_CLIENT_DONT_DESTROY(client)__attribute__((cleanup(sd_dhcp6_client_unrefp))) __attribute__
((unused)) sd_dhcp6_client *_dont_destroy_client = sd_dhcp6_client_ref
(client)
;
357
358 assert(client)do { if ((__builtin_expect(!!(!(client)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("client"), "../src/libsystemd-network/sd-dhcp6-client.c"
, 358, __PRETTY_FUNCTION__); } while (0)
;
359
360 client_notify(client, error);
361
362 client_reset(client);
363}
364
365static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
366 _cleanup_free___attribute__((cleanup(freep))) DHCP6Message *message = NULL((void*)0);
367 struct in6_addr all_servers =
368 IN6ADDR_ALL_DHCP6_RELAY_AGENTS_AND_SERVERS_INIT{ { { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02 } } }
;
369 size_t len, optlen = 512;
370 uint8_t *opt;
371 int r;
372 usec_t elapsed_usec;
373 be16_t elapsed_time;
374
375 assert(client)do { if ((__builtin_expect(!!(!(client)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("client"), "../src/libsystemd-network/sd-dhcp6-client.c"
, 375, __PRETTY_FUNCTION__); } while (0)
;
376
377 len = sizeof(DHCP6Message) + optlen;
378
379 message = malloc0(len)(calloc(1, (len)));
380 if (!message)
381 return -ENOMEM12;
382
383 opt = (uint8_t *)(message + 1);
384
385 message->transaction_id = client->transaction_id;
386
387 switch(client->state) {
388 case DHCP6_STATE_INFORMATION_REQUEST:
389 message->type = DHCP6_INFORMATION_REQUEST;
390
391 break;
392
393 case DHCP6_STATE_SOLICITATION:
394 message->type = DHCP6_SOLICIT;
395
396 r = dhcp6_option_append(&opt, &optlen,
397 SD_DHCP6_OPTION_RAPID_COMMIT, 0, NULL((void*)0));
398 if (r < 0)
399 return r;
400
401 r = dhcp6_option_append_ia(&opt, &optlen, &client->ia_na);
402 if (r < 0)
403 return r;
404
405 if (client->fqdn) {
406 r = dhcp6_option_append_fqdn(&opt, &optlen, client->fqdn);
407 if (r < 0)
408 return r;
409 }
410
411 if (client->prefix_delegation) {
412 r = dhcp6_option_append_pd(opt, optlen, &client->ia_pd);
413 if (r < 0)
414 return r;
415
416 opt += r;
417 optlen -= r;
418 }
419
420 break;
421
422 case DHCP6_STATE_REQUEST:
423 case DHCP6_STATE_RENEW:
424
425 if (client->state == DHCP6_STATE_REQUEST)
426 message->type = DHCP6_REQUEST;
427 else
428 message->type = DHCP6_RENEW;
429
430 r = dhcp6_option_append(&opt, &optlen, SD_DHCP6_OPTION_SERVERID,
431 client->lease->serverid_len,
432 client->lease->serverid);
433 if (r < 0)
434 return r;
435
436 r = dhcp6_option_append_ia(&opt, &optlen, &client->lease->ia);
437 if (r < 0)
438 return r;
439
440 if (client->fqdn) {
441 r = dhcp6_option_append_fqdn(&opt, &optlen, client->fqdn);
442 if (r < 0)
443 return r;
444 }
445
446 if (client->prefix_delegation) {
447 r = dhcp6_option_append_pd(opt, optlen, &client->lease->pd);
448 if (r < 0)
449 return r;
450
451 opt += r;
452 optlen -= r;
453 }
454
455 break;
456
457 case DHCP6_STATE_REBIND:
458 message->type = DHCP6_REBIND;
459
460 r = dhcp6_option_append_ia(&opt, &optlen, &client->lease->ia);
461 if (r < 0)
462 return r;
463
464 if (client->fqdn) {
465 r = dhcp6_option_append_fqdn(&opt, &optlen, client->fqdn);
466 if (r < 0)
467 return r;
468 }
469
470 if (client->prefix_delegation) {
471 r = dhcp6_option_append_pd(opt, optlen, &client->lease->pd);
472 if (r < 0)
473 return r;
474
475 opt += r;
476 optlen -= r;
477 }
478
479 break;
480
481 case DHCP6_STATE_STOPPED:
482 case DHCP6_STATE_BOUND:
483 return -EINVAL22;
484 }
485
486 r = dhcp6_option_append(&opt, &optlen, SD_DHCP6_OPTION_ORO,
487 client->req_opts_len * sizeof(be16_t),
488 client->req_opts);
489 if (r < 0)
490 return r;
491
492 assert(client->duid_len)do { if ((__builtin_expect(!!(!(client->duid_len)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("client->duid_len"), "../src/libsystemd-network/sd-dhcp6-client.c"
, 492, __PRETTY_FUNCTION__); } while (0)
;
493 r = dhcp6_option_append(&opt, &optlen, SD_DHCP6_OPTION_CLIENTID,
494 client->duid_len, &client->duid);
495 if (r < 0)
496 return r;
497
498 elapsed_usec = time_now - client->transaction_start;
499 if (elapsed_usec < 0xffff * USEC_PER_MSEC((usec_t) 1000ULL) * 10)
500 elapsed_time = htobe16(elapsed_usec / USEC_PER_MSEC((usec_t) 1000ULL) / 10);
501 else
502 elapsed_time = 0xffff;
503
504 r = dhcp6_option_append(&opt, &optlen, SD_DHCP6_OPTION_ELAPSED_TIME,
505 sizeof(elapsed_time), &elapsed_time);
506 if (r < 0)
507 return r;
508
509 r = dhcp6_network_send_udp_socket(client->fd, &all_servers, message,
510 len - optlen);
511 if (r < 0)
512 return r;
513
514 log_dhcp6_client(client, "Sent %s",log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))),
0, "../src/libsystemd-network/sd-dhcp6-client.c", 515, __func__
, "DHCPv6 CLIENT: " "Sent %s", dhcp6_message_type_to_string(message
->type))
515 dhcp6_message_type_to_string(message->type))log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))),
0, "../src/libsystemd-network/sd-dhcp6-client.c", 515, __func__
, "DHCPv6 CLIENT: " "Sent %s", dhcp6_message_type_to_string(message
->type))
;
516
517 return 0;
518}
519
520static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata) {
521 sd_dhcp6_client *client = userdata;
522
523 assert(s)do { if ((__builtin_expect(!!(!(s)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("s"), "../src/libsystemd-network/sd-dhcp6-client.c"
, 523, __PRETTY_FUNCTION__); } while (0)
;
524 assert(client)do { if ((__builtin_expect(!!(!(client)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("client"), "../src/libsystemd-network/sd-dhcp6-client.c"
, 524, __PRETTY_FUNCTION__); } while (0)
;
525 assert(client->lease)do { if ((__builtin_expect(!!(!(client->lease)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("client->lease"), "../src/libsystemd-network/sd-dhcp6-client.c"
, 525, __PRETTY_FUNCTION__); } while (0)
;
526
527 client->lease->ia.timeout_t2 =
528 sd_event_source_unref(client->lease->ia.timeout_t2);
529
530 log_dhcp6_client(client, "Timeout T2")log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))),
0, "../src/libsystemd-network/sd-dhcp6-client.c", 530, __func__
, "DHCPv6 CLIENT: " "Timeout T2")
;
531
532 client_start(client, DHCP6_STATE_REBIND);
533
534 return 0;
535}
536
537static int client_timeout_t1(sd_event_source *s, uint64_t usec, void *userdata) {
538 sd_dhcp6_client *client = userdata;
539
540 assert(s)do { if ((__builtin_expect(!!(!(s)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("s"), "../src/libsystemd-network/sd-dhcp6-client.c"
, 540, __PRETTY_FUNCTION__); } while (0)
;
541 assert(client)do { if ((__builtin_expect(!!(!(client)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("client"), "../src/libsystemd-network/sd-dhcp6-client.c"
, 541, __PRETTY_FUNCTION__); } while (0)
;
542 assert(client->lease)do { if ((__builtin_expect(!!(!(client->lease)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("client->lease"), "../src/libsystemd-network/sd-dhcp6-client.c"
, 542, __PRETTY_FUNCTION__); } while (0)
;
543
544 client->lease->ia.timeout_t1 =
545 sd_event_source_unref(client->lease->ia.timeout_t1);
546
547 log_dhcp6_client(client, "Timeout T1")log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))),
0, "../src/libsystemd-network/sd-dhcp6-client.c", 547, __func__
, "DHCPv6 CLIENT: " "Timeout T1")
;
548
549 client_start(client, DHCP6_STATE_RENEW);
550
551 return 0;
552}
553
554static int client_timeout_resend_expire(sd_event_source *s, uint64_t usec, void *userdata) {
555 sd_dhcp6_client *client = userdata;
556 DHCP6_CLIENT_DONT_DESTROY(client)__attribute__((cleanup(sd_dhcp6_client_unrefp))) __attribute__
((unused)) sd_dhcp6_client *_dont_destroy_client = sd_dhcp6_client_ref
(client)
;
557 enum DHCP6State state;
558
559 assert(s)do { if ((__builtin_expect(!!(!(s)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("s"), "../src/libsystemd-network/sd-dhcp6-client.c"
, 559, __PRETTY_FUNCTION__); } while (0)
;
560 assert(client)do { if ((__builtin_expect(!!(!(client)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("client"), "../src/libsystemd-network/sd-dhcp6-client.c"
, 560, __PRETTY_FUNCTION__); } while (0)
;
561 assert(client->event)do { if ((__builtin_expect(!!(!(client->event)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("client->event"), "../src/libsystemd-network/sd-dhcp6-client.c"
, 561, __PRETTY_FUNCTION__); } while (0)
;
562
563 state = client->state;
564
565 client_stop(client, SD_DHCP6_CLIENT_EVENT_RESEND_EXPIRE);
566
567 /* RFC 3315, section 18.1.4., says that "...the client may choose to
568 use a Solicit message to locate a new DHCP server..." */
569 if (state == DHCP6_STATE_REBIND)
570 client_start(client, DHCP6_STATE_SOLICITATION);
571
572 return 0;
573}
574
575static usec_t client_timeout_compute_random(usec_t val) {
576 return val - val / 10 +
577 (random_u32() % (2 * USEC_PER_SEC((usec_t) 1000000ULL))) * val / 10 / USEC_PER_SEC((usec_t) 1000000ULL);
578}
579
580static int client_timeout_resend(sd_event_source *s, uint64_t usec, void *userdata) {
581 int r = 0;
582 sd_dhcp6_client *client = userdata;
583 usec_t time_now, init_retransmit_time = 0, max_retransmit_time = 0;
584 usec_t max_retransmit_duration = 0;
585 uint8_t max_retransmit_count = 0;
586 char time_string[FORMAT_TIMESPAN_MAX64];
587 uint32_t expire = 0;
588
589 assert(s)do { if ((__builtin_expect(!!(!(s)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("s"), "../src/libsystemd-network/sd-dhcp6-client.c"
, 589, __PRETTY_FUNCTION__); } while (0)
;
590 assert(client)do { if ((__builtin_expect(!!(!(client)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("client"), "../src/libsystemd-network/sd-dhcp6-client.c"
, 590, __PRETTY_FUNCTION__); } while (0)
;
591 assert(client->event)do { if ((__builtin_expect(!!(!(client->event)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("client->event"), "../src/libsystemd-network/sd-dhcp6-client.c"
, 591, __PRETTY_FUNCTION__); } while (0)
;
592
593 client->timeout_resend = sd_event_source_unref(client->timeout_resend);
594
595 switch (client->state) {
596 case DHCP6_STATE_INFORMATION_REQUEST:
597 init_retransmit_time = DHCP6_INF_TIMEOUT1 * ((usec_t) 1000000ULL);
598 max_retransmit_time = DHCP6_INF_MAX_RT120 * ((usec_t) 1000000ULL);
599
600 break;
601
602 case DHCP6_STATE_SOLICITATION:
603
604 if (client->retransmit_count && client->lease) {
605 client_start(client, DHCP6_STATE_REQUEST);
606 return 0;
607 }
608
609 init_retransmit_time = DHCP6_SOL_TIMEOUT1 * ((usec_t) 1000000ULL);
610 max_retransmit_time = DHCP6_SOL_MAX_RT120 * ((usec_t) 1000000ULL);
611
612 break;
613
614 case DHCP6_STATE_REQUEST:
615 init_retransmit_time = DHCP6_REQ_TIMEOUT1 * ((usec_t) 1000000ULL);
616 max_retransmit_time = DHCP6_REQ_MAX_RT120 * ((usec_t) 1000000ULL);
617 max_retransmit_count = DHCP6_REQ_MAX_RC10;
618
619 break;
620
621 case DHCP6_STATE_RENEW:
622 init_retransmit_time = DHCP6_REN_TIMEOUT10 * ((usec_t) 1000000ULL);
623 max_retransmit_time = DHCP6_REN_MAX_RT600 * ((usec_t) 1000000ULL);
624
625 /* RFC 3315, section 18.1.3. says max retransmit duration will
626 be the remaining time until T2. Instead of setting MRD,
627 wait for T2 to trigger with the same end result */
628
629 break;
630
631 case DHCP6_STATE_REBIND:
632 init_retransmit_time = DHCP6_REB_TIMEOUT10 * ((usec_t) 1000000ULL);
633 max_retransmit_time = DHCP6_REB_MAX_RT600 * ((usec_t) 1000000ULL);
634
635 if (!client->timeout_resend_expire) {
636 r = dhcp6_lease_ia_rebind_expire(&client->lease->ia,
637 &expire);
638 if (r < 0) {
639 client_stop(client, r);
640 return 0;
641 }
642 max_retransmit_duration = expire * USEC_PER_SEC((usec_t) 1000000ULL);
643 }
644
645 break;
646
647 case DHCP6_STATE_STOPPED:
648 case DHCP6_STATE_BOUND:
649 return 0;
650 }
651
652 if (max_retransmit_count &&
653 client->retransmit_count >= max_retransmit_count) {
654 client_stop(client, SD_DHCP6_CLIENT_EVENT_RETRANS_MAX);
655 return 0;
656 }
657
658 r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
659 if (r < 0)
660 goto error;
661
662 r = client_send_message(client, time_now);
663 if (r >= 0)
664 client->retransmit_count++;
665
666 if (!client->retransmit_time) {
667 client->retransmit_time =
668 client_timeout_compute_random(init_retransmit_time);
669
670 if (client->state == DHCP6_STATE_SOLICITATION)
671 client->retransmit_time += init_retransmit_time / 10;
672
673 } else {
674 if (max_retransmit_time &&
675 client->retransmit_time > max_retransmit_time / 2)
676 client->retransmit_time = client_timeout_compute_random(max_retransmit_time);
677 else
678 client->retransmit_time += client_timeout_compute_random(client->retransmit_time);
679 }
680
681 log_dhcp6_client(client, "Next retransmission in %s",log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))),
0, "../src/libsystemd-network/sd-dhcp6-client.c", 682, __func__
, "DHCPv6 CLIENT: " "Next retransmission in %s", format_timespan
(time_string, 64, client->retransmit_time, ((usec_t) 1000000ULL
)))
682 format_timespan(time_string, FORMAT_TIMESPAN_MAX, client->retransmit_time, USEC_PER_SEC))log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))),
0, "../src/libsystemd-network/sd-dhcp6-client.c", 682, __func__
, "DHCPv6 CLIENT: " "Next retransmission in %s", format_timespan
(time_string, 64, client->retransmit_time, ((usec_t) 1000000ULL
)))
;
683
684 r = sd_event_add_time(client->event, &client->timeout_resend,
685 clock_boottime_or_monotonic(),
686 time_now + client->retransmit_time,
687 10 * USEC_PER_MSEC((usec_t) 1000ULL), client_timeout_resend,
688 client);
689 if (r < 0)
690 goto error;
691
692 r = sd_event_source_set_priority(client->timeout_resend,
693 client->event_priority);
694 if (r < 0)
695 goto error;
696
697 r = sd_event_source_set_description(client->timeout_resend, "dhcp6-resend-timer");
698 if (r < 0)
699 goto error;
700
701 if (max_retransmit_duration && !client->timeout_resend_expire) {
702
703 log_dhcp6_client(client, "Max retransmission duration %"PRIu64" secs",log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))),
0, "../src/libsystemd-network/sd-dhcp6-client.c", 704, __func__
, "DHCPv6 CLIENT: " "Max retransmission duration %""l" "u"" secs"
, max_retransmit_duration / ((usec_t) 1000000ULL))
704 max_retransmit_duration / USEC_PER_SEC)log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))),
0, "../src/libsystemd-network/sd-dhcp6-client.c", 704, __func__
, "DHCPv6 CLIENT: " "Max retransmission duration %""l" "u"" secs"
, max_retransmit_duration / ((usec_t) 1000000ULL))
;
705
706 r = sd_event_add_time(client->event,
707 &client->timeout_resend_expire,
708 clock_boottime_or_monotonic(),
709 time_now + max_retransmit_duration,
710 USEC_PER_SEC((usec_t) 1000000ULL),
711 client_timeout_resend_expire, client);
712 if (r < 0)
713 goto error;
714
715 r = sd_event_source_set_priority(client->timeout_resend_expire,
716 client->event_priority);
717 if (r < 0)
718 goto error;
719
720 r = sd_event_source_set_description(client->timeout_resend_expire, "dhcp6-resend-expire-timer");
721 if (r < 0)
722 goto error;
723 }
724
725error:
726 if (r < 0)
727 client_stop(client, r);
728
729 return 0;
730}
731
732static int client_ensure_iaid(sd_dhcp6_client *client) {
733 int r;
734 be32_t iaid;
735
736 assert(client)do { if ((__builtin_expect(!!(!(client)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("client"), "../src/libsystemd-network/sd-dhcp6-client.c"
, 736, __PRETTY_FUNCTION__); } while (0)
;
737
738 if (client->ia_na.ia_na.id)
739 return 0;
740
741 r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr, client->mac_addr_len, &iaid);
742 if (r < 0)
743 return r;
744
745 client->ia_na.ia_na.id = iaid;
746 client->ia_pd.ia_pd.id = iaid;
747
748 return 0;
749}
750
751static int client_parse_message(
752 sd_dhcp6_client *client,
753 DHCP6Message *message,
754 size_t len,
755 sd_dhcp6_lease *lease) {
756 size_t pos = 0;
757 int r;
758 bool_Bool clientid = false0;
759 uint32_t lt_t1 = ~0, lt_t2 = ~0;
760
761 assert(client)do { if ((__builtin_expect(!!(!(client)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("client"), "../src/libsystemd-network/sd-dhcp6-client.c"
, 761, __PRETTY_FUNCTION__); } while (0)
;
762 assert(message)do { if ((__builtin_expect(!!(!(message)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("message"), "../src/libsystemd-network/sd-dhcp6-client.c"
, 762, __PRETTY_FUNCTION__); } while (0)
;
763 assert(len >= sizeof(DHCP6Message))do { if ((__builtin_expect(!!(!(len >= sizeof(DHCP6Message
))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("len >= sizeof(DHCP6Message)"
), "../src/libsystemd-network/sd-dhcp6-client.c", 763, __PRETTY_FUNCTION__
); } while (0)
;
764 assert(lease)do { if ((__builtin_expect(!!(!(lease)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("lease"), "../src/libsystemd-network/sd-dhcp6-client.c"
, 764, __PRETTY_FUNCTION__); } while (0)
;
765
766 len -= sizeof(DHCP6Message);
767
768 while (pos < len) {
769 DHCP6Option *option = (DHCP6Option *)&message->options[pos];
770 uint16_t optcode, optlen;
771 int status;
772 uint8_t *optval;
773 be32_t iaid_lease;
774
775 if (len < offsetof(DHCP6Option, data)__builtin_offsetof(DHCP6Option, data) ||
776 len < offsetof(DHCP6Option, data)__builtin_offsetof(DHCP6Option, data) + be16toh(option->len))
777 return -ENOBUFS105;
778
779 optcode = be16toh(option->code);
780 optlen = be16toh(option->len);
781 optval = option->data;
782
783 switch (optcode) {
784 case SD_DHCP6_OPTION_CLIENTID:
785 if (clientid) {
786 log_dhcp6_client(client, "%s contains multiple clientids",log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))),
0, "../src/libsystemd-network/sd-dhcp6-client.c", 787, __func__
, "DHCPv6 CLIENT: " "%s contains multiple clientids", dhcp6_message_type_to_string
(message->type))
787 dhcp6_message_type_to_string(message->type))log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))),
0, "../src/libsystemd-network/sd-dhcp6-client.c", 787, __func__
, "DHCPv6 CLIENT: " "%s contains multiple clientids", dhcp6_message_type_to_string
(message->type))
;
788 return -EINVAL22;
789 }
790
791 if (optlen != client->duid_len ||
792 memcmp(&client->duid, optval, optlen) != 0) {
793 log_dhcp6_client(client, "%s DUID does not match",log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))),
0, "../src/libsystemd-network/sd-dhcp6-client.c", 794, __func__
, "DHCPv6 CLIENT: " "%s DUID does not match", dhcp6_message_type_to_string
(message->type))
794 dhcp6_message_type_to_string(message->type))log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))),
0, "../src/libsystemd-network/sd-dhcp6-client.c", 794, __func__
, "DHCPv6 CLIENT: " "%s DUID does not match", dhcp6_message_type_to_string
(message->type))
;
795
796 return -EINVAL22;
797 }
798 clientid = true1;
799
800 break;
801
802 case SD_DHCP6_OPTION_SERVERID:
803 r = dhcp6_lease_get_serverid(lease, NULL((void*)0), NULL((void*)0));
804 if (r >= 0) {
805 log_dhcp6_client(client, "%s contains multiple serverids",log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))),
0, "../src/libsystemd-network/sd-dhcp6-client.c", 806, __func__
, "DHCPv6 CLIENT: " "%s contains multiple serverids", dhcp6_message_type_to_string
(message->type))
806 dhcp6_message_type_to_string(message->type))log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))),
0, "../src/libsystemd-network/sd-dhcp6-client.c", 806, __func__
, "DHCPv6 CLIENT: " "%s contains multiple serverids", dhcp6_message_type_to_string
(message->type))
;
807 return -EINVAL22;
808 }
809
810 r = dhcp6_lease_set_serverid(lease, optval, optlen);
811 if (r < 0)
812 return r;
813
814 break;
815
816 case SD_DHCP6_OPTION_PREFERENCE:
817 if (optlen != 1)
818 return -EINVAL22;
819
820 r = dhcp6_lease_set_preference(lease, optval[0]);
821 if (r < 0)
822 return r;
823
824 break;
825
826 case SD_DHCP6_OPTION_STATUS_CODE:
827 status = dhcp6_option_parse_status(option);
828 if (status) {
829 log_dhcp6_client(client, "%s Status %s",log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))),
0, "../src/libsystemd-network/sd-dhcp6-client.c", 831, __func__
, "DHCPv6 CLIENT: " "%s Status %s", dhcp6_message_type_to_string
(message->type), dhcp6_message_status_to_string(status))
830 dhcp6_message_type_to_string(message->type),log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))),
0, "../src/libsystemd-network/sd-dhcp6-client.c", 831, __func__
, "DHCPv6 CLIENT: " "%s Status %s", dhcp6_message_type_to_string
(message->type), dhcp6_message_status_to_string(status))
831 dhcp6_message_status_to_string(status))log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))),
0, "../src/libsystemd-network/sd-dhcp6-client.c", 831, __func__
, "DHCPv6 CLIENT: " "%s Status %s", dhcp6_message_type_to_string
(message->type), dhcp6_message_status_to_string(status))
;
832 dhcp6_lease_free_ia(&lease->ia);
833 dhcp6_lease_free_ia(&lease->pd);
834
835 return -EINVAL22;
836 }
837
838 break;
839
840 case SD_DHCP6_OPTION_IA_NA:
841 if (client->state == DHCP6_STATE_INFORMATION_REQUEST) {
842 log_dhcp6_client(client, "Information request ignoring IA NA option")log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))),
0, "../src/libsystemd-network/sd-dhcp6-client.c", 842, __func__
, "DHCPv6 CLIENT: " "Information request ignoring IA NA option"
)
;
843
844 break;
845 }
846
847 r = dhcp6_option_parse_ia(option, &lease->ia);
848 if (r < 0 && r != -ENOMSG42)
849 return r;
850
851 r = dhcp6_lease_get_iaid(lease, &iaid_lease);
852 if (r < 0)
853 return r;
854
855 if (client->ia_na.ia_na.id != iaid_lease) {
856 log_dhcp6_client(client, "%s has wrong IAID for IA NA",log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))),
0, "../src/libsystemd-network/sd-dhcp6-client.c", 857, __func__
, "DHCPv6 CLIENT: " "%s has wrong IAID for IA NA", dhcp6_message_type_to_string
(message->type))
857 dhcp6_message_type_to_string(message->type))log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))),
0, "../src/libsystemd-network/sd-dhcp6-client.c", 857, __func__
, "DHCPv6 CLIENT: " "%s has wrong IAID for IA NA", dhcp6_message_type_to_string
(message->type))
;
858 return -EINVAL22;
859 }
860
861 if (lease->ia.addresses) {
862 lt_t1 = MIN(lt_t1, be32toh(lease->ia.ia_na.lifetime_t1))__extension__ ({ const typeof((lt_t1)) __unique_prefix_A16 = (
(lt_t1)); const typeof((be32toh(lease->ia.ia_na.lifetime_t1
))) __unique_prefix_B17 = ((be32toh(lease->ia.ia_na.lifetime_t1
))); __unique_prefix_A16 < __unique_prefix_B17 ? __unique_prefix_A16
: __unique_prefix_B17; })
;
863 lt_t2 = MIN(lt_t2, be32toh(lease->ia.ia_na.lifetime_t1))__extension__ ({ const typeof((lt_t2)) __unique_prefix_A18 = (
(lt_t2)); const typeof((be32toh(lease->ia.ia_na.lifetime_t1
))) __unique_prefix_B19 = ((be32toh(lease->ia.ia_na.lifetime_t1
))); __unique_prefix_A18 < __unique_prefix_B19 ? __unique_prefix_A18
: __unique_prefix_B19; })
;
864 }
865
866 break;
867
868 case SD_DHCP6_OPTION_IA_PD:
869 if (client->state == DHCP6_STATE_INFORMATION_REQUEST) {
870 log_dhcp6_client(client, "Information request ignoring IA PD option")log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))),
0, "../src/libsystemd-network/sd-dhcp6-client.c", 870, __func__
, "DHCPv6 CLIENT: " "Information request ignoring IA PD option"
)
;
871
872 break;
873 }
874
875 r = dhcp6_option_parse_ia(option, &lease->pd);
876 if (r < 0 && r != -ENOMSG42)
877 return r;
878
879 r = dhcp6_lease_get_iaid(lease, &iaid_lease);
880 if (r < 0)
881 return r;
882
883 if (client->ia_pd.ia_pd.id != iaid_lease) {
884 log_dhcp6_client(client, "%s has wrong IAID for IA PD",log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))),
0, "../src/libsystemd-network/sd-dhcp6-client.c", 885, __func__
, "DHCPv6 CLIENT: " "%s has wrong IAID for IA PD", dhcp6_message_type_to_string
(message->type))
885 dhcp6_message_type_to_string(message->type))log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))),
0, "../src/libsystemd-network/sd-dhcp6-client.c", 885, __func__
, "DHCPv6 CLIENT: " "%s has wrong IAID for IA PD", dhcp6_message_type_to_string
(message->type))
;
886 return -EINVAL22;
887 }
888
889 if (lease->pd.addresses) {
890 lt_t1 = MIN(lt_t1, be32toh(lease->pd.ia_pd.lifetime_t1))__extension__ ({ const typeof((lt_t1)) __unique_prefix_A20 = (
(lt_t1)); const typeof((be32toh(lease->pd.ia_pd.lifetime_t1
))) __unique_prefix_B21 = ((be32toh(lease->pd.ia_pd.lifetime_t1
))); __unique_prefix_A20 < __unique_prefix_B21 ? __unique_prefix_A20
: __unique_prefix_B21; })
;
891 lt_t2 = MIN(lt_t2, be32toh(lease->pd.ia_pd.lifetime_t2))__extension__ ({ const typeof((lt_t2)) __unique_prefix_A22 = (
(lt_t2)); const typeof((be32toh(lease->pd.ia_pd.lifetime_t2
))) __unique_prefix_B23 = ((be32toh(lease->pd.ia_pd.lifetime_t2
))); __unique_prefix_A22 < __unique_prefix_B23 ? __unique_prefix_A22
: __unique_prefix_B23; })
;
892 }
893
894 break;
895
896 case SD_DHCP6_OPTION_RAPID_COMMIT:
897 r = dhcp6_lease_set_rapid_commit(lease);
898 if (r < 0)
899 return r;
900
901 break;
902
903 case SD_DHCP6_OPTION_DNS_SERVERS:
904 r = dhcp6_lease_set_dns(lease, optval, optlen);
905 if (r < 0)
906 return r;
907
908 break;
909
910 case SD_DHCP6_OPTION_DOMAIN_LIST:
911 r = dhcp6_lease_set_domains(lease, optval, optlen);
912 if (r < 0)
913 return r;
914
915 break;
916
917 case SD_DHCP6_OPTION_NTP_SERVER:
918 r = dhcp6_lease_set_ntp(lease, optval, optlen);
919 if (r < 0)
920 return r;
921
922 break;
923
924 case SD_DHCP6_OPTION_SNTP_SERVERS:
925 r = dhcp6_lease_set_sntp(lease, optval, optlen);
926 if (r < 0)
927 return r;
928
929 break;
930 }
931
932 pos += sizeof(*option) + optlen;
933 }
934
935 if (!clientid) {
936 log_dhcp6_client(client, "%s has incomplete options",log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))),
0, "../src/libsystemd-network/sd-dhcp6-client.c", 937, __func__
, "DHCPv6 CLIENT: " "%s has incomplete options", dhcp6_message_type_to_string
(message->type))
937 dhcp6_message_type_to_string(message->type))log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))),
0, "../src/libsystemd-network/sd-dhcp6-client.c", 937, __func__
, "DHCPv6 CLIENT: " "%s has incomplete options", dhcp6_message_type_to_string
(message->type))
;
938 return -EINVAL22;
939 }
940
941 if (client->state != DHCP6_STATE_INFORMATION_REQUEST) {
942 r = dhcp6_lease_get_serverid(lease, NULL((void*)0), NULL((void*)0));
943 if (r < 0) {
944 log_dhcp6_client(client, "%s has no server id",log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))),
0, "../src/libsystemd-network/sd-dhcp6-client.c", 945, __func__
, "DHCPv6 CLIENT: " "%s has no server id", dhcp6_message_type_to_string
(message->type))
945 dhcp6_message_type_to_string(message->type))log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))),
0, "../src/libsystemd-network/sd-dhcp6-client.c", 945, __func__
, "DHCPv6 CLIENT: " "%s has no server id", dhcp6_message_type_to_string
(message->type))
;
946 return -EINVAL22;
947 }
948
949 } else {
950 if (lease->ia.addresses) {
951 lease->ia.ia_na.lifetime_t1 = htobe32(lt_t1);
952 lease->ia.ia_na.lifetime_t2 = htobe32(lt_t2);
953 }
954
955 if (lease->pd.addresses) {
956 lease->pd.ia_pd.lifetime_t1 = htobe32(lt_t1);
957 lease->pd.ia_pd.lifetime_t2 = htobe32(lt_t2);
958 }
959 }
960
961 return 0;
962}
963
964static int client_receive_reply(sd_dhcp6_client *client, DHCP6Message *reply, size_t len) {
965 _cleanup_(sd_dhcp6_lease_unrefp)__attribute__((cleanup(sd_dhcp6_lease_unrefp))) sd_dhcp6_lease *lease = NULL((void*)0);
966 bool_Bool rapid_commit;
967 int r;
968
969 assert(client)do { if ((__builtin_expect(!!(!(client)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("client"), "../src/libsystemd-network/sd-dhcp6-client.c"
, 969, __PRETTY_FUNCTION__); } while (0)
;
970 assert(reply)do { if ((__builtin_expect(!!(!(reply)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("reply"), "../src/libsystemd-network/sd-dhcp6-client.c"
, 970, __PRETTY_FUNCTION__); } while (0)
;
971
972 if (reply->type != DHCP6_REPLY)
973 return 0;
974
975 r = dhcp6_lease_new(&lease);
976 if (r < 0)
977 return -ENOMEM12;
978
979 r = client_parse_message(client, reply, len, lease);
980 if (r < 0)
981 return r;
982
983 if (client->state == DHCP6_STATE_SOLICITATION) {
984 r = dhcp6_lease_get_rapid_commit(lease, &rapid_commit);
985 if (r < 0)
986 return r;
987
988 if (!rapid_commit)
989 return 0;
990 }
991
992 client_set_lease(client, lease);
993 lease = NULL((void*)0);
994
995 return DHCP6_STATE_BOUND;
996}
997
998static int client_receive_advertise(sd_dhcp6_client *client, DHCP6Message *advertise, size_t len) {
999 _cleanup_(sd_dhcp6_lease_unrefp)__attribute__((cleanup(sd_dhcp6_lease_unrefp))) sd_dhcp6_lease *lease = NULL((void*)0);
1000 uint8_t pref_advertise = 0, pref_lease = 0;
1001 int r;
1002
1003 if (advertise->type != DHCP6_ADVERTISE)
1004 return 0;
1005
1006 r = dhcp6_lease_new(&lease);
1007 if (r < 0)
1008 return r;
1009
1010 r = client_parse_message(client, advertise, len, lease);
1011 if (r < 0)
1012 return r;
1013
1014 r = dhcp6_lease_get_preference(lease, &pref_advertise);
1015 if (r < 0)
1016 return r;
1017
1018 r = dhcp6_lease_get_preference(client->lease, &pref_lease);
1019
1020 if (r < 0 || pref_advertise > pref_lease) {
1021 client_set_lease(client, lease);
1022 lease = NULL((void*)0);
1023 r = 0;
1024 }
1025
1026 if (pref_advertise == 255 || client->retransmit_count > 1)
1027 r = DHCP6_STATE_REQUEST;
1028
1029 return r;
1030}
1031
1032static int client_receive_message(
1033 sd_event_source *s,
1034 int fd, uint32_t
1035 revents,
1036 void *userdata) {
1037
1038 sd_dhcp6_client *client = userdata;
1039 DHCP6_CLIENT_DONT_DESTROY(client)__attribute__((cleanup(sd_dhcp6_client_unrefp))) __attribute__
((unused)) sd_dhcp6_client *_dont_destroy_client = sd_dhcp6_client_ref
(client)
;
1040 _cleanup_free___attribute__((cleanup(freep))) DHCP6Message *message = NULL((void*)0);
1041 ssize_t buflen, len;
1042 int r = 0;
1043
1044 assert(s)do { if ((__builtin_expect(!!(!(s)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("s"), "../src/libsystemd-network/sd-dhcp6-client.c"
, 1044, __PRETTY_FUNCTION__); } while (0)
;
1045 assert(client)do { if ((__builtin_expect(!!(!(client)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("client"), "../src/libsystemd-network/sd-dhcp6-client.c"
, 1045, __PRETTY_FUNCTION__); } while (0)
;
1046 assert(client->event)do { if ((__builtin_expect(!!(!(client->event)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("client->event"), "../src/libsystemd-network/sd-dhcp6-client.c"
, 1046, __PRETTY_FUNCTION__); } while (0)
;
1047
1048 buflen = next_datagram_size_fd(fd);
1049 if (buflen < 0)
1050 return buflen;
1051
1052 message = malloc(buflen);
1053 if (!message)
1054 return -ENOMEM12;
1055
1056 len = recv(fd, message, buflen, 0);
1057 if (len < 0) {
1058 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; })
)
1059 return 0;
1060
1061 return log_dhcp6_client_errno(client, errno, "Could not receive message from UDP socket: %m")log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))),
(*__errno_location ()), "../src/libsystemd-network/sd-dhcp6-client.c"
, 1061, __func__, "DHCPv6 CLIENT: " "Could not receive message from UDP socket: %m"
)
;
1062
1063 }
1064 if ((size_t) len < sizeof(DHCP6Message)) {
1065 log_dhcp6_client(client, "Too small to be DHCP6 message: ignoring")log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))),
0, "../src/libsystemd-network/sd-dhcp6-client.c", 1065, __func__
, "DHCPv6 CLIENT: " "Too small to be DHCP6 message: ignoring"
)
;
1066 return 0;
1067 }
1068
1069 switch(message->type) {
1070 case DHCP6_SOLICIT:
1071 case DHCP6_REQUEST:
1072 case DHCP6_CONFIRM:
1073 case DHCP6_RENEW:
1074 case DHCP6_REBIND:
1075 case DHCP6_RELEASE:
1076 case DHCP6_DECLINE:
1077 case DHCP6_INFORMATION_REQUEST:
1078 case DHCP6_RELAY_FORW:
1079 case DHCP6_RELAY_REPL:
1080 return 0;
1081
1082 case DHCP6_ADVERTISE:
1083 case DHCP6_REPLY:
1084 case DHCP6_RECONFIGURE:
1085 break;
1086
1087 default:
1088 log_dhcp6_client(client, "Unknown message type %d", message->type)log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))),
0, "../src/libsystemd-network/sd-dhcp6-client.c", 1088, __func__
, "DHCPv6 CLIENT: " "Unknown message type %d", message->type
)
;
1089 return 0;
1090 }
1091
1092 if (client->transaction_id != (message->transaction_id &
1093 htobe32(0x00ffffff)))
1094 return 0;
1095
1096 switch (client->state) {
1097 case DHCP6_STATE_INFORMATION_REQUEST:
1098 r = client_receive_reply(client, message, len);
1099 if (r < 0)
1100 return 0;
1101
1102 client_notify(client, SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST);
1103
1104 client_start(client, DHCP6_STATE_STOPPED);
1105
1106 break;
1107
1108 case DHCP6_STATE_SOLICITATION:
1109 r = client_receive_advertise(client, message, len);
1110
1111 if (r == DHCP6_STATE_REQUEST) {
1112 client_start(client, r);
1113
1114 break;
1115 }
1116
1117 _fallthrough_; /* for Soliciation Rapid Commit option check */
1118 case DHCP6_STATE_REQUEST:
1119 case DHCP6_STATE_RENEW:
1120 case DHCP6_STATE_REBIND:
1121
1122 r = client_receive_reply(client, message, len);
1123 if (r < 0)
1124 return 0;
1125
1126 if (r == DHCP6_STATE_BOUND) {
1127
1128 r = client_start(client, DHCP6_STATE_BOUND);
1129 if (r < 0) {
1130 client_stop(client, r);
1131 return 0;
1132 }
1133
1134 client_notify(client, SD_DHCP6_CLIENT_EVENT_IP_ACQUIRE);
1135 }
1136
1137 break;
1138
1139 case DHCP6_STATE_BOUND:
1140
1141 break;
1142
1143 case DHCP6_STATE_STOPPED:
1144 return 0;
1145 }
1146
1147 if (r >= 0)
1148 log_dhcp6_client(client, "Recv %s",log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))),
0, "../src/libsystemd-network/sd-dhcp6-client.c", 1149, __func__
, "DHCPv6 CLIENT: " "Recv %s", dhcp6_message_type_to_string(message
->type))
1149 dhcp6_message_type_to_string(message->type))log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))),
0, "../src/libsystemd-network/sd-dhcp6-client.c", 1149, __func__
, "DHCPv6 CLIENT: " "Recv %s", dhcp6_message_type_to_string(message
->type))
;
1150
1151 return 0;
1152}
1153
1154static int client_start(sd_dhcp6_client *client, enum DHCP6State state) {
1155 int r;
1156 usec_t timeout, time_now;
1157 char time_string[FORMAT_TIMESPAN_MAX64];
1158
1159 assert_return(client, -EINVAL)do { if (!(((__builtin_expect(!!(client),1))) ? (1) : (log_assert_failed_return_realm
(LOG_REALM_SYSTEMD, ("client"), "../src/libsystemd-network/sd-dhcp6-client.c"
, 1159, __PRETTY_FUNCTION__), 0))) return (-22); } while (0)
;
1160 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-dhcp6-client.c", 1160, __PRETTY_FUNCTION__
), 0))) return (-22); } while (0)
;
1161 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-dhcp6-client.c"
, 1161, __PRETTY_FUNCTION__), 0))) return (-22); } while (0)
;
1162 assert_return(client->state != state, -EINVAL)do { if (!(((__builtin_expect(!!(client->state != state),1
))) ? (1) : (log_assert_failed_return_realm(LOG_REALM_SYSTEMD
, ("client->state != state"), "../src/libsystemd-network/sd-dhcp6-client.c"
, 1162, __PRETTY_FUNCTION__), 0))) return (-22); } while (0)
;
1163
1164 client->timeout_resend_expire =
1165 sd_event_source_unref(client->timeout_resend_expire);
1166 client->timeout_resend = sd_event_source_unref(client->timeout_resend);
1167 client->retransmit_time = 0;
1168 client->retransmit_count = 0;
1169
1170 r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
1171 if (r < 0)
1172 return r;
1173
1174 if (!client->receive_message) {
1175 r = sd_event_add_io(client->event, &client->receive_message,
1176 client->fd, EPOLLINEPOLLIN, client_receive_message,
1177 client);
1178 if (r < 0)
1179 goto error;
1180
1181 r = sd_event_source_set_priority(client->receive_message,
1182 client->event_priority);
1183 if (r < 0)
1184 goto error;
1185
1186 r = sd_event_source_set_description(client->receive_message,
1187 "dhcp6-receive-message");
1188 if (r < 0)
1189 goto error;
1190 }
1191
1192 switch (state) {
1193 case DHCP6_STATE_STOPPED:
1194 if (client->state == DHCP6_STATE_INFORMATION_REQUEST) {
1195 client->state = DHCP6_STATE_STOPPED;
1196
1197 return 0;
1198 }
1199
1200 _fallthrough_;
1201 case DHCP6_STATE_SOLICITATION:
1202 client->state = DHCP6_STATE_SOLICITATION;
1203
1204 break;
1205
1206 case DHCP6_STATE_INFORMATION_REQUEST:
1207 case DHCP6_STATE_REQUEST:
1208 case DHCP6_STATE_RENEW:
1209 case DHCP6_STATE_REBIND:
1210
1211 client->state = state;
1212
1213 break;
1214
1215 case DHCP6_STATE_BOUND:
1216
1217 if (client->lease->ia.ia_na.lifetime_t1 == 0xffffffff ||
1218 client->lease->ia.ia_na.lifetime_t2 == 0xffffffff) {
1219
1220 log_dhcp6_client(client, "Infinite T1 0x%08x or T2 0x%08x",log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))),
0, "../src/libsystemd-network/sd-dhcp6-client.c", 1222, __func__
, "DHCPv6 CLIENT: " "Infinite T1 0x%08x or T2 0x%08x", be32toh
(client->lease->ia.ia_na.lifetime_t1), be32toh(client->
lease->ia.ia_na.lifetime_t2))
1221 be32toh(client->lease->ia.ia_na.lifetime_t1),log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))),
0, "../src/libsystemd-network/sd-dhcp6-client.c", 1222, __func__
, "DHCPv6 CLIENT: " "Infinite T1 0x%08x or T2 0x%08x", be32toh
(client->lease->ia.ia_na.lifetime_t1), be32toh(client->
lease->ia.ia_na.lifetime_t2))
1222 be32toh(client->lease->ia.ia_na.lifetime_t2))log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))),
0, "../src/libsystemd-network/sd-dhcp6-client.c", 1222, __func__
, "DHCPv6 CLIENT: " "Infinite T1 0x%08x or T2 0x%08x", be32toh
(client->lease->ia.ia_na.lifetime_t1), be32toh(client->
lease->ia.ia_na.lifetime_t2))
;
1223
1224 return 0;
1225 }
1226
1227 timeout = client_timeout_compute_random(be32toh(client->lease->ia.ia_na.lifetime_t1) * USEC_PER_SEC((usec_t) 1000000ULL));
1228
1229 log_dhcp6_client(client, "T1 expires in %s",log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))),
0, "../src/libsystemd-network/sd-dhcp6-client.c", 1230, __func__
, "DHCPv6 CLIENT: " "T1 expires in %s", format_timespan(time_string
, 64, timeout, ((usec_t) 1000000ULL)))
1230 format_timespan(time_string, FORMAT_TIMESPAN_MAX, timeout, USEC_PER_SEC))log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))),
0, "../src/libsystemd-network/sd-dhcp6-client.c", 1230, __func__
, "DHCPv6 CLIENT: " "T1 expires in %s", format_timespan(time_string
, 64, timeout, ((usec_t) 1000000ULL)))
;
1231
1232 r = sd_event_add_time(client->event,
1233 &client->lease->ia.timeout_t1,
1234 clock_boottime_or_monotonic(), time_now + timeout,
1235 10 * USEC_PER_SEC((usec_t) 1000000ULL), client_timeout_t1,
1236 client);
1237 if (r < 0)
1238 goto error;
1239
1240 r = sd_event_source_set_priority(client->lease->ia.timeout_t1,
1241 client->event_priority);
1242 if (r < 0)
1243 goto error;
1244
1245 r = sd_event_source_set_description(client->lease->ia.timeout_t1, "dhcp6-t1-timeout");
1246 if (r < 0)
1247 goto error;
1248
1249 timeout = client_timeout_compute_random(be32toh(client->lease->ia.ia_na.lifetime_t2) * USEC_PER_SEC((usec_t) 1000000ULL));
1250
1251 log_dhcp6_client(client, "T2 expires in %s",log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))),
0, "../src/libsystemd-network/sd-dhcp6-client.c", 1252, __func__
, "DHCPv6 CLIENT: " "T2 expires in %s", format_timespan(time_string
, 64, timeout, ((usec_t) 1000000ULL)))
1252 format_timespan(time_string, FORMAT_TIMESPAN_MAX, timeout, USEC_PER_SEC))log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))),
0, "../src/libsystemd-network/sd-dhcp6-client.c", 1252, __func__
, "DHCPv6 CLIENT: " "T2 expires in %s", format_timespan(time_string
, 64, timeout, ((usec_t) 1000000ULL)))
;
1253
1254 r = sd_event_add_time(client->event,
1255 &client->lease->ia.timeout_t2,
1256 clock_boottime_or_monotonic(), time_now + timeout,
1257 10 * USEC_PER_SEC((usec_t) 1000000ULL), client_timeout_t2,
1258 client);
1259 if (r < 0)
1260 goto error;
1261
1262 r = sd_event_source_set_priority(client->lease->ia.timeout_t2,
1263 client->event_priority);
1264 if (r < 0)
1265 goto error;
1266
1267 r = sd_event_source_set_description(client->lease->ia.timeout_t2, "dhcp6-t2-timeout");
1268 if (r < 0)
1269 goto error;
1270
1271 client->state = state;
1272
1273 return 0;
1274 }
1275
1276 client->transaction_id = random_u32() & htobe32(0x00ffffff);
1277 client->transaction_start = time_now;
1278
1279 r = sd_event_add_time(client->event, &client->timeout_resend,
1280 clock_boottime_or_monotonic(), 0, 0, client_timeout_resend,
1281 client);
1282 if (r < 0)
1283 goto error;
1284
1285 r = sd_event_source_set_priority(client->timeout_resend,
1286 client->event_priority);
1287 if (r < 0)
1288 goto error;
1289
1290 r = sd_event_source_set_description(client->timeout_resend, "dhcp6-resend-timeout");
1291 if (r < 0)
1292 goto error;
1293
1294 return 0;
1295
1296 error:
1297 client_reset(client);
1298 return r;
1299}
1300
1301int sd_dhcp6_client_stop(sd_dhcp6_client *client) {
1302 assert_return(client, -EINVAL)do { if (!(((__builtin_expect(!!(client),1))) ? (1) : (log_assert_failed_return_realm
(LOG_REALM_SYSTEMD, ("client"), "../src/libsystemd-network/sd-dhcp6-client.c"
, 1302, __PRETTY_FUNCTION__), 0))) return (-22); } while (0)
;
1303
1304 client_stop(client, SD_DHCP6_CLIENT_EVENT_STOP);
1305
1306 client->fd = safe_close(client->fd);
1307
1308 return 0;
1309}
1310
1311int sd_dhcp6_client_is_running(sd_dhcp6_client *client) {
1312 assert_return(client, -EINVAL)do { if (!(((__builtin_expect(!!(client),1))) ? (1) : (log_assert_failed_return_realm
(LOG_REALM_SYSTEMD, ("client"), "../src/libsystemd-network/sd-dhcp6-client.c"
, 1312, __PRETTY_FUNCTION__), 0))) return (-22); } while (0)
;
1313
1314 return client->state != DHCP6_STATE_STOPPED;
1315}
1316
1317int sd_dhcp6_client_start(sd_dhcp6_client *client) {
1318 enum DHCP6State state = DHCP6_STATE_SOLICITATION;
1319 int r = 0;
1320
1321 assert_return(client, -EINVAL)do { if (!(((__builtin_expect(!!(client),1))) ? (1) : (log_assert_failed_return_realm
(LOG_REALM_SYSTEMD, ("client"), "../src/libsystemd-network/sd-dhcp6-client.c"
, 1321, __PRETTY_FUNCTION__), 0))) return (-22); } while (0)
;
1322 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-dhcp6-client.c", 1322, __PRETTY_FUNCTION__
), 0))) return (-22); } while (0)
;
1323 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-dhcp6-client.c"
, 1323, __PRETTY_FUNCTION__), 0))) return (-22); } while (0)
;
1324 assert_return(in_addr_is_link_local(AF_INET6, (const union in_addr_union *) &client->local_address) > 0, -EINVAL)do { if (!(((__builtin_expect(!!(in_addr_is_link_local(10, (const
union in_addr_union *) &client->local_address) > 0
),1))) ? (1) : (log_assert_failed_return_realm(LOG_REALM_SYSTEMD
, ("in_addr_is_link_local(AF_INET6, (const union in_addr_union *) &client->local_address) > 0"
), "../src/libsystemd-network/sd-dhcp6-client.c", 1324, __PRETTY_FUNCTION__
), 0))) return (-22); } while (0)
;
1325
1326 if (!IN_SET(client->state, DHCP6_STATE_STOPPED)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){DHCP6_STATE_STOPPED})/sizeof(int)]; switch
(client->state) { case DHCP6_STATE_STOPPED: _found = 1; break
; default: break; } _found; })
)
1327 return -EBUSY16;
1328
1329 r = client_reset(client);
1330 if (r < 0)
1331 return r;
1332
1333 r = client_ensure_iaid(client);
1334 if (r < 0)
1335 return r;
1336
1337 r = client_ensure_duid(client);
1338 if (r < 0)
1339 return r;
1340
1341 if (client->fd < 0) {
1342 r = dhcp6_network_bind_udp_socket(client->ifindex, &client->local_address);
1343 if (r < 0) {
1344 _cleanup_free___attribute__((cleanup(freep))) char *p = NULL((void*)0);
1345
1346 (void) in_addr_to_string(AF_INET610, (const union in_addr_union*) &client->local_address, &p);
1347 return log_dhcp6_client_errno(client, r,log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))),
r, "../src/libsystemd-network/sd-dhcp6-client.c", 1348, __func__
, "DHCPv6 CLIENT: " "Failed to bind to UDP socket at address %s: %m"
, strna(p))
1348 "Failed to bind to UDP socket at address %s: %m", strna(p))log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))),
r, "../src/libsystemd-network/sd-dhcp6-client.c", 1348, __func__
, "DHCPv6 CLIENT: " "Failed to bind to UDP socket at address %s: %m"
, strna(p))
;
1349 }
1350
1351 client->fd = r;
1352 }
1353
1354 if (client->information_request)
1355 state = DHCP6_STATE_INFORMATION_REQUEST;
1356
1357 log_dhcp6_client(client, "Started in %s mode",log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))),
0, "../src/libsystemd-network/sd-dhcp6-client.c", 1359, __func__
, "DHCPv6 CLIENT: " "Started in %s mode", client->information_request
? "Information request": "Managed")
1358 client->information_request? "Information request":log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))),
0, "../src/libsystemd-network/sd-dhcp6-client.c", 1359, __func__
, "DHCPv6 CLIENT: " "Started in %s mode", client->information_request
? "Information request": "Managed")
1359 "Managed")log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))),
0, "../src/libsystemd-network/sd-dhcp6-client.c", 1359, __func__
, "DHCPv6 CLIENT: " "Started in %s mode", client->information_request
? "Information request": "Managed")
;
1360
1361 return client_start(client, state);
1362}
1363
1364int sd_dhcp6_client_attach_event(sd_dhcp6_client *client, sd_event *event, int64_t priority) {
1365 int r;
1366
1367 assert_return(client, -EINVAL)do { if (!(((__builtin_expect(!!(client),1))) ? (1) : (log_assert_failed_return_realm
(LOG_REALM_SYSTEMD, ("client"), "../src/libsystemd-network/sd-dhcp6-client.c"
, 1367, __PRETTY_FUNCTION__), 0))) return (-22); } while (0)
;
1368 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-dhcp6-client.c", 1368, __PRETTY_FUNCTION__
), 0))) return (-16); } while (0)
;
1369
1370 if (event)
1371 client->event = sd_event_ref(event);
1372 else {
1373 r = sd_event_default(&client->event);
1374 if (r < 0)
1375 return 0;
1376 }
1377
1378 client->event_priority = priority;
1379
1380 return 0;
1381}
1382
1383int sd_dhcp6_client_detach_event(sd_dhcp6_client *client) {
1384 assert_return(client, -EINVAL)do { if (!(((__builtin_expect(!!(client),1))) ? (1) : (log_assert_failed_return_realm
(LOG_REALM_SYSTEMD, ("client"), "../src/libsystemd-network/sd-dhcp6-client.c"
, 1384, __PRETTY_FUNCTION__), 0))) return (-22); } while (0)
;
1385
1386 client->event = sd_event_unref(client->event);
1387
1388 return 0;
1389}
1390
1391sd_event *sd_dhcp6_client_get_event(sd_dhcp6_client *client) {
1392 assert_return(client, NULL)do { if (!(((__builtin_expect(!!(client),1))) ? (1) : (log_assert_failed_return_realm
(LOG_REALM_SYSTEMD, ("client"), "../src/libsystemd-network/sd-dhcp6-client.c"
, 1392, __PRETTY_FUNCTION__), 0))) return (((void*)0)); } while
(0)
;
1393
1394 return client->event;
1395}
1396
1397sd_dhcp6_client *sd_dhcp6_client_ref(sd_dhcp6_client *client) {
1398
1399 if (!client)
1400 return NULL((void*)0);
1401
1402 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-dhcp6-client.c", 1402, __PRETTY_FUNCTION__
); } while (0)
;
1403 client->n_ref++;
1404
1405 return client;
1406}
1407
1408sd_dhcp6_client *sd_dhcp6_client_unref(sd_dhcp6_client *client) {
1409
1410 if (!client)
1411 return NULL((void*)0);
1412
1413 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-dhcp6-client.c", 1413, __PRETTY_FUNCTION__
); } while (0)
;
1414 client->n_ref--;
1415
1416 if (client->n_ref > 0)
1417 return NULL((void*)0);
1418
1419 client_reset(client);
1420
1421 client->fd = safe_close(client->fd);
1422
1423 sd_dhcp6_client_detach_event(client);
1424
1425 free(client->req_opts);
1426 free(client->fqdn);
1427 return mfree(client);
1428}
1429
1430int sd_dhcp6_client_new(sd_dhcp6_client **ret) {
1431 _cleanup_(sd_dhcp6_client_unrefp)__attribute__((cleanup(sd_dhcp6_client_unrefp))) sd_dhcp6_client *client = NULL((void*)0);
1432 size_t t;
1433
1434 assert_return(ret, -EINVAL)do { if (!(((__builtin_expect(!!(ret),1))) ? (1) : (log_assert_failed_return_realm
(LOG_REALM_SYSTEMD, ("ret"), "../src/libsystemd-network/sd-dhcp6-client.c"
, 1434, __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
1435
1436 client = new0(sd_dhcp6_client, 1)((sd_dhcp6_client*) calloc((1), sizeof(sd_dhcp6_client)));
5
Memory is allocated
1437 if (!client)
6
Assuming 'client' is non-null
7
Taking false branch
1438 return -ENOMEM12;
1439
1440 client->n_ref = 1;
1441 client->ia_na.type = SD_DHCP6_OPTION_IA_NA;
1442 client->ia_pd.type = SD_DHCP6_OPTION_IA_PD;
1443 client->ifindex = -1;
1444 client->fd = -1;
1445
1446 client->req_opts_len = 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)))
;
1447 client->req_opts = new0(be16_t, client->req_opts_len)((be16_t*) calloc((client->req_opts_len), sizeof(be16_t)));
1448 if (!client->req_opts)
8
Assuming field 'req_opts' is null
9
Taking true branch
1449 return -ENOMEM12;
10
Potential leak of memory pointed to by 'client'
1450
1451 for (t = 0; t < client->req_opts_len; t++)
1452 client->req_opts[t] = htobe16(default_req_opts[t]);
1453
1454 *ret = TAKE_PTR(client)({ typeof(client) _ptr_ = (client); (client) = ((void*)0); _ptr_
; })
;
1455
1456 return 0;
1457}