Lines Matching defs:client
25 #include "sd-dhcp6-client.h"
108 #define DHCP6_CLIENT_DONT_DESTROY(client) \
109 _cleanup_(sd_dhcp6_client_unrefp) _unused_ sd_dhcp6_client *_dont_destroy_##client = sd_dhcp6_client_ref(client)
111 static int client_start(sd_dhcp6_client *client, enum DHCP6State state);
113 int sd_dhcp6_client_set_callback(sd_dhcp6_client *client, sd_dhcp6_client_cb_t cb, void *userdata) {
114 assert_return(client, -EINVAL);
116 client->cb = cb;
117 client->userdata = userdata;
122 int sd_dhcp6_client_set_index(sd_dhcp6_client *client, int interface_index) {
123 assert_return(client, -EINVAL);
126 assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY);
128 client->index = interface_index;
133 int sd_dhcp6_client_set_local_address(sd_dhcp6_client *client, const struct in6_addr *local_address) {
134 assert_return(client, -EINVAL);
138 assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY);
140 client->local_address = *local_address;
146 sd_dhcp6_client *client,
150 assert_return(client, -EINVAL);
155 assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY);
164 if (client->mac_addr_len == addr_len &&
165 memcmp(&client->mac_addr, addr, addr_len) == 0)
168 memcpy(&client->mac_addr, addr, addr_len);
169 client->mac_addr_len = addr_len;
170 client->arp_type = arp_type;
175 static int client_ensure_duid(sd_dhcp6_client *client) {
176 if (client->duid_len != 0)
179 return dhcp_identifier_set_duid_en(&client->duid, &client->duid_len);
183 sd_dhcp6_client *client,
186 assert_return(client, -EINVAL);
190 assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY);
194 if (duid_len <= sizeof(client->duid.llt))
198 if (duid_len != sizeof(client->duid.en))
202 if (duid_len <= sizeof(client->duid.ll))
206 if (duid_len != sizeof(client->duid.uuid))
214 client->duid.type = htobe16(type);
215 memcpy(&client->duid.raw.data, duid, duid_len);
216 client->duid_len = duid_len + sizeof(client->duid.type);
221 int sd_dhcp6_client_set_information_request(sd_dhcp6_client *client, int enabled) {
222 assert_return(client, -EINVAL);
223 assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY);
225 client->information_request = enabled;
230 int sd_dhcp6_client_get_information_request(sd_dhcp6_client *client, int *enabled) {
231 assert_return(client, -EINVAL);
234 *enabled = client->information_request;
239 int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client, uint16_t option) {
242 assert_return(client, -EINVAL);
243 assert_return(client->state == DHCP6_STATE_STOPPED, -EBUSY);
256 for (t = 0; t < client->req_opts_len; t++)
257 if (client->req_opts[t] == htobe16(option))
260 if (!GREEDY_REALLOC(client->req_opts, client->req_opts_allocated,
261 client->req_opts_len + 1))
264 client->req_opts[client->req_opts_len++] = htobe16(option);
269 int sd_dhcp6_client_get_lease(sd_dhcp6_client *client, sd_dhcp6_lease **ret) {
270 assert_return(client, -EINVAL);
272 if (!client->lease)
276 *ret = client->lease;
281 static void client_notify(sd_dhcp6_client *client, int event) {
282 if (client->cb)
283 client->cb(client, event, client->userdata);
286 static void client_set_lease(sd_dhcp6_client *client, sd_dhcp6_lease *lease) {
287 if (client->lease) {
288 dhcp6_lease_clear_timers(&client->lease->ia);
289 sd_dhcp6_lease_unref(client->lease);
291 client->lease = lease;
294 static int client_reset(sd_dhcp6_client *client) {
295 assert_return(client, -EINVAL);
297 client_set_lease(client, NULL);
299 client->receive_message =
300 sd_event_source_unref(client->receive_message);
302 client->fd = safe_close(client->fd);
304 client->transaction_id = 0;
305 client->transaction_start = 0;
307 client->ia_na.timeout_t1 =
308 sd_event_source_unref(client->ia_na.timeout_t1);
309 client->ia_na.timeout_t2 =
310 sd_event_source_unref(client->ia_na.timeout_t2);
312 client->retransmit_time = 0;
313 client->retransmit_count = 0;
314 client->timeout_resend = sd_event_source_unref(client->timeout_resend);
315 client->timeout_resend_expire =
316 sd_event_source_unref(client->timeout_resend_expire);
318 client->state = DHCP6_STATE_STOPPED;
323 static void client_stop(sd_dhcp6_client *client, int error) {
324 DHCP6_CLIENT_DONT_DESTROY(client);
326 assert(client);
328 client_notify(client, error);
330 client_reset(client);
333 static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
351 message->transaction_id = client->transaction_id;
353 switch(client->state) {
367 r = dhcp6_option_append_ia(&opt, &optlen, &client->ia_na);
376 if (client->state == DHCP6_STATE_REQUEST)
382 client->lease->serverid_len,
383 client->lease->serverid);
387 r = dhcp6_option_append_ia(&opt, &optlen, &client->lease->ia);
396 r = dhcp6_option_append_ia(&opt, &optlen, &client->lease->ia);
408 client->req_opts_len * sizeof(be16_t),
409 client->req_opts);
413 assert (client->duid_len);
415 client->duid_len, &client->duid);
419 elapsed_usec = time_now - client->transaction_start;
430 r = dhcp6_network_send_udp_socket(client->fd, &all_servers, message,
435 log_dhcp6_client(client, "Sent %s",
443 sd_dhcp6_client *client = userdata;
446 assert_return(client, -EINVAL);
447 assert_return(client->lease, -EINVAL);
449 client->lease->ia.timeout_t2 =
450 sd_event_source_unref(client->lease->ia.timeout_t2);
452 log_dhcp6_client(client, "Timeout T2");
454 client_start(client, DHCP6_STATE_REBIND);
461 sd_dhcp6_client *client = userdata;
464 assert_return(client, -EINVAL);
465 assert_return(client->lease, -EINVAL);
467 client->lease->ia.timeout_t1 =
468 sd_event_source_unref(client->lease->ia.timeout_t1);
470 log_dhcp6_client(client, "Timeout T1");
472 client_start(client, DHCP6_STATE_RENEW);
479 sd_dhcp6_client *client = userdata;
480 DHCP6_CLIENT_DONT_DESTROY(client);
484 assert(client);
485 assert(client->event);
487 state = client->state;
489 client_stop(client, SD_DHCP6_CLIENT_EVENT_RESEND_EXPIRE);
491 /* RFC 3315, section 18.1.4., says that "...the client may choose to
494 client_start(client, DHCP6_STATE_SOLICITATION);
507 sd_dhcp6_client *client = userdata;
515 assert(client);
516 assert(client->event);
518 client->timeout_resend = sd_event_source_unref(client->timeout_resend);
520 switch (client->state) {
529 if (client->retransmit_count && client->lease) {
530 client_start(client, DHCP6_STATE_REQUEST);
560 if (!client->timeout_resend_expire) {
561 r = dhcp6_lease_ia_rebind_expire(&client->lease->ia,
564 client_stop(client, r);
578 client->retransmit_count >= max_retransmit_count) {
579 client_stop(client, SD_DHCP6_CLIENT_EVENT_RETRANS_MAX);
583 r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
587 r = client_send_message(client, time_now);
589 client->retransmit_count++;
591 if (!client->retransmit_time) {
592 client->retransmit_time =
595 if (client->state == DHCP6_STATE_SOLICITATION)
596 client->retransmit_time += init_retransmit_time / 10;
600 client->retransmit_time > max_retransmit_time / 2)
601 client->retransmit_time = client_timeout_compute_random(max_retransmit_time);
603 client->retransmit_time += client_timeout_compute_random(client->retransmit_time);
606 log_dhcp6_client(client, "Next retransmission in %s",
607 format_timespan(time_string, FORMAT_TIMESPAN_MAX, client->retransmit_time, USEC_PER_SEC));
609 r = sd_event_add_time(client->event, &client->timeout_resend,
611 time_now + client->retransmit_time,
613 client);
617 r = sd_event_source_set_priority(client->timeout_resend,
618 client->event_priority);
622 r = sd_event_source_set_description(client->timeout_resend, "dhcp6-resend-timer");
626 if (max_retransmit_duration && !client->timeout_resend_expire) {
628 log_dhcp6_client(client, "Max retransmission duration %"PRIu64" secs",
631 r = sd_event_add_time(client->event,
632 &client->timeout_resend_expire,
636 client_timeout_resend_expire, client);
640 r = sd_event_source_set_priority(client->timeout_resend_expire,
641 client->event_priority);
645 r = sd_event_source_set_description(client->timeout_resend_expire, "dhcp6-resend-expire-timer");
652 client_stop(client, r);
657 static int client_ensure_iaid(sd_dhcp6_client *client) {
660 assert(client);
662 if (client->ia_na.id)
665 r = dhcp_identifier_set_iaid(client->index, client->mac_addr, client->mac_addr_len, &client->ia_na.id);
672 static int client_parse_message(sd_dhcp6_client *client,
690 log_dhcp6_client(client, "%s contains multiple clientids",
695 if (optlen != client->duid_len ||
696 memcmp(&client->duid, optval, optlen) != 0) {
697 log_dhcp6_client(client, "%s DUID does not match",
709 log_dhcp6_client(client, "%s contains multiple serverids",
736 log_dhcp6_client(client, "%s Status %s",
745 if (client->state == DHCP6_STATE_INFORMATION_REQUEST) {
746 log_dhcp6_client(client, "Information request ignoring IA NA option");
760 if (client->ia_na.id != iaid_lease) {
761 log_dhcp6_client(client, "%s has wrong IAID",
810 log_dhcp6_client(client, "%s has incomplete options",
815 if (client->state != DHCP6_STATE_INFORMATION_REQUEST) {
818 log_dhcp6_client(client, "%s has no server id",
825 static int client_receive_reply(sd_dhcp6_client *client, DHCP6Message *reply, size_t len) {
837 r = client_parse_message(client, reply, len, lease);
841 if (client->state == DHCP6_STATE_SOLICITATION) {
850 client_set_lease(client, lease);
856 static int client_receive_advertise(sd_dhcp6_client *client, DHCP6Message *advertise, size_t len) {
868 r = client_parse_message(client, advertise, len, lease);
876 r = dhcp6_lease_get_preference(client->lease, &pref_lease);
879 client_set_lease(client, lease);
884 if (pref_advertise == 255 || client->retransmit_count > 1)
891 sd_dhcp6_client *client = userdata;
892 DHCP6_CLIENT_DONT_DESTROY(client);
897 assert(client);
898 assert(client->event);
916 log_dhcp6_client(client, "Could not receive message from UDP socket: %m");
941 log_dhcp6_client(client, "unknown message type %d",
946 if (client->transaction_id != (message->transaction_id &
950 switch (client->state) {
952 r = client_receive_reply(client, message, len);
956 client_notify(client, SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST);
958 client_start(client, DHCP6_STATE_STOPPED);
963 r = client_receive_advertise(client, message, len);
966 client_start(client, r);
976 r = client_receive_reply(client, message, len);
982 r = client_start(client, DHCP6_STATE_BOUND);
984 client_stop(client, r);
988 client_notify(client, SD_DHCP6_CLIENT_EVENT_IP_ACQUIRE);
1002 log_dhcp6_client(client, "Recv %s",
1009 static int client_start(sd_dhcp6_client *client, enum DHCP6State state) {
1014 assert_return(client, -EINVAL);
1015 assert_return(client->event, -EINVAL);
1016 assert_return(client->index > 0, -EINVAL);
1017 assert_return(client->state != state, -EINVAL);
1019 client->timeout_resend_expire =
1020 sd_event_source_unref(client->timeout_resend_expire);
1021 client->timeout_resend = sd_event_source_unref(client->timeout_resend);
1022 client->retransmit_time = 0;
1023 client->retransmit_count = 0;
1025 r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
1031 if (client->state == DHCP6_STATE_INFORMATION_REQUEST) {
1032 client->state = DHCP6_STATE_STOPPED;
1039 client->state = DHCP6_STATE_SOLICITATION;
1048 client->state = state;
1054 if (client->lease->ia.lifetime_t1 == 0xffffffff ||
1055 client->lease->ia.lifetime_t2 == 0xffffffff) {
1057 log_dhcp6_client(client, "infinite T1 0x%08x or T2 0x%08x",
1058 be32toh(client->lease->ia.lifetime_t1),
1059 be32toh(client->lease->ia.lifetime_t2));
1064 timeout = client_timeout_compute_random(be32toh(client->lease->ia.lifetime_t1) * USEC_PER_SEC);
1066 log_dhcp6_client(client, "T1 expires in %s",
1069 r = sd_event_add_time(client->event,
1070 &client->lease->ia.timeout_t1,
1073 client);
1077 r = sd_event_source_set_priority(client->lease->ia.timeout_t1,
1078 client->event_priority);
1082 r = sd_event_source_set_description(client->lease->ia.timeout_t1, "dhcp6-t1-timeout");
1086 timeout = client_timeout_compute_random(be32toh(client->lease->ia.lifetime_t2) * USEC_PER_SEC);
1088 log_dhcp6_client(client, "T2 expires in %s",
1091 r = sd_event_add_time(client->event,
1092 &client->lease->ia.timeout_t2,
1095 client);
1099 r = sd_event_source_set_priority(client->lease->ia.timeout_t2,
1100 client->event_priority);
1104 r = sd_event_source_set_description(client->lease->ia.timeout_t2, "dhcp6-t2-timeout");
1108 client->state = state;
1113 client->transaction_id = random_u32() & htobe32(0x00ffffff);
1114 client->transaction_start = time_now;
1116 r = sd_event_add_time(client->event, &client->timeout_resend,
1118 client);
1122 r = sd_event_source_set_priority(client->timeout_resend,
1123 client->event_priority);
1127 r = sd_event_source_set_description(client->timeout_resend, "dhcp6-resend-timeout");
1134 int sd_dhcp6_client_stop(sd_dhcp6_client *client) {
1135 assert_return(client, -EINVAL);
1137 client_stop(client, SD_DHCP6_CLIENT_EVENT_STOP);
1142 int sd_dhcp6_client_is_running(sd_dhcp6_client *client) {
1143 assert_return(client, -EINVAL);
1145 return client->state != DHCP6_STATE_STOPPED;
1148 int sd_dhcp6_client_start(sd_dhcp6_client *client) {
1152 assert_return(client, -EINVAL);
1153 assert_return(client->event, -EINVAL);
1154 assert_return(client->index > 0, -EINVAL);
1155 assert_return(in_addr_is_link_local(AF_INET6, (const union in_addr_union *) &client->local_address) > 0, -EINVAL);
1157 if (!IN_SET(client->state, DHCP6_STATE_STOPPED))
1160 r = client_reset(client);
1164 r = client_ensure_iaid(client);
1168 r = client_ensure_duid(client);
1172 r = dhcp6_network_bind_udp_socket(client->index, &client->local_address);
1176 client->fd = r;
1178 r = sd_event_add_io(client->event, &client->receive_message,
1179 client->fd, EPOLLIN, client_receive_message,
1180 client);
1184 r = sd_event_source_set_priority(client->receive_message,
1185 client->event_priority);
1189 r = sd_event_source_set_description(client->receive_message,
1194 if (client->information_request)
1197 log_dhcp6_client(client, "Started in %s mode",
1198 client->information_request? "Information request":
1201 return client_start(client, state);
1204 client_reset(client);
1208 int sd_dhcp6_client_attach_event(sd_dhcp6_client *client, sd_event *event, int priority) {
1211 assert_return(client, -EINVAL);
1212 assert_return(!client->event, -EBUSY);
1215 client->event = sd_event_ref(event);
1217 r = sd_event_default(&client->event);
1222 client->event_priority = priority;
1227 int sd_dhcp6_client_detach_event(sd_dhcp6_client *client) {
1228 assert_return(client, -EINVAL);
1230 client->event = sd_event_unref(client->event);
1235 sd_event *sd_dhcp6_client_get_event(sd_dhcp6_client *client) {
1236 if (!client)
1239 return client->event;
1242 sd_dhcp6_client *sd_dhcp6_client_ref(sd_dhcp6_client *client) {
1244 if (!client)
1247 assert(client->n_ref >= 1);
1248 client->n_ref++;
1250 return client;
1253 sd_dhcp6_client *sd_dhcp6_client_unref(sd_dhcp6_client *client) {
1255 if (!client)
1258 assert(client->n_ref >= 1);
1259 client->n_ref--;
1261 if (client->n_ref > 0)
1264 client_reset(client);
1266 sd_dhcp6_client_detach_event(client);
1268 free(client->req_opts);
1269 free(client);
1275 _cleanup_(sd_dhcp6_client_unrefp) sd_dhcp6_client *client = NULL;
1280 client = new0(sd_dhcp6_client, 1);
1281 if (!client)
1284 client->n_ref = 1;
1286 client->ia_na.type = SD_DHCP6_OPTION_IA_NA;
1288 client->index = -1;
1290 client->fd = -1;
1292 client->req_opts_len = ELEMENTSOF(default_req_opts);
1294 client->req_opts = new0(be16_t, client->req_opts_len);
1295 if (!client->req_opts)
1298 for (t = 0; t < client->req_opts_len; t++)
1299 client->req_opts[t] = htobe16(default_req_opts[t]);
1301 *ret = client;
1302 client = NULL;