]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/sd-dhcp-client.c
sd-dhcp-client: allow getting/setting the client ID
[thirdparty/systemd.git] / src / libsystemd-network / sd-dhcp-client.c
1 /***
2 This file is part of systemd.
3
4 Copyright (C) 2013 Intel Corporation. All rights reserved.
5
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #include <stdlib.h>
21 #include <errno.h>
22 #include <string.h>
23 #include <stdio.h>
24 #include <net/ethernet.h>
25 #include <net/if_arp.h>
26 #include <linux/if_infiniband.h>
27 #include <netinet/ether.h>
28 #include <sys/param.h>
29 #include <sys/ioctl.h>
30
31 #include "util.h"
32 #include "list.h"
33 #include "refcnt.h"
34 #include "async.h"
35
36 #include "dhcp-protocol.h"
37 #include "dhcp-internal.h"
38 #include "dhcp-lease-internal.h"
39 #include "sd-dhcp-client.h"
40
41 #define MAX_CLIENT_ID_LEN 64 /* Arbitrary limit */
42 #define MAX_MAC_ADDR_LEN INFINIBAND_ALEN
43
44 struct sd_dhcp_client {
45 RefCount n_ref;
46
47 DHCPState state;
48 sd_event *event;
49 int event_priority;
50 sd_event_source *timeout_resend;
51 int index;
52 int fd;
53 union sockaddr_union link;
54 sd_event_source *receive_message;
55 bool request_broadcast;
56 uint8_t *req_opts;
57 size_t req_opts_allocated;
58 size_t req_opts_size;
59 be32_t last_addr;
60 uint8_t mac_addr[MAX_MAC_ADDR_LEN];
61 size_t mac_addr_len;
62 uint16_t arp_type;
63 union {
64 struct {
65 uint8_t type; /* 0: Generic (non-LL) (RFC 2132) */
66 uint8_t data[MAX_CLIENT_ID_LEN];
67 } _packed_ gen;
68 struct {
69 uint8_t type; /* 1: Ethernet Link-Layer (RFC 2132) */
70 uint8_t haddr[ETH_ALEN];
71 } _packed_ eth;
72 struct {
73 uint8_t type; /* 2 - 254: ARP/Link-Layer (RFC 2132) */
74 uint8_t haddr[0];
75 } _packed_ ll;
76 struct {
77 uint8_t type; /* 255: Node-specific (RFC 4361) */
78 uint8_t iaid[4];
79 uint8_t duid[MAX_CLIENT_ID_LEN - 4];
80 } _packed_ ns;
81 struct {
82 uint8_t type;
83 uint8_t data[MAX_CLIENT_ID_LEN];
84 } _packed_ raw;
85 } client_id;
86 size_t client_id_len;
87 char *hostname;
88 char *vendor_class_identifier;
89 uint32_t mtu;
90 uint32_t xid;
91 usec_t start_time;
92 unsigned int attempt;
93 usec_t request_sent;
94 sd_event_source *timeout_t1;
95 sd_event_source *timeout_t2;
96 sd_event_source *timeout_expire;
97 sd_dhcp_client_cb_t cb;
98 void *userdata;
99 sd_dhcp_lease *lease;
100 };
101
102 static const uint8_t default_req_opts[] = {
103 DHCP_OPTION_SUBNET_MASK,
104 DHCP_OPTION_ROUTER,
105 DHCP_OPTION_HOST_NAME,
106 DHCP_OPTION_DOMAIN_NAME,
107 DHCP_OPTION_DOMAIN_NAME_SERVER,
108 DHCP_OPTION_NTP_SERVER,
109 };
110
111 static int client_receive_message_raw(sd_event_source *s, int fd,
112 uint32_t revents, void *userdata);
113 static int client_receive_message_udp(sd_event_source *s, int fd,
114 uint32_t revents, void *userdata);
115 static void client_stop(sd_dhcp_client *client, int error);
116
117 int sd_dhcp_client_set_callback(sd_dhcp_client *client, sd_dhcp_client_cb_t cb,
118 void *userdata) {
119 assert_return(client, -EINVAL);
120
121 client->cb = cb;
122 client->userdata = userdata;
123
124 return 0;
125 }
126
127 int sd_dhcp_client_set_request_broadcast(sd_dhcp_client *client, int broadcast) {
128 assert_return(client, -EINVAL);
129
130 client->request_broadcast = !!broadcast;
131
132 return 0;
133 }
134
135 int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option) {
136 size_t i;
137
138 assert_return(client, -EINVAL);
139 assert_return (IN_SET(client->state, DHCP_STATE_INIT,
140 DHCP_STATE_STOPPED), -EBUSY);
141
142 switch(option) {
143 case DHCP_OPTION_PAD:
144 case DHCP_OPTION_OVERLOAD:
145 case DHCP_OPTION_MESSAGE_TYPE:
146 case DHCP_OPTION_PARAMETER_REQUEST_LIST:
147 case DHCP_OPTION_END:
148 return -EINVAL;
149
150 default:
151 break;
152 }
153
154 for (i = 0; i < client->req_opts_size; i++)
155 if (client->req_opts[i] == option)
156 return -EEXIST;
157
158 if (!GREEDY_REALLOC(client->req_opts, client->req_opts_allocated,
159 client->req_opts_size + 1))
160 return -ENOMEM;
161
162 client->req_opts[client->req_opts_size++] = option;
163
164 return 0;
165 }
166
167 int sd_dhcp_client_set_request_address(sd_dhcp_client *client,
168 const struct in_addr *last_addr) {
169 assert_return(client, -EINVAL);
170 assert_return (IN_SET(client->state, DHCP_STATE_INIT,
171 DHCP_STATE_STOPPED), -EBUSY);
172
173 if (last_addr)
174 client->last_addr = last_addr->s_addr;
175 else
176 client->last_addr = INADDR_ANY;
177
178 return 0;
179 }
180
181 int sd_dhcp_client_set_index(sd_dhcp_client *client, int interface_index) {
182 assert_return(client, -EINVAL);
183 assert_return (IN_SET(client->state, DHCP_STATE_INIT,
184 DHCP_STATE_STOPPED), -EBUSY);
185 assert_return(interface_index > 0, -EINVAL);
186
187 client->index = interface_index;
188
189 return 0;
190 }
191
192 int sd_dhcp_client_set_mac(sd_dhcp_client *client, const uint8_t *addr,
193 size_t addr_len, uint16_t arp_type) {
194 DHCP_CLIENT_DONT_DESTROY(client);
195 bool need_restart = false;
196
197 assert_return(client, -EINVAL);
198 assert_return(addr, -EINVAL);
199 assert_return(addr_len > 0 && addr_len <= MAX_MAC_ADDR_LEN, -EINVAL);
200 assert_return(arp_type > 0, -EINVAL);
201
202 if (arp_type == ARPHRD_ETHER)
203 assert_return(addr_len == ETH_ALEN, -EINVAL);
204 else if (arp_type == ARPHRD_INFINIBAND)
205 assert_return(addr_len == INFINIBAND_ALEN, -EINVAL);
206 else
207 return -EINVAL;
208
209 if (client->mac_addr_len == addr_len &&
210 memcmp(&client->mac_addr, addr, addr_len) == 0)
211 return 0;
212
213 if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) {
214 log_dhcp_client(client, "Changing MAC address on running DHCP "
215 "client, restarting");
216 need_restart = true;
217 client_stop(client, DHCP_EVENT_STOP);
218 }
219
220 memcpy(&client->mac_addr, addr, addr_len);
221 client->mac_addr_len = addr_len;
222 client->arp_type = arp_type;
223
224 if (need_restart && client->state != DHCP_STATE_STOPPED)
225 sd_dhcp_client_start(client);
226
227 return 0;
228 }
229
230 int sd_dhcp_client_get_client_id(sd_dhcp_client *client, uint8_t *type,
231 const uint8_t **data, size_t *data_len) {
232
233 assert_return(client, -EINVAL);
234 assert_return(type, -EINVAL);
235 assert_return(data, -EINVAL);
236 assert_return(data_len, -EINVAL);
237
238 *type = 0;
239 *data = NULL;
240 *data_len = 0;
241 if (client->client_id_len) {
242 *type = client->client_id.raw.type;
243 *data = client->client_id.raw.data;
244 *data_len = client->client_id_len -
245 sizeof (client->client_id.raw.type);
246 }
247
248 return 0;
249 }
250
251 int sd_dhcp_client_set_client_id(sd_dhcp_client *client, uint8_t type,
252 const uint8_t *data, size_t data_len) {
253 DHCP_CLIENT_DONT_DESTROY(client);
254 bool need_restart = false;
255
256 assert_return(client, -EINVAL);
257 assert_return(data, -EINVAL);
258 assert_return(data_len > 0 && data_len <= MAX_CLIENT_ID_LEN, -EINVAL);
259
260 switch (type) {
261 case ARPHRD_ETHER:
262 if (data_len != ETH_ALEN)
263 return -EINVAL;
264 break;
265 case ARPHRD_INFINIBAND:
266 if (data_len != INFINIBAND_ALEN)
267 return -EINVAL;
268 break;
269 default:
270 break;
271 }
272
273 if (client->client_id_len == data_len + sizeof (client->client_id.raw.type) &&
274 client->client_id.raw.type == type &&
275 memcmp(&client->client_id.raw.data, data, data_len) == 0)
276 return 0;
277
278 if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) {
279 log_dhcp_client(client, "Changing client ID on running DHCP "
280 "client, restarting");
281 need_restart = true;
282 client_stop(client, DHCP_EVENT_STOP);
283 }
284
285 client->client_id.raw.type = type;
286 memcpy(&client->client_id.raw.data, data, data_len);
287 client->client_id_len = data_len + sizeof (client->client_id.raw.type);
288
289 if (need_restart && client->state != DHCP_STATE_STOPPED)
290 sd_dhcp_client_start(client);
291
292 return 0;
293 }
294
295 int sd_dhcp_client_set_hostname(sd_dhcp_client *client,
296 const char *hostname) {
297 char *new_hostname = NULL;
298
299 assert_return(client, -EINVAL);
300
301 if (streq_ptr(client->hostname, hostname))
302 return 0;
303
304 if (hostname) {
305 new_hostname = strdup(hostname);
306 if (!new_hostname)
307 return -ENOMEM;
308 }
309
310 free(client->hostname);
311 client->hostname = new_hostname;
312
313 return 0;
314 }
315
316 int sd_dhcp_client_set_vendor_class_identifier(sd_dhcp_client *client,
317 const char *vci) {
318 char *new_vci = NULL;
319
320 assert_return(client, -EINVAL);
321
322 new_vci = strdup(vci);
323 if (!new_vci)
324 return -ENOMEM;
325
326 free(client->vendor_class_identifier);
327
328 client->vendor_class_identifier = new_vci;
329
330 return 0;
331 }
332
333 int sd_dhcp_client_set_mtu(sd_dhcp_client *client, uint32_t mtu) {
334 assert_return(client, -EINVAL);
335 assert_return(mtu >= DHCP_DEFAULT_MIN_SIZE, -ERANGE);
336
337 client->mtu = mtu;
338
339 return 0;
340 }
341
342 int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret) {
343 assert_return(client, -EINVAL);
344 assert_return(ret, -EINVAL);
345
346 if (client->state != DHCP_STATE_BOUND &&
347 client->state != DHCP_STATE_RENEWING &&
348 client->state != DHCP_STATE_REBINDING)
349 return -EADDRNOTAVAIL;
350
351 *ret = sd_dhcp_lease_ref(client->lease);
352
353 return 0;
354 }
355
356 static void client_notify(sd_dhcp_client *client, int event) {
357 if (client->cb)
358 client->cb(client, event, client->userdata);
359 }
360
361 static int client_initialize(sd_dhcp_client *client) {
362 assert_return(client, -EINVAL);
363
364 client->receive_message =
365 sd_event_source_unref(client->receive_message);
366
367 client->fd = asynchronous_close(client->fd);
368
369 client->timeout_resend = sd_event_source_unref(client->timeout_resend);
370
371 client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
372 client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
373 client->timeout_expire = sd_event_source_unref(client->timeout_expire);
374
375 client->attempt = 1;
376
377 client->state = DHCP_STATE_INIT;
378 client->xid = 0;
379
380 if (client->lease)
381 client->lease = sd_dhcp_lease_unref(client->lease);
382
383 return 0;
384 }
385
386 static void client_stop(sd_dhcp_client *client, int error) {
387 assert(client);
388
389 if (error < 0)
390 log_dhcp_client(client, "STOPPED: %s", strerror(-error));
391 else if (error == DHCP_EVENT_STOP)
392 log_dhcp_client(client, "STOPPED");
393 else
394 log_dhcp_client(client, "STOPPED: Unknown event");
395
396 client_notify(client, error);
397
398 client_initialize(client);
399 }
400
401 static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret,
402 uint8_t type, size_t *_optlen, size_t *_optoffset) {
403 _cleanup_free_ DHCPPacket *packet;
404 size_t optlen, optoffset, size;
405 be16_t max_size;
406 usec_t time_now;
407 uint16_t secs;
408 int r;
409
410 assert(client);
411 assert(client->start_time);
412 assert(ret);
413 assert(_optlen);
414 assert(_optoffset);
415 assert(type == DHCP_DISCOVER || type == DHCP_REQUEST);
416
417 optlen = DHCP_MIN_OPTIONS_SIZE;
418 size = sizeof(DHCPPacket) + optlen;
419
420 packet = malloc0(size);
421 if (!packet)
422 return -ENOMEM;
423
424 r = dhcp_message_init(&packet->dhcp, BOOTREQUEST, client->xid, type,
425 client->arp_type, optlen, &optoffset);
426 if (r < 0)
427 return r;
428
429 /* Although 'secs' field is a SHOULD in RFC 2131, certain DHCP servers
430 refuse to issue an DHCP lease if 'secs' is set to zero */
431 r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
432 if (r < 0)
433 return r;
434 assert(time_now >= client->start_time);
435
436 /* seconds between sending first and last DISCOVER
437 * must always be strictly positive to deal with broken servers */
438 secs = ((time_now - client->start_time) / USEC_PER_SEC) ? : 1;
439 packet->dhcp.secs = htobe16(secs);
440
441 /* RFC2132 section 4.1
442 A client that cannot receive unicast IP datagrams until its protocol
443 software has been configured with an IP address SHOULD set the
444 BROADCAST bit in the 'flags' field to 1 in any DHCPDISCOVER or
445 DHCPREQUEST messages that client sends. The BROADCAST bit will
446 provide a hint to the DHCP server and BOOTP relay agent to broadcast
447 any messages to the client on the client's subnet.
448
449 Note: some interfaces needs this to be enabled, but some networks
450 needs this to be disabled as broadcasts are filteretd, so this
451 needs to be configurable */
452 if (client->request_broadcast || client->arp_type != ARPHRD_ETHER)
453 packet->dhcp.flags = htobe16(0x8000);
454
455 /* RFC2132 section 4.1.1:
456 The client MUST include its hardware address in the ’chaddr’ field, if
457 necessary for delivery of DHCP reply messages. Non-Ethernet
458 interfaces will leave 'chaddr' empty and use the client identifier
459 instead (eg, RFC 4390 section 2.1).
460 */
461 if (client->arp_type == ARPHRD_ETHER)
462 memcpy(&packet->dhcp.chaddr, &client->mac_addr, ETH_ALEN);
463
464 /* If no client identifier exists, construct one from an ethernet
465 address if present */
466 if (client->client_id_len == 0 && client->arp_type == ARPHRD_ETHER) {
467 client->client_id.eth.type = ARPHRD_ETHER;
468 memcpy(&client->client_id.eth.haddr, &client->mac_addr, ETH_ALEN);
469 client->client_id_len = sizeof (client->client_id.eth);
470 }
471
472 /* Some DHCP servers will refuse to issue an DHCP lease if the Client
473 Identifier option is not set */
474 if (client->client_id_len) {
475 r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0,
476 DHCP_OPTION_CLIENT_IDENTIFIER,
477 client->client_id_len,
478 &client->client_id.raw);
479 if (r < 0)
480 return r;
481 }
482
483 /* RFC2131 section 3.5:
484 in its initial DHCPDISCOVER or DHCPREQUEST message, a
485 client may provide the server with a list of specific
486 parameters the client is interested in. If the client
487 includes a list of parameters in a DHCPDISCOVER message,
488 it MUST include that list in any subsequent DHCPREQUEST
489 messages.
490 */
491 r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0,
492 DHCP_OPTION_PARAMETER_REQUEST_LIST,
493 client->req_opts_size, client->req_opts);
494 if (r < 0)
495 return r;
496
497 /* RFC2131 section 3.5:
498 The client SHOULD include the ’maximum DHCP message size’ option to
499 let the server know how large the server may make its DHCP messages.
500
501 Note (from ConnMan): Some DHCP servers will send bigger DHCP packets
502 than the defined default size unless the Maximum Messge Size option
503 is explicitely set
504
505 RFC3442 "Requirements to Avoid Sizing Constraints":
506 Because a full routing table can be quite large, the standard 576
507 octet maximum size for a DHCP message may be too short to contain
508 some legitimate Classless Static Route options. Because of this,
509 clients implementing the Classless Static Route option SHOULD send a
510 Maximum DHCP Message Size [4] option if the DHCP client's TCP/IP
511 stack is capable of receiving larger IP datagrams. In this case, the
512 client SHOULD set the value of this option to at least the MTU of the
513 interface that the client is configuring. The client MAY set the
514 value of this option higher, up to the size of the largest UDP packet
515 it is prepared to accept. (Note that the value specified in the
516 Maximum DHCP Message Size option is the total maximum packet size,
517 including IP and UDP headers.)
518 */
519 max_size = htobe16(size);
520 r = dhcp_option_append(&packet->dhcp, client->mtu, &optoffset, 0,
521 DHCP_OPTION_MAXIMUM_MESSAGE_SIZE,
522 2, &max_size);
523 if (r < 0)
524 return r;
525
526 *_optlen = optlen;
527 *_optoffset = optoffset;
528 *ret = packet;
529 packet = NULL;
530
531 return 0;
532 }
533
534 static int dhcp_client_send_raw(sd_dhcp_client *client, DHCPPacket *packet,
535 size_t len) {
536 dhcp_packet_append_ip_headers(packet, INADDR_ANY, DHCP_PORT_CLIENT,
537 INADDR_BROADCAST, DHCP_PORT_SERVER, len);
538
539 return dhcp_network_send_raw_socket(client->fd, &client->link,
540 packet, len);
541 }
542
543 static int client_send_discover(sd_dhcp_client *client) {
544 _cleanup_free_ DHCPPacket *discover = NULL;
545 size_t optoffset, optlen;
546 int r;
547
548 assert(client);
549 assert(client->state == DHCP_STATE_INIT ||
550 client->state == DHCP_STATE_SELECTING);
551
552 r = client_message_init(client, &discover, DHCP_DISCOVER,
553 &optlen, &optoffset);
554 if (r < 0)
555 return r;
556
557 /* the client may suggest values for the network address
558 and lease time in the DHCPDISCOVER message. The client may include
559 the ’requested IP address’ option to suggest that a particular IP
560 address be assigned, and may include the ’IP address lease time’
561 option to suggest the lease time it would like.
562 */
563 if (client->last_addr != INADDR_ANY) {
564 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
565 DHCP_OPTION_REQUESTED_IP_ADDRESS,
566 4, &client->last_addr);
567 if (r < 0)
568 return r;
569 }
570
571 /* it is unclear from RFC 2131 if client should send hostname in
572 DHCPDISCOVER but dhclient does and so we do as well
573 */
574 if (client->hostname) {
575 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
576 DHCP_OPTION_HOST_NAME,
577 strlen(client->hostname), client->hostname);
578 if (r < 0)
579 return r;
580 }
581
582 if (client->vendor_class_identifier) {
583 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
584 DHCP_OPTION_VENDOR_CLASS_IDENTIFIER,
585 strlen(client->vendor_class_identifier),
586 client->vendor_class_identifier);
587 if (r < 0)
588 return r;
589 }
590
591 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
592 DHCP_OPTION_END, 0, NULL);
593 if (r < 0)
594 return r;
595
596 /* We currently ignore:
597 The client SHOULD wait a random time between one and ten seconds to
598 desynchronize the use of DHCP at startup.
599 */
600 r = dhcp_client_send_raw(client, discover, sizeof(DHCPPacket) + optoffset);
601 if (r < 0)
602 return r;
603
604 log_dhcp_client(client, "DISCOVER");
605
606 return 0;
607 }
608
609 static int client_send_request(sd_dhcp_client *client) {
610 _cleanup_free_ DHCPPacket *request = NULL;
611 size_t optoffset, optlen;
612 int r;
613
614 r = client_message_init(client, &request, DHCP_REQUEST,
615 &optlen, &optoffset);
616 if (r < 0)
617 return r;
618
619 switch (client->state) {
620 /* See RFC2131 section 4.3.2 (note that there is a typo in the RFC,
621 SELECTING should be REQUESTING)
622 */
623
624 case DHCP_STATE_REQUESTING:
625 /* Client inserts the address of the selected server in ’server
626 identifier’, ’ciaddr’ MUST be zero, ’requested IP address’ MUST be
627 filled in with the yiaddr value from the chosen DHCPOFFER.
628 */
629
630 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
631 DHCP_OPTION_SERVER_IDENTIFIER,
632 4, &client->lease->server_address);
633 if (r < 0)
634 return r;
635
636 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
637 DHCP_OPTION_REQUESTED_IP_ADDRESS,
638 4, &client->lease->address);
639 if (r < 0)
640 return r;
641
642 break;
643
644 case DHCP_STATE_INIT_REBOOT:
645 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
646 option MUST be filled in with client’s notion of its previously
647 assigned address. ’ciaddr’ MUST be zero.
648 */
649 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
650 DHCP_OPTION_REQUESTED_IP_ADDRESS,
651 4, &client->last_addr);
652 if (r < 0)
653 return r;
654 break;
655
656 case DHCP_STATE_RENEWING:
657 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
658 option MUST NOT be filled in, ’ciaddr’ MUST be filled in with
659 client’s IP address.
660 */
661
662 /* fall through */
663 case DHCP_STATE_REBINDING:
664 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
665 option MUST NOT be filled in, ’ciaddr’ MUST be filled in with
666 client’s IP address.
667
668 This message MUST be broadcast to the 0xffffffff IP broadcast address.
669 */
670 request->dhcp.ciaddr = client->lease->address;
671
672 break;
673
674 case DHCP_STATE_INIT:
675 case DHCP_STATE_SELECTING:
676 case DHCP_STATE_REBOOTING:
677 case DHCP_STATE_BOUND:
678 case DHCP_STATE_STOPPED:
679 return -EINVAL;
680 }
681
682 if (client->hostname) {
683 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
684 DHCP_OPTION_HOST_NAME,
685 strlen(client->hostname), client->hostname);
686 if (r < 0)
687 return r;
688 }
689
690 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
691 DHCP_OPTION_END, 0, NULL);
692 if (r < 0)
693 return r;
694
695 if (client->state == DHCP_STATE_RENEWING) {
696 r = dhcp_network_send_udp_socket(client->fd,
697 client->lease->server_address,
698 DHCP_PORT_SERVER,
699 &request->dhcp,
700 sizeof(DHCPMessage) + optoffset);
701 } else {
702 r = dhcp_client_send_raw(client, request, sizeof(DHCPPacket) + optoffset);
703 }
704 if (r < 0)
705 return r;
706
707 switch (client->state) {
708 case DHCP_STATE_REQUESTING:
709 log_dhcp_client(client, "REQUEST (requesting)");
710 break;
711 case DHCP_STATE_INIT_REBOOT:
712 log_dhcp_client(client, "REQUEST (init-reboot)");
713 break;
714 case DHCP_STATE_RENEWING:
715 log_dhcp_client(client, "REQUEST (renewing)");
716 break;
717 case DHCP_STATE_REBINDING:
718 log_dhcp_client(client, "REQUEST (rebinding)");
719 break;
720 default:
721 log_dhcp_client(client, "REQUEST (invalid)");
722 break;
723 }
724
725 return 0;
726 }
727
728 static int client_start(sd_dhcp_client *client);
729
730 static int client_timeout_resend(sd_event_source *s, uint64_t usec,
731 void *userdata) {
732 sd_dhcp_client *client = userdata;
733 DHCP_CLIENT_DONT_DESTROY(client);
734 usec_t next_timeout = 0;
735 uint64_t time_now;
736 uint32_t time_left;
737 int r;
738
739 assert(s);
740 assert(client);
741 assert(client->event);
742
743 r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
744 if (r < 0)
745 goto error;
746
747 switch (client->state) {
748 case DHCP_STATE_RENEWING:
749
750 time_left = (client->lease->t2 - client->lease->t1) / 2;
751 if (time_left < 60)
752 time_left = 60;
753
754 next_timeout = time_now + time_left * USEC_PER_SEC;
755
756 break;
757
758 case DHCP_STATE_REBINDING:
759
760 time_left = (client->lease->lifetime - client->lease->t2) / 2;
761 if (time_left < 60)
762 time_left = 60;
763
764 next_timeout = time_now + time_left * USEC_PER_SEC;
765 break;
766
767 case DHCP_STATE_REBOOTING:
768 /* start over as we did not receive a timely ack or nak */
769 r = client_initialize(client);
770 if (r < 0)
771 goto error;
772
773 r = client_start(client);
774 if (r < 0)
775 goto error;
776 else {
777 log_dhcp_client(client, "REBOOTED");
778 return 0;
779 }
780
781 case DHCP_STATE_INIT:
782 case DHCP_STATE_INIT_REBOOT:
783 case DHCP_STATE_SELECTING:
784 case DHCP_STATE_REQUESTING:
785 case DHCP_STATE_BOUND:
786
787 if (client->attempt < 64)
788 client->attempt *= 2;
789
790 next_timeout = time_now + (client->attempt - 1) * USEC_PER_SEC;
791
792 break;
793
794 case DHCP_STATE_STOPPED:
795 r = -EINVAL;
796 goto error;
797 }
798
799 next_timeout += (random_u32() & 0x1fffff);
800
801 client->timeout_resend = sd_event_source_unref(client->timeout_resend);
802
803 r = sd_event_add_time(client->event,
804 &client->timeout_resend,
805 clock_boottime_or_monotonic(),
806 next_timeout, 10 * USEC_PER_MSEC,
807 client_timeout_resend, client);
808 if (r < 0)
809 goto error;
810
811 r = sd_event_source_set_priority(client->timeout_resend,
812 client->event_priority);
813 if (r < 0)
814 goto error;
815
816 r = sd_event_source_set_description(client->timeout_resend, "dhcp4-resend-timer");
817 if (r < 0)
818 goto error;
819
820 switch (client->state) {
821 case DHCP_STATE_INIT:
822 r = client_send_discover(client);
823 if (r >= 0) {
824 client->state = DHCP_STATE_SELECTING;
825 client->attempt = 1;
826 } else {
827 if (client->attempt >= 64)
828 goto error;
829 }
830
831 break;
832
833 case DHCP_STATE_SELECTING:
834 r = client_send_discover(client);
835 if (r < 0 && client->attempt >= 64)
836 goto error;
837
838 break;
839
840 case DHCP_STATE_INIT_REBOOT:
841 case DHCP_STATE_REQUESTING:
842 case DHCP_STATE_RENEWING:
843 case DHCP_STATE_REBINDING:
844 r = client_send_request(client);
845 if (r < 0 && client->attempt >= 64)
846 goto error;
847
848 if (client->state == DHCP_STATE_INIT_REBOOT)
849 client->state = DHCP_STATE_REBOOTING;
850
851 client->request_sent = time_now;
852
853 break;
854
855 case DHCP_STATE_REBOOTING:
856 case DHCP_STATE_BOUND:
857
858 break;
859
860 case DHCP_STATE_STOPPED:
861 r = -EINVAL;
862 goto error;
863 }
864
865 return 0;
866
867 error:
868 client_stop(client, r);
869
870 /* Errors were dealt with when stopping the client, don't spill
871 errors into the event loop handler */
872 return 0;
873 }
874
875 static int client_initialize_io_events(sd_dhcp_client *client,
876 sd_event_io_handler_t io_callback) {
877 int r;
878
879 assert(client);
880 assert(client->event);
881
882 r = sd_event_add_io(client->event, &client->receive_message,
883 client->fd, EPOLLIN, io_callback,
884 client);
885 if (r < 0)
886 goto error;
887
888 r = sd_event_source_set_priority(client->receive_message,
889 client->event_priority);
890 if (r < 0)
891 goto error;
892
893 r = sd_event_source_set_description(client->receive_message, "dhcp4-receive-message");
894 if (r < 0)
895 goto error;
896
897 error:
898 if (r < 0)
899 client_stop(client, r);
900
901 return 0;
902 }
903
904 static int client_initialize_time_events(sd_dhcp_client *client) {
905 int r;
906
907 assert(client);
908 assert(client->event);
909
910 client->timeout_resend = sd_event_source_unref(client->timeout_resend);
911
912 r = sd_event_add_time(client->event,
913 &client->timeout_resend,
914 clock_boottime_or_monotonic(),
915 0, 0,
916 client_timeout_resend, client);
917 if (r < 0)
918 goto error;
919
920 r = sd_event_source_set_priority(client->timeout_resend,
921 client->event_priority);
922
923 r = sd_event_source_set_description(client->timeout_resend, "dhcp4-resend-timer");
924 if (r < 0)
925 goto error;
926
927 error:
928 if (r < 0)
929 client_stop(client, r);
930
931 return 0;
932
933 }
934
935 static int client_initialize_events(sd_dhcp_client *client,
936 sd_event_io_handler_t io_callback) {
937 client_initialize_io_events(client, io_callback);
938 client_initialize_time_events(client);
939
940 return 0;
941 }
942
943 static int client_start(sd_dhcp_client *client) {
944 int r;
945
946 assert_return(client, -EINVAL);
947 assert_return(client->event, -EINVAL);
948 assert_return(client->index > 0, -EINVAL);
949 assert_return(client->fd < 0, -EBUSY);
950 assert_return(client->xid == 0, -EINVAL);
951 assert_return(client->state == DHCP_STATE_INIT ||
952 client->state == DHCP_STATE_INIT_REBOOT, -EBUSY);
953
954 client->xid = random_u32();
955
956 r = dhcp_network_bind_raw_socket(client->index, &client->link,
957 client->xid, client->mac_addr,
958 client->mac_addr_len, client->arp_type);
959 if (r < 0) {
960 client_stop(client, r);
961 return r;
962 }
963 client->fd = r;
964
965 if (client->state == DHCP_STATE_INIT || client->state == DHCP_STATE_INIT_REBOOT)
966 client->start_time = now(clock_boottime_or_monotonic());
967
968 return client_initialize_events(client, client_receive_message_raw);
969 }
970
971 static int client_timeout_expire(sd_event_source *s, uint64_t usec,
972 void *userdata) {
973 sd_dhcp_client *client = userdata;
974 DHCP_CLIENT_DONT_DESTROY(client);
975
976 log_dhcp_client(client, "EXPIRED");
977
978 client_notify(client, DHCP_EVENT_EXPIRED);
979
980 /* lease was lost, start over if not freed or stopped in callback */
981 if (client->state != DHCP_STATE_STOPPED) {
982 client_initialize(client);
983 client_start(client);
984 }
985
986 return 0;
987 }
988
989 static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata) {
990 sd_dhcp_client *client = userdata;
991 DHCP_CLIENT_DONT_DESTROY(client);
992 int r;
993
994 client->receive_message = sd_event_source_unref(client->receive_message);
995 client->fd = asynchronous_close(client->fd);
996
997 client->state = DHCP_STATE_REBINDING;
998 client->attempt = 1;
999
1000 r = dhcp_network_bind_raw_socket(client->index, &client->link,
1001 client->xid, client->mac_addr,
1002 client->mac_addr_len, client->arp_type);
1003 if (r < 0) {
1004 client_stop(client, r);
1005 return 0;
1006 }
1007 client->fd = r;
1008
1009 return client_initialize_events(client, client_receive_message_raw);
1010 }
1011
1012 static int client_timeout_t1(sd_event_source *s, uint64_t usec,
1013 void *userdata) {
1014 sd_dhcp_client *client = userdata;
1015 DHCP_CLIENT_DONT_DESTROY(client);
1016
1017 client->state = DHCP_STATE_RENEWING;
1018 client->attempt = 1;
1019
1020 return client_initialize_time_events(client);
1021 }
1022
1023 static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer,
1024 size_t len) {
1025 _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
1026 int r;
1027
1028 r = dhcp_lease_new(&lease);
1029 if (r < 0)
1030 return r;
1031
1032 r = dhcp_option_parse(offer, len, dhcp_lease_parse_options, lease);
1033 if (r != DHCP_OFFER) {
1034 log_dhcp_client(client, "received message was not an OFFER, ignoring");
1035 return -ENOMSG;
1036 }
1037
1038 lease->next_server = offer->siaddr;
1039
1040 lease->address = offer->yiaddr;
1041
1042 if (lease->address == INADDR_ANY ||
1043 lease->server_address == INADDR_ANY ||
1044 lease->lifetime == 0) {
1045 log_dhcp_client(client, "received lease lacks address, server "
1046 "address or lease lifetime, ignoring");
1047 return -ENOMSG;
1048 }
1049
1050 if (lease->subnet_mask == INADDR_ANY) {
1051 r = dhcp_lease_set_default_subnet_mask(lease);
1052 if (r < 0) {
1053 log_dhcp_client(client, "received lease lacks subnet "
1054 "mask, and a fallback one can not be "
1055 "generated, ignoring");
1056 return -ENOMSG;
1057 }
1058 }
1059
1060 sd_dhcp_lease_unref(client->lease);
1061 client->lease = lease;
1062 lease = NULL;
1063
1064 log_dhcp_client(client, "OFFER");
1065
1066 return 0;
1067 }
1068
1069 static int client_handle_forcerenew(sd_dhcp_client *client, DHCPMessage *force,
1070 size_t len) {
1071 int r;
1072
1073 r = dhcp_option_parse(force, len, NULL, NULL);
1074 if (r != DHCP_FORCERENEW)
1075 return -ENOMSG;
1076
1077 log_dhcp_client(client, "FORCERENEW");
1078
1079 return 0;
1080 }
1081
1082 static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack,
1083 size_t len) {
1084 _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
1085 int r;
1086
1087 r = dhcp_lease_new(&lease);
1088 if (r < 0)
1089 return r;
1090
1091 r = dhcp_option_parse(ack, len, dhcp_lease_parse_options, lease);
1092 if (r == DHCP_NAK) {
1093 log_dhcp_client(client, "NAK");
1094 return -EADDRNOTAVAIL;
1095 }
1096
1097 if (r != DHCP_ACK) {
1098 log_dhcp_client(client, "received message was not an ACK, ignoring");
1099 return -ENOMSG;
1100 }
1101
1102 lease->next_server = ack->siaddr;
1103
1104 lease->address = ack->yiaddr;
1105
1106 if (lease->address == INADDR_ANY ||
1107 lease->server_address == INADDR_ANY ||
1108 lease->lifetime == 0) {
1109 log_dhcp_client(client, "received lease lacks address, server "
1110 "address or lease lifetime, ignoring");
1111 return -ENOMSG;
1112 }
1113
1114 if (lease->subnet_mask == INADDR_ANY) {
1115 r = dhcp_lease_set_default_subnet_mask(lease);
1116 if (r < 0) {
1117 log_dhcp_client(client, "received lease lacks subnet "
1118 "mask, and a fallback one can not be "
1119 "generated, ignoring");
1120 return -ENOMSG;
1121 }
1122 }
1123
1124 r = DHCP_EVENT_IP_ACQUIRE;
1125 if (client->lease) {
1126 if (client->lease->address != lease->address ||
1127 client->lease->subnet_mask != lease->subnet_mask ||
1128 client->lease->router != lease->router) {
1129 r = DHCP_EVENT_IP_CHANGE;
1130 } else
1131 r = DHCP_EVENT_RENEW;
1132
1133 client->lease = sd_dhcp_lease_unref(client->lease);
1134 }
1135
1136 client->lease = lease;
1137 lease = NULL;
1138
1139 log_dhcp_client(client, "ACK");
1140
1141 return r;
1142 }
1143
1144 static uint64_t client_compute_timeout(sd_dhcp_client *client,
1145 uint32_t lifetime, double factor) {
1146 assert(client);
1147 assert(client->request_sent);
1148 assert(lifetime);
1149
1150 return client->request_sent + ((lifetime - 3) * USEC_PER_SEC * factor) +
1151 + (random_u32() & 0x1fffff);
1152 }
1153
1154 static int client_set_lease_timeouts(sd_dhcp_client *client) {
1155 usec_t time_now;
1156 uint64_t lifetime_timeout;
1157 uint64_t t2_timeout;
1158 uint64_t t1_timeout;
1159 char time_string[FORMAT_TIMESPAN_MAX];
1160 int r;
1161
1162 assert(client);
1163 assert(client->event);
1164 assert(client->lease);
1165 assert(client->lease->lifetime);
1166
1167 client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
1168 client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
1169 client->timeout_expire = sd_event_source_unref(client->timeout_expire);
1170
1171 /* don't set timers for infinite leases */
1172 if (client->lease->lifetime == 0xffffffff)
1173 return 0;
1174
1175 r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
1176 if (r < 0)
1177 return r;
1178 assert(client->request_sent <= time_now);
1179
1180 /* convert the various timeouts from relative (secs) to absolute (usecs) */
1181 lifetime_timeout = client_compute_timeout(client, client->lease->lifetime, 1);
1182 if (client->lease->t1 && client->lease->t2) {
1183 /* both T1 and T2 are given */
1184 if (client->lease->t1 < client->lease->t2 &&
1185 client->lease->t2 < client->lease->lifetime) {
1186 /* they are both valid */
1187 t2_timeout = client_compute_timeout(client, client->lease->t2, 1);
1188 t1_timeout = client_compute_timeout(client, client->lease->t1, 1);
1189 } else {
1190 /* discard both */
1191 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
1192 client->lease->t2 = (client->lease->lifetime * 7) / 8;
1193 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
1194 client->lease->t1 = client->lease->lifetime / 2;
1195 }
1196 } else if (client->lease->t2 && client->lease->t2 < client->lease->lifetime) {
1197 /* only T2 is given, and it is valid */
1198 t2_timeout = client_compute_timeout(client, client->lease->t2, 1);
1199 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
1200 client->lease->t1 = client->lease->lifetime / 2;
1201 if (t2_timeout <= t1_timeout) {
1202 /* the computed T1 would be invalid, so discard T2 */
1203 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
1204 client->lease->t2 = (client->lease->lifetime * 7) / 8;
1205 }
1206 } else if (client->lease->t1 && client->lease->t1 < client->lease->lifetime) {
1207 /* only T1 is given, and it is valid */
1208 t1_timeout = client_compute_timeout(client, client->lease->t1, 1);
1209 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
1210 client->lease->t2 = (client->lease->lifetime * 7) / 8;
1211 if (t2_timeout <= t1_timeout) {
1212 /* the computed T2 would be invalid, so discard T1 */
1213 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
1214 client->lease->t2 = client->lease->lifetime / 2;
1215 }
1216 } else {
1217 /* fall back to the default timeouts */
1218 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
1219 client->lease->t1 = client->lease->lifetime / 2;
1220 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
1221 client->lease->t2 = (client->lease->lifetime * 7) / 8;
1222 }
1223
1224 /* arm lifetime timeout */
1225 r = sd_event_add_time(client->event, &client->timeout_expire,
1226 clock_boottime_or_monotonic(),
1227 lifetime_timeout, 10 * USEC_PER_MSEC,
1228 client_timeout_expire, client);
1229 if (r < 0)
1230 return r;
1231
1232 r = sd_event_source_set_priority(client->timeout_expire,
1233 client->event_priority);
1234 if (r < 0)
1235 return r;
1236
1237 r = sd_event_source_set_description(client->timeout_expire, "dhcp4-lifetime");
1238 if (r < 0)
1239 return r;
1240
1241 log_dhcp_client(client, "lease expires in %s",
1242 format_timespan(time_string, FORMAT_TIMESPAN_MAX,
1243 lifetime_timeout - time_now, 0));
1244
1245 /* don't arm earlier timeouts if this has already expired */
1246 if (lifetime_timeout <= time_now)
1247 return 0;
1248
1249 /* arm T2 timeout */
1250 r = sd_event_add_time(client->event,
1251 &client->timeout_t2,
1252 clock_boottime_or_monotonic(),
1253 t2_timeout,
1254 10 * USEC_PER_MSEC,
1255 client_timeout_t2, client);
1256 if (r < 0)
1257 return r;
1258
1259 r = sd_event_source_set_priority(client->timeout_t2,
1260 client->event_priority);
1261 if (r < 0)
1262 return r;
1263
1264 r = sd_event_source_set_description(client->timeout_t2, "dhcp4-t2-timeout");
1265 if (r < 0)
1266 return r;
1267
1268 log_dhcp_client(client, "T2 expires in %s",
1269 format_timespan(time_string, FORMAT_TIMESPAN_MAX,
1270 t2_timeout - time_now, 0));
1271
1272 /* don't arm earlier timeout if this has already expired */
1273 if (t2_timeout <= time_now)
1274 return 0;
1275
1276 /* arm T1 timeout */
1277 r = sd_event_add_time(client->event,
1278 &client->timeout_t1,
1279 clock_boottime_or_monotonic(),
1280 t1_timeout, 10 * USEC_PER_MSEC,
1281 client_timeout_t1, client);
1282 if (r < 0)
1283 return r;
1284
1285 r = sd_event_source_set_priority(client->timeout_t1,
1286 client->event_priority);
1287 if (r < 0)
1288 return r;
1289
1290 r = sd_event_source_set_description(client->timeout_t1, "dhcp4-t1-timer");
1291 if (r < 0)
1292 return r;
1293
1294 log_dhcp_client(client, "T1 expires in %s",
1295 format_timespan(time_string, FORMAT_TIMESPAN_MAX,
1296 t1_timeout - time_now, 0));
1297
1298 return 0;
1299 }
1300
1301 static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message,
1302 int len) {
1303 DHCP_CLIENT_DONT_DESTROY(client);
1304 int r = 0, notify_event = 0;
1305
1306 assert(client);
1307 assert(client->event);
1308 assert(message);
1309
1310 switch (client->state) {
1311 case DHCP_STATE_SELECTING:
1312
1313 r = client_handle_offer(client, message, len);
1314 if (r >= 0) {
1315
1316 client->timeout_resend =
1317 sd_event_source_unref(client->timeout_resend);
1318
1319 client->state = DHCP_STATE_REQUESTING;
1320 client->attempt = 1;
1321
1322 r = sd_event_add_time(client->event,
1323 &client->timeout_resend,
1324 clock_boottime_or_monotonic(),
1325 0, 0,
1326 client_timeout_resend, client);
1327 if (r < 0)
1328 goto error;
1329
1330 r = sd_event_source_set_priority(client->timeout_resend,
1331 client->event_priority);
1332 if (r < 0)
1333 goto error;
1334
1335 r = sd_event_source_set_description(client->timeout_resend, "dhcp4-resend-timer");
1336 if (r < 0)
1337 goto error;
1338 } else if (r == -ENOMSG)
1339 /* invalid message, let's ignore it */
1340 return 0;
1341
1342 break;
1343
1344 case DHCP_STATE_REBOOTING:
1345 case DHCP_STATE_REQUESTING:
1346 case DHCP_STATE_RENEWING:
1347 case DHCP_STATE_REBINDING:
1348
1349 r = client_handle_ack(client, message, len);
1350 if (r >= 0) {
1351 client->timeout_resend =
1352 sd_event_source_unref(client->timeout_resend);
1353 client->receive_message =
1354 sd_event_source_unref(client->receive_message);
1355 client->fd = asynchronous_close(client->fd);
1356
1357 if (IN_SET(client->state, DHCP_STATE_REQUESTING,
1358 DHCP_STATE_REBOOTING))
1359 notify_event = DHCP_EVENT_IP_ACQUIRE;
1360 else if (r != DHCP_EVENT_IP_ACQUIRE)
1361 notify_event = r;
1362
1363 client->state = DHCP_STATE_BOUND;
1364 client->attempt = 1;
1365
1366 client->last_addr = client->lease->address;
1367
1368 r = client_set_lease_timeouts(client);
1369 if (r < 0)
1370 goto error;
1371
1372 r = dhcp_network_bind_udp_socket(client->lease->address,
1373 DHCP_PORT_CLIENT);
1374 if (r < 0) {
1375 log_dhcp_client(client, "could not bind UDP socket");
1376 goto error;
1377 }
1378
1379 client->fd = r;
1380
1381 client_initialize_io_events(client, client_receive_message_udp);
1382
1383 if (notify_event) {
1384 client_notify(client, notify_event);
1385 if (client->state == DHCP_STATE_STOPPED)
1386 return 0;
1387 }
1388
1389 } else if (r == -EADDRNOTAVAIL) {
1390 /* got a NAK, let's restart the client */
1391 client->timeout_resend =
1392 sd_event_source_unref(client->timeout_resend);
1393
1394 r = client_initialize(client);
1395 if (r < 0)
1396 goto error;
1397
1398 r = client_start(client);
1399 if (r < 0)
1400 goto error;
1401
1402 log_dhcp_client(client, "REBOOTED");
1403
1404 return 0;
1405 } else if (r == -ENOMSG)
1406 /* invalid message, let's ignore it */
1407 return 0;
1408
1409 break;
1410
1411 case DHCP_STATE_BOUND:
1412 r = client_handle_forcerenew(client, message, len);
1413 if (r >= 0) {
1414 r = client_timeout_t1(NULL, 0, client);
1415 if (r < 0)
1416 goto error;
1417 } else if (r == -ENOMSG)
1418 /* invalid message, let's ignore it */
1419 return 0;
1420
1421 break;
1422
1423 case DHCP_STATE_INIT:
1424 case DHCP_STATE_INIT_REBOOT:
1425
1426 break;
1427
1428 case DHCP_STATE_STOPPED:
1429 r = -EINVAL;
1430 goto error;
1431 }
1432
1433 error:
1434 if (r < 0)
1435 client_stop(client, r);
1436
1437 return r;
1438 }
1439
1440 static int client_receive_message_udp(sd_event_source *s, int fd,
1441 uint32_t revents, void *userdata) {
1442 sd_dhcp_client *client = userdata;
1443 _cleanup_free_ DHCPMessage *message = NULL;
1444 int buflen = 0, len, r;
1445 const struct ether_addr zero_mac = { { 0, 0, 0, 0, 0, 0 } };
1446 const struct ether_addr *expected_chaddr = NULL;
1447 uint8_t expected_hlen = 0;
1448
1449 assert(s);
1450 assert(client);
1451
1452 r = ioctl(fd, FIONREAD, &buflen);
1453 if (r < 0)
1454 return r;
1455
1456 if (buflen < 0)
1457 /* this can't be right */
1458 return -EIO;
1459
1460 message = malloc0(buflen);
1461 if (!message)
1462 return -ENOMEM;
1463
1464 len = read(fd, message, buflen);
1465 if (len < 0) {
1466 log_dhcp_client(client, "could not receive message from UDP "
1467 "socket: %m");
1468 return 0;
1469 } else if ((size_t)len < sizeof(DHCPMessage)) {
1470 log_dhcp_client(client, "too small to be a DHCP message: ignoring");
1471 return 0;
1472 }
1473
1474 if (be32toh(message->magic) != DHCP_MAGIC_COOKIE) {
1475 log_dhcp_client(client, "not a DHCP message: ignoring");
1476 return 0;
1477 }
1478
1479 if (message->op != BOOTREPLY) {
1480 log_dhcp_client(client, "not a BOOTREPLY message: ignoring");
1481 return 0;
1482 }
1483
1484 if (message->htype != client->arp_type) {
1485 log_dhcp_client(client, "packet type does not match client type");
1486 return 0;
1487 }
1488
1489 if (client->arp_type == ARPHRD_ETHER) {
1490 expected_hlen = ETH_ALEN;
1491 expected_chaddr = (const struct ether_addr *) &client->mac_addr;
1492 } else {
1493 /* Non-ethernet links expect zero chaddr */
1494 expected_hlen = 0;
1495 expected_chaddr = &zero_mac;
1496 }
1497
1498 if (message->hlen != expected_hlen) {
1499 log_dhcp_client(client, "unexpected packet hlen %d", message->hlen);
1500 return 0;
1501 }
1502
1503 if (memcmp(&message->chaddr[0], expected_chaddr, ETH_ALEN)) {
1504 log_dhcp_client(client, "received chaddr does not match "
1505 "expected: ignoring");
1506 return 0;
1507 }
1508
1509 if (client->state != DHCP_STATE_BOUND &&
1510 be32toh(message->xid) != client->xid) {
1511 /* in BOUND state, we may receive FORCERENEW with xid set by server,
1512 so ignore the xid in this case */
1513 log_dhcp_client(client, "received xid (%u) does not match "
1514 "expected (%u): ignoring",
1515 be32toh(message->xid), client->xid);
1516 return 0;
1517 }
1518
1519 return client_handle_message(client, message, len);
1520 }
1521
1522 static int client_receive_message_raw(sd_event_source *s, int fd,
1523 uint32_t revents, void *userdata) {
1524 sd_dhcp_client *client = userdata;
1525 _cleanup_free_ DHCPPacket *packet = NULL;
1526 uint8_t cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))];
1527 struct iovec iov = {};
1528 struct msghdr msg = {
1529 .msg_iov = &iov,
1530 .msg_iovlen = 1,
1531 .msg_control = cmsgbuf,
1532 .msg_controllen = sizeof(cmsgbuf),
1533 };
1534 struct cmsghdr *cmsg;
1535 bool checksum = true;
1536 int buflen = 0, len, r;
1537
1538 assert(s);
1539 assert(client);
1540
1541 r = ioctl(fd, FIONREAD, &buflen);
1542 if (r < 0)
1543 return r;
1544
1545 if (buflen < 0)
1546 /* this can't be right */
1547 return -EIO;
1548
1549 packet = malloc0(buflen);
1550 if (!packet)
1551 return -ENOMEM;
1552
1553 iov.iov_base = packet;
1554 iov.iov_len = buflen;
1555
1556 len = recvmsg(fd, &msg, 0);
1557 if (len < 0) {
1558 log_dhcp_client(client, "could not receive message from raw "
1559 "socket: %m");
1560 return 0;
1561 } else if ((size_t)len < sizeof(DHCPPacket))
1562 return 0;
1563
1564 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
1565 if (cmsg->cmsg_level == SOL_PACKET &&
1566 cmsg->cmsg_type == PACKET_AUXDATA &&
1567 cmsg->cmsg_len == CMSG_LEN(sizeof(struct tpacket_auxdata))) {
1568 struct tpacket_auxdata *aux = (struct tpacket_auxdata*)CMSG_DATA(cmsg);
1569
1570 checksum = !(aux->tp_status & TP_STATUS_CSUMNOTREADY);
1571 break;
1572 }
1573 }
1574
1575 r = dhcp_packet_verify_headers(packet, len, checksum);
1576 if (r < 0)
1577 return 0;
1578
1579 len -= DHCP_IP_UDP_SIZE;
1580
1581 return client_handle_message(client, &packet->dhcp, len);
1582 }
1583
1584 int sd_dhcp_client_start(sd_dhcp_client *client) {
1585 int r;
1586
1587 assert_return(client, -EINVAL);
1588
1589 r = client_initialize(client);
1590 if (r < 0)
1591 return r;
1592
1593 if (client->last_addr)
1594 client->state = DHCP_STATE_INIT_REBOOT;
1595
1596 r = client_start(client);
1597 if (r >= 0)
1598 log_dhcp_client(client, "STARTED on ifindex %u", client->index);
1599
1600 return r;
1601 }
1602
1603 int sd_dhcp_client_stop(sd_dhcp_client *client) {
1604 DHCP_CLIENT_DONT_DESTROY(client);
1605
1606 assert_return(client, -EINVAL);
1607
1608 client_stop(client, DHCP_EVENT_STOP);
1609 client->state = DHCP_STATE_STOPPED;
1610
1611 return 0;
1612 }
1613
1614 int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event,
1615 int priority) {
1616 int r;
1617
1618 assert_return(client, -EINVAL);
1619 assert_return(!client->event, -EBUSY);
1620
1621 if (event)
1622 client->event = sd_event_ref(event);
1623 else {
1624 r = sd_event_default(&client->event);
1625 if (r < 0)
1626 return 0;
1627 }
1628
1629 client->event_priority = priority;
1630
1631 return 0;
1632 }
1633
1634 int sd_dhcp_client_detach_event(sd_dhcp_client *client) {
1635 assert_return(client, -EINVAL);
1636
1637 client->event = sd_event_unref(client->event);
1638
1639 return 0;
1640 }
1641
1642 sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client) {
1643 if (!client)
1644 return NULL;
1645
1646 return client->event;
1647 }
1648
1649 sd_dhcp_client *sd_dhcp_client_ref(sd_dhcp_client *client) {
1650 if (client)
1651 assert_se(REFCNT_INC(client->n_ref) >= 2);
1652
1653 return client;
1654 }
1655
1656 sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client) {
1657 if (client && REFCNT_DEC(client->n_ref) <= 0) {
1658 log_dhcp_client(client, "FREE");
1659
1660 client_initialize(client);
1661
1662 client->receive_message =
1663 sd_event_source_unref(client->receive_message);
1664
1665 sd_dhcp_client_detach_event(client);
1666
1667 sd_dhcp_lease_unref(client->lease);
1668
1669 free(client->req_opts);
1670 free(client->hostname);
1671 free(client->vendor_class_identifier);
1672 free(client);
1673 }
1674
1675 return NULL;
1676 }
1677
1678 int sd_dhcp_client_new(sd_dhcp_client **ret) {
1679 _cleanup_dhcp_client_unref_ sd_dhcp_client *client = NULL;
1680
1681 assert_return(ret, -EINVAL);
1682
1683 client = new0(sd_dhcp_client, 1);
1684 if (!client)
1685 return -ENOMEM;
1686
1687 client->n_ref = REFCNT_INIT;
1688 client->state = DHCP_STATE_INIT;
1689 client->index = -1;
1690 client->fd = -1;
1691 client->attempt = 1;
1692 client->mtu = DHCP_DEFAULT_MIN_SIZE;
1693
1694 client->req_opts_size = ELEMENTSOF(default_req_opts);
1695
1696 client->req_opts = memdup(default_req_opts, client->req_opts_size);
1697 if (!client->req_opts)
1698 return -ENOMEM;
1699
1700 *ret = client;
1701 client = NULL;
1702
1703 return 0;
1704 }