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