• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/odhcp6c/src/dhcpv6.c

  1 /**
  2  * Copyright (C) 2012-2014 Steven Barth <steven@midlink.org>
  3  * Copyright (C) 2017-2018 Hans Dedecker <dedeckeh@gmail.com>
  4  *
  5  * This program is free software; you can redistribute it and/or modify
  6  * it under the terms of the GNU General Public License v2 as published by
  7  * the Free Software Foundation.
  8  *
  9  * This program is distributed in the hope that it will be useful,
 10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 12  * GNU General Public License for more details.
 13  *
 14  */
 15 
 16 #include <arpa/inet.h>
 17 #include <ctype.h>
 18 #include <errno.h>
 19 #include <fcntl.h>
 20 #include <inttypes.h>
 21 #include <libubox/md5.h>
 22 #include <limits.h>
 23 #include <netinet/in.h>
 24 #include <net/if.h>
 25 #include <net/ethernet.h>
 26 #include <resolv.h>
 27 #include <signal.h>
 28 #include <stdbool.h>
 29 #include <stdlib.h>
 30 #include <string.h>
 31 #include <sys/ioctl.h>
 32 #include <sys/socket.h>
 33 #include <sys/time.h>
 34 #include <time.h>
 35 #include <unistd.h>
 36 
 37 #include "config.h"
 38 #include "odhcp6c.h"
 39 
 40 #define ALL_DHCPV6_RELAYS {{{0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
 41                 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02}}}
 42 #define DHCPV6_CLIENT_PORT 546
 43 #define DHCPV6_SERVER_PORT 547
 44 #define DHCPV6_DUID_LLADDR 3
 45 
 46 #define DHCPV6_SOL_MAX_RT_MIN 60
 47 #define DHCPV6_SOL_MAX_RT_MAX 86400
 48 #define DHCPV6_INF_MAX_RT_MIN 60
 49 #define DHCPV6_INF_MAX_RT_MAX 86400
 50 
 51 static bool dhcpv6_response_is_valid(const void *buf, ssize_t len,
 52                 const uint8_t transaction[3], enum dhcpv6_msg req_msg_type,
 53                 const struct in6_addr *daddr);
 54 
 55 static unsigned int dhcpv6_parse_ia(void *opt, void *end, int *ret);
 56 
 57 static unsigned int dhcpv6_calc_refresh_timers(void);
 58 static void dhcpv6_handle_status_code(_o_unused const enum dhcpv6_msg orig,
 59                 const uint16_t code, const void *status_msg, const int len,
 60                 int *ret);
 61 static void dhcpv6_handle_ia_status_code(const enum dhcpv6_msg orig,
 62                 const struct dhcpv6_ia_hdr *ia_hdr, const uint16_t code,
 63                 const void *status_msg, const int len,
 64                 bool handled_status_codes[_DHCPV6_Status_Max],
 65                 int *ret);
 66 static void dhcpv6_add_server_cand(const struct dhcpv6_server_cand *cand);
 67 static void dhcpv6_clear_all_server_cand(void);
 68 
 69 static void dhcpv6_log_status_code(const uint16_t code, const char *scope,
 70                 const void *status_msg, int len);
 71 
 72 static reply_handler dhcpv6_handle_reply;
 73 static reply_handler dhcpv6_handle_advert;
 74 static reply_handler dhcpv6_handle_rebind_reply;
 75 static reply_handler dhcpv6_handle_reconfigure;
 76 static int dhcpv6_commit_advert(void);
 77 
 78 // RFC 3315 - 5.5 Timeout and Delay values
 79 static const struct dhcpv6_retx dhcpv6_retx_default[_DHCPV6_MSG_MAX] = {
 80         [DHCPV6_MSG_UNKNOWN] = {
 81                 0,
 82                 1,
 83                 120,
 84                 0,
 85                 "<POLL>",
 86                 dhcpv6_handle_reconfigure,
 87                 NULL,
 88                 false,
 89                 0,
 90                 0,
 91                 0,
 92                 {0, 0, 0},
 93                 0,
 94                 0,
 95                 0,
 96                 -1,
 97                 0
 98         },
 99         [DHCPV6_MSG_SOLICIT] = {
100                 DHCPV6_MAX_DELAY,
101                 DHCPV6_SOL_INIT_RT,
102                 DHCPV6_SOL_MAX_RT,
103                 0,
104                 "SOLICIT",
105                 dhcpv6_handle_advert,
106                 dhcpv6_commit_advert,
107                 false,
108                 0,
109                 0,
110                 0,
111                 {0, 0, 0},
112                 0,
113                 0,
114                 0,
115                 -1,
116                 0
117         },
118         [DHCPV6_MSG_REQUEST] = {
119                 0,
120                 DHCPV6_REQ_INIT_RT,
121                 DHCPV6_REQ_MAX_RT,
122                 DHCPV6_REQ_MAX_RC,
123                 "REQUEST",
124                 dhcpv6_handle_reply,
125                 NULL,
126                 false,
127                 0,
128                 0,
129                 0,
130                 {0, 0, 0},
131                 0,
132                 0,
133                 0,
134                 -1,
135                 0
136         },
137         [DHCPV6_MSG_RENEW] = {
138                 0,
139                 DHCPV6_REN_INIT_RT,
140                 DHCPV6_REN_MAX_RT,
141                 0,
142                 "RENEW",
143                 dhcpv6_handle_reply,
144                 NULL,
145                 false,
146                 0,
147                 0,
148                 0,
149                 {0, 0, 0},
150                 0,
151                 0,
152                 0,
153                 -1,
154                 0
155         },
156         [DHCPV6_MSG_REBIND] = {
157                 0,
158                 DHCPV6_REB_INIT_RT,
159                 DHCPV6_REB_MAX_RT,
160                 0,
161                 "REBIND",
162                         dhcpv6_handle_rebind_reply,
163                 NULL,
164                 false,
165                 0,
166                 0,
167                 0,
168                 {0, 0, 0},
169                 0,
170                 0,
171                 0,
172                 -1,
173                 0
174         },
175         [DHCPV6_MSG_RELEASE] = {
176                 0,
177                 DHCPV6_REL_INIT_RT,
178                 0,
179                 DHCPV6_REL_MAX_RC,
180                 "RELEASE",
181                 NULL,
182                 NULL,
183                 false,
184                 0,
185                 0,
186                 0,
187                 {0, 0, 0},
188                 0,
189                 0,
190                 0,
191                 -1,
192                 0
193         },
194         [DHCPV6_MSG_DECLINE] = {
195                 0,
196                 DHCPV6_DEC_INIT_RT,
197                 0,
198                 DHCPV6_DEC_MAX_RC,
199                 "DECLINE",
200                 NULL,
201                 NULL,
202                 false,
203                 0,
204                 0,
205                 0,
206                 {0, 0, 0},
207                 0,
208                 0,
209                 0,
210                 -1,
211                 0
212         },
213         [DHCPV6_MSG_INFO_REQ] = {
214                 DHCPV6_MAX_DELAY,
215                 DHCPV6_INF_INIT_RT,
216                 DHCPV6_INF_MAX_RT,
217                 0,
218                 "INFOREQ",
219                 dhcpv6_handle_reply,
220                 NULL,
221                 false,
222                 0,
223                 0,
224                 0,
225                 {0, 0, 0},
226                 0,
227                 0,
228                 0,
229                 -1,
230                 0
231         },
232 };
233 static struct dhcpv6_retx dhcpv6_retx[_DHCPV6_MSG_MAX] = {0};
234 
235 // Sockets
236 static int sock = -1;
237 static int ifindex = -1;
238 static int64_t t1 = 0, t2 = 0, t3 = 0;
239 
240 // IA states
241 static enum odhcp6c_ia_mode na_mode = IA_MODE_NONE, pd_mode = IA_MODE_NONE;
242 static bool stateful_only_mode = false;
243 static bool accept_reconfig = false;
244 // Server unicast address
245 static struct in6_addr server_addr = IN6ADDR_ANY_INIT;
246 
247 // Initial state of the DHCPv6 service
248 static enum dhcpv6_state dhcpv6_state = DHCPV6_INIT;
249 static int dhcpv6_state_timeout = 0;
250 
251 // Authentication options
252 static enum odhcp6c_auth_protocol auth_protocol = AUTH_PROT_RKAP;
253 static uint8_t reconf_key[16];
254 
255 // client options
256 static unsigned int client_options = 0;
257 
258 // counters for statistics
259 static struct dhcpv6_stats dhcpv6_stats = {0};
260 
261 // config
262 static struct config_dhcp* config_dhcp = NULL;
263 
264 // store unique ifname hash to use as IA->IAID
265 static uint32_t ifname_hash_iaid = 0;
266 
267 static uint32_t ntohl_unaligned(const uint8_t *data)
268 {
269         uint32_t buf;
270 
271         memcpy(&buf, data, sizeof(buf));
272         return ntohl(buf);
273 }
274 
275 static void dhcpv6_next_state(void)
276 {
277         dhcpv6_state++;
278         dhcpv6_reset_state_timeout();
279 }
280 
281 static void dhcpv6_prev_state(void)
282 {
283         dhcpv6_state--;
284         dhcpv6_reset_state_timeout();
285 }
286 
287 static void dhcpv6_inc_counter(enum dhcpv6_msg type)
288 {
289         switch (type) {
290         case DHCPV6_MSG_SOLICIT:
291                 dhcpv6_stats.solicit++;
292                 break;
293 
294         case DHCPV6_MSG_ADVERT:
295                 dhcpv6_stats.advertise++;
296                 break;
297 
298         case DHCPV6_MSG_REQUEST:
299                 dhcpv6_stats.request++;
300                 break;
301 
302         case DHCPV6_MSG_RENEW:
303                 dhcpv6_stats.renew++;
304                 break;
305 
306         case DHCPV6_MSG_REBIND:
307                 dhcpv6_stats.rebind++;
308                 break;
309 
310         case DHCPV6_MSG_REPLY:
311                 dhcpv6_stats.reply++;
312                 break;
313 
314         case DHCPV6_MSG_RELEASE:
315                 dhcpv6_stats.release++;
316                 break;
317 
318         case DHCPV6_MSG_DECLINE:
319                 dhcpv6_stats.decline++;
320                 break;
321 
322         case DHCPV6_MSG_RECONF:
323                 dhcpv6_stats.reconfigure++;
324                 break;
325 
326         case DHCPV6_MSG_INFO_REQ:
327                 dhcpv6_stats.information_request++;
328                 break;
329 
330         default:
331                 break;
332         }
333 }
334 
335 static char *dhcpv6_msg_to_str(enum dhcpv6_msg msg)
336 {
337         switch (msg) {
338         case DHCPV6_MSG_SOLICIT:
339                 return "SOLICIT";
340 
341         case DHCPV6_MSG_ADVERT:
342                 return "ADVERTISE";
343 
344         case DHCPV6_MSG_REQUEST:
345                 return "REQUEST";
346 
347         case DHCPV6_MSG_RENEW:
348                 return "RENEW";
349 
350         case DHCPV6_MSG_REBIND:
351                 return "REBIND";
352 
353         case DHCPV6_MSG_REPLY:
354                 return "REPLY";
355 
356         case DHCPV6_MSG_RELEASE:
357                 return "RELEASE";
358 
359         case DHCPV6_MSG_DECLINE:
360                 return "DECLINE";
361 
362         case DHCPV6_MSG_RECONF:
363                 return "RECONFIGURE";
364 
365         case DHCPV6_MSG_INFO_REQ:
366                 return "INFORMATION REQUEST";
367 
368         default:
369                 break;
370         }
371 
372         return "UNKNOWN";
373 }
374 
375 static char *dhcpv6_status_code_to_str(uint16_t code)
376 {
377         switch (code) {
378         case DHCPV6_Success:
379                 return "Success";
380 
381         case DHCPV6_UnspecFail:
382                 return "Unspecified Failure";
383 
384         case DHCPV6_NoAddrsAvail:
385                 return "No Address Available";
386 
387         case DHCPV6_NoBinding:
388                 return "No Binding";
389 
390         case DHCPV6_NotOnLink:
391                 return "Not On Link";
392 
393         case DHCPV6_UseMulticast:
394                 return "Use Multicast";
395 
396         case DHCPV6_NoPrefixAvail:
397                 return "No Prefix Available";
398 
399         default:
400                 break;
401         }
402 
403         return "Unknown";
404 }
405 
406 const char *dhcpv6_state_to_str(enum dhcpv6_state state)
407 {
408         switch (state) {
409         case DHCPV6_INIT:
410                 return "INIT";
411 
412         case DHCPV6_SOLICIT:
413                 return "SOLICIT";
414 
415         case DHCPV6_SOLICIT_PROCESSING:
416                 return "SOLICIT_PROCESSING";
417 
418         case DHCPV6_ADVERT:
419                 return "ADVERT";
420 
421         case DHCPV6_REQUEST:
422                 return "REQUEST";
423 
424         case DHCPV6_REQUEST_PROCESSING:
425                 return "REQUEST_PROCESSING";
426 
427         case DHCPV6_REPLY:
428                 return "REPLY";
429 
430         case DHCPV6_BOUND:
431                 return "BOUND";
432 
433         case DHCPV6_BOUND_PROCESSING:
434                 return "BOUND_PROCESSING";
435 
436         case DHCPV6_BOUND_REPLY:
437                 return "BOUND_REPLY";
438 
439         case DHCPV6_RECONF:
440                 return "RECONF";
441 
442         case DHCPV6_RECONF_PROCESSING:
443                 return "RECONF_PROCESSING";
444 
445         case DHCPV6_RECONF_REPLY:
446                 return "RECONF_REPLY";
447 
448         case DHCPV6_RENEW:
449                 return "RENEW";
450 
451         case DHCPV6_RENEW_PROCESSING:
452                 return "RENEW_PROCESSING";
453 
454         case DHCPV6_RENEW_REPLY:
455                 return "RENEW_REPLY";
456 
457         case DHCPV6_REBIND:
458                 return "REBIND";
459 
460         case DHCPV6_REBIND_PROCESSING:
461                 return "REBIND_PROCESSING";
462 
463         case DHCPV6_REBIND_REPLY:
464                 return "REBIND_REPLY";
465 
466         case DHCPV6_INFO:
467                 return "INFO";
468 
469         case DHCPV6_INFO_PROCESSING:
470                 return "INFO_PROCESSING";
471 
472         case DHCPV6_INFO_REPLY:
473                 return "INFO_REPLY";
474 
475         case DHCPV6_EXIT:
476                 return "EXIT";
477 
478         default:
479                 return "INVALID_STATE";
480         }
481 }
482 
483 static int fd_set_nonblocking(int sockfd)
484 {
485         int flags = fcntl(sockfd, F_GETFL, 0);
486         if (flags == -1) {
487                 error(
488                         "Failed to get the dhcpv6 socket flags: fcntl F_GETFL failed (%s)",
489                         strerror(errno));
490                 return -1;
491         }
492 
493         // Set the socket to non-blocking
494         if (fcntl(sockfd, F_SETFL, flags | O_NONBLOCK) == -1) {
495                 error(
496                         "Failed to set the dhcpv6 socket to non-blocking: fcntl F_SETFL failed (%s)",
497                         strerror(errno));
498                 return -1;
499         }
500 
501         return 0;
502 }
503 
504 int dhcpv6_get_socket(void)
505 {
506         return sock;
507 }
508 
509 enum dhcpv6_state dhcpv6_get_state(void)
510 {
511         return dhcpv6_state;
512 }
513 
514 void dhcpv6_set_state(enum dhcpv6_state state)
515 {
516         dhcpv6_state = state;
517         dhcpv6_reset_state_timeout();
518 }
519 
520 int dhcpv6_get_state_timeout(void)
521 {
522         return dhcpv6_state_timeout;
523 }
524 
525 void dhcpv6_set_state_timeout(int timeout)
526 {
527         if (timeout > 0 && (dhcpv6_state_timeout == 0 || timeout < dhcpv6_state_timeout)) {
528                 dhcpv6_state_timeout = timeout;
529         }
530 }
531 
532 void dhcpv6_reset_state_timeout(void)
533 {
534         dhcpv6_state_timeout = 0;
535 }
536 
537 struct dhcpv6_stats dhcpv6_get_stats(void)
538 {
539         return dhcpv6_stats;
540 }
541 
542 void dhcpv6_reset_stats(void)
543 {
544         memset(&dhcpv6_stats, 0, sizeof(dhcpv6_stats));
545 }
546 
547 uint32_t hash_ifname(const char *s) {
548         uint32_t h = 0;
549         while (*s) h = h * 31 + *s++;
550         return h;
551 }
552 
553 int init_dhcpv6(const char *ifname)
554 {
555         config_dhcp = config_dhcp_get();
556 
557         memcpy(dhcpv6_retx, dhcpv6_retx_default, sizeof(dhcpv6_retx));
558         config_apply_dhcp_rtx(dhcpv6_retx);
559 
560         client_options = config_dhcp->client_options;
561         na_mode = config_dhcp->ia_na_mode;
562         pd_mode = config_dhcp->ia_pd_mode;
563         stateful_only_mode = config_dhcp->stateful_only_mode;
564         auth_protocol = config_dhcp->auth_protocol;
565 
566         sock = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP);
567         if (sock < 0)
568                 goto failure;
569 
570         // Detect interface
571         struct ifreq ifr;
572         memset(&ifr, 0, sizeof(ifr));
573         strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name) - 1);
574         if (ioctl(sock, SIOCGIFINDEX, &ifr) < 0)
575                 goto failure;
576 
577         ifname_hash_iaid = hash_ifname(ifname);
578 
579         ifindex = ifr.ifr_ifindex;
580 
581         // Set the socket to non-blocking mode
582         if (fd_set_nonblocking(sock) < 0)
583                 goto failure;
584 
585         // Build our FQDN
586         size_t fqdn_len;
587         odhcp6c_get_state(STATE_OUR_FQDN, &fqdn_len);
588         if(fqdn_len == 0) {
589                 char fqdn_buf[256];
590                 gethostname(fqdn_buf, sizeof(fqdn_buf));
591                 struct {
592                         uint16_t type;
593                         uint16_t len;
594                         uint8_t flags;
595                         uint8_t data[256];
596                 } fqdn = {0};
597                 int dn_result = dn_comp(fqdn_buf, fqdn.data,
598                                 sizeof(fqdn.data), NULL, NULL);
599                 fqdn_len = 0;
600                 if (dn_result > 0) {
601                         fqdn.type = htons(DHCPV6_OPT_FQDN);
602                         fqdn.len = htons(1 + dn_result);
603                         fqdn.flags = 0;
604                         fqdn_len = DHCPV6_OPT_HDR_SIZE + 1 + dn_result;
605                 }
606                 odhcp6c_add_state(STATE_OUR_FQDN, &fqdn, fqdn_len);
607         }
608 
609         // Create client DUID
610         size_t client_id_len;
611         odhcp6c_get_state(STATE_CLIENT_ID, &client_id_len);
612         if (client_id_len == 0) {
613                 uint8_t duid[14] = {0, DHCPV6_OPT_CLIENTID, 0, 10, 0,
614                                 DHCPV6_DUID_LLADDR, 0, 1};
615 
616                 if (ioctl(sock, SIOCGIFHWADDR, &ifr) >= 0)
617                         memcpy(&duid[8], ifr.ifr_hwaddr.sa_data, ETHER_ADDR_LEN);
618 
619                 uint8_t zero[ETHER_ADDR_LEN] = {0, 0, 0, 0, 0, 0};
620                 struct ifreq ifs[100], *ifp, *ifend;
621                 struct ifconf ifc;
622                 ifc.ifc_req = ifs;
623                 ifc.ifc_len = sizeof(ifs);
624 
625                 if (!memcmp(&duid[8], zero, ETHER_ADDR_LEN) &&
626                                 ioctl(sock, SIOCGIFCONF, &ifc) >= 0) {
627                         // If our interface doesn't have an address...
628                         ifend = ifs + (ifc.ifc_len / sizeof(struct ifreq));
629                         for (ifp = ifc.ifc_req; ifp < ifend &&
630                                         !memcmp(&duid[8], zero, ETHER_ADDR_LEN); ifp++) {
631                                 memcpy(ifr.ifr_name, ifp->ifr_name,
632                                                 sizeof(ifr.ifr_name));
633                                 if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0)
634                                         continue;
635 
636                                 memcpy(&duid[8], ifr.ifr_hwaddr.sa_data,
637                                                 ETHER_ADDR_LEN);
638                         }
639                 }
640 
641                 odhcp6c_add_state(STATE_CLIENT_ID, duid, sizeof(duid));
642         }
643 
644         // Create ORO
645         if (!(client_options & DHCPV6_STRICT_OPTIONS)) {
646                 uint16_t oro[] = {
647                         htons(DHCPV6_OPT_SIP_SERVER_D),
648                         htons(DHCPV6_OPT_SIP_SERVER_A),
649                         htons(DHCPV6_OPT_DNS_SERVERS),
650                         htons(DHCPV6_OPT_DNS_DOMAIN),
651                         htons(DHCPV6_OPT_SNTP_SERVERS),
652                         htons(DHCPV6_OPT_NTP_SERVER),
653                         htons(DHCPV6_OPT_PD_EXCLUDE),
654                         /* RFC8910: Clients that support this option SHOULD include it */
655                         htons(DHCPV6_OPT_CAPTIVE_PORTAL),
656                 };
657                 odhcp6c_add_state(STATE_ORO, oro, sizeof(oro));
658         }
659         // Required ORO
660         uint16_t req_oro[] = {
661                 htons(DHCPV6_OPT_INF_MAX_RT),
662                 htons(DHCPV6_OPT_SOL_MAX_RT),
663                 htons(DHCPV6_OPT_INFO_REFRESH),
664         };
665         odhcp6c_add_state(STATE_ORO, req_oro, sizeof(req_oro));
666 
667         // Configure IPv6-options
668         int val = 1;
669         if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val)) < 0)
670                 goto failure;
671 
672         if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0)
673                 goto failure;
674 
675         if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &val, sizeof(val)) < 0)
676                 goto failure;
677 
678         if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen(ifname)) < 0)
679                 goto failure;
680 
681         if (setsockopt(sock, SOL_SOCKET, SO_PRIORITY, &(config_dhcp->sk_prio), sizeof(config_dhcp->sk_prio)) < 0)
682                 goto failure;
683 
684         val = config_dhcp->dscp << 2;
685         if (setsockopt(sock, IPPROTO_IPV6, IPV6_TCLASS, &val, sizeof(val)) < 0) {
686                 goto failure;
687         }
688 
689         struct sockaddr_in6 client_addr = { .sin6_family = AF_INET6,
690                 .sin6_port = htons(DHCPV6_CLIENT_PORT), .sin6_flowinfo = 0 };
691 
692         if (bind(sock, (struct sockaddr*)&client_addr, sizeof(client_addr)) < 0)
693                 goto failure;
694 
695         return 0;
696 
697 failure:
698         if (sock >= 0)
699                 close(sock);
700 
701         return -1;
702 }
703 
704 enum {
705         IOV_HDR=0,
706         IOV_ORO,
707         IOV_CL_ID,
708         IOV_SRV_ID,
709         IOV_OPTS,
710         IOV_RECONF_ACCEPT,
711         IOV_FQDN,
712         IOV_HDR_IA_NA,
713         IOV_IA_NA,
714         IOV_IA_PD,
715         IOV_TOTAL
716 };
717 
718 int dhcpv6_get_ia_mode(void)
719 {
720         int mode = DHCPV6_UNKNOWN;
721 
722         if (na_mode == IA_MODE_NONE && pd_mode == IA_MODE_NONE)
723                 mode = DHCPV6_STATELESS;
724         else if (na_mode == IA_MODE_FORCE || pd_mode == IA_MODE_FORCE)
725                 mode = DHCPV6_STATEFUL;
726 
727         return mode;
728 }
729 
730 static void dhcpv6_send(enum dhcpv6_msg req_msg_type, uint8_t trid[3], uint32_t ecs)
731 {
732         // Build FQDN
733         size_t fqdn_len;
734         void *fqdn = odhcp6c_get_state(STATE_OUR_FQDN, &fqdn_len);
735 
736         // Build Client ID
737         size_t cl_id_len;
738         void *cl_id = odhcp6c_get_state(STATE_CLIENT_ID, &cl_id_len);
739 
740         // Get Server ID
741         size_t srv_id_len;
742         void *srv_id = odhcp6c_get_state(STATE_SERVER_ID, &srv_id_len);
743 
744         // Build IA_PDs
745         size_t ia_pd_entry_cnt = 0, ia_pd_len = 0;
746         uint8_t *ia_pd;
747         struct odhcp6c_entry *pd_entries = odhcp6c_get_state(STATE_IA_PD, &ia_pd_entry_cnt);
748         ia_pd_entry_cnt /= sizeof(*pd_entries);
749 
750         if (req_msg_type == DHCPV6_MSG_SOLICIT || (req_msg_type == DHCPV6_MSG_REQUEST && ia_pd_entry_cnt == 0 && pd_mode != IA_MODE_NONE)) {
751                 odhcp6c_clear_state(STATE_IA_PD);
752                 size_t n_prefixes;
753                 struct odhcp6c_request_prefix *request_prefixes = odhcp6c_get_state(STATE_IA_PD_INIT, &n_prefixes);
754                 n_prefixes /= sizeof(struct odhcp6c_request_prefix);
755 
756                 ia_pd = alloca(n_prefixes * (sizeof(struct dhcpv6_ia_hdr) + sizeof(struct dhcpv6_ia_prefix)));
757 
758                 for (size_t i = 0; i < n_prefixes; i++) {
759                         struct dhcpv6_ia_hdr hdr_ia_pd = {
760                                 htons(DHCPV6_OPT_IA_PD),
761                                 htons(sizeof(hdr_ia_pd) - DHCPV6_OPT_HDR_SIZE +
762                                       sizeof(struct dhcpv6_ia_prefix) * !!request_prefixes[i].length),
763                                 request_prefixes[i].iaid, 0, 0
764                         };
765                         struct dhcpv6_ia_prefix pref = {
766                                 .type = htons(DHCPV6_OPT_IA_PREFIX),
767                                 .len = htons(sizeof(pref) - DHCPV6_OPT_HDR_SIZE),
768                                 .prefix = request_prefixes[i].length,
769                                 .addr = request_prefixes[i].addr
770                         };
771                         memcpy(ia_pd + ia_pd_len, &hdr_ia_pd, sizeof(hdr_ia_pd));
772                         ia_pd_len += sizeof(hdr_ia_pd);
773                         if (request_prefixes[i].length) {
774                                 memcpy(ia_pd + ia_pd_len, &pref, sizeof(pref));
775                                 ia_pd_len += sizeof(pref);
776                         }
777                 }
778         } else {
779                 // we're too lazy to count our distinct IAIDs,
780                 // so just allocate maximally needed space
781                 ia_pd = alloca(ia_pd_entry_cnt * (sizeof(struct dhcpv6_ia_prefix) + 10 +
782                                         sizeof(struct dhcpv6_ia_hdr)));
783 
784                 for (size_t i = 0; i < ia_pd_entry_cnt; ++i) {
785                         uint32_t iaid = pd_entries[i].iaid;
786 
787                         // check if this is an unprocessed IAID and skip if not.
788                         bool new_iaid = true;
789                         for (int j = i-1; j >= 0; j--) {
790                                 if (pd_entries[j].iaid == iaid) {
791                                         new_iaid = false;
792                                         break;
793                                 }
794                         }
795 
796                         if (!new_iaid)
797                                 continue;
798 
799                         // construct header
800                         struct dhcpv6_ia_hdr hdr_ia_pd = {
801                                 htons(DHCPV6_OPT_IA_PD),
802                                 htons(sizeof(hdr_ia_pd) - DHCPV6_OPT_HDR_SIZE),
803                                 iaid, 0, 0
804                         };
805 
806                         memcpy(ia_pd + ia_pd_len, &hdr_ia_pd, sizeof(hdr_ia_pd));
807                         struct dhcpv6_ia_hdr *hdr = (struct dhcpv6_ia_hdr *) (ia_pd + ia_pd_len);
808                         ia_pd_len += sizeof(hdr_ia_pd);
809 
810                         for (size_t j = i; j < ia_pd_entry_cnt; j++) {
811                                 if (pd_entries[j].iaid != iaid)
812                                         continue;
813 
814                                 uint8_t ex_len = 0;
815                                 if (pd_entries[j].exclusion_length > 0)
816                                         ex_len = ((pd_entries[j].exclusion_length - pd_entries[j].length - 1) / 8) + 6;
817 
818                                 struct dhcpv6_ia_prefix p = {
819                                         .type = htons(DHCPV6_OPT_IA_PREFIX),
820                                         .len = htons(sizeof(p) - DHCPV6_OPT_HDR_SIZE_U + ex_len),
821                                         .prefix = pd_entries[j].length,
822                                         .addr = pd_entries[j].target
823                                 };
824 
825                                 if (req_msg_type == DHCPV6_MSG_REQUEST) {
826                                         p.preferred = htonl(pd_entries[j].preferred);
827                                         p.valid = htonl(pd_entries[j].valid);
828                                 }
829 
830                                 memcpy(ia_pd + ia_pd_len, &p, sizeof(p));
831                                 ia_pd_len += sizeof(p);
832 
833                                 if (ex_len) {
834                                         ia_pd[ia_pd_len++] = 0;
835                                         ia_pd[ia_pd_len++] = DHCPV6_OPT_PD_EXCLUDE;
836                                         ia_pd[ia_pd_len++] = 0;
837                                         ia_pd[ia_pd_len++] = ex_len - DHCPV6_OPT_HDR_SIZE;
838                                         ia_pd[ia_pd_len++] = pd_entries[j].exclusion_length;
839 
840                                         uint32_t excl = ntohl(pd_entries[j].router.s6_addr32[1]);
841                                         excl >>= (64 - pd_entries[j].exclusion_length);
842                                         excl <<= 8 - ((pd_entries[j].exclusion_length - pd_entries[j].length) % 8);
843 
844                                         for (size_t k = ex_len - 5; k > 0; --k, excl >>= 8)
845                                                 ia_pd[ia_pd_len + k] = excl & 0xff;
846 
847                                         ia_pd_len += ex_len - 5;
848                                 }
849 
850                                 hdr->len = htons(ntohs(hdr->len) + ntohs(p.len) + 4U);
851                         }
852                 }
853         }
854 
855         // Build IA_NAs
856         size_t ia_na_entry_cnt, ia_na_len = 0;
857         void *ia_na = NULL;
858         struct odhcp6c_entry *ia_entries = odhcp6c_get_state(STATE_IA_NA, &ia_na_entry_cnt);
859         ia_na_entry_cnt /= sizeof(*ia_entries);
860 
861         struct dhcpv6_ia_hdr hdr_ia_na = {
862                 .type = htons(DHCPV6_OPT_IA_NA),
863                 .len = htons(sizeof(hdr_ia_na) - DHCPV6_OPT_HDR_SIZE),
864                 .iaid = htonl(ifname_hash_iaid),
865                 .t1 = 0,
866                 .t2 = 0,
867         };
868 
869         struct dhcpv6_ia_addr ia_na_array[ia_na_entry_cnt];
870         for (size_t i = 0; i < ia_na_entry_cnt; ++i) {
871                 ia_na_array[i].type = htons(DHCPV6_OPT_IA_ADDR);
872                 ia_na_array[i].len = htons(sizeof(ia_na_array[i]) - DHCPV6_OPT_HDR_SIZE_U);
873                 ia_na_array[i].addr = ia_entries[i].target;
874 
875                 if (req_msg_type == DHCPV6_MSG_REQUEST) {
876                         ia_na_array[i].preferred = htonl(ia_entries[i].preferred);
877                         ia_na_array[i].valid = htonl(ia_entries[i].valid);
878                 } else {
879                         ia_na_array[i].preferred = 0;
880                         ia_na_array[i].valid = 0;
881                 }
882         }
883 
884         ia_na = ia_na_array;
885         ia_na_len = sizeof(ia_na_array);
886         hdr_ia_na.len = htons(ntohs(hdr_ia_na.len) + ia_na_len);
887 
888         // Reconfigure Accept
889         struct {
890                 uint16_t type;
891                 uint16_t length;
892         } reconf_accept = {htons(DHCPV6_OPT_RECONF_ACCEPT), 0};
893 
894         // Option list
895         size_t opts_len;
896         void *opts = odhcp6c_get_state(STATE_OPTS, &opts_len);
897 
898         // Option Request List
899         size_t oro_entries, oro_len = 0;
900         uint16_t *oro, *s_oro = odhcp6c_get_state(STATE_ORO, &oro_entries);
901 
902         oro_entries /= sizeof(*s_oro);
903         oro = alloca(oro_entries * sizeof(*oro));
904 
905         for (size_t i = 0; i < oro_entries; i++) {
906                 struct odhcp6c_opt *opt = odhcp6c_find_opt(htons(s_oro[i]));
907 
908                 if (opt) {
909                         if (!(opt->flags & OPT_ORO))
910                                 continue;
911 
912                         if ((opt->flags & OPT_ORO_SOLICIT) && req_msg_type != DHCPV6_MSG_SOLICIT)
913                                 continue;
914 
915                         if ((opt->flags & OPT_ORO_STATELESS) && req_msg_type != DHCPV6_MSG_INFO_REQ)
916                                 continue;
917 
918                         if ((opt->flags & OPT_ORO_STATEFUL) && req_msg_type == DHCPV6_MSG_INFO_REQ)
919                                 continue;
920                 }
921 
922                 oro[oro_len++] = s_oro[i];
923         }
924         oro_len *= sizeof(*oro);
925 
926         // Prepare Header
927         struct {
928                 uint8_t type;
929                 uint8_t trid[3];
930                 uint16_t elapsed_type;
931                 uint16_t elapsed_len;
932                 uint16_t elapsed_value;
933                 uint16_t oro_type;
934                 uint16_t oro_len;
935         } hdr = {
936                 req_msg_type, {trid[0], trid[1], trid[2]},
937                 htons(DHCPV6_OPT_ELAPSED), htons(2),
938                         htons((ecs > 0xffff) ? 0xffff : ecs),
939                 htons(DHCPV6_OPT_ORO), htons(oro_len),
940         };
941 
942         struct iovec iov[IOV_TOTAL] = {
943                 [IOV_HDR] = {&hdr, sizeof(hdr)},
944                 [IOV_ORO] = {oro, oro_len},
945                 [IOV_CL_ID] = {cl_id, cl_id_len},
946                 [IOV_SRV_ID] = {srv_id, srv_id_len},
947                 [IOV_OPTS] = { opts, opts_len },
948                 [IOV_RECONF_ACCEPT] = {&reconf_accept, sizeof(reconf_accept)},
949                 [IOV_FQDN] = {fqdn, fqdn_len},
950                 [IOV_HDR_IA_NA] = {&hdr_ia_na, sizeof(hdr_ia_na)},
951                 [IOV_IA_NA] = {ia_na, ia_na_len},
952                 [IOV_IA_PD] = {ia_pd, ia_pd_len},
953         };
954 
955         size_t cnt = IOV_TOTAL;
956         if (req_msg_type == DHCPV6_MSG_INFO_REQ)
957                 cnt = IOV_HDR_IA_NA;
958 
959         // Disable IAs if not used
960         if (req_msg_type != DHCPV6_MSG_SOLICIT && req_msg_type != DHCPV6_MSG_REQUEST && ia_na_len == 0)
961                 iov[IOV_HDR_IA_NA].iov_len = 0;
962 
963         if (na_mode == IA_MODE_NONE)
964                 iov[IOV_HDR_IA_NA].iov_len = 0;
965 
966         if ((req_msg_type != DHCPV6_MSG_SOLICIT && req_msg_type != DHCPV6_MSG_REQUEST) ||
967                         !(client_options & DHCPV6_ACCEPT_RECONFIGURE))
968                 iov[IOV_RECONF_ACCEPT].iov_len = 0;
969 
970         if (!(client_options & DHCPV6_CLIENT_FQDN)) {
971                 iov[IOV_FQDN].iov_len = 0;
972         } else {
973                 switch (req_msg_type) {
974                 /*  RFC4704 ยง5
975                         A client MUST only include the Client FQDN option in SOLICIT,
976                         REQUEST, RENEW, or REBIND messages.
977                 */
978                 case DHCPV6_MSG_SOLICIT:
979                 case DHCPV6_MSG_REQUEST:
980                 case DHCPV6_MSG_RENEW:
981                 case DHCPV6_MSG_REBIND:
982                 /*  RFC4704 ยง6
983                         Servers MUST only include a Client FQDN option in ADVERTISE and REPLY
984                         messages...
985                 case DHCPV6_MSG_ADVERT:
986                 case DHCPV6_MSG_REPLY:
987                 */
988                         /* leave FQDN as-is */
989                     break;
990                 default:
991                         /* remaining MSG types cannot contain client FQDN */
992                         iov[IOV_FQDN].iov_len = 0;
993                     break;
994                 }
995         }
996 
997         struct sockaddr_in6 srv = {AF_INET6, htons(DHCPV6_SERVER_PORT),
998                 0, ALL_DHCPV6_RELAYS, ifindex};
999         struct msghdr msg = {.msg_name = &srv, .msg_namelen = sizeof(srv),
1000                         .msg_iov = iov, .msg_iovlen = cnt};
1001 
1002         switch (req_msg_type) {
1003         case DHCPV6_MSG_REQUEST:
1004         case DHCPV6_MSG_RENEW:
1005         case DHCPV6_MSG_RELEASE:
1006         case DHCPV6_MSG_DECLINE:
1007                 if (!IN6_IS_ADDR_UNSPECIFIED(&server_addr) &&
1008                         odhcp6c_addr_in_scope(&server_addr)) {
1009                         srv.sin6_addr = server_addr;
1010                         if (!IN6_IS_ADDR_LINKLOCAL(&server_addr))
1011                                 srv.sin6_scope_id = 0;
1012                 }
1013                 break;
1014         default:
1015                 break;
1016         }
1017 
1018         if (sendmsg(sock, &msg, 0) < 0) {
1019                 char in6_str[INET6_ADDRSTRLEN];
1020 
1021                 error("Failed to send %s message to %s (%s)",
1022                         dhcpv6_msg_to_str(req_msg_type),
1023                         inet_ntop(AF_INET6, (const void *)&srv.sin6_addr,
1024                                 in6_str, sizeof(in6_str)), strerror(errno));
1025                 dhcpv6_stats.transmit_failures++;
1026         } else {
1027                 dhcpv6_inc_counter(req_msg_type);
1028         }
1029 }
1030 
1031 static int64_t dhcpv6_rand_delay(int64_t time)
1032 {
1033         int random;
1034         odhcp6c_random(&random, sizeof(random));
1035 
1036         return (time * ((int64_t)random % (config_dhcp->rand_factor*10LL))) / 10000LL;
1037 }
1038 
1039 // Message validation checks according to RFC3315 chapter 15
1040 static bool dhcpv6_response_is_valid(const void *buf, ssize_t len,
1041                 const uint8_t transaction[3], enum dhcpv6_msg req_msg_type,
1042                 const struct in6_addr *daddr)
1043 {
1044         const struct dhcpv6_header *response_buf = buf;
1045         if (len < (ssize_t)sizeof(*response_buf) || memcmp(response_buf->tr_id,
1046                         transaction, sizeof(response_buf->tr_id)))
1047                 return false; // Invalid reply
1048 
1049         if (req_msg_type == DHCPV6_MSG_SOLICIT) {
1050                 if (response_buf->msg_type != DHCPV6_MSG_ADVERT &&
1051                                 response_buf->msg_type != DHCPV6_MSG_REPLY)
1052                         return false;
1053         } else if (req_msg_type == DHCPV6_MSG_UNKNOWN) {
1054                 if (!accept_reconfig || response_buf->msg_type != DHCPV6_MSG_RECONF)
1055                         return false;
1056         } else if (response_buf->msg_type != DHCPV6_MSG_REPLY) {
1057                 return false;
1058         }
1059 
1060         uint8_t *end = ((uint8_t*)buf) + len, *odata = NULL,
1061                 rcmsg = DHCPV6_MSG_UNKNOWN;
1062         uint16_t otype, olen = UINT16_MAX;
1063         bool clientid_ok = false, serverid_ok = false, rcauth_ok = false,
1064                 auth_present = false, ia_present = false, options_valid = true;
1065 
1066         size_t client_id_len, server_id_len;
1067         void *client_id = odhcp6c_get_state(STATE_CLIENT_ID, &client_id_len);
1068         void *server_id = odhcp6c_get_state(STATE_SERVER_ID, &server_id_len);
1069 
1070         dhcpv6_for_each_option(&response_buf[1], end, otype, olen, odata) {
1071                 switch (otype) {
1072                 case DHCPV6_OPT_CLIENTID:
1073                         clientid_ok = (olen + DHCPV6_OPT_HDR_SIZE_U == client_id_len) && !memcmp(
1074                                         &odata[-DHCPV6_OPT_HDR_SIZE], client_id, client_id_len);                        
1075                         break;
1076 
1077                 case DHCPV6_OPT_SERVERID:
1078                         if (server_id_len)
1079                                 serverid_ok = (olen + DHCPV6_OPT_HDR_SIZE_U == server_id_len) && !memcmp(
1080                                                 &odata[-DHCPV6_OPT_HDR_SIZE], server_id, server_id_len);
1081                         else
1082                                 serverid_ok = true;
1083                         break;
1084 
1085                 case DHCPV6_OPT_AUTH:
1086                         struct dhcpv6_auth *r = (void*)&odata[-DHCPV6_OPT_HDR_SIZE];
1087                         if (auth_present) {
1088                                 options_valid = false;
1089                                 continue;
1090                         }
1091 
1092                         auth_present = true;
1093                         if (auth_protocol == AUTH_PROT_RKAP) {
1094                                 struct dhcpv6_auth_reconfigure *rkap = (void*)r->data;
1095                                 if (r->protocol != AUTH_PROT_RKAP || r->algorithm != AUTH_ALG_HMACMD5 || r->len != 28 || rkap->reconf_type != RKAP_TYPE_HMACMD5)
1096                                         continue;
1097 
1098                                 md5_ctx_t md5;
1099                                 uint8_t serverhash[16], secretbytes[64];
1100                                 uint32_t hash[4];
1101                                 memcpy(serverhash, rkap->key, sizeof(serverhash));
1102                                 memset(rkap->key, 0, sizeof(rkap->key));
1103 
1104                                 memset(secretbytes, 0, sizeof(secretbytes));
1105                                 memcpy(secretbytes, reconf_key, sizeof(reconf_key));
1106 
1107                                 for (size_t i = 0; i < sizeof(secretbytes); ++i)
1108                                         secretbytes[i] ^= 0x36;
1109 
1110                                 md5_begin(&md5);
1111                                 md5_hash(secretbytes, sizeof(secretbytes), &md5);
1112                                 md5_hash(buf, len, &md5);
1113                                 md5_end(hash, &md5);
1114 
1115                                 for (size_t i = 0; i < sizeof(secretbytes); ++i) {
1116                                         secretbytes[i] ^= 0x36;
1117                                         secretbytes[i] ^= 0x5c;
1118                                 }
1119 
1120                                 md5_begin(&md5);
1121                                 md5_hash(secretbytes, sizeof(secretbytes), &md5);
1122                                 md5_hash(hash, 16, &md5);
1123                                 md5_end(hash, &md5);
1124 
1125                                 rcauth_ok = !memcmp(hash, serverhash, sizeof(hash));
1126                         } else if (auth_protocol == AUTH_PROT_TOKEN) {
1127                                 if (r->protocol != AUTH_PROT_TOKEN || r->algorithm != AUTH_ALG_TOKEN || r->len < 12)
1128                                         continue;
1129 
1130                                 uint16_t token_len = r->len - 11;
1131                                 if (config_dhcp->auth_token == NULL || strlen(config_dhcp->auth_token) != token_len)
1132                                         continue;
1133 
1134                                 rcauth_ok = !memcmp(r->data, config_dhcp->auth_token, token_len);
1135                         }
1136                         break;
1137                 case DHCPV6_OPT_RECONF_MESSAGE:
1138                         if (olen != 1)
1139                                 return false;
1140                         rcmsg = odata[0];
1141                         break;
1142 
1143                 case DHCPV6_OPT_IA_PD:
1144                 case DHCPV6_OPT_IA_NA:
1145                         ia_present = true;
1146                         if (olen < sizeof(struct dhcpv6_ia_hdr) - DHCPV6_OPT_HDR_SIZE)
1147                                 options_valid = false;
1148                         break;
1149 
1150                 case DHCPV6_OPT_IA_ADDR:
1151                 case DHCPV6_OPT_IA_PREFIX:
1152                 case DHCPV6_OPT_PD_EXCLUDE:
1153                         // Options are not allowed on global level
1154                         options_valid = false;
1155                         break;
1156 
1157                 default:
1158                         break;
1159                 }
1160         }
1161 
1162         if (!options_valid || ((odata + olen) > end))
1163                 return false;
1164 
1165         if (req_msg_type == DHCPV6_MSG_INFO_REQ && ia_present)
1166                 return false;
1167 
1168         if (response_buf->msg_type == DHCPV6_MSG_RECONF) {
1169                 if ((rcmsg != DHCPV6_MSG_RENEW && rcmsg != DHCPV6_MSG_REBIND && rcmsg != DHCPV6_MSG_INFO_REQ) ||
1170                         (rcmsg == DHCPV6_MSG_INFO_REQ && ia_present) ||
1171                         !rcauth_ok || IN6_IS_ADDR_MULTICAST(daddr))
1172                         return false;
1173         }
1174 
1175         return clientid_ok && serverid_ok;
1176 }
1177 
1178 static int dhcpv6_handle_reconfigure(enum dhcpv6_msg orig, const int rc,
1179                 const void *opt, const void *end, _o_unused const struct sockaddr_in6 *from)
1180 {
1181         uint16_t otype, olen;
1182         uint8_t *odata;
1183         enum dhcpv6_msg msg = DHCPV6_MSG_UNKNOWN;
1184 
1185         dhcpv6_for_each_option(opt, end, otype, olen, odata) {
1186                 if (otype == DHCPV6_OPT_RECONF_MESSAGE && olen == 1) {
1187                         switch (odata[0]) {
1188                         case DHCPV6_MSG_REBIND:
1189                                 if (t2 != UINT32_MAX)
1190                                         t2 = 0;
1191                                 _o_fallthrough;
1192                         case DHCPV6_MSG_RENEW:
1193                                 if (t1 != UINT32_MAX)
1194                                         t1 = 0;
1195                                 _o_fallthrough;
1196                         case DHCPV6_MSG_INFO_REQ:
1197                                 msg = odata[0];
1198                                 notice("Need to respond with %s in reply to %s",
1199                                        dhcpv6_msg_to_str(msg), dhcpv6_msg_to_str(DHCPV6_MSG_RECONF));
1200                                 break;
1201 
1202                         default:
1203                                 break;
1204                         }
1205                 }
1206         }
1207 
1208         if (msg != DHCPV6_MSG_UNKNOWN)
1209                 dhcpv6_handle_reply(orig, rc, NULL, NULL, NULL);
1210 
1211         return (msg == DHCPV6_MSG_UNKNOWN? -1: (int)msg);
1212 }
1213 
1214 // Collect all advertised servers
1215 static int dhcpv6_handle_advert(enum dhcpv6_msg orig, const int rc,
1216                 const void *opt, const void *end, _o_unused const struct sockaddr_in6 *from)
1217 {
1218         uint16_t olen, otype;
1219         uint8_t *odata, pref = 0;
1220         struct dhcpv6_server_cand cand = {false, false, 0, 0, {0},
1221                                         IN6ADDR_ANY_INIT, DHCPV6_SOL_MAX_RT,
1222                                         DHCPV6_INF_MAX_RT, NULL, NULL, 0, 0};
1223         bool have_na = false;
1224         int have_pd = 0;
1225 
1226         dhcpv6_for_each_option(opt, end, otype, olen, odata) {
1227                 if (orig == DHCPV6_MSG_SOLICIT &&
1228                                 ((otype == DHCPV6_OPT_IA_PD && pd_mode != IA_MODE_NONE) ||
1229                                  (otype == DHCPV6_OPT_IA_NA && na_mode != IA_MODE_NONE)) &&
1230                                 olen > sizeof(struct dhcpv6_ia_hdr) - DHCPV6_OPT_HDR_SIZE) {
1231                         struct dhcpv6_ia_hdr *ia_hdr = (void*)(&odata[-DHCPV6_OPT_HDR_SIZE]);
1232                         dhcpv6_parse_ia(ia_hdr, odata + olen + sizeof(*ia_hdr), NULL);
1233                 }
1234 
1235                 switch (otype) {
1236                 case DHCPV6_OPT_SERVERID:
1237                         if (olen <= DHCPV6_DUID_MAX_LEN) {
1238                                 memcpy(cand.duid, odata, olen);
1239                                 cand.duid_len = olen;
1240                         }
1241                         break;
1242 
1243                 case DHCPV6_OPT_PREF:
1244                         if (olen >= 1 && cand.preference >= 0)
1245                                 cand.preference = pref = odata[0];
1246                         break;
1247 
1248                 case DHCPV6_OPT_UNICAST:
1249                         if (olen == sizeof(cand.server_addr) &&
1250                             !(client_options & DHCPV6_IGNORE_OPT_UNICAST))
1251                                 cand.server_addr = *(struct in6_addr *)odata;
1252                         break;
1253 
1254                 case DHCPV6_OPT_RECONF_ACCEPT:
1255                         cand.wants_reconfigure = true;
1256                         break;
1257 
1258                 case DHCPV6_OPT_SOL_MAX_RT:
1259                         if (olen == 4) {
1260                                 uint32_t sol_max_rt = ntohl_unaligned(odata);
1261                                 if (sol_max_rt >= DHCPV6_SOL_MAX_RT_MIN &&
1262                                     sol_max_rt <= DHCPV6_SOL_MAX_RT_MAX)
1263                                         cand.sol_max_rt = sol_max_rt;
1264                         }
1265                         break;
1266 
1267                 case DHCPV6_OPT_INF_MAX_RT:
1268                         if (olen == 4) {
1269                                 uint32_t inf_max_rt = ntohl_unaligned(odata);
1270                                 if (inf_max_rt >= DHCPV6_INF_MAX_RT_MIN &&
1271                                     inf_max_rt <= DHCPV6_INF_MAX_RT_MAX)
1272                                         cand.inf_max_rt = inf_max_rt;
1273                         }
1274                         break;
1275 
1276                 case DHCPV6_OPT_IA_PD:
1277                         if (olen >= sizeof(struct dhcpv6_ia_hdr) - DHCPV6_OPT_HDR_SIZE) {
1278                                 struct dhcpv6_ia_hdr *h = (struct dhcpv6_ia_hdr *)&odata[-DHCPV6_OPT_HDR_SIZE];
1279                                 uint8_t *oend = odata + olen, *d;
1280 
1281                                 dhcpv6_for_each_option(&h[1], oend, otype, olen, d) {
1282                                         if (otype == DHCPV6_OPT_IA_PREFIX &&
1283                                             olen >= sizeof(struct dhcpv6_ia_prefix) - DHCPV6_OPT_HDR_SIZE) {
1284                                                 struct dhcpv6_ia_prefix *p =
1285                                                         (struct dhcpv6_ia_prefix *)&d[-DHCPV6_OPT_HDR_SIZE];
1286                                                 have_pd = p->prefix;
1287                                         }
1288                                 }
1289                         }
1290                         break;
1291 
1292                 case DHCPV6_OPT_IA_NA:
1293                         if (olen >= sizeof(struct dhcpv6_ia_hdr) - DHCPV6_OPT_HDR_SIZE) {
1294                                 struct dhcpv6_ia_hdr *h = (struct dhcpv6_ia_hdr *)&odata[-DHCPV6_OPT_HDR_SIZE];
1295                                 uint8_t *oend = odata + olen, *d;
1296 
1297                                 dhcpv6_for_each_option(&h[1], oend, otype, olen, d) {
1298                                         if (otype == DHCPV6_OPT_IA_ADDR &&
1299                                             olen >= sizeof(struct dhcpv6_ia_addr) - DHCPV6_OPT_HDR_SIZE)
1300                                                 have_na = true;
1301                                 }
1302                         }
1303                         break;
1304 
1305                 default:
1306                         break;
1307                 }
1308         }
1309 
1310         if ((stateful_only_mode && !have_na && !have_pd) ||
1311                         (!have_na && na_mode == IA_MODE_FORCE) ||
1312                         (!have_pd && pd_mode == IA_MODE_FORCE)) {
1313                 /*
1314                  * RFC7083 states to process the SOL_MAX_RT and
1315                  * INF_MAX_RT options even if the DHCPv6 server
1316                  * did not propose any IA_NA and/or IA_PD
1317                  */
1318                 dhcpv6_retx[DHCPV6_MSG_SOLICIT].max_timeo = cand.sol_max_rt;
1319                 dhcpv6_retx[DHCPV6_MSG_INFO_REQ].max_timeo = cand.inf_max_rt;
1320                 return -1;
1321         }
1322 
1323         if (na_mode != IA_MODE_NONE && !have_na) {
1324                 cand.has_noaddravail = true;
1325                 cand.preference -= 1000;
1326         }
1327 
1328         if (pd_mode != IA_MODE_NONE) {
1329                 if (have_pd)
1330                         cand.preference += 2000 + (128 - have_pd);
1331                 else
1332                         cand.preference -= 2000;
1333         }
1334 
1335         if (cand.duid_len > 0) {
1336                 cand.ia_na = odhcp6c_move_state(STATE_IA_NA, &cand.ia_na_len);
1337                 cand.ia_pd = odhcp6c_move_state(STATE_IA_PD, &cand.ia_pd_len);
1338                 dhcpv6_add_server_cand(&cand);
1339         }
1340 
1341         return (rc > 1 || (pref == 255 && cand.preference > 0)) ? 1 : -1;
1342 }
1343 
1344 static int dhcpv6_commit_advert(void)
1345 {
1346         return dhcpv6_promote_server_cand();
1347 }
1348 
1349 static int dhcpv6_handle_rebind_reply(enum dhcpv6_msg orig, const int rc,
1350                 const void *opt, const void *end, const struct sockaddr_in6 *from)
1351 {
1352         dhcpv6_handle_advert(orig, rc, opt, end, from);
1353         if (dhcpv6_commit_advert() < 0)
1354                 return -1;
1355 
1356         return dhcpv6_handle_reply(orig, rc, opt, end, from);
1357 }
1358 
1359 static int dhcpv6_handle_reply(enum dhcpv6_msg orig, _o_unused const int rc,
1360                 const void *opt, const void *end, const struct sockaddr_in6 *from)
1361 {
1362         uint8_t *odata;
1363         uint16_t otype, olen;
1364         uint32_t refresh = config_dhcp->irt_default;
1365         int ret = 1;
1366         unsigned int state_IAs;
1367         unsigned int updated_IAs = 0;
1368         bool handled_status_codes[_DHCPV6_Status_Max] = { false, };
1369 
1370         odhcp6c_expire(true);
1371 
1372         if (orig == DHCPV6_MSG_UNKNOWN) {
1373                 static time_t last_update = 0;
1374                 time_t now = odhcp6c_get_milli_time() / 1000;
1375 
1376                 uint32_t elapsed = (last_update > 0) ? now - last_update : 0;
1377                 last_update = now;
1378 
1379                 if (t1 != UINT32_MAX)
1380                         t1 -= elapsed;
1381 
1382                 if (t2 != UINT32_MAX)
1383                         t2 -= elapsed;
1384 
1385                 if (t3 != UINT32_MAX)
1386                         t3 -= elapsed;
1387 
1388                 if (t1 < 0)
1389                         t1 = 0;
1390 
1391                 if (t2 < 0)
1392                         t2 = 0;
1393 
1394                 if (t3 < 0)
1395                         t3 = 0;
1396         }
1397 
1398         if (orig == DHCPV6_MSG_REQUEST && !odhcp6c_is_bound()) {
1399                 // Delete NA and PD we have in the state from the Advert
1400                 odhcp6c_clear_state(STATE_IA_NA);
1401                 odhcp6c_clear_state(STATE_IA_PD);
1402         }
1403 
1404         if (opt) {
1405                 odhcp6c_clear_state(STATE_DNS);
1406                 odhcp6c_clear_state(STATE_SEARCH);
1407                 odhcp6c_clear_state(STATE_SNTP_IP);
1408                 odhcp6c_clear_state(STATE_NTP_IP);
1409                 odhcp6c_clear_state(STATE_NTP_FQDN);
1410                 odhcp6c_clear_state(STATE_SIP_IP);
1411                 odhcp6c_clear_state(STATE_SIP_FQDN);
1412                 odhcp6c_clear_state(STATE_AFTR_NAME);
1413                 odhcp6c_clear_state(STATE_S46_MAPT);
1414                 odhcp6c_clear_state(STATE_S46_MAPE);
1415                 odhcp6c_clear_state(STATE_S46_LW);
1416                 odhcp6c_clear_state(STATE_CAPT_PORT_DHCPV6);
1417                 odhcp6c_clear_state(STATE_PASSTHRU);
1418                 odhcp6c_clear_state(STATE_CUSTOM_OPTS);
1419 
1420                 // Parse and find all matching IAs
1421                 dhcpv6_for_each_option(opt, end, otype, olen, odata) {
1422                         struct odhcp6c_opt *dopt = odhcp6c_find_opt(otype);
1423 
1424                         switch (otype) {
1425 
1426                         case DHCPV6_OPT_IA_NA:
1427                         case DHCPV6_OPT_IA_PD:
1428                                 if (olen > sizeof(struct dhcpv6_ia_hdr) - DHCPV6_OPT_HDR_SIZE) {
1429                                         struct dhcpv6_ia_hdr *ia_hdr = (void*)(&odata[-DHCPV6_OPT_HDR_SIZE]);
1430 
1431                                         if ((na_mode == IA_MODE_NONE && otype == DHCPV6_OPT_IA_NA) ||
1432                                                 (pd_mode == IA_MODE_NONE && otype == DHCPV6_OPT_IA_PD))
1433                                                 continue;
1434 
1435                                         // Test ID
1436                                         if (ia_hdr->iaid != htonl(ifname_hash_iaid) && otype == DHCPV6_OPT_IA_NA)
1437                                                 continue;
1438 
1439                                         uint16_t code = DHCPV6_Success;
1440                                         uint16_t stype, slen;
1441                                         uint8_t *sdata;
1442                                         bool dhcpv6_successful_once = false;
1443                                         // Get and handle status code
1444                                         dhcpv6_for_each_option(&ia_hdr[1], odata + olen, stype, slen, sdata) {
1445                                                 if (stype == DHCPV6_OPT_STATUS && slen >= 2) {
1446                                                         uint8_t *mdata = (slen > 2) ? &sdata[2] : NULL;
1447                                                         uint16_t mlen = (slen > 2) ? slen - 2 : 0;
1448 
1449                                                         code = ((int)sdata[0] << 8) | ((int)sdata[1]);
1450 
1451                                                         if (code == DHCPV6_Success) {
1452                                                                 dhcpv6_successful_once = true;
1453                                                                 continue;
1454                                                         }
1455 
1456                                                         dhcpv6_handle_ia_status_code(orig, ia_hdr,
1457                                                                 code, mdata, mlen, handled_status_codes, &ret);
1458 
1459                                                         break;
1460                                                 }
1461                                         }
1462 
1463                                         if (!dhcpv6_successful_once && code != DHCPV6_Success)
1464                                                 continue;
1465 
1466                                         updated_IAs += dhcpv6_parse_ia(ia_hdr, odata + olen, &ret);
1467                                 }
1468                                 break;
1469 
1470                         case DHCPV6_OPT_UNICAST:
1471                                 if (olen == sizeof(server_addr) &&
1472                                     !(client_options & DHCPV6_IGNORE_OPT_UNICAST))
1473                                         server_addr = *(struct in6_addr *)odata;
1474                                 break;
1475 
1476                         case DHCPV6_OPT_STATUS:
1477                                 if (olen >= 2) {
1478                                         uint8_t *mdata = (olen > 2) ? &odata[2] : NULL;
1479                                         uint16_t mlen = (olen > 2) ? olen - 2 : 0;
1480                                         uint16_t code = ((int)odata[0] << 8) | ((int)odata[1]);
1481 
1482                                         dhcpv6_handle_status_code(orig, code, mdata, mlen, &ret);
1483                                 }
1484                                 break;
1485 
1486                         case DHCPV6_OPT_DNS_SERVERS:
1487                                 if (olen % sizeof(struct in6_addr) == 0)
1488                                         odhcp6c_add_state(STATE_DNS, odata, olen);
1489                                 break;
1490 
1491                         case DHCPV6_OPT_DNS_DOMAIN:
1492                                 odhcp6c_add_state(STATE_SEARCH, odata, olen);
1493                                 break;
1494 
1495                         case DHCPV6_OPT_SNTP_SERVERS:
1496                                 if (olen % sizeof(struct in6_addr) == 0)
1497                                         odhcp6c_add_state(STATE_SNTP_IP, odata, olen);
1498                                 break;
1499 
1500                         case DHCPV6_OPT_NTP_SERVER:
1501                                 uint16_t stype, slen;
1502                                 uint8_t *sdata;
1503                                 // Test status and bail if error
1504                                 dhcpv6_for_each_option(odata, odata + olen,
1505                                                 stype, slen, sdata) {
1506                                         if (slen == sizeof(struct in6_addr) && (stype == NTP_MC_ADDR || stype == NTP_SRV_ADDR))
1507                                                 odhcp6c_add_state(STATE_NTP_IP, sdata, slen);
1508                                         else if (slen > 0 && stype == NTP_SRV_FQDN)
1509                                                 odhcp6c_add_state(STATE_NTP_FQDN, sdata, slen);
1510                                 }
1511                                 break;
1512 
1513                         case DHCPV6_OPT_SIP_SERVER_A:
1514                                 if (olen == sizeof(struct in6_addr))
1515                                         odhcp6c_add_state(STATE_SIP_IP, odata, olen);
1516                                 break;
1517 
1518                         case DHCPV6_OPT_SIP_SERVER_D:
1519                                 odhcp6c_add_state(STATE_SIP_FQDN, odata, olen);
1520                                 break;
1521 
1522                         case DHCPV6_OPT_INFO_REFRESH:
1523                                 if (olen == 4)
1524                                         refresh = ntohl_unaligned(odata);
1525                                 break;
1526 
1527                         case DHCPV6_OPT_AUTH:
1528                                 struct dhcpv6_auth *r = (void*)&odata[-DHCPV6_OPT_HDR_SIZE];
1529                                 if (auth_protocol == AUTH_PROT_RKAP) {
1530                                         struct dhcpv6_auth_reconfigure *rkap = (void*)r->data;
1531                                         if (r->protocol == AUTH_PROT_RKAP || r->algorithm == AUTH_ALG_HMACMD5 ||
1532                                                 r->len == 28 || rkap->reconf_type == RKAP_TYPE_KEY)
1533                                                 memcpy(reconf_key, rkap->key, sizeof(rkap->key));
1534                                 }
1535                                 break;
1536 
1537                         case DHCPV6_OPT_AFTR_NAME:
1538                                 if (olen > 3) {
1539                                         size_t cur_len;
1540                                         odhcp6c_get_state(STATE_AFTR_NAME, &cur_len);
1541                                         if (cur_len == 0)
1542                                                 odhcp6c_add_state(STATE_AFTR_NAME, odata, olen);
1543                                 }
1544                                 break;
1545 
1546                         case DHCPV6_OPT_SOL_MAX_RT:
1547                                 if (olen == 4) {
1548                                         uint32_t sol_max_rt = ntohl_unaligned(odata);
1549                                         if (sol_max_rt >= DHCPV6_SOL_MAX_RT_MIN && sol_max_rt <= DHCPV6_SOL_MAX_RT_MAX)
1550                                                 dhcpv6_retx[DHCPV6_MSG_SOLICIT].max_timeo = sol_max_rt;
1551                                 }
1552                                 break;
1553 
1554                         case DHCPV6_OPT_INF_MAX_RT:
1555                                 if (olen == 4) {
1556                                         uint32_t inf_max_rt = ntohl_unaligned(odata);
1557                                         if (inf_max_rt >= DHCPV6_INF_MAX_RT_MIN && inf_max_rt <= DHCPV6_INF_MAX_RT_MAX)
1558                                                 dhcpv6_retx[DHCPV6_MSG_INFO_REQ].max_timeo = inf_max_rt;
1559                                 }
1560                                 break;
1561 
1562                         case DHCPV6_OPT_S46_CONT_MAPT:
1563                                 odhcp6c_add_state(STATE_S46_MAPT, odata, olen);
1564                                 break;
1565 
1566                         case DHCPV6_OPT_S46_CONT_MAPE:
1567                                 size_t mape_len;
1568                                 odhcp6c_get_state(STATE_S46_MAPE, &mape_len);
1569                                 if (mape_len == 0)
1570                                         odhcp6c_add_state(STATE_S46_MAPE, odata, olen);
1571                                 break;
1572 
1573                         case DHCPV6_OPT_S46_CONT_LW:
1574                                 odhcp6c_add_state(STATE_S46_LW, odata, olen);
1575                                 break;
1576 
1577                         case DHCPV6_OPT_CAPTIVE_PORTAL: /* RFC8910 ยง2.2 */
1578                                 size_t ref_len = sizeof(URN_IETF_CAPT_PORT_UNRESTR) - 1;
1579                                 /* RFC8910 ยง2:
1580                                  * Networks with no captive portals may explicitly indicate this
1581                                  * condition by using this option with the IANA-assigned URI for
1582                                  * this purpose. Clients observing the URI value ... may forego
1583                                  * time-consuming forms of captive portal detection. */
1584                                 if (memcmp(odata, URN_IETF_CAPT_PORT_UNRESTR, ref_len)) {
1585                                         /* RFC8910 ยง2.2:
1586                                          * Note that the URI parameter is not null terminated.
1587                                          * Allocate new buffer including room for '\0' */
1588                                         size_t uri_len = olen + 1;
1589                                         uint8_t *copy = malloc(uri_len);
1590                                         if (!copy)
1591                                                 continue;
1592                                         memcpy(copy, odata, olen);
1593                                         copy[uri_len] = '\0';
1594                                         odhcp6c_add_state(STATE_CAPT_PORT_DHCPV6, odata, olen);
1595                                         free(copy);
1596                                 }
1597                                 break;
1598 
1599                         default:
1600                                 odhcp6c_add_state(STATE_CUSTOM_OPTS, &odata[-DHCPV6_OPT_HDR_SIZE], olen + DHCPV6_OPT_HDR_SIZE);
1601                                 break;
1602                         }
1603 
1604                         // Pass-through unless explicitly disabled, for every option
1605                         if (!dopt || !(dopt->flags & OPT_NO_PASSTHRU))
1606                                 odhcp6c_add_state(STATE_PASSTHRU, &odata[-DHCPV6_OPT_HDR_SIZE], olen + DHCPV6_OPT_HDR_SIZE);
1607                 }
1608         }
1609 
1610         // Bail out if fatal status code was received
1611         if (ret <= 0)
1612                 return ret;
1613 
1614         switch (orig) {
1615         case DHCPV6_MSG_REQUEST:
1616         case DHCPV6_MSG_REBIND:
1617         case DHCPV6_MSG_RENEW:
1618                 state_IAs = dhcpv6_calc_refresh_timers();
1619                 // In case there're no state IA entries
1620                 // keep sending request/renew/rebind messages
1621                 if (state_IAs == 0) {
1622                         ret = 0;
1623                         break;
1624                 }
1625 
1626                 switch (orig) {
1627                 case DHCPV6_MSG_REQUEST:
1628                         // All server candidates can be cleared if not yet bound
1629                         if (!odhcp6c_is_bound())
1630                                 dhcpv6_clear_all_server_cand();
1631 
1632                         odhcp6c_clear_state(STATE_SERVER_ADDR);
1633                         odhcp6c_add_state(STATE_SERVER_ADDR, &from->sin6_addr, sizeof(struct in6_addr));
1634                         break;
1635                 case DHCPV6_MSG_RENEW:
1636                         // Send further renews if T1 is not set and if
1637                         // there're IAs which were not in the Reply message
1638                         if (!t1 && state_IAs != updated_IAs) {
1639                                 if (updated_IAs)
1640                                         // Publish updates
1641                                         notify_state_change("updated", 0, false);
1642 
1643                                 /*
1644                                  * RFC8415 states following in ยง18.2.10.1 :
1645                                  * Sends a Renew/Rebind if any of the IAs are not in the Reply
1646                                  * message, but as this likely indicates that the server that
1647                                  * responded does not support that IA type, sending immediately is
1648                                  * unlikely to produce a different result.  Therefore, the client
1649                                  * MUST rate-limit its transmissions (see Section 14.1) and MAY just
1650                                  * wait for the normal retransmission time (as if the Reply message
1651                                  * had not been received).  The client continues to use other
1652                                  * bindings for which the server did return information
1653                                  */
1654                                 ret = -1;
1655                         }
1656                         break;
1657                 case DHCPV6_MSG_REBIND:
1658                         odhcp6c_clear_state(STATE_SERVER_ADDR);
1659                         odhcp6c_add_state(STATE_SERVER_ADDR, &from->sin6_addr, sizeof(struct in6_addr));
1660 
1661                         // Send further rebinds if T1 and T2 is not set and if
1662                         // there're IAs which were not in the Reply message
1663                         if (!t1 && !t2 && state_IAs != updated_IAs) {
1664                                 if (updated_IAs)
1665                                         // Publish updates
1666                                         notify_state_change("updated", 0, false);
1667 
1668                                 /*
1669                                  * RFC8415 states following in ยง18.2.10.1 :
1670                                  * Sends a Renew/Rebind if any of the IAs are not in the Reply
1671                                  * message, but as this likely indicates that the server that
1672                                  * responded does not support that IA type, sending immediately is
1673                                  * unlikely to produce a different result.  Therefore, the client
1674                                  * MUST rate-limit its transmissions (see Section 14.1) and MAY just
1675                                  * wait for the normal retransmission time (as if the Reply message
1676                                  * had not been received).  The client continues to use other
1677                                  * bindings for which the server did return information
1678                                  */
1679                                 ret = -1;
1680                         }
1681                         break;
1682 
1683                 default:
1684                         break;
1685                 }
1686                 break;
1687 
1688         case DHCPV6_MSG_INFO_REQ:
1689                 // All server candidates can be cleared if not yet bound
1690                 if (!odhcp6c_is_bound())
1691                         dhcpv6_clear_all_server_cand();
1692 
1693                 odhcp6c_clear_state(STATE_SERVER_ADDR);
1694                 odhcp6c_add_state(STATE_SERVER_ADDR, &from->sin6_addr, sizeof(struct in6_addr));
1695 
1696                 t1 = (refresh < config_dhcp->irt_min) ? config_dhcp->irt_min : refresh;
1697                 break;
1698 
1699         default:
1700                 break;
1701         }
1702 
1703         return ret;
1704 }
1705 
1706 static unsigned int dhcpv6_parse_ia(void *opt, void *end, int *ret)
1707 {
1708         struct dhcpv6_ia_hdr *ia_hdr = (struct dhcpv6_ia_hdr *)opt;
1709         unsigned int updated_IAs = 0;
1710         uint32_t t1, t2;
1711         uint16_t otype, olen;
1712         uint8_t *odata;
1713         char buf[INET6_ADDRSTRLEN];
1714 
1715         t1 = ntohl(ia_hdr->t1);
1716         t2 = ntohl(ia_hdr->t2);
1717 
1718         /* RFC 8415 ยง21.4
1719         If a client receives an IA_NA with T1 greater than T2 and both T1 and
1720         T2 are greater than 0, the client discards the IA_NA option and
1721         processes the remainder of the message as though the server had not
1722         included the invalid IA_NA option. */
1723         if (t1 > t2 && t1 > 0 && t2 > 0)
1724                 return 0;
1725 
1726         info("%s %04x T1 %d T2 %d", ntohs(ia_hdr->type) == DHCPV6_OPT_IA_PD ? "IA_PD" : "IA_NA", ntohl(ia_hdr->iaid), t1, t2);
1727 
1728         // Update address IA
1729         dhcpv6_for_each_option(&ia_hdr[1], end, otype, olen, odata) {
1730                 struct odhcp6c_entry entry = {
1731                         .router = IN6ADDR_ANY_INIT,
1732                         .auxlen = 0,
1733                         .length = 0,
1734                         .ra_flags = 0,
1735                         .exclusion_length = 0,
1736                         .target = IN6ADDR_ANY_INIT,
1737                         .priority = 0,
1738                         .valid = 0,
1739                         .preferred = 0,
1740                         .t1 = 0,
1741                         .t2 = 0,
1742                         .iaid = ia_hdr->iaid,
1743                 };
1744 
1745                 switch (otype) {
1746                 case DHCPV6_OPT_IA_PREFIX: {
1747                         struct dhcpv6_ia_prefix *prefix = (void*)&odata[-DHCPV6_OPT_HDR_SIZE];
1748                         if (olen + DHCPV6_OPT_HDR_SIZE_U < sizeof(*prefix))
1749                                 continue;
1750 
1751                         entry.valid = ntohl(prefix->valid);
1752                         entry.preferred = ntohl(prefix->preferred);
1753 
1754                         if (entry.preferred > entry.valid)
1755                                 continue;
1756 
1757                         /*      RFC 8415 ยง21.21
1758                         Recommended values for T1 and T2 are 0.5 and 0.8 times the
1759                         shortest preferred lifetime of the prefixes in the IA_PD that the
1760                         server is willing to extend. */
1761                         entry.t1 = (t1 ? t1 : (entry.preferred != UINT32_MAX ? 0.5 * entry.preferred : UINT32_MAX));
1762                         entry.t2 = (t2 ? t2 : (entry.preferred != UINT32_MAX ? 0.8 * entry.preferred : UINT32_MAX));
1763                         if (entry.t1 > entry.t2)
1764                                 entry.t1 = entry.t2;
1765 
1766                         entry.length = prefix->prefix;
1767                         entry.target = prefix->addr;
1768                         uint16_t stype, slen;
1769                         uint8_t *sdata;
1770 
1771                         // Parse sub-options for PD-exclude or error status code
1772                         bool update_state = true;
1773                         dhcpv6_for_each_option(odata + sizeof(*prefix) - DHCPV6_OPT_HDR_SIZE,
1774                                         odata + olen, stype, slen, sdata) {
1775                                 if (stype == DHCPV6_OPT_STATUS && slen >= 2) {
1776                                         /* RFC 8415 ยง21.22
1777                                         The status of any operations involving this IA Prefix option is
1778                                         indicated in a Status Code option (see Section 21.13) in the
1779                                         IAprefix-options field. */
1780                                         uint8_t *status_msg = (slen > 2) ? &sdata[2] : NULL;
1781                                         uint16_t msg_len = (slen > 2) ? slen - 2 : 0;
1782                                         uint16_t code = ((int)sdata[0]) << 8 | ((int)sdata[1]);
1783 
1784                                         if (code == DHCPV6_Success)
1785                                                 continue;
1786 
1787                                         dhcpv6_log_status_code(code, "IA_PREFIX", status_msg, msg_len);
1788                                         if (ret) *ret = 0; // renewal failed
1789                                 } else if (stype == DHCPV6_OPT_PD_EXCLUDE && slen > 2) {
1790                                         /*      RFC 6603 ยง4.2 Prefix Exclude option */
1791                                         uint8_t exclude_length = sdata[0];
1792                                         if (exclude_length > 64)
1793                                                 exclude_length = 64;
1794 
1795                                         if (entry.length < 32 || exclude_length <= entry.length) {
1796                                                 update_state = false;
1797                                                 continue;
1798                                         }
1799 
1800                                         uint8_t bytes_needed = ((exclude_length - entry.length - 1) / 8) + 1;
1801                                         if (slen <= bytes_needed) {
1802                                                 update_state = false;
1803                                                 continue;
1804                                         }
1805 
1806                                         // this decrements through the ipaddr bytes masking against 
1807                                         // the address in the option until byte 0, the option length field.
1808                                         uint32_t excluded_bits = 0;
1809                                         do {
1810                                                 excluded_bits = excluded_bits << 8 | sdata[bytes_needed];
1811                                         } while (--bytes_needed);
1812 
1813                                         excluded_bits >>= 8 - ((exclude_length - entry.length) % 8);
1814                                         excluded_bits <<= 64 - exclude_length;
1815 
1816                                         // Re-using router field to hold the prefix
1817                                         entry.router = entry.target; // base prefix
1818                                         entry.router.s6_addr32[1] |= htonl(excluded_bits);
1819                                         entry.exclusion_length = exclude_length;
1820                                 }
1821                         }
1822 
1823                         if (update_state) {
1824                                 if (odhcp6c_update_entry(STATE_IA_PD, &entry, 0))
1825                                         updated_IAs++;
1826 
1827                                 info("%s/%d preferred %d valid %d",
1828                                                 inet_ntop(AF_INET6, &entry.target, buf, sizeof(buf)),
1829                                                 entry.length, entry.preferred , entry.valid);
1830                         }
1831 
1832                         entry.priority = 0;
1833                         memset(&entry.router, 0, sizeof(entry.router));
1834                         break;
1835                 }
1836                 case DHCPV6_OPT_IA_ADDR: {
1837                         struct dhcpv6_ia_addr *addr = (void*)&odata[-DHCPV6_OPT_HDR_SIZE];
1838                         if (olen + DHCPV6_OPT_HDR_SIZE_U < sizeof(*addr))
1839                                 continue;
1840 
1841                         entry.preferred = ntohl(addr->preferred);
1842                         entry.valid = ntohl(addr->valid);
1843 
1844                         if (entry.preferred > entry.valid)
1845                                 continue;
1846 
1847                         entry.t1 = (t1 ? t1 : (entry.preferred != UINT32_MAX ? 0.5 * entry.preferred : UINT32_MAX));
1848                         entry.t2 = (t2 ? t2 : (entry.preferred != UINT32_MAX ? 0.8 * entry.preferred : UINT32_MAX));
1849                         if (entry.t1 > entry.t2)
1850                                 entry.t1 = entry.t2;
1851 
1852                         entry.length = 128;
1853                         entry.target = addr->addr;
1854                         uint16_t stype, slen;
1855                         uint8_t *sdata;
1856 
1857                         bool update_state = true;
1858                         dhcpv6_for_each_option(odata + sizeof(*addr) - DHCPV6_OPT_HDR_SIZE_U,
1859                                         odata + olen, stype, slen, sdata) {
1860                                 if (stype == DHCPV6_OPT_STATUS && slen >= 2) {
1861                                         /* RFC 8415 ยง21.6
1862                                         The status of any operations involving this IA Address is indicated
1863                                         in a Status Code option in the IAaddr-options field, as specified in
1864                                         Section 21.13. */
1865                                         uint8_t *status_msg = (slen > 2) ? &sdata[2] : NULL;
1866                                         uint16_t msg_len = (slen > 2) ? slen - 2 : 0;
1867                                         uint16_t code = ((int)sdata[0]) << 8 | ((int)sdata[1]);
1868 
1869                                         if (code == DHCPV6_Success)
1870                                                 continue;
1871 
1872                                         dhcpv6_log_status_code(code, "IA_ADDR", status_msg, msg_len);
1873                                         if (ret) *ret = 0; // renewal failed
1874                                         update_state = false;
1875                                 }
1876                         }
1877 
1878                         if (update_state) {
1879                                 if (odhcp6c_update_entry(STATE_IA_NA, &entry, 0))
1880                                         updated_IAs++;
1881 
1882                                 info("%s preferred %d valid %d",
1883                                                 inet_ntop(AF_INET6, &entry.target, buf, sizeof(buf)),
1884                                                 entry.preferred , entry.valid);
1885                         }
1886                         break;
1887                 }
1888                 default:
1889                         break;
1890                 }
1891         }
1892 
1893         return updated_IAs;
1894 }
1895 
1896 static unsigned int dhcpv6_calc_refresh_timers(void)
1897 {
1898         struct odhcp6c_entry *pd_entries;
1899         struct odhcp6c_entry *ia_entries;
1900         size_t ia_na_entry_cnt, ia_pd_entry_cnt, i;
1901         size_t invalid_entries = 0;
1902         int64_t l_t1 = UINT32_MAX, l_t2 = UINT32_MAX, l_t3 = 0;
1903 
1904         ia_entries = odhcp6c_get_state(STATE_IA_NA, &ia_na_entry_cnt);
1905         ia_na_entry_cnt /= sizeof(*ia_entries);
1906 
1907         for (i = 0; i < ia_na_entry_cnt; i++) {
1908                 /* Exclude invalid IA_NA entries */
1909                 if (!ia_entries[i].valid) {
1910                         invalid_entries++;
1911                         continue;
1912                 }
1913 
1914                 if (ia_entries[i].t1 < l_t1)
1915                         l_t1 = ia_entries[i].t1;
1916 
1917                 if (ia_entries[i].t2 < l_t2)
1918                         l_t2 = ia_entries[i].t2;
1919 
1920                 if (ia_entries[i].valid > l_t3)
1921                         l_t3 = ia_entries[i].valid;
1922         }
1923 
1924         pd_entries = odhcp6c_get_state(STATE_IA_PD, &ia_pd_entry_cnt);
1925         ia_pd_entry_cnt /= sizeof(*pd_entries);
1926 
1927         for (i = 0; i < ia_pd_entry_cnt; i++) {
1928                 /* Exclude invalid IA_PD entries */
1929                 if (!pd_entries[i].valid) {
1930                         invalid_entries++;
1931                         continue;
1932                 }
1933 
1934                 if (pd_entries[i].t1 < l_t1)
1935                         l_t1 = pd_entries[i].t1;
1936 
1937                 if (pd_entries[i].t2 < l_t2)
1938                         l_t2 = pd_entries[i].t2;
1939 
1940                 if (pd_entries[i].valid > l_t3)
1941                         l_t3 = pd_entries[i].valid;
1942         }
1943 
1944         if (ia_pd_entry_cnt + ia_na_entry_cnt - invalid_entries) {
1945                 t1 = l_t1;
1946                 t2 = l_t2;
1947                 t3 = l_t3;
1948 
1949                 info("T1 %"PRId64"s, T2 %"PRId64"s, T3 %"PRId64"s", t1, t2, t3);
1950         }
1951 
1952         return (unsigned int)(ia_pd_entry_cnt + ia_na_entry_cnt);
1953 }
1954 
1955 static void dhcpv6_log_status_code(const uint16_t code, const char *scope,
1956                 const void *status_msg, int len)
1957 {
1958         const char *src = status_msg;
1959         char buf[len + 3];
1960         char *dst = buf;
1961 
1962         if (len) {
1963                 *dst++ = '(';
1964                 while (len--) {
1965                         *dst = isprint((unsigned char)*src) ? *src : '?';
1966                         src++;
1967                         dst++;
1968                 }
1969                 *dst++ = ')';
1970         }
1971 
1972         *dst = 0;
1973 
1974         warn("Server returned %s status '%s %s'",
1975                 scope, dhcpv6_status_code_to_str(code), buf);
1976 }
1977 
1978 static void dhcpv6_handle_status_code(const enum dhcpv6_msg orig,
1979                 const uint16_t code, const void *status_msg, const int len,
1980                 int *ret)
1981 {
1982         dhcpv6_log_status_code(code, "message", status_msg, len);
1983 
1984         switch (code) {
1985         case DHCPV6_UnspecFail:
1986                 // Generic failure
1987                 *ret = 0;
1988                 break;
1989 
1990         case DHCPV6_UseMulticast:
1991                 switch(orig) {
1992                 case DHCPV6_MSG_REQUEST:
1993                 case DHCPV6_MSG_RENEW:
1994                 case DHCPV6_MSG_RELEASE:
1995                 case DHCPV6_MSG_DECLINE:
1996                         // Message needs to be retransmitted according to RFC3315 chapter 18.1.8
1997                         server_addr = in6addr_any;
1998                         *ret = 0;
1999                         break;
2000                 default:
2001                         break;
2002                 }
2003                 break;
2004 
2005         case DHCPV6_NoAddrsAvail:
2006         case DHCPV6_NoPrefixAvail:
2007                 if (orig == DHCPV6_MSG_REQUEST)
2008                         *ret = 0; // Failure
2009                 break;
2010 
2011         default:
2012                 break;
2013         }
2014 }
2015 
2016 static void dhcpv6_handle_ia_status_code(const enum dhcpv6_msg orig,
2017                 const struct dhcpv6_ia_hdr *ia_hdr, const uint16_t code,
2018                 const void *status_msg, const int len,
2019                 bool handled_status_codes[_DHCPV6_Status_Max], int *ret)
2020 {
2021         dhcpv6_log_status_code(code, ntohs(ia_hdr->type) == DHCPV6_OPT_IA_NA ?
2022                 "IA_NA" : "IA_PD", status_msg, len);
2023 
2024         switch (code) {
2025         case DHCPV6_NoBinding:
2026                 switch (orig) {
2027                 case DHCPV6_MSG_RENEW:
2028                 case DHCPV6_MSG_REBIND:
2029                         if ((*ret > 0) && !handled_status_codes[code]) {
2030                                 dhcpv6_set_state(DHCPV6_REQUEST);
2031                                 *ret = -1;
2032                         }
2033                         break;
2034 
2035                 default:
2036                         *ret = 0;
2037                         break;
2038                 }
2039                 break;
2040 
2041         case DHCPV6_NoAddrsAvail:
2042         case DHCPV6_NoPrefixAvail:
2043                 break;
2044 
2045         default:
2046                 *ret = 0;
2047                 break;
2048         }
2049 }
2050 
2051 // Note this always takes ownership of cand->ia_na and cand->ia_pd
2052 static void dhcpv6_add_server_cand(const struct dhcpv6_server_cand *cand)
2053 {
2054         size_t cand_len, i;
2055         struct dhcpv6_server_cand *srv_candidates = odhcp6c_get_state(STATE_SERVER_CAND, &cand_len);
2056 
2057         // Remove identical DUID server candidate
2058         for (i = 0; i < cand_len / sizeof(*srv_candidates); ++i) {
2059                 if (cand->duid_len == srv_candidates[i].duid_len &&
2060                                 !memcmp(cand->duid, srv_candidates[i].duid, cand->duid_len)) {
2061                         free(srv_candidates[i].ia_na);
2062                         free(srv_candidates[i].ia_pd);
2063                         odhcp6c_remove_state(STATE_SERVER_CAND, i * sizeof(*srv_candidates), sizeof(*srv_candidates));
2064                         break;
2065                 }
2066         }
2067 
2068         for (i = 0, srv_candidates = odhcp6c_get_state(STATE_SERVER_CAND, &cand_len);
2069                 i < cand_len / sizeof(*srv_candidates); ++i) {
2070                 if (srv_candidates[i].preference < cand->preference)
2071                         break;
2072         }
2073 
2074         if (odhcp6c_insert_state(STATE_SERVER_CAND, i * sizeof(*srv_candidates), cand, sizeof(*cand))) {
2075                 free(cand->ia_na);
2076                 free(cand->ia_pd);
2077         }
2078 }
2079 
2080 static void dhcpv6_clear_all_server_cand(void)
2081 {
2082         size_t cand_len, i;
2083         struct dhcpv6_server_cand *srv_candidates = odhcp6c_get_state(STATE_SERVER_CAND, &cand_len);
2084 
2085         // Server candidates need deep delete for IA_NA/IA_PD
2086         for (i = 0; i < cand_len / sizeof(*srv_candidates); ++i) {
2087                 free(srv_candidates[i].ia_na);
2088                 free(srv_candidates[i].ia_pd);
2089         }
2090         odhcp6c_clear_state(STATE_SERVER_CAND);
2091 }
2092 
2093 int dhcpv6_promote_server_cand(void)
2094 {
2095         size_t cand_len;
2096         struct dhcpv6_server_cand *cand = odhcp6c_get_state(STATE_SERVER_CAND, &cand_len);
2097         uint16_t hdr[2];
2098         int ret = DHCPV6_STATELESS;
2099 
2100         // Clear lingering candidate state info
2101         odhcp6c_clear_state(STATE_SERVER_ID);
2102         odhcp6c_clear_state(STATE_IA_NA);
2103         odhcp6c_clear_state(STATE_IA_PD);
2104 
2105         if (!cand_len)
2106                 return -1;
2107 
2108         if (!cand->ia_pd_len && cand->has_noaddravail) {
2109                 bool override = false;
2110 
2111                 if (na_mode == IA_MODE_TRY) {
2112                         na_mode = IA_MODE_NONE;
2113                         override = true;
2114                 }
2115 
2116                 if (pd_mode == IA_MODE_TRY) {
2117                         pd_mode = IA_MODE_NONE;
2118                         override = true;
2119                 }
2120 
2121                 if (override) {
2122                         dhcpv6_retx[DHCPV6_MSG_SOLICIT].max_timeo = cand->sol_max_rt;
2123                         dhcpv6_retx[DHCPV6_MSG_INFO_REQ].max_timeo = cand->inf_max_rt;
2124 
2125                         return -1;
2126                 }
2127         }
2128 
2129         hdr[0] = htons(DHCPV6_OPT_SERVERID);
2130         hdr[1] = htons(cand->duid_len);
2131         odhcp6c_add_state(STATE_SERVER_ID, hdr, sizeof(hdr));
2132         odhcp6c_add_state(STATE_SERVER_ID, cand->duid, cand->duid_len);
2133         accept_reconfig = cand->wants_reconfigure;
2134         memset(reconf_key, 0, sizeof(reconf_key));
2135 
2136         if (cand->ia_na_len) {
2137                 odhcp6c_add_state(STATE_IA_NA, cand->ia_na, cand->ia_na_len);
2138                 free(cand->ia_na);
2139                 if (na_mode != IA_MODE_NONE)
2140                         ret = DHCPV6_STATEFUL;
2141         }
2142 
2143         if (cand->ia_pd_len) {
2144                 odhcp6c_add_state(STATE_IA_PD, cand->ia_pd, cand->ia_pd_len);
2145                 free(cand->ia_pd);
2146                 if (pd_mode != IA_MODE_NONE)
2147                         ret = DHCPV6_STATEFUL;
2148         }
2149 
2150         dhcpv6_retx[DHCPV6_MSG_SOLICIT].max_timeo = cand->sol_max_rt;
2151         dhcpv6_retx[DHCPV6_MSG_INFO_REQ].max_timeo = cand->inf_max_rt;
2152 
2153         odhcp6c_remove_state(STATE_SERVER_CAND, 0, sizeof(*cand));
2154 
2155         return ret;
2156 }
2157 
2158 int dhcpv6_send_request(enum dhcpv6_msg req_msg_type)
2159 {
2160         struct dhcpv6_retx *retx = &dhcpv6_retx[req_msg_type];
2161         uint64_t current_milli_time = 0;
2162 
2163         if (!retx->is_retransmit) {
2164                 // Initial delay handling
2165                 if (retx->max_delay) {
2166                         if (retx->delay_msec == 0) {
2167                                 // Initial delay before starting the transaction
2168                                 retx->delay_msec = (dhcpv6_rand_delay((10000 * retx->max_delay) / 2) + (1000 * retx->max_delay) / 2);
2169                                 dhcpv6_set_state_timeout(retx->delay_msec);
2170                                 // Add current time to calculate absolute time
2171                                 retx->delay_msec += odhcp6c_get_milli_time();
2172                                 return 1;
2173                         } else {
2174                                 // Wait until delay expires
2175                                 current_milli_time = odhcp6c_get_milli_time();
2176                                 if (current_milli_time < retx->delay_msec) {
2177                                         // Still waiting
2178                                         dhcpv6_set_state_timeout(retx->delay_msec - current_milli_time);
2179                                         return 1;
2180                                 }
2181                                 retx->delay_msec = 0;
2182                         }
2183                 }
2184 
2185                 retx->is_retransmit = true;
2186                 retx->rc = 0;
2187                 retx->timeout = UINT32_MAX;
2188                 retx->reply_ret = -1;
2189 
2190                 if (req_msg_type == DHCPV6_MSG_UNKNOWN)
2191                         retx->timeout = t1;
2192                 else if (req_msg_type == DHCPV6_MSG_RENEW)
2193                         retx->timeout = (t2 > t1) ? t2 - t1 : ((t1 == UINT32_MAX) ? UINT32_MAX : 0);
2194                 else if (req_msg_type == DHCPV6_MSG_REBIND)
2195                         retx->timeout = (t3 > t2) ? t3 - t2 : ((t2 == UINT32_MAX) ? UINT32_MAX : 0);
2196 
2197                 if (retx->timeout == 0)
2198                         return -1;
2199 
2200                 notice("Starting %s transaction (timeout %"PRIu64"s, max rc %d)",
2201                         retx->name, retx->timeout, retx->max_rc);
2202 
2203                 // Generate transaction ID
2204                 if (req_msg_type != DHCPV6_MSG_UNKNOWN) {
2205                         odhcp6c_random(retx->tr_id, sizeof(retx->tr_id));
2206                 }
2207 
2208                 // Record start time
2209                 retx->start = odhcp6c_get_milli_time();
2210                 retx->round_start = retx->start;
2211                 // Reset retransmission timeout initial value
2212                 retx->rto = 0;
2213         }
2214 
2215         if (retx->rto == 0) {
2216                 int64_t delay = dhcpv6_rand_delay(retx->init_timeo * 1000);
2217 
2218                 // First RT MUST be strictly greater than IRT for solicit messages (RFC3313 17.1.2)
2219                 while (req_msg_type == DHCPV6_MSG_SOLICIT && delay <= 0)
2220                         delay = dhcpv6_rand_delay(retx->init_timeo * 1000);
2221 
2222                 // First timeout
2223                 retx->rto = (retx->init_timeo * 1000 + delay);
2224         } else {
2225                 // Exponential back-off with randomization to avoid synchronization
2226                 retx->rto = (2 * retx->rto + dhcpv6_rand_delay(retx->rto));
2227         }
2228 
2229         if (retx->max_timeo && (retx->rto >= retx->max_timeo * 1000)) {
2230                 // Cap to max timeout if set and exceeded
2231                 retx->rto = retx->max_timeo * 1000 +
2232                         dhcpv6_rand_delay(retx->max_timeo * 1000);
2233         }
2234 
2235         // Calculate end for this round and elapsed time
2236         retx->round_end = retx->round_start + retx->rto;
2237         uint64_t elapsed = retx->round_start - retx->start;
2238 
2239         // Don't wait too long if timeout differs from infinite
2240         if ((retx->timeout != UINT32_MAX) && (retx->round_end - retx->start > retx->timeout * 1000))
2241                 retx->round_end = retx->timeout * 1000 + retx->start;
2242 
2243         dhcpv6_set_state_timeout(retx->round_end - odhcp6c_get_milli_time());
2244 
2245         // Built and send package
2246         switch (req_msg_type) {
2247         case DHCPV6_MSG_UNKNOWN:
2248                 break;
2249         default:
2250                 notice("Send %s message (elapsed %"PRIu64"ms, rc %d)",
2251                                 retx->name, elapsed, retx->rc);
2252                 _o_fallthrough;
2253         case DHCPV6_MSG_SOLICIT:
2254         case DHCPV6_MSG_INFO_REQ:
2255                 dhcpv6_send(req_msg_type, retx->tr_id, elapsed / 10);
2256                 retx->rc++;
2257         }
2258 
2259         if (dhcpv6_get_state() != DHCPV6_EXIT)
2260                 dhcpv6_next_state();
2261 
2262         return 0;
2263 }
2264 
2265 int dhcpv6_receive_response(enum dhcpv6_msg req_msg_type)
2266 {
2267         ssize_t len = -1;
2268         struct dhcpv6_retx *retx = &dhcpv6_retx[req_msg_type];
2269 
2270         uint8_t buf[1536];
2271         union {
2272                 struct cmsghdr hdr;
2273                 uint8_t buf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
2274         } cmsg_buf;
2275 
2276         struct iovec iov = {buf, sizeof(buf)};
2277         struct sockaddr_in6 addr;
2278         struct msghdr msg = {.msg_name = &addr, .msg_namelen = sizeof(addr),
2279                         .msg_iov = &iov, .msg_iovlen = 1, .msg_control = cmsg_buf.buf,
2280                         .msg_controllen = sizeof(cmsg_buf)};
2281         struct in6_pktinfo *pktinfo = NULL;
2282         const struct dhcpv6_header *hdr = (const struct dhcpv6_header *)buf;
2283 
2284         // Receive cycle
2285         len = recvmsg(sock, &msg, 0);
2286         if (len < 0) {
2287                 error("Error occurred when reading the response of (%s) error(%s)",
2288                         retx->name, strerror(errno));
2289                 return -1;
2290         }
2291 
2292         for (struct cmsghdr *ch = CMSG_FIRSTHDR(&msg); ch != NULL;
2293                 ch = CMSG_NXTHDR(&msg, ch)) {
2294                 if (ch->cmsg_level == SOL_IPV6 &&
2295                         ch->cmsg_type == IPV6_PKTINFO) {
2296                         pktinfo = (struct in6_pktinfo *)CMSG_DATA(ch);
2297                         break;
2298                 }
2299         }
2300 
2301         if (pktinfo == NULL) {
2302                 dhcpv6_stats.discarded_packets++;
2303                 return -1;
2304         }
2305 
2306         if (!dhcpv6_response_is_valid(buf, len, retx->tr_id, req_msg_type,
2307                                          &pktinfo->ipi6_addr)) {
2308                 dhcpv6_stats.discarded_packets++;
2309                 return -1;
2310         }
2311 
2312         dhcpv6_inc_counter(hdr->msg_type);
2313 
2314         uint8_t *opt = &buf[4];
2315         uint8_t *opt_end = opt + len - DHCPV6_OPT_HDR_SIZE;
2316         retx->round_start = odhcp6c_get_milli_time();
2317         uint64_t elapsed = retx->round_start - retx->start;
2318 
2319         notice("Got a valid %s after %"PRIu64"ms",
2320                 dhcpv6_msg_to_str(hdr->msg_type), elapsed);
2321 
2322         if (retx->handler_reply) {
2323                 retx->reply_ret = retx->handler_reply(req_msg_type, retx->rc, opt, opt_end, &addr);
2324                 len = retx->reply_ret;
2325         }
2326 
2327         // Clamp round end (Round Trip Time) to 1s max wait after receiving a valid response (in milliseconds)
2328         if (len > 0 && retx->round_end - retx->round_start > 1000)
2329                 retx->round_end = 1000 + retx->round_start;
2330 
2331         return retx->reply_ret;
2332 }
2333 
2334 int dhcpv6_state_processing(enum dhcpv6_msg req_msg_type)
2335 {
2336         struct dhcpv6_retx *retx = &dhcpv6_retx[req_msg_type];
2337         int ret = retx->reply_ret;
2338         retx->round_start = odhcp6c_get_milli_time();
2339         uint64_t elapsed = retx->round_start - retx->start;
2340 
2341         if (retx->round_start >= retx->round_end || ret >=0 ) {
2342                 if (retx->handler_finish)
2343                         ret = retx->handler_finish();
2344 
2345                 if (ret < 0 && ((retx->timeout == UINT32_MAX) || (elapsed / 1000 < retx->timeout)) &&
2346                         (!retx->max_rc || retx->rc < retx->max_rc)) {
2347                                 retx->reply_ret = -1;
2348                                 dhcpv6_prev_state();
2349                 } else {
2350                         retx->is_retransmit = false;
2351                         dhcpv6_next_state();
2352                 }
2353         } else {
2354                 // This sets the response polling timeout (round_end - round_start) in milliseconds
2355                 dhcpv6_set_state_timeout(retx->round_end - retx->round_start);
2356         }
2357 
2358         return ret;
2359 }
2360 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt