1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright (C) 2014 Intel Corporation. All rights reserved.
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
24 #include <sys/ioctl.h>
27 #include "udev-util.h"
29 #include "siphash24.h"
33 #include "network-internal.h"
34 #include "sd-dhcp6-client.h"
35 #include "dhcp6-protocol.h"
36 #include "dhcp6-internal.h"
37 #include "dhcp6-lease-internal.h"
39 #define SYSTEMD_PEN 43793
40 #define HASH_KEY SD_ID128_MAKE(80,11,8c,c2,fe,4a,03,ee,3e,d6,0c,6f,36,39,14,09)
42 struct sd_dhcp6_client {
45 enum DHCP6State state;
49 struct ether_addr mac_addr;
51 be32_t transaction_id;
52 struct sd_dhcp6_lease *lease;
55 size_t req_opts_allocated;
57 sd_event_source *receive_message;
58 usec_t retransmit_time;
59 uint8_t retransmit_count;
60 sd_event_source *timeout_resend;
61 sd_event_source *timeout_resend_expire;
62 sd_dhcp6_client_cb_t cb;
66 uint16_t type; /* DHCP6_DUID_EN */
72 static const uint16_t default_req_opts[] = {
73 DHCP6_OPTION_DNS_SERVERS,
74 DHCP6_OPTION_DOMAIN_LIST,
75 DHCP6_OPTION_NTP_SERVER,
78 const char * dhcp6_message_type_table[_DHCP6_MESSAGE_MAX] = {
79 [DHCP6_SOLICIT] = "SOLICIT",
80 [DHCP6_ADVERTISE] = "ADVERTISE",
81 [DHCP6_REQUEST] = "REQUEST",
82 [DHCP6_CONFIRM] = "CONFIRM",
83 [DHCP6_RENEW] = "RENEW",
84 [DHCP6_REBIND] = "REBIND",
85 [DHCP6_REPLY] = "REPLY",
86 [DHCP6_RELEASE] = "RELEASE",
87 [DHCP6_DECLINE] = "DECLINE",
88 [DHCP6_RECONFIGURE] = "RECONFIGURE",
89 [DHCP6_INFORMATION_REQUEST] = "INFORMATION-REQUEST",
90 [DHCP6_RELAY_FORW] = "RELAY-FORW",
91 [DHCP6_RELAY_REPL] = "RELAY-REPL",
94 DEFINE_STRING_TABLE_LOOKUP(dhcp6_message_type, int);
96 const char * dhcp6_message_status_table[_DHCP6_STATUS_MAX] = {
97 [DHCP6_STATUS_SUCCESS] = "Success",
98 [DHCP6_STATUS_UNSPEC_FAIL] = "Unspecified failure",
99 [DHCP6_STATUS_NO_ADDRS_AVAIL] = "No addresses available",
100 [DHCP6_STATUS_NO_BINDING] = "Binding unavailable",
101 [DHCP6_STATUS_NOT_ON_LINK] = "Not on link",
102 [DHCP6_STATUS_USE_MULTICAST] = "Use multicast",
105 DEFINE_STRING_TABLE_LOOKUP(dhcp6_message_status, int);
107 DEFINE_TRIVIAL_CLEANUP_FUNC(sd_dhcp6_client*, sd_dhcp6_client_unref);
108 #define _cleanup_dhcp6_client_unref_ _cleanup_(sd_dhcp6_client_unrefp)
110 #define DHCP6_CLIENT_DONT_DESTROY(client) \
111 _cleanup_dhcp6_client_unref_ _unused_ sd_dhcp6_client *_dont_destroy_##client = sd_dhcp6_client_ref(client)
113 static int client_start(sd_dhcp6_client *client, enum DHCP6State state);
115 int sd_dhcp6_client_set_callback(sd_dhcp6_client *client,
116 sd_dhcp6_client_cb_t cb, void *userdata)
118 assert_return(client, -EINVAL);
121 client->userdata = userdata;
126 int sd_dhcp6_client_set_index(sd_dhcp6_client *client, int interface_index)
128 assert_return(client, -EINVAL);
129 assert_return(interface_index >= -1, -EINVAL);
131 client->index = interface_index;
136 int sd_dhcp6_client_set_mac(sd_dhcp6_client *client,
137 const struct ether_addr *mac_addr)
139 assert_return(client, -EINVAL);
142 memcpy(&client->mac_addr, mac_addr, sizeof(client->mac_addr));
144 memset(&client->mac_addr, 0x00, sizeof(client->mac_addr));
149 int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client,
153 assert_return(client, -EINVAL);
154 assert_return(client->state == DHCP6_STATE_STOPPED, -EBUSY);
157 case DHCP6_OPTION_DNS_SERVERS:
158 case DHCP6_OPTION_DOMAIN_LIST:
159 case DHCP6_OPTION_SNTP_SERVERS:
160 case DHCP6_OPTION_NTP_SERVER:
167 for (t = 0; t < client->req_opts_len; t++)
168 if (client->req_opts[t] == htobe16(option))
171 if (!GREEDY_REALLOC(client->req_opts, client->req_opts_allocated,
172 client->req_opts_len + 1))
175 client->req_opts[client->req_opts_len++] = htobe16(option);
180 int sd_dhcp6_client_get_lease(sd_dhcp6_client *client, sd_dhcp6_lease **ret) {
181 assert_return(client, -EINVAL);
182 assert_return(ret, -EINVAL);
187 *ret = sd_dhcp6_lease_ref(client->lease);
192 static void client_notify(sd_dhcp6_client *client, int event) {
194 client->cb(client, event, client->userdata);
197 static int client_reset(sd_dhcp6_client *client) {
198 assert_return(client, -EINVAL);
200 client->receive_message =
201 sd_event_source_unref(client->receive_message);
203 client->fd = safe_close(client->fd);
205 client->transaction_id = 0;
207 client->ia_na.timeout_t1 =
208 sd_event_source_unref(client->ia_na.timeout_t1);
209 client->ia_na.timeout_t2 =
210 sd_event_source_unref(client->ia_na.timeout_t2);
212 client->retransmit_time = 0;
213 client->retransmit_count = 0;
214 client->timeout_resend = sd_event_source_unref(client->timeout_resend);
215 client->timeout_resend_expire =
216 sd_event_source_unref(client->timeout_resend_expire);
218 client->state = DHCP6_STATE_STOPPED;
223 static void client_stop(sd_dhcp6_client *client, int error) {
224 DHCP6_CLIENT_DONT_DESTROY(client);
228 client_notify(client, error);
230 client_reset(client);
233 static int client_send_message(sd_dhcp6_client *client) {
234 _cleanup_free_ DHCP6Message *message = NULL;
235 struct in6_addr all_servers =
236 IN6ADDR_ALL_DHCP6_RELAY_AGENTS_AND_SERVERS_INIT;
237 size_t len, optlen = 512;
241 len = sizeof(DHCP6Message) + optlen;
243 message = malloc0(len);
247 opt = (uint8_t *)(message + 1);
249 message->transaction_id = client->transaction_id;
251 switch(client->state) {
252 case DHCP6_STATE_SOLICITATION:
253 message->type = DHCP6_SOLICIT;
255 r = dhcp6_option_append_ia(&opt, &optlen, &client->ia_na);
261 case DHCP6_STATE_REQUEST:
262 message->type = DHCP6_REQUEST;
264 r = dhcp6_option_append(&opt, &optlen, DHCP6_OPTION_SERVERID,
265 client->lease->serverid_len,
266 client->lease->serverid);
270 r = dhcp6_option_append_ia(&opt, &optlen, &client->lease->ia);
276 case DHCP6_STATE_STOPPED:
278 case DHCP6_STATE_BOUND:
282 r = dhcp6_option_append(&opt, &optlen, DHCP6_OPTION_ORO,
283 client->req_opts_len * sizeof(be16_t),
288 r = dhcp6_option_append(&opt, &optlen, DHCP6_OPTION_CLIENTID,
289 sizeof(client->duid), &client->duid);
293 r = dhcp6_network_send_udp_socket(client->fd, &all_servers, message,
298 log_dhcp6_client(client, "Sent %s",
299 dhcp6_message_type_to_string(message->type));
304 static int client_timeout_t2(sd_event_source *s, uint64_t usec,
306 sd_dhcp6_client *client = userdata;
308 assert_return(s, -EINVAL);
309 assert_return(client, -EINVAL);
310 assert_return(client->lease, -EINVAL);
312 client->lease->ia.timeout_t2 =
313 sd_event_source_unref(client->lease->ia.timeout_t2);
315 log_dhcp6_client(client, "Timeout T2");
320 static int client_timeout_t1(sd_event_source *s, uint64_t usec,
322 sd_dhcp6_client *client = userdata;
324 assert_return(s, -EINVAL);
325 assert_return(client, -EINVAL);
326 assert_return(client->lease, -EINVAL);
328 client->lease->ia.timeout_t1 =
329 sd_event_source_unref(client->lease->ia.timeout_t1);
331 log_dhcp6_client(client, "Timeout T1");
336 static int client_timeout_resend_expire(sd_event_source *s, uint64_t usec,
338 sd_dhcp6_client *client = userdata;
342 assert(client->event);
344 client_stop(client, DHCP6_EVENT_RESEND_EXPIRE);
349 static usec_t client_timeout_compute_random(usec_t val) {
350 return val - val / 10 +
351 (random_u32() % (2 * USEC_PER_SEC)) * val / 10 / USEC_PER_SEC;
354 static int client_timeout_resend(sd_event_source *s, uint64_t usec,
357 sd_dhcp6_client *client = userdata;
358 usec_t time_now, init_retransmit_time, max_retransmit_time;
359 usec_t max_retransmit_duration;
360 uint8_t max_retransmit_count = 0;
361 char time_string[FORMAT_TIMESPAN_MAX];
365 assert(client->event);
367 client->timeout_resend = sd_event_source_unref(client->timeout_resend);
369 switch (client->state) {
370 case DHCP6_STATE_SOLICITATION:
372 if (client->retransmit_count && client->lease) {
373 client_start(client, DHCP6_STATE_REQUEST);
377 init_retransmit_time = DHCP6_SOL_TIMEOUT;
378 max_retransmit_time = DHCP6_SOL_MAX_RT;
379 max_retransmit_count = 0;
380 max_retransmit_duration = 0;
384 case DHCP6_STATE_REQUEST:
385 init_retransmit_time = DHCP6_REQ_TIMEOUT;
386 max_retransmit_time = DHCP6_REQ_MAX_RT;
387 max_retransmit_count = DHCP6_REQ_MAX_RC;
388 max_retransmit_duration = 0;
392 case DHCP6_STATE_STOPPED:
394 case DHCP6_STATE_BOUND:
398 if (max_retransmit_count &&
399 client->retransmit_count >= max_retransmit_count) {
400 client_stop(client, DHCP6_EVENT_RETRANS_MAX);
404 r = client_send_message(client);
406 client->retransmit_count++;
409 r = sd_event_now(client->event, CLOCK_MONOTONIC, &time_now);
413 if (!client->retransmit_time) {
414 client->retransmit_time =
415 client_timeout_compute_random(init_retransmit_time);
417 if (client->state == DHCP6_STATE_SOLICITATION)
418 client->retransmit_time += init_retransmit_time / 10;
421 if (max_retransmit_time &&
422 client->retransmit_time > max_retransmit_time / 2)
423 client->retransmit_time = client_timeout_compute_random(max_retransmit_time);
425 client->retransmit_time += client_timeout_compute_random(client->retransmit_time);
428 log_dhcp6_client(client, "Next retransmission in %s",
429 format_timespan(time_string, FORMAT_TIMESPAN_MAX,
430 client->retransmit_time, 0));
432 r = sd_event_add_time(client->event, &client->timeout_resend,
434 time_now + client->retransmit_time,
435 10 * USEC_PER_MSEC, client_timeout_resend,
440 r = sd_event_source_set_priority(client->timeout_resend,
441 client->event_priority);
445 if (max_retransmit_duration && !client->timeout_resend_expire) {
447 log_dhcp6_client(client, "Max retransmission duration %"PRIu64" secs",
448 max_retransmit_duration / USEC_PER_SEC);
450 r = sd_event_add_time(client->event,
451 &client->timeout_resend_expire,
453 time_now + max_retransmit_duration,
455 client_timeout_resend_expire, client);
459 r = sd_event_source_set_priority(client->timeout_resend_expire,
460 client->event_priority);
467 client_stop(client, r);
472 static int client_ensure_iaid(sd_dhcp6_client *client) {
473 const char *name = NULL;
478 if (client->ia_na.id)
481 if (detect_container(NULL) <= 0) {
482 /* not in a container, udev will be around */
483 _cleanup_udev_unref_ struct udev *udev;
484 _cleanup_udev_device_unref_ struct udev_device *device = NULL;
485 char ifindex_str[2 + DECIMAL_STR_MAX(int)];
491 sprintf(ifindex_str, "n%d", client->index);
492 device = udev_device_new_from_device_id(udev, ifindex_str);
496 if (udev_device_get_is_initialized(device) <= 0)
500 name = net_get_name(device);
504 siphash24((uint8_t*)&id, name, strlen(name), HASH_KEY.bytes);
506 /* fall back to mac address if no predictable name available */
507 siphash24((uint8_t*)&id, &client->mac_addr, ETH_ALEN,
510 /* fold into 32 bits */
511 client->ia_na.id = (id & 0xffffffff) ^ (id >> 32);
516 static int client_parse_message(sd_dhcp6_client *client,
517 DHCP6Message *message, size_t len,
518 sd_dhcp6_lease *lease) {
520 uint8_t *optval, *option = (uint8_t *)(message + 1), *id = NULL;
521 uint16_t optcode, status;
522 size_t optlen, id_len;
523 bool clientid = false;
526 while ((r = dhcp6_option_parse(&option, &len, &optcode, &optlen,
529 case DHCP6_OPTION_CLIENTID:
531 log_dhcp6_client(client, "%s contains multiple clientids",
532 dhcp6_message_type_to_string(message->type));
536 if (optlen != sizeof(client->duid) ||
537 memcmp(&client->duid, optval, optlen) != 0) {
538 log_dhcp6_client(client, "%s DUID does not match",
539 dhcp6_message_type_to_string(message->type));
547 case DHCP6_OPTION_SERVERID:
548 r = dhcp6_lease_get_serverid(lease, &id, &id_len);
550 log_dhcp6_client(client, "%s contains multiple serverids",
551 dhcp6_message_type_to_string(message->type));
555 r = dhcp6_lease_set_serverid(lease, optval, optlen);
561 case DHCP6_OPTION_PREFERENCE:
565 r = dhcp6_lease_set_preference(lease, *optval);
571 case DHCP6_OPTION_STATUS_CODE:
575 status = optval[0] << 8 | optval[1];
577 log_dhcp6_client(client, "%s Status %s",
578 dhcp6_message_type_to_string(message->type),
579 dhcp6_message_status_to_string(status));
585 case DHCP6_OPTION_IA_NA:
586 r = dhcp6_option_parse_ia(&optval, &optlen, optcode,
588 if (r < 0 && r != -ENOMSG)
591 r = dhcp6_lease_get_iaid(lease, &iaid_lease);
595 if (client->ia_na.id != iaid_lease) {
596 log_dhcp6_client(client, "%s has wrong IAID",
597 dhcp6_message_type_to_string(message->type));
605 if ((r < 0 && r != -ENOMSG) || !clientid) {
606 log_dhcp6_client(client, "%s has incomplete options",
607 dhcp6_message_type_to_string(message->type));
611 r = dhcp6_lease_get_serverid(lease, &id, &id_len);
613 log_dhcp6_client(client, "%s has no server id",
614 dhcp6_message_type_to_string(message->type));
619 static int client_receive_reply(sd_dhcp6_client *client, DHCP6Message *reply,
623 _cleanup_dhcp6_lease_free_ sd_dhcp6_lease *lease = NULL;
625 if (reply->type != DHCP6_REPLY)
628 r = dhcp6_lease_new(&lease);
632 r = client_parse_message(client, reply, len, lease);
636 dhcp6_lease_clear_timers(&client->lease->ia);
638 client->lease = sd_dhcp6_lease_unref(client->lease);
639 client->lease = lease;
642 return DHCP6_STATE_BOUND;
645 static int client_receive_advertise(sd_dhcp6_client *client,
646 DHCP6Message *advertise, size_t len) {
648 _cleanup_dhcp6_lease_free_ sd_dhcp6_lease *lease = NULL;
649 uint8_t pref_advertise = 0, pref_lease = 0;
651 if (advertise->type != DHCP6_ADVERTISE)
654 r = dhcp6_lease_new(&lease);
658 r = client_parse_message(client, advertise, len, lease);
662 r = dhcp6_lease_get_preference(lease, &pref_advertise);
666 r = dhcp6_lease_get_preference(client->lease, &pref_lease);
667 if (!client->lease || r < 0 || pref_advertise > pref_lease) {
668 sd_dhcp6_lease_unref(client->lease);
669 client->lease = lease;
674 if (pref_advertise == 255 || client->retransmit_count > 1)
675 r = DHCP6_STATE_REQUEST;
680 static int client_receive_message(sd_event_source *s, int fd, uint32_t revents,
682 sd_dhcp6_client *client = userdata;
683 DHCP6_CLIENT_DONT_DESTROY(client);
684 _cleanup_free_ DHCP6Message *message;
689 assert(client->event);
691 r = ioctl(fd, FIONREAD, &buflen);
692 if (r < 0 || buflen <= 0)
693 buflen = DHCP6_MIN_OPTIONS_SIZE;
695 message = malloc0(buflen);
699 len = read(fd, message, buflen);
700 if ((size_t)len < sizeof(DHCP6Message)) {
701 log_dhcp6_client(client, "could not receive message from UDP socket: %m");
705 switch(message->type) {
713 case DHCP6_INFORMATION_REQUEST:
714 case DHCP6_RELAY_FORW:
715 case DHCP6_RELAY_REPL:
718 case DHCP6_ADVERTISE:
720 case DHCP6_RECONFIGURE:
724 log_dhcp6_client(client, "unknown message type %d",
729 if (client->transaction_id != (message->transaction_id &
730 htobe32(0x00ffffff)))
733 switch (client->state) {
734 case DHCP6_STATE_SOLICITATION:
735 r = client_receive_advertise(client, message, len);
737 if (r == DHCP6_STATE_REQUEST)
738 client_start(client, r);
742 case DHCP6_STATE_REQUEST:
743 r = client_receive_reply(client, message, len);
747 if (r == DHCP6_STATE_BOUND) {
749 r = client_start(client, DHCP6_STATE_BOUND);
751 client_stop(client, r);
755 client_notify(client, DHCP6_EVENT_IP_ACQUIRE);
760 case DHCP6_STATE_BOUND:
764 case DHCP6_STATE_STOPPED:
770 log_dhcp6_client(client, "Recv %s",
771 dhcp6_message_type_to_string(message->type));
777 static int client_start(sd_dhcp6_client *client, enum DHCP6State state)
780 usec_t timeout, time_now;
781 char time_string[FORMAT_TIMESPAN_MAX];
783 assert_return(client, -EINVAL);
784 assert_return(client->event, -EINVAL);
785 assert_return(client->index > 0, -EINVAL);
786 assert_return(client->state != state, -EINVAL);
788 client->timeout_resend_expire =
789 sd_event_source_unref(client->timeout_resend_expire);
790 client->timeout_resend = sd_event_source_unref(client->timeout_resend);
791 client->retransmit_time = 0;
792 client->retransmit_count = 0;
795 case DHCP6_STATE_STOPPED:
797 case DHCP6_STATE_SOLICITATION:
799 r = client_ensure_iaid(client);
803 r = dhcp6_network_bind_udp_socket(client->index, NULL);
809 r = sd_event_add_io(client->event, &client->receive_message,
810 client->fd, EPOLLIN, client_receive_message,
815 r = sd_event_source_set_priority(client->receive_message,
816 client->event_priority);
820 client->state = DHCP6_STATE_SOLICITATION;
824 case DHCP6_STATE_REQUEST:
826 client->state = state;
830 case DHCP6_STATE_BOUND:
832 r = sd_event_now(client->event, CLOCK_MONOTONIC, &time_now);
836 if (client->lease->ia.lifetime_t1 == 0xffffffff ||
837 client->lease->ia.lifetime_t2 == 0xffffffff) {
839 log_dhcp6_client(client, "infinite T1 0x%08x or T2 0x%08x",
840 be32toh(client->lease->ia.lifetime_t1),
841 be32toh(client->lease->ia.lifetime_t2));
846 timeout = client_timeout_compute_random(be32toh(client->lease->ia.lifetime_t1) * USEC_PER_SEC);
848 log_dhcp6_client(client, "T1 expires in %s",
849 format_timespan(time_string,
853 r = sd_event_add_time(client->event,
854 &client->lease->ia.timeout_t1,
855 CLOCK_MONOTONIC, time_now + timeout,
856 10 * USEC_PER_SEC, client_timeout_t1,
861 r = sd_event_source_set_priority(client->lease->ia.timeout_t1,
862 client->event_priority);
866 timeout = client_timeout_compute_random(be32toh(client->lease->ia.lifetime_t2) * USEC_PER_SEC);
868 log_dhcp6_client(client, "T2 expires in %s",
869 format_timespan(time_string,
873 r = sd_event_add_time(client->event,
874 &client->lease->ia.timeout_t2,
875 CLOCK_MONOTONIC, time_now + timeout,
876 10 * USEC_PER_SEC, client_timeout_t2,
881 r = sd_event_source_set_priority(client->lease->ia.timeout_t2,
882 client->event_priority);
889 client->transaction_id = random_u32() & htobe32(0x00ffffff);
891 r = sd_event_add_time(client->event, &client->timeout_resend,
892 CLOCK_MONOTONIC, 0, 0, client_timeout_resend,
897 r = sd_event_source_set_priority(client->timeout_resend,
898 client->event_priority);
905 int sd_dhcp6_client_stop(sd_dhcp6_client *client)
907 client_stop(client, DHCP6_EVENT_STOP);
912 int sd_dhcp6_client_start(sd_dhcp6_client *client)
916 assert_return(client, -EINVAL);
917 assert_return(client->event, -EINVAL);
918 assert_return(client->index > 0, -EINVAL);
920 r = client_reset(client);
924 return client_start(client, DHCP6_STATE_SOLICITATION);
927 int sd_dhcp6_client_attach_event(sd_dhcp6_client *client, sd_event *event,
932 assert_return(client, -EINVAL);
933 assert_return(!client->event, -EBUSY);
936 client->event = sd_event_ref(event);
938 r = sd_event_default(&client->event);
943 client->event_priority = priority;
948 int sd_dhcp6_client_detach_event(sd_dhcp6_client *client) {
949 assert_return(client, -EINVAL);
951 client->event = sd_event_unref(client->event);
956 sd_event *sd_dhcp6_client_get_event(sd_dhcp6_client *client) {
960 return client->event;
963 sd_dhcp6_client *sd_dhcp6_client_ref(sd_dhcp6_client *client) {
965 assert_se(REFCNT_INC(client->n_ref) >= 2);
970 sd_dhcp6_client *sd_dhcp6_client_unref(sd_dhcp6_client *client) {
971 if (client && REFCNT_DEC(client->n_ref) <= 0) {
972 client_reset(client);
974 sd_dhcp6_client_detach_event(client);
976 free(client->req_opts);
985 int sd_dhcp6_client_new(sd_dhcp6_client **ret)
987 _cleanup_dhcp6_client_unref_ sd_dhcp6_client *client = NULL;
988 sd_id128_t machine_id;
992 assert_return(ret, -EINVAL);
994 client = new0(sd_dhcp6_client, 1);
998 client->n_ref = REFCNT_INIT;
1000 client->ia_na.type = DHCP6_OPTION_IA_NA;
1006 /* initialize DUID */
1007 client->duid.type = htobe16(DHCP6_DUID_EN);
1008 client->duid.pen = htobe32(SYSTEMD_PEN);
1010 r = sd_id128_get_machine(&machine_id);
1014 /* a bit of snake-oil perhaps, but no need to expose the machine-id
1016 siphash24(client->duid.id, &machine_id, sizeof(machine_id),
1019 client->req_opts_len = ELEMENTSOF(default_req_opts);
1021 client->req_opts = new0(be16_t, client->req_opts_len);
1022 if (!client->req_opts)
1025 for (t = 0; t < client->req_opts_len; t++)
1026 client->req_opts[t] = htobe16(default_req_opts[t]);