• 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 (na_mode == IA_MODE_NONE) {
961                 iov[IOV_HDR_IA_NA].iov_len = 0;
962         } else if (ia_na_len == 0) {
963                 /* RFC7550 ยง4.2
964                  *    Solution: a client SHOULD accept Advertise messages, even
965                  *    when not all IA option types are being offered. And, in
966                  *    this case, the client SHOULD include the not offered IA
967                  *    option types in its Request. A client SHOULD only ignore
968                  *    an Advertise message when none of the requested IA
969                  *    options include offered addresses or delegated prefixes.
970                  *    Note that ignored messages MUST still be processed for
971                  *    SOL_MAX_RT and INF_MAX_RT options as specified in
972                  *    [RFC7083].
973                  */
974 
975                 switch (req_msg_type) {
976                 case DHCPV6_MSG_REQUEST:
977                         /* Some broken ISPs won't behave properly if IA_NA is
978                          * sent on Requests when they have provided an empty
979                          * IA_NA on Advertise.
980                          * Therefore we don't comply with RFC7550 and omit
981                          * IA_NA as a workaround.
982                          */
983                         iov[IOV_HDR_IA_NA].iov_len = 0;
984                         break;
985                 case DHCPV6_MSG_SOLICIT:
986                         break;
987                 default:
988                         iov[IOV_HDR_IA_NA].iov_len = 0;
989                         break;
990                 }
991         }
992 
993         if ((req_msg_type != DHCPV6_MSG_SOLICIT && req_msg_type != DHCPV6_MSG_REQUEST) ||
994                         !(client_options & DHCPV6_ACCEPT_RECONFIGURE))
995                 iov[IOV_RECONF_ACCEPT].iov_len = 0;
996 
997         if (!(client_options & DHCPV6_CLIENT_FQDN)) {
998                 iov[IOV_FQDN].iov_len = 0;
999         } else {
1000                 switch (req_msg_type) {
1001                 /*  RFC4704 ยง5
1002                         A client MUST only include the Client FQDN option in SOLICIT,
1003                         REQUEST, RENEW, or REBIND messages.
1004                 */
1005                 case DHCPV6_MSG_SOLICIT:
1006                 case DHCPV6_MSG_REQUEST:
1007                 case DHCPV6_MSG_RENEW:
1008                 case DHCPV6_MSG_REBIND:
1009                 /*  RFC4704 ยง6
1010                         Servers MUST only include a Client FQDN option in ADVERTISE and REPLY
1011                         messages...
1012                 case DHCPV6_MSG_ADVERT:
1013                 case DHCPV6_MSG_REPLY:
1014                 */
1015                         /* leave FQDN as-is */
1016                         break;
1017                 default:
1018                         /* remaining MSG types cannot contain client FQDN */
1019                         iov[IOV_FQDN].iov_len = 0;
1020                         break;
1021                 }
1022         }
1023 
1024         struct sockaddr_in6 srv = {AF_INET6, htons(DHCPV6_SERVER_PORT),
1025                 0, ALL_DHCPV6_RELAYS, ifindex};
1026         struct msghdr msg = {.msg_name = &srv, .msg_namelen = sizeof(srv),
1027                         .msg_iov = iov, .msg_iovlen = cnt};
1028 
1029         switch (req_msg_type) {
1030         case DHCPV6_MSG_REQUEST:
1031         case DHCPV6_MSG_RENEW:
1032         case DHCPV6_MSG_RELEASE:
1033         case DHCPV6_MSG_DECLINE:
1034                 if (!IN6_IS_ADDR_UNSPECIFIED(&server_addr) &&
1035                         odhcp6c_addr_in_scope(&server_addr)) {
1036                         srv.sin6_addr = server_addr;
1037                         if (!IN6_IS_ADDR_LINKLOCAL(&server_addr))
1038                                 srv.sin6_scope_id = 0;
1039                 }
1040                 break;
1041         default:
1042                 break;
1043         }
1044 
1045         if (sendmsg(sock, &msg, 0) < 0) {
1046                 char in6_str[INET6_ADDRSTRLEN];
1047 
1048                 error("Failed to send %s message to %s (%s)",
1049                         dhcpv6_msg_to_str(req_msg_type),
1050                         inet_ntop(AF_INET6, (const void *)&srv.sin6_addr,
1051                                 in6_str, sizeof(in6_str)), strerror(errno));
1052                 dhcpv6_stats.transmit_failures++;
1053         } else {
1054                 dhcpv6_inc_counter(req_msg_type);
1055         }
1056 }
1057 
1058 static int64_t dhcpv6_rand_delay(int64_t time)
1059 {
1060         int random;
1061         odhcp6c_random(&random, sizeof(random));
1062 
1063         return (time * ((int64_t)random % (config_dhcp->rand_factor*10LL))) / 10000LL;
1064 }
1065 
1066 // Message validation checks according to RFC3315 chapter 15
1067 static bool dhcpv6_response_is_valid(const void *buf, ssize_t len,
1068                 const uint8_t transaction[3], enum dhcpv6_msg req_msg_type,
1069                 const struct in6_addr *daddr)
1070 {
1071         const struct dhcpv6_header *response_buf = buf;
1072         if (len < (ssize_t)sizeof(*response_buf) || memcmp(response_buf->tr_id,
1073                         transaction, sizeof(response_buf->tr_id)))
1074                 return false; // Invalid reply
1075 
1076         if (req_msg_type == DHCPV6_MSG_SOLICIT) {
1077                 if (response_buf->msg_type != DHCPV6_MSG_ADVERT &&
1078                                 response_buf->msg_type != DHCPV6_MSG_REPLY)
1079                         return false;
1080         } else if (req_msg_type == DHCPV6_MSG_UNKNOWN) {
1081                 if (!accept_reconfig || response_buf->msg_type != DHCPV6_MSG_RECONF)
1082                         return false;
1083         } else if (response_buf->msg_type != DHCPV6_MSG_REPLY) {
1084                 return false;
1085         }
1086 
1087         uint8_t *end = ((uint8_t*)buf) + len, *odata = NULL,
1088                 rcmsg = DHCPV6_MSG_UNKNOWN;
1089         uint16_t otype, olen = UINT16_MAX;
1090         bool clientid_ok = false, serverid_ok = false, rcauth_ok = false,
1091                 auth_present = false, ia_present = false, options_valid = true;
1092 
1093         size_t client_id_len, server_id_len;
1094         void *client_id = odhcp6c_get_state(STATE_CLIENT_ID, &client_id_len);
1095         void *server_id = odhcp6c_get_state(STATE_SERVER_ID, &server_id_len);
1096 
1097         dhcpv6_for_each_option(&response_buf[1], end, otype, olen, odata) {
1098                 switch (otype) {
1099                 case DHCPV6_OPT_CLIENTID:
1100                         clientid_ok = (olen + DHCPV6_OPT_HDR_SIZE_U == client_id_len) && !memcmp(
1101                                         &odata[-DHCPV6_OPT_HDR_SIZE], client_id, client_id_len);                        
1102                         break;
1103 
1104                 case DHCPV6_OPT_SERVERID:
1105                         if (server_id_len)
1106                                 serverid_ok = (olen + DHCPV6_OPT_HDR_SIZE_U == server_id_len) && !memcmp(
1107                                                 &odata[-DHCPV6_OPT_HDR_SIZE], server_id, server_id_len);
1108                         else
1109                                 serverid_ok = true;
1110                         break;
1111 
1112                 case DHCPV6_OPT_AUTH:
1113                         struct dhcpv6_auth *r = (void*)&odata[-DHCPV6_OPT_HDR_SIZE];
1114                         if (auth_present) {
1115                                 options_valid = false;
1116                                 continue;
1117                         }
1118 
1119                         auth_present = true;
1120                         if (auth_protocol == AUTH_PROT_RKAP) {
1121                                 struct dhcpv6_auth_reconfigure *rkap = (void*)r->data;
1122                                 if (r->protocol != AUTH_PROT_RKAP || r->algorithm != AUTH_ALG_HMACMD5 || r->len != 28 || rkap->reconf_type != RKAP_TYPE_HMACMD5)
1123                                         continue;
1124 
1125                                 md5_ctx_t md5;
1126                                 uint8_t serverhash[16], secretbytes[64];
1127                                 uint32_t hash[4];
1128                                 memcpy(serverhash, rkap->key, sizeof(serverhash));
1129                                 memset(rkap->key, 0, sizeof(rkap->key));
1130 
1131                                 memset(secretbytes, 0, sizeof(secretbytes));
1132                                 memcpy(secretbytes, reconf_key, sizeof(reconf_key));
1133 
1134                                 for (size_t i = 0; i < sizeof(secretbytes); ++i)
1135                                         secretbytes[i] ^= 0x36;
1136 
1137                                 md5_begin(&md5);
1138                                 md5_hash(secretbytes, sizeof(secretbytes), &md5);
1139                                 md5_hash(buf, len, &md5);
1140                                 md5_end(hash, &md5);
1141 
1142                                 for (size_t i = 0; i < sizeof(secretbytes); ++i) {
1143                                         secretbytes[i] ^= 0x36;
1144                                         secretbytes[i] ^= 0x5c;
1145                                 }
1146 
1147                                 md5_begin(&md5);
1148                                 md5_hash(secretbytes, sizeof(secretbytes), &md5);
1149                                 md5_hash(hash, 16, &md5);
1150                                 md5_end(hash, &md5);
1151 
1152                                 rcauth_ok = !memcmp(hash, serverhash, sizeof(hash));
1153                         } else if (auth_protocol == AUTH_PROT_TOKEN) {
1154                                 if (r->protocol != AUTH_PROT_TOKEN || r->algorithm != AUTH_ALG_TOKEN || r->len < 12)
1155                                         continue;
1156 
1157                                 uint16_t token_len = r->len - 11;
1158                                 if (config_dhcp->auth_token == NULL || strlen(config_dhcp->auth_token) != token_len)
1159                                         continue;
1160 
1161                                 rcauth_ok = !memcmp(r->data, config_dhcp->auth_token, token_len);
1162                         }
1163                         break;
1164                 case DHCPV6_OPT_RECONF_MESSAGE:
1165                         if (olen != 1)
1166                                 return false;
1167                         rcmsg = odata[0];
1168                         break;
1169 
1170                 case DHCPV6_OPT_IA_PD:
1171                 case DHCPV6_OPT_IA_NA:
1172                         ia_present = true;
1173                         if (olen < sizeof(struct dhcpv6_ia_hdr) - DHCPV6_OPT_HDR_SIZE)
1174                                 options_valid = false;
1175                         break;
1176 
1177                 case DHCPV6_OPT_IA_ADDR:
1178                 case DHCPV6_OPT_IA_PREFIX:
1179                 case DHCPV6_OPT_PD_EXCLUDE:
1180                         // Options are not allowed on global level
1181                         options_valid = false;
1182                         break;
1183 
1184                 default:
1185                         break;
1186                 }
1187         }
1188 
1189         if (!options_valid || ((odata + olen) > end))
1190                 return false;
1191 
1192         if (req_msg_type == DHCPV6_MSG_INFO_REQ && ia_present)
1193                 return false;
1194 
1195         if (response_buf->msg_type == DHCPV6_MSG_RECONF) {
1196                 if ((rcmsg != DHCPV6_MSG_RENEW && rcmsg != DHCPV6_MSG_REBIND && rcmsg != DHCPV6_MSG_INFO_REQ) ||
1197                         (rcmsg == DHCPV6_MSG_INFO_REQ && ia_present) ||
1198                         !rcauth_ok || IN6_IS_ADDR_MULTICAST(daddr))
1199                         return false;
1200         }
1201 
1202         return clientid_ok && serverid_ok;
1203 }
1204 
1205 static int dhcpv6_handle_reconfigure(enum dhcpv6_msg orig, const int rc,
1206                 const void *opt, const void *end, _o_unused const struct sockaddr_in6 *from)
1207 {
1208         uint16_t otype, olen;
1209         uint8_t *odata;
1210         enum dhcpv6_msg msg = DHCPV6_MSG_UNKNOWN;
1211 
1212         dhcpv6_for_each_option(opt, end, otype, olen, odata) {
1213                 if (otype == DHCPV6_OPT_RECONF_MESSAGE && olen == 1) {
1214                         switch (odata[0]) {
1215                         case DHCPV6_MSG_REBIND:
1216                                 if (t2 != UINT32_MAX)
1217                                         t2 = 0;
1218                                 _o_fallthrough;
1219                         case DHCPV6_MSG_RENEW:
1220                                 if (t1 != UINT32_MAX)
1221                                         t1 = 0;
1222                                 _o_fallthrough;
1223                         case DHCPV6_MSG_INFO_REQ:
1224                                 msg = odata[0];
1225                                 notice("Need to respond with %s in reply to %s",
1226                                        dhcpv6_msg_to_str(msg), dhcpv6_msg_to_str(DHCPV6_MSG_RECONF));
1227                                 break;
1228 
1229                         default:
1230                                 break;
1231                         }
1232                 }
1233         }
1234 
1235         if (msg != DHCPV6_MSG_UNKNOWN)
1236                 dhcpv6_handle_reply(orig, rc, NULL, NULL, NULL);
1237 
1238         return (msg == DHCPV6_MSG_UNKNOWN? -1: (int)msg);
1239 }
1240 
1241 // Collect all advertised servers
1242 static int dhcpv6_handle_advert(enum dhcpv6_msg orig, const int rc,
1243                 const void *opt, const void *end, _o_unused const struct sockaddr_in6 *from)
1244 {
1245         uint16_t olen, otype;
1246         uint8_t *odata, pref = 0;
1247         struct dhcpv6_server_cand cand = {false, false, 0, 0, {0},
1248                                         IN6ADDR_ANY_INIT, DHCPV6_SOL_MAX_RT,
1249                                         DHCPV6_INF_MAX_RT, NULL, NULL, 0, 0};
1250         bool have_na = false;
1251         int have_pd = 0;
1252 
1253         dhcpv6_for_each_option(opt, end, otype, olen, odata) {
1254                 if (orig == DHCPV6_MSG_SOLICIT &&
1255                                 ((otype == DHCPV6_OPT_IA_PD && pd_mode != IA_MODE_NONE) ||
1256                                  (otype == DHCPV6_OPT_IA_NA && na_mode != IA_MODE_NONE)) &&
1257                                 olen > sizeof(struct dhcpv6_ia_hdr) - DHCPV6_OPT_HDR_SIZE) {
1258                         struct dhcpv6_ia_hdr *ia_hdr = (void*)(&odata[-DHCPV6_OPT_HDR_SIZE]);
1259                         dhcpv6_parse_ia(ia_hdr, odata + olen + sizeof(*ia_hdr), NULL);
1260                 }
1261 
1262                 switch (otype) {
1263                 case DHCPV6_OPT_SERVERID:
1264                         if (olen <= DHCPV6_DUID_MAX_LEN) {
1265                                 memcpy(cand.duid, odata, olen);
1266                                 cand.duid_len = olen;
1267                         }
1268                         break;
1269 
1270                 case DHCPV6_OPT_PREF:
1271                         if (olen >= 1 && cand.preference >= 0)
1272                                 cand.preference = pref = odata[0];
1273                         break;
1274 
1275                 case DHCPV6_OPT_UNICAST:
1276                         if (olen == sizeof(cand.server_addr) &&
1277                             !(client_options & DHCPV6_IGNORE_OPT_UNICAST))
1278                                 cand.server_addr = *(struct in6_addr *)odata;
1279                         break;
1280 
1281                 case DHCPV6_OPT_RECONF_ACCEPT:
1282                         cand.wants_reconfigure = true;
1283                         break;
1284 
1285                 case DHCPV6_OPT_SOL_MAX_RT:
1286                         if (olen == 4) {
1287                                 uint32_t sol_max_rt = ntohl_unaligned(odata);
1288                                 if (sol_max_rt >= DHCPV6_SOL_MAX_RT_MIN &&
1289                                     sol_max_rt <= DHCPV6_SOL_MAX_RT_MAX)
1290                                         cand.sol_max_rt = sol_max_rt;
1291                         }
1292                         break;
1293 
1294                 case DHCPV6_OPT_INF_MAX_RT:
1295                         if (olen == 4) {
1296                                 uint32_t inf_max_rt = ntohl_unaligned(odata);
1297                                 if (inf_max_rt >= DHCPV6_INF_MAX_RT_MIN &&
1298                                     inf_max_rt <= DHCPV6_INF_MAX_RT_MAX)
1299                                         cand.inf_max_rt = inf_max_rt;
1300                         }
1301                         break;
1302 
1303                 case DHCPV6_OPT_IA_PD:
1304                         if (olen >= sizeof(struct dhcpv6_ia_hdr) - DHCPV6_OPT_HDR_SIZE) {
1305                                 struct dhcpv6_ia_hdr *h = (struct dhcpv6_ia_hdr *)&odata[-DHCPV6_OPT_HDR_SIZE];
1306                                 uint8_t *oend = odata + olen, *d;
1307 
1308                                 dhcpv6_for_each_option(&h[1], oend, otype, olen, d) {
1309                                         if (otype == DHCPV6_OPT_IA_PREFIX &&
1310                                             olen >= sizeof(struct dhcpv6_ia_prefix) - DHCPV6_OPT_HDR_SIZE) {
1311                                                 struct dhcpv6_ia_prefix *p =
1312                                                         (struct dhcpv6_ia_prefix *)&d[-DHCPV6_OPT_HDR_SIZE];
1313                                                 have_pd = p->prefix;
1314                                         }
1315                                 }
1316                         }
1317                         break;
1318 
1319                 case DHCPV6_OPT_IA_NA:
1320                         if (olen >= sizeof(struct dhcpv6_ia_hdr) - DHCPV6_OPT_HDR_SIZE) {
1321                                 struct dhcpv6_ia_hdr *h = (struct dhcpv6_ia_hdr *)&odata[-DHCPV6_OPT_HDR_SIZE];
1322                                 uint8_t *oend = odata + olen, *d;
1323 
1324                                 dhcpv6_for_each_option(&h[1], oend, otype, olen, d) {
1325                                         if (otype == DHCPV6_OPT_IA_ADDR &&
1326                                             olen >= sizeof(struct dhcpv6_ia_addr) - DHCPV6_OPT_HDR_SIZE)
1327                                                 have_na = true;
1328                                 }
1329                         }
1330                         break;
1331 
1332                 default:
1333                         break;
1334                 }
1335         }
1336 
1337         if ((stateful_only_mode && !have_na && !have_pd) ||
1338                         (!have_na && na_mode == IA_MODE_FORCE) ||
1339                         (!have_pd && pd_mode == IA_MODE_FORCE)) {
1340                 /*
1341                  * RFC7083 states to process the SOL_MAX_RT and
1342                  * INF_MAX_RT options even if the DHCPv6 server
1343                  * did not propose any IA_NA and/or IA_PD
1344                  */
1345                 dhcpv6_retx[DHCPV6_MSG_SOLICIT].max_timeo = cand.sol_max_rt;
1346                 dhcpv6_retx[DHCPV6_MSG_INFO_REQ].max_timeo = cand.inf_max_rt;
1347                 return -1;
1348         }
1349 
1350         if (na_mode != IA_MODE_NONE && !have_na) {
1351                 cand.has_noaddravail = true;
1352                 cand.preference -= 1000;
1353         }
1354 
1355         if (pd_mode != IA_MODE_NONE) {
1356                 if (have_pd)
1357                         cand.preference += 2000 + (128 - have_pd);
1358                 else
1359                         cand.preference -= 2000;
1360         }
1361 
1362         if (cand.duid_len > 0) {
1363                 cand.ia_na = odhcp6c_move_state(STATE_IA_NA, &cand.ia_na_len);
1364                 cand.ia_pd = odhcp6c_move_state(STATE_IA_PD, &cand.ia_pd_len);
1365                 dhcpv6_add_server_cand(&cand);
1366         }
1367 
1368         return (rc > 1 || (pref == 255 && cand.preference > 0)) ? 1 : -1;
1369 }
1370 
1371 static int dhcpv6_commit_advert(void)
1372 {
1373         return dhcpv6_promote_server_cand();
1374 }
1375 
1376 static int dhcpv6_handle_rebind_reply(enum dhcpv6_msg orig, const int rc,
1377                 const void *opt, const void *end, const struct sockaddr_in6 *from)
1378 {
1379         dhcpv6_handle_advert(orig, rc, opt, end, from);
1380         if (dhcpv6_commit_advert() < 0)
1381                 return -1;
1382 
1383         return dhcpv6_handle_reply(orig, rc, opt, end, from);
1384 }
1385 
1386 static int dhcpv6_handle_reply(enum dhcpv6_msg orig, _o_unused const int rc,
1387                 const void *opt, const void *end, const struct sockaddr_in6 *from)
1388 {
1389         uint8_t *odata;
1390         uint16_t otype, olen;
1391         uint32_t refresh = config_dhcp->irt_default;
1392         int ret = 1;
1393         unsigned int state_IAs;
1394         unsigned int updated_IAs = 0;
1395         bool handled_status_codes[_DHCPV6_Status_Max] = { false, };
1396 
1397         odhcp6c_expire(true);
1398 
1399         if (orig == DHCPV6_MSG_UNKNOWN) {
1400                 static time_t last_update = 0;
1401                 time_t now = odhcp6c_get_milli_time() / 1000;
1402 
1403                 uint32_t elapsed = (last_update > 0) ? now - last_update : 0;
1404                 last_update = now;
1405 
1406                 if (t1 != UINT32_MAX)
1407                         t1 -= elapsed;
1408 
1409                 if (t2 != UINT32_MAX)
1410                         t2 -= elapsed;
1411 
1412                 if (t3 != UINT32_MAX)
1413                         t3 -= elapsed;
1414 
1415                 if (t1 < 0)
1416                         t1 = 0;
1417 
1418                 if (t2 < 0)
1419                         t2 = 0;
1420 
1421                 if (t3 < 0)
1422                         t3 = 0;
1423         }
1424 
1425         if (orig == DHCPV6_MSG_REQUEST && !odhcp6c_is_bound()) {
1426                 // Delete NA and PD we have in the state from the Advert
1427                 odhcp6c_clear_state(STATE_IA_NA);
1428                 odhcp6c_clear_state(STATE_IA_PD);
1429         }
1430 
1431         if (opt) {
1432                 odhcp6c_clear_state(STATE_DNS);
1433                 odhcp6c_clear_state(STATE_SEARCH);
1434                 odhcp6c_clear_state(STATE_SNTP_IP);
1435                 odhcp6c_clear_state(STATE_NTP_IP);
1436                 odhcp6c_clear_state(STATE_NTP_FQDN);
1437                 odhcp6c_clear_state(STATE_SIP_IP);
1438                 odhcp6c_clear_state(STATE_SIP_FQDN);
1439                 odhcp6c_clear_state(STATE_AFTR_NAME);
1440                 odhcp6c_clear_state(STATE_S46_MAPT);
1441                 odhcp6c_clear_state(STATE_S46_MAPE);
1442                 odhcp6c_clear_state(STATE_S46_LW);
1443                 odhcp6c_clear_state(STATE_CAPT_PORT_DHCPV6);
1444                 odhcp6c_clear_state(STATE_PASSTHRU);
1445                 odhcp6c_clear_state(STATE_CUSTOM_OPTS);
1446 
1447                 // Parse and find all matching IAs
1448                 dhcpv6_for_each_option(opt, end, otype, olen, odata) {
1449                         struct odhcp6c_opt *dopt = odhcp6c_find_opt(otype);
1450 
1451                         switch (otype) {
1452 
1453                         case DHCPV6_OPT_IA_NA:
1454                         case DHCPV6_OPT_IA_PD:
1455                                 if (olen > sizeof(struct dhcpv6_ia_hdr) - DHCPV6_OPT_HDR_SIZE) {
1456                                         struct dhcpv6_ia_hdr *ia_hdr = (void*)(&odata[-DHCPV6_OPT_HDR_SIZE]);
1457 
1458                                         if ((na_mode == IA_MODE_NONE && otype == DHCPV6_OPT_IA_NA) ||
1459                                                 (pd_mode == IA_MODE_NONE && otype == DHCPV6_OPT_IA_PD))
1460                                                 continue;
1461 
1462                                         // Test ID
1463                                         if (ia_hdr->iaid != htonl(ifname_hash_iaid) && otype == DHCPV6_OPT_IA_NA)
1464                                                 continue;
1465 
1466                                         uint16_t code = DHCPV6_Success;
1467                                         uint16_t stype, slen;
1468                                         uint8_t *sdata;
1469                                         bool dhcpv6_successful_once = false;
1470                                         // Get and handle status code
1471                                         dhcpv6_for_each_option(&ia_hdr[1], odata + olen, stype, slen, sdata) {
1472                                                 if (stype == DHCPV6_OPT_STATUS && slen >= 2) {
1473                                                         uint8_t *mdata = (slen > 2) ? &sdata[2] : NULL;
1474                                                         uint16_t mlen = (slen > 2) ? slen - 2 : 0;
1475 
1476                                                         code = ((int)sdata[0] << 8) | ((int)sdata[1]);
1477 
1478                                                         if (code == DHCPV6_Success) {
1479                                                                 dhcpv6_successful_once = true;
1480                                                                 continue;
1481                                                         }
1482 
1483                                                         dhcpv6_handle_ia_status_code(orig, ia_hdr,
1484                                                                 code, mdata, mlen, handled_status_codes, &ret);
1485 
1486                                                         break;
1487                                                 }
1488                                         }
1489 
1490                                         if (!dhcpv6_successful_once && code != DHCPV6_Success)
1491                                                 continue;
1492 
1493                                         updated_IAs += dhcpv6_parse_ia(ia_hdr, odata + olen, &ret);
1494                                 }
1495                                 break;
1496 
1497                         case DHCPV6_OPT_UNICAST:
1498                                 if (olen == sizeof(server_addr) &&
1499                                     !(client_options & DHCPV6_IGNORE_OPT_UNICAST))
1500                                         server_addr = *(struct in6_addr *)odata;
1501                                 break;
1502 
1503                         case DHCPV6_OPT_STATUS:
1504                                 if (olen >= 2) {
1505                                         uint8_t *mdata = (olen > 2) ? &odata[2] : NULL;
1506                                         uint16_t mlen = (olen > 2) ? olen - 2 : 0;
1507                                         uint16_t code = ((int)odata[0] << 8) | ((int)odata[1]);
1508 
1509                                         dhcpv6_handle_status_code(orig, code, mdata, mlen, &ret);
1510                                 }
1511                                 break;
1512 
1513                         case DHCPV6_OPT_DNS_SERVERS:
1514                                 if (olen % sizeof(struct in6_addr) == 0)
1515                                         odhcp6c_add_state(STATE_DNS, odata, olen);
1516                                 break;
1517 
1518                         case DHCPV6_OPT_DNS_DOMAIN:
1519                                 odhcp6c_add_state(STATE_SEARCH, odata, olen);
1520                                 break;
1521 
1522                         case DHCPV6_OPT_SNTP_SERVERS:
1523                                 if (olen % sizeof(struct in6_addr) == 0)
1524                                         odhcp6c_add_state(STATE_SNTP_IP, odata, olen);
1525                                 break;
1526 
1527                         case DHCPV6_OPT_NTP_SERVER:
1528                                 uint16_t stype, slen;
1529                                 uint8_t *sdata;
1530                                 // Test status and bail if error
1531                                 dhcpv6_for_each_option(odata, odata + olen,
1532                                                 stype, slen, sdata) {
1533                                         if (slen == sizeof(struct in6_addr) && (stype == NTP_MC_ADDR || stype == NTP_SRV_ADDR))
1534                                                 odhcp6c_add_state(STATE_NTP_IP, sdata, slen);
1535                                         else if (slen > 0 && stype == NTP_SRV_FQDN)
1536                                                 odhcp6c_add_state(STATE_NTP_FQDN, sdata, slen);
1537                                 }
1538                                 break;
1539 
1540                         case DHCPV6_OPT_SIP_SERVER_A:
1541                                 if (olen == sizeof(struct in6_addr))
1542                                         odhcp6c_add_state(STATE_SIP_IP, odata, olen);
1543                                 break;
1544 
1545                         case DHCPV6_OPT_SIP_SERVER_D:
1546                                 odhcp6c_add_state(STATE_SIP_FQDN, odata, olen);
1547                                 break;
1548 
1549                         case DHCPV6_OPT_INFO_REFRESH:
1550                                 if (olen == 4)
1551                                         refresh = ntohl_unaligned(odata);
1552                                 break;
1553 
1554                         case DHCPV6_OPT_AUTH:
1555                                 struct dhcpv6_auth *r = (void*)&odata[-DHCPV6_OPT_HDR_SIZE];
1556                                 if (auth_protocol == AUTH_PROT_RKAP) {
1557                                         struct dhcpv6_auth_reconfigure *rkap = (void*)r->data;
1558                                         if (r->protocol == AUTH_PROT_RKAP || r->algorithm == AUTH_ALG_HMACMD5 ||
1559                                                 r->len == 28 || rkap->reconf_type == RKAP_TYPE_KEY)
1560                                                 memcpy(reconf_key, rkap->key, sizeof(rkap->key));
1561                                 }
1562                                 break;
1563 
1564                         case DHCPV6_OPT_AFTR_NAME:
1565                                 if (olen > 3) {
1566                                         size_t cur_len;
1567                                         odhcp6c_get_state(STATE_AFTR_NAME, &cur_len);
1568                                         if (cur_len == 0)
1569                                                 odhcp6c_add_state(STATE_AFTR_NAME, odata, olen);
1570                                 }
1571                                 break;
1572 
1573                         case DHCPV6_OPT_SOL_MAX_RT:
1574                                 if (olen == 4) {
1575                                         uint32_t sol_max_rt = ntohl_unaligned(odata);
1576                                         if (sol_max_rt >= DHCPV6_SOL_MAX_RT_MIN && sol_max_rt <= DHCPV6_SOL_MAX_RT_MAX)
1577                                                 dhcpv6_retx[DHCPV6_MSG_SOLICIT].max_timeo = sol_max_rt;
1578                                 }
1579                                 break;
1580 
1581                         case DHCPV6_OPT_INF_MAX_RT:
1582                                 if (olen == 4) {
1583                                         uint32_t inf_max_rt = ntohl_unaligned(odata);
1584                                         if (inf_max_rt >= DHCPV6_INF_MAX_RT_MIN && inf_max_rt <= DHCPV6_INF_MAX_RT_MAX)
1585                                                 dhcpv6_retx[DHCPV6_MSG_INFO_REQ].max_timeo = inf_max_rt;
1586                                 }
1587                                 break;
1588 
1589                         case DHCPV6_OPT_S46_CONT_MAPT:
1590                                 odhcp6c_add_state(STATE_S46_MAPT, odata, olen);
1591                                 break;
1592 
1593                         case DHCPV6_OPT_S46_CONT_MAPE:
1594                                 size_t mape_len;
1595                                 odhcp6c_get_state(STATE_S46_MAPE, &mape_len);
1596                                 if (mape_len == 0)
1597                                         odhcp6c_add_state(STATE_S46_MAPE, odata, olen);
1598                                 break;
1599 
1600                         case DHCPV6_OPT_S46_CONT_LW:
1601                                 odhcp6c_add_state(STATE_S46_LW, odata, olen);
1602                                 break;
1603 
1604                         case DHCPV6_OPT_CAPTIVE_PORTAL: /* RFC8910 ยง2.2 */
1605                                 size_t ref_len = sizeof(URN_IETF_CAPT_PORT_UNRESTR) - 1;
1606                                 /* RFC8910 ยง2:
1607                                  * Networks with no captive portals may explicitly indicate this
1608                                  * condition by using this option with the IANA-assigned URI for
1609                                  * this purpose. Clients observing the URI value ... may forego
1610                                  * time-consuming forms of captive portal detection. */
1611                                 if (memcmp(odata, URN_IETF_CAPT_PORT_UNRESTR, ref_len)) {
1612                                         /* RFC8910 ยง2.2:
1613                                          * Note that the URI parameter is not null terminated.
1614                                          * Allocate new buffer including room for '\0' */
1615                                         size_t uri_len = olen + 1;
1616                                         uint8_t *copy = malloc(uri_len);
1617                                         if (!copy)
1618                                                 continue;
1619                                         memcpy(copy, odata, olen);
1620                                         copy[uri_len] = '\0';
1621                                         odhcp6c_add_state(STATE_CAPT_PORT_DHCPV6, odata, olen);
1622                                         free(copy);
1623                                 }
1624                                 break;
1625 
1626                         default:
1627                                 odhcp6c_add_state(STATE_CUSTOM_OPTS, &odata[-DHCPV6_OPT_HDR_SIZE], olen + DHCPV6_OPT_HDR_SIZE);
1628                                 break;
1629                         }
1630 
1631                         // Pass-through unless explicitly disabled, for every option
1632                         if (!dopt || !(dopt->flags & OPT_NO_PASSTHRU))
1633                                 odhcp6c_add_state(STATE_PASSTHRU, &odata[-DHCPV6_OPT_HDR_SIZE], olen + DHCPV6_OPT_HDR_SIZE);
1634                 }
1635         }
1636 
1637         // Bail out if fatal status code was received
1638         if (ret <= 0)
1639                 return ret;
1640 
1641         switch (orig) {
1642         case DHCPV6_MSG_REQUEST:
1643         case DHCPV6_MSG_REBIND:
1644         case DHCPV6_MSG_RENEW:
1645                 state_IAs = dhcpv6_calc_refresh_timers();
1646                 // In case there're no state IA entries
1647                 // keep sending request/renew/rebind messages
1648                 if (state_IAs == 0) {
1649                         ret = 0;
1650                         break;
1651                 }
1652 
1653                 switch (orig) {
1654                 case DHCPV6_MSG_REQUEST:
1655                         // All server candidates can be cleared if not yet bound
1656                         if (!odhcp6c_is_bound())
1657                                 dhcpv6_clear_all_server_cand();
1658 
1659                         odhcp6c_clear_state(STATE_SERVER_ADDR);
1660                         odhcp6c_add_state(STATE_SERVER_ADDR, &from->sin6_addr, sizeof(struct in6_addr));
1661                         break;
1662                 case DHCPV6_MSG_RENEW:
1663                         // Send further renews if T1 is not set and if
1664                         // there're IAs which were not in the Reply message
1665                         if (!t1 && state_IAs != updated_IAs) {
1666                                 if (updated_IAs)
1667                                         // Publish updates
1668                                         notify_state_change("updated", 0, false);
1669 
1670                                 /*
1671                                  * RFC8415 states following in ยง18.2.10.1 :
1672                                  * Sends a Renew/Rebind if any of the IAs are not in the Reply
1673                                  * message, but as this likely indicates that the server that
1674                                  * responded does not support that IA type, sending immediately is
1675                                  * unlikely to produce a different result.  Therefore, the client
1676                                  * MUST rate-limit its transmissions (see Section 14.1) and MAY just
1677                                  * wait for the normal retransmission time (as if the Reply message
1678                                  * had not been received).  The client continues to use other
1679                                  * bindings for which the server did return information
1680                                  */
1681                                 ret = -1;
1682                         }
1683                         break;
1684                 case DHCPV6_MSG_REBIND:
1685                         odhcp6c_clear_state(STATE_SERVER_ADDR);
1686                         odhcp6c_add_state(STATE_SERVER_ADDR, &from->sin6_addr, sizeof(struct in6_addr));
1687 
1688                         // Send further rebinds if T1 and T2 is not set and if
1689                         // there're IAs which were not in the Reply message
1690                         if (!t1 && !t2 && state_IAs != updated_IAs) {
1691                                 if (updated_IAs)
1692                                         // Publish updates
1693                                         notify_state_change("updated", 0, false);
1694 
1695                                 /*
1696                                  * RFC8415 states following in ยง18.2.10.1 :
1697                                  * Sends a Renew/Rebind if any of the IAs are not in the Reply
1698                                  * message, but as this likely indicates that the server that
1699                                  * responded does not support that IA type, sending immediately is
1700                                  * unlikely to produce a different result.  Therefore, the client
1701                                  * MUST rate-limit its transmissions (see Section 14.1) and MAY just
1702                                  * wait for the normal retransmission time (as if the Reply message
1703                                  * had not been received).  The client continues to use other
1704                                  * bindings for which the server did return information
1705                                  */
1706                                 ret = -1;
1707                         }
1708                         break;
1709 
1710                 default:
1711                         break;
1712                 }
1713                 break;
1714 
1715         case DHCPV6_MSG_INFO_REQ:
1716                 // All server candidates can be cleared if not yet bound
1717                 if (!odhcp6c_is_bound())
1718                         dhcpv6_clear_all_server_cand();
1719 
1720                 odhcp6c_clear_state(STATE_SERVER_ADDR);
1721                 odhcp6c_add_state(STATE_SERVER_ADDR, &from->sin6_addr, sizeof(struct in6_addr));
1722 
1723                 t1 = (refresh < config_dhcp->irt_min) ? config_dhcp->irt_min : refresh;
1724                 break;
1725 
1726         default:
1727                 break;
1728         }
1729 
1730         return ret;
1731 }
1732 
1733 static unsigned int dhcpv6_parse_ia(void *opt, void *end, int *ret)
1734 {
1735         struct dhcpv6_ia_hdr *ia_hdr = (struct dhcpv6_ia_hdr *)opt;
1736         unsigned int updated_IAs = 0;
1737         uint32_t t1, t2;
1738         uint16_t otype, olen;
1739         uint8_t *odata;
1740         char buf[INET6_ADDRSTRLEN];
1741 
1742         t1 = ntohl(ia_hdr->t1);
1743         t2 = ntohl(ia_hdr->t2);
1744 
1745         /* RFC 8415 ยง21.4
1746         If a client receives an IA_NA with T1 greater than T2 and both T1 and
1747         T2 are greater than 0, the client discards the IA_NA option and
1748         processes the remainder of the message as though the server had not
1749         included the invalid IA_NA option. */
1750         if (t1 > t2 && t1 > 0 && t2 > 0)
1751                 return 0;
1752 
1753         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);
1754 
1755         // Update address IA
1756         dhcpv6_for_each_option(&ia_hdr[1], end, otype, olen, odata) {
1757                 struct odhcp6c_entry entry = {
1758                         .router = IN6ADDR_ANY_INIT,
1759                         .auxlen = 0,
1760                         .length = 0,
1761                         .ra_flags = 0,
1762                         .exclusion_length = 0,
1763                         .target = IN6ADDR_ANY_INIT,
1764                         .priority = 0,
1765                         .valid = 0,
1766                         .preferred = 0,
1767                         .t1 = 0,
1768                         .t2 = 0,
1769                         .iaid = ia_hdr->iaid,
1770                 };
1771 
1772                 switch (otype) {
1773                 case DHCPV6_OPT_IA_PREFIX: {
1774                         struct dhcpv6_ia_prefix *prefix = (void*)&odata[-DHCPV6_OPT_HDR_SIZE];
1775                         if (olen + DHCPV6_OPT_HDR_SIZE_U < sizeof(*prefix))
1776                                 continue;
1777 
1778                         entry.valid = ntohl(prefix->valid);
1779                         entry.preferred = ntohl(prefix->preferred);
1780 
1781                         if (entry.preferred > entry.valid)
1782                                 continue;
1783 
1784                         /*      RFC 8415 ยง21.21
1785                         Recommended values for T1 and T2 are 0.5 and 0.8 times the
1786                         shortest preferred lifetime of the prefixes in the IA_PD that the
1787                         server is willing to extend. */
1788                         entry.t1 = (t1 ? t1 : (entry.preferred != UINT32_MAX ? 0.5 * entry.preferred : UINT32_MAX));
1789                         entry.t2 = (t2 ? t2 : (entry.preferred != UINT32_MAX ? 0.8 * entry.preferred : UINT32_MAX));
1790                         if (entry.t1 > entry.t2)
1791                                 entry.t1 = entry.t2;
1792 
1793                         entry.length = prefix->prefix;
1794                         entry.target = prefix->addr;
1795                         uint16_t stype, slen;
1796                         uint8_t *sdata;
1797 
1798                         // Parse sub-options for PD-exclude or error status code
1799                         bool update_state = true;
1800                         dhcpv6_for_each_option(odata + sizeof(*prefix) - DHCPV6_OPT_HDR_SIZE,
1801                                         odata + olen, stype, slen, sdata) {
1802                                 if (stype == DHCPV6_OPT_STATUS && slen >= 2) {
1803                                         /* RFC 8415 ยง21.22
1804                                         The status of any operations involving this IA Prefix option is
1805                                         indicated in a Status Code option (see Section 21.13) in the
1806                                         IAprefix-options field. */
1807                                         uint8_t *status_msg = (slen > 2) ? &sdata[2] : NULL;
1808                                         uint16_t msg_len = (slen > 2) ? slen - 2 : 0;
1809                                         uint16_t code = ((int)sdata[0]) << 8 | ((int)sdata[1]);
1810 
1811                                         if (code == DHCPV6_Success)
1812                                                 continue;
1813 
1814                                         dhcpv6_log_status_code(code, "IA_PREFIX", status_msg, msg_len);
1815                                         if (ret) *ret = 0; // renewal failed
1816                                 } else if (stype == DHCPV6_OPT_PD_EXCLUDE && slen > 2) {
1817                                         /*      RFC 6603 ยง4.2 Prefix Exclude option */
1818                                         uint8_t exclude_length = sdata[0];
1819                                         if (exclude_length > 64)
1820                                                 exclude_length = 64;
1821 
1822                                         if (entry.length < 32 || exclude_length <= entry.length) {
1823                                                 update_state = false;
1824                                                 continue;
1825                                         }
1826 
1827                                         uint8_t bytes_needed = ((exclude_length - entry.length - 1) / 8) + 1;
1828                                         if (slen <= bytes_needed) {
1829                                                 update_state = false;
1830                                                 continue;
1831                                         }
1832 
1833                                         // this decrements through the ipaddr bytes masking against 
1834                                         // the address in the option until byte 0, the option length field.
1835                                         uint32_t excluded_bits = 0;
1836                                         do {
1837                                                 excluded_bits = excluded_bits << 8 | sdata[bytes_needed];
1838                                         } while (--bytes_needed);
1839 
1840                                         excluded_bits >>= 8 - ((exclude_length - entry.length) % 8);
1841                                         excluded_bits <<= 64 - exclude_length;
1842 
1843                                         // Re-using router field to hold the prefix
1844                                         entry.router = entry.target; // base prefix
1845                                         entry.router.s6_addr32[1] |= htonl(excluded_bits);
1846                                         entry.exclusion_length = exclude_length;
1847                                 }
1848                         }
1849 
1850                         if (update_state) {
1851                                 if (odhcp6c_update_entry(STATE_IA_PD, &entry, 0))
1852                                         updated_IAs++;
1853 
1854                                 info("%s/%d preferred %d valid %d",
1855                                                 inet_ntop(AF_INET6, &entry.target, buf, sizeof(buf)),
1856                                                 entry.length, entry.preferred , entry.valid);
1857                         }
1858 
1859                         entry.priority = 0;
1860                         memset(&entry.router, 0, sizeof(entry.router));
1861                         break;
1862                 }
1863                 case DHCPV6_OPT_IA_ADDR: {
1864                         struct dhcpv6_ia_addr *addr = (void*)&odata[-DHCPV6_OPT_HDR_SIZE];
1865                         if (olen + DHCPV6_OPT_HDR_SIZE_U < sizeof(*addr))
1866                                 continue;
1867 
1868                         entry.preferred = ntohl(addr->preferred);
1869                         entry.valid = ntohl(addr->valid);
1870 
1871                         if (entry.preferred > entry.valid)
1872                                 continue;
1873 
1874                         entry.t1 = (t1 ? t1 : (entry.preferred != UINT32_MAX ? 0.5 * entry.preferred : UINT32_MAX));
1875                         entry.t2 = (t2 ? t2 : (entry.preferred != UINT32_MAX ? 0.8 * entry.preferred : UINT32_MAX));
1876                         if (entry.t1 > entry.t2)
1877                                 entry.t1 = entry.t2;
1878 
1879                         entry.length = 128;
1880                         entry.target = addr->addr;
1881                         uint16_t stype, slen;
1882                         uint8_t *sdata;
1883 
1884                         bool update_state = true;
1885                         dhcpv6_for_each_option(odata + sizeof(*addr) - DHCPV6_OPT_HDR_SIZE_U,
1886                                         odata + olen, stype, slen, sdata) {
1887                                 if (stype == DHCPV6_OPT_STATUS && slen >= 2) {
1888                                         /* RFC 8415 ยง21.6
1889                                         The status of any operations involving this IA Address is indicated
1890                                         in a Status Code option in the IAaddr-options field, as specified in
1891                                         Section 21.13. */
1892                                         uint8_t *status_msg = (slen > 2) ? &sdata[2] : NULL;
1893                                         uint16_t msg_len = (slen > 2) ? slen - 2 : 0;
1894                                         uint16_t code = ((int)sdata[0]) << 8 | ((int)sdata[1]);
1895 
1896                                         if (code == DHCPV6_Success)
1897                                                 continue;
1898 
1899                                         dhcpv6_log_status_code(code, "IA_ADDR", status_msg, msg_len);
1900                                         if (ret) *ret = 0; // renewal failed
1901                                         update_state = false;
1902                                 }
1903                         }
1904 
1905                         if (update_state) {
1906                                 if (odhcp6c_update_entry(STATE_IA_NA, &entry, 0))
1907                                         updated_IAs++;
1908 
1909                                 info("%s preferred %d valid %d",
1910                                                 inet_ntop(AF_INET6, &entry.target, buf, sizeof(buf)),
1911                                                 entry.preferred , entry.valid);
1912                         }
1913                         break;
1914                 }
1915                 default:
1916                         break;
1917                 }
1918         }
1919 
1920         return updated_IAs;
1921 }
1922 
1923 static unsigned int dhcpv6_calc_refresh_timers(void)
1924 {
1925         struct odhcp6c_entry *pd_entries;
1926         struct odhcp6c_entry *ia_entries;
1927         size_t ia_na_entry_cnt, ia_pd_entry_cnt, i;
1928         size_t invalid_entries = 0;
1929         int64_t l_t1 = UINT32_MAX, l_t2 = UINT32_MAX, l_t3 = 0;
1930 
1931         ia_entries = odhcp6c_get_state(STATE_IA_NA, &ia_na_entry_cnt);
1932         ia_na_entry_cnt /= sizeof(*ia_entries);
1933 
1934         for (i = 0; i < ia_na_entry_cnt; i++) {
1935                 /* Exclude invalid IA_NA entries */
1936                 if (!ia_entries[i].valid) {
1937                         invalid_entries++;
1938                         continue;
1939                 }
1940 
1941                 if (ia_entries[i].t1 < l_t1)
1942                         l_t1 = ia_entries[i].t1;
1943 
1944                 if (ia_entries[i].t2 < l_t2)
1945                         l_t2 = ia_entries[i].t2;
1946 
1947                 if (ia_entries[i].valid > l_t3)
1948                         l_t3 = ia_entries[i].valid;
1949         }
1950 
1951         pd_entries = odhcp6c_get_state(STATE_IA_PD, &ia_pd_entry_cnt);
1952         ia_pd_entry_cnt /= sizeof(*pd_entries);
1953 
1954         for (i = 0; i < ia_pd_entry_cnt; i++) {
1955                 /* Exclude invalid IA_PD entries */
1956                 if (!pd_entries[i].valid) {
1957                         invalid_entries++;
1958                         continue;
1959                 }
1960 
1961                 if (pd_entries[i].t1 < l_t1)
1962                         l_t1 = pd_entries[i].t1;
1963 
1964                 if (pd_entries[i].t2 < l_t2)
1965                         l_t2 = pd_entries[i].t2;
1966 
1967                 if (pd_entries[i].valid > l_t3)
1968                         l_t3 = pd_entries[i].valid;
1969         }
1970 
1971         if (ia_pd_entry_cnt + ia_na_entry_cnt - invalid_entries) {
1972                 t1 = l_t1;
1973                 t2 = l_t2;
1974                 t3 = l_t3;
1975 
1976                 info("T1 %"PRId64"s, T2 %"PRId64"s, T3 %"PRId64"s", t1, t2, t3);
1977         }
1978 
1979         return (unsigned int)(ia_pd_entry_cnt + ia_na_entry_cnt);
1980 }
1981 
1982 static void dhcpv6_log_status_code(const uint16_t code, const char *scope,
1983                 const void *status_msg, int len)
1984 {
1985         const char *src = status_msg;
1986         char buf[len + 3];
1987         char *dst = buf;
1988 
1989         if (len) {
1990                 *dst++ = '(';
1991                 while (len--) {
1992                         *dst = isprint((unsigned char)*src) ? *src : '?';
1993                         src++;
1994                         dst++;
1995                 }
1996                 *dst++ = ')';
1997         }
1998 
1999         *dst = 0;
2000 
2001         warn("Server returned %s status '%s %s'",
2002                 scope, dhcpv6_status_code_to_str(code), buf);
2003 }
2004 
2005 static void dhcpv6_handle_status_code(const enum dhcpv6_msg orig,
2006                 const uint16_t code, const void *status_msg, const int len,
2007                 int *ret)
2008 {
2009         dhcpv6_log_status_code(code, "message", status_msg, len);
2010 
2011         switch (code) {
2012         case DHCPV6_UnspecFail:
2013                 // Generic failure
2014                 *ret = 0;
2015                 break;
2016 
2017         case DHCPV6_UseMulticast:
2018                 switch(orig) {
2019                 case DHCPV6_MSG_REQUEST:
2020                 case DHCPV6_MSG_RENEW:
2021                 case DHCPV6_MSG_RELEASE:
2022                 case DHCPV6_MSG_DECLINE:
2023                         // Message needs to be retransmitted according to RFC3315 chapter 18.1.8
2024                         server_addr = in6addr_any;
2025                         *ret = 0;
2026                         break;
2027                 default:
2028                         break;
2029                 }
2030                 break;
2031 
2032         case DHCPV6_NoAddrsAvail:
2033         case DHCPV6_NoPrefixAvail:
2034                 if (orig == DHCPV6_MSG_REQUEST)
2035                         *ret = 0; // Failure
2036                 break;
2037 
2038         default:
2039                 break;
2040         }
2041 }
2042 
2043 static void dhcpv6_handle_ia_status_code(const enum dhcpv6_msg orig,
2044                 const struct dhcpv6_ia_hdr *ia_hdr, const uint16_t code,
2045                 const void *status_msg, const int len,
2046                 bool handled_status_codes[_DHCPV6_Status_Max], int *ret)
2047 {
2048         dhcpv6_log_status_code(code, ntohs(ia_hdr->type) == DHCPV6_OPT_IA_NA ?
2049                 "IA_NA" : "IA_PD", status_msg, len);
2050 
2051         switch (code) {
2052         case DHCPV6_NoBinding:
2053                 switch (orig) {
2054                 case DHCPV6_MSG_RENEW:
2055                 case DHCPV6_MSG_REBIND:
2056                         if ((*ret > 0) && !handled_status_codes[code]) {
2057                                 dhcpv6_set_state(DHCPV6_REQUEST);
2058                                 *ret = -1;
2059                         }
2060                         break;
2061 
2062                 default:
2063                         *ret = 0;
2064                         break;
2065                 }
2066                 break;
2067 
2068         case DHCPV6_NoAddrsAvail:
2069         case DHCPV6_NoPrefixAvail:
2070                 break;
2071 
2072         default:
2073                 *ret = 0;
2074                 break;
2075         }
2076 }
2077 
2078 // Note this always takes ownership of cand->ia_na and cand->ia_pd
2079 static void dhcpv6_add_server_cand(const struct dhcpv6_server_cand *cand)
2080 {
2081         size_t cand_len, i;
2082         struct dhcpv6_server_cand *srv_candidates = odhcp6c_get_state(STATE_SERVER_CAND, &cand_len);
2083 
2084         // Remove identical DUID server candidate
2085         for (i = 0; i < cand_len / sizeof(*srv_candidates); ++i) {
2086                 if (cand->duid_len == srv_candidates[i].duid_len &&
2087                                 !memcmp(cand->duid, srv_candidates[i].duid, cand->duid_len)) {
2088                         free(srv_candidates[i].ia_na);
2089                         free(srv_candidates[i].ia_pd);
2090                         odhcp6c_remove_state(STATE_SERVER_CAND, i * sizeof(*srv_candidates), sizeof(*srv_candidates));
2091                         break;
2092                 }
2093         }
2094 
2095         for (i = 0, srv_candidates = odhcp6c_get_state(STATE_SERVER_CAND, &cand_len);
2096                 i < cand_len / sizeof(*srv_candidates); ++i) {
2097                 if (srv_candidates[i].preference < cand->preference)
2098                         break;
2099         }
2100 
2101         if (odhcp6c_insert_state(STATE_SERVER_CAND, i * sizeof(*srv_candidates), cand, sizeof(*cand))) {
2102                 free(cand->ia_na);
2103                 free(cand->ia_pd);
2104         }
2105 }
2106 
2107 static void dhcpv6_clear_all_server_cand(void)
2108 {
2109         size_t cand_len, i;
2110         struct dhcpv6_server_cand *srv_candidates = odhcp6c_get_state(STATE_SERVER_CAND, &cand_len);
2111 
2112         // Server candidates need deep delete for IA_NA/IA_PD
2113         for (i = 0; i < cand_len / sizeof(*srv_candidates); ++i) {
2114                 free(srv_candidates[i].ia_na);
2115                 free(srv_candidates[i].ia_pd);
2116         }
2117         odhcp6c_clear_state(STATE_SERVER_CAND);
2118 }
2119 
2120 int dhcpv6_promote_server_cand(void)
2121 {
2122         size_t cand_len;
2123         struct dhcpv6_server_cand *cand = odhcp6c_get_state(STATE_SERVER_CAND, &cand_len);
2124         uint16_t hdr[2];
2125         int ret = DHCPV6_STATELESS;
2126 
2127         // Clear lingering candidate state info
2128         odhcp6c_clear_state(STATE_SERVER_ID);
2129         odhcp6c_clear_state(STATE_IA_NA);
2130         odhcp6c_clear_state(STATE_IA_PD);
2131 
2132         if (!cand_len)
2133                 return -1;
2134 
2135         if (!cand->ia_pd_len && cand->has_noaddravail) {
2136                 bool override = false;
2137 
2138                 if (na_mode == IA_MODE_TRY) {
2139                         na_mode = IA_MODE_NONE;
2140                         override = true;
2141                 }
2142 
2143                 if (pd_mode == IA_MODE_TRY) {
2144                         pd_mode = IA_MODE_NONE;
2145                         override = true;
2146                 }
2147 
2148                 if (override) {
2149                         dhcpv6_retx[DHCPV6_MSG_SOLICIT].max_timeo = cand->sol_max_rt;
2150                         dhcpv6_retx[DHCPV6_MSG_INFO_REQ].max_timeo = cand->inf_max_rt;
2151 
2152                         return -1;
2153                 }
2154         }
2155 
2156         hdr[0] = htons(DHCPV6_OPT_SERVERID);
2157         hdr[1] = htons(cand->duid_len);
2158         odhcp6c_add_state(STATE_SERVER_ID, hdr, sizeof(hdr));
2159         odhcp6c_add_state(STATE_SERVER_ID, cand->duid, cand->duid_len);
2160         accept_reconfig = cand->wants_reconfigure;
2161         memset(reconf_key, 0, sizeof(reconf_key));
2162 
2163         if (cand->ia_na_len) {
2164                 odhcp6c_add_state(STATE_IA_NA, cand->ia_na, cand->ia_na_len);
2165                 free(cand->ia_na);
2166                 if (na_mode != IA_MODE_NONE)
2167                         ret = DHCPV6_STATEFUL;
2168         }
2169 
2170         if (cand->ia_pd_len) {
2171                 odhcp6c_add_state(STATE_IA_PD, cand->ia_pd, cand->ia_pd_len);
2172                 free(cand->ia_pd);
2173                 if (pd_mode != IA_MODE_NONE)
2174                         ret = DHCPV6_STATEFUL;
2175         }
2176 
2177         dhcpv6_retx[DHCPV6_MSG_SOLICIT].max_timeo = cand->sol_max_rt;
2178         dhcpv6_retx[DHCPV6_MSG_INFO_REQ].max_timeo = cand->inf_max_rt;
2179 
2180         odhcp6c_remove_state(STATE_SERVER_CAND, 0, sizeof(*cand));
2181 
2182         return ret;
2183 }
2184 
2185 int dhcpv6_send_request(enum dhcpv6_msg req_msg_type)
2186 {
2187         struct dhcpv6_retx *retx = &dhcpv6_retx[req_msg_type];
2188         uint64_t current_milli_time = 0;
2189 
2190         if (!retx->is_retransmit) {
2191                 // Initial delay handling
2192                 if (retx->max_delay) {
2193                         if (retx->delay_msec == 0) {
2194                                 // Initial delay before starting the transaction
2195                                 retx->delay_msec = (dhcpv6_rand_delay((10000 * retx->max_delay) / 2) + (1000 * retx->max_delay) / 2);
2196                                 dhcpv6_set_state_timeout(retx->delay_msec);
2197                                 // Add current time to calculate absolute time
2198                                 retx->delay_msec += odhcp6c_get_milli_time();
2199                                 return 1;
2200                         } else {
2201                                 // Wait until delay expires
2202                                 current_milli_time = odhcp6c_get_milli_time();
2203                                 if (current_milli_time < retx->delay_msec) {
2204                                         // Still waiting
2205                                         dhcpv6_set_state_timeout(retx->delay_msec - current_milli_time);
2206                                         return 1;
2207                                 }
2208                                 retx->delay_msec = 0;
2209                         }
2210                 }
2211 
2212                 retx->is_retransmit = true;
2213                 retx->rc = 0;
2214                 retx->timeout = UINT32_MAX;
2215                 retx->reply_ret = -1;
2216 
2217                 if (req_msg_type == DHCPV6_MSG_UNKNOWN)
2218                         retx->timeout = t1;
2219                 else if (req_msg_type == DHCPV6_MSG_RENEW)
2220                         retx->timeout = (t2 > t1) ? t2 - t1 : ((t1 == UINT32_MAX) ? UINT32_MAX : 0);
2221                 else if (req_msg_type == DHCPV6_MSG_REBIND)
2222                         retx->timeout = (t3 > t2) ? t3 - t2 : ((t2 == UINT32_MAX) ? UINT32_MAX : 0);
2223 
2224                 if (retx->timeout == 0)
2225                         return -1;
2226 
2227                 notice("Starting %s transaction (timeout %"PRIu64"s, max rc %d)",
2228                         retx->name, retx->timeout, retx->max_rc);
2229 
2230                 // Generate transaction ID
2231                 if (req_msg_type != DHCPV6_MSG_UNKNOWN) {
2232                         odhcp6c_random(retx->tr_id, sizeof(retx->tr_id));
2233                 }
2234 
2235                 // Record start time
2236                 retx->start = odhcp6c_get_milli_time();
2237                 retx->round_start = retx->start;
2238                 // Reset retransmission timeout initial value
2239                 retx->rto = 0;
2240         }
2241 
2242         if (retx->rto == 0) {
2243                 int64_t delay = dhcpv6_rand_delay(retx->init_timeo * 1000);
2244 
2245                 // First RT MUST be strictly greater than IRT for solicit messages (RFC3313 17.1.2)
2246                 while (req_msg_type == DHCPV6_MSG_SOLICIT && delay <= 0)
2247                         delay = dhcpv6_rand_delay(retx->init_timeo * 1000);
2248 
2249                 // First timeout
2250                 retx->rto = (retx->init_timeo * 1000 + delay);
2251         } else {
2252                 // Exponential back-off with randomization to avoid synchronization
2253                 retx->rto = (2 * retx->rto + dhcpv6_rand_delay(retx->rto));
2254         }
2255 
2256         if (retx->max_timeo && (retx->rto >= retx->max_timeo * 1000)) {
2257                 // Cap to max timeout if set and exceeded
2258                 retx->rto = retx->max_timeo * 1000 +
2259                         dhcpv6_rand_delay(retx->max_timeo * 1000);
2260         }
2261 
2262         // Calculate end for this round and elapsed time
2263         retx->round_end = retx->round_start + retx->rto;
2264         uint64_t elapsed = retx->round_start - retx->start;
2265 
2266         // Don't wait too long if timeout differs from infinite
2267         if ((retx->timeout != UINT32_MAX) && (retx->round_end - retx->start > retx->timeout * 1000))
2268                 retx->round_end = retx->timeout * 1000 + retx->start;
2269 
2270         dhcpv6_set_state_timeout(retx->round_end - odhcp6c_get_milli_time());
2271 
2272         // Built and send package
2273         switch (req_msg_type) {
2274         case DHCPV6_MSG_UNKNOWN:
2275                 break;
2276         default:
2277                 notice("Send %s message (elapsed %"PRIu64"ms, rc %d)",
2278                                 retx->name, elapsed, retx->rc);
2279                 _o_fallthrough;
2280         case DHCPV6_MSG_SOLICIT:
2281         case DHCPV6_MSG_INFO_REQ:
2282                 dhcpv6_send(req_msg_type, retx->tr_id, elapsed / 10);
2283                 retx->rc++;
2284         }
2285 
2286         if (dhcpv6_get_state() != DHCPV6_EXIT)
2287                 dhcpv6_next_state();
2288 
2289         return 0;
2290 }
2291 
2292 int dhcpv6_receive_response(enum dhcpv6_msg req_msg_type)
2293 {
2294         ssize_t len = -1;
2295         struct dhcpv6_retx *retx = &dhcpv6_retx[req_msg_type];
2296 
2297         uint8_t buf[1536];
2298         union {
2299                 struct cmsghdr hdr;
2300                 uint8_t buf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
2301         } cmsg_buf;
2302 
2303         struct iovec iov = {buf, sizeof(buf)};
2304         struct sockaddr_in6 addr;
2305         struct msghdr msg = {.msg_name = &addr, .msg_namelen = sizeof(addr),
2306                         .msg_iov = &iov, .msg_iovlen = 1, .msg_control = cmsg_buf.buf,
2307                         .msg_controllen = sizeof(cmsg_buf)};
2308         struct in6_pktinfo *pktinfo = NULL;
2309         const struct dhcpv6_header *hdr = (const struct dhcpv6_header *)buf;
2310 
2311         // Receive cycle
2312         len = recvmsg(sock, &msg, 0);
2313         if (len < 0) {
2314                 error("Error occurred when reading the response of (%s) error(%s)",
2315                         retx->name, strerror(errno));
2316                 return -1;
2317         }
2318 
2319         for (struct cmsghdr *ch = CMSG_FIRSTHDR(&msg); ch != NULL;
2320                 ch = CMSG_NXTHDR(&msg, ch)) {
2321                 if (ch->cmsg_level == SOL_IPV6 &&
2322                         ch->cmsg_type == IPV6_PKTINFO) {
2323                         pktinfo = (struct in6_pktinfo *)CMSG_DATA(ch);
2324                         break;
2325                 }
2326         }
2327 
2328         if (pktinfo == NULL) {
2329                 dhcpv6_stats.discarded_packets++;
2330                 return -1;
2331         }
2332 
2333         if (!dhcpv6_response_is_valid(buf, len, retx->tr_id, req_msg_type,
2334                                          &pktinfo->ipi6_addr)) {
2335                 dhcpv6_stats.discarded_packets++;
2336                 return -1;
2337         }
2338 
2339         dhcpv6_inc_counter(hdr->msg_type);
2340 
2341         uint8_t *opt = &buf[4];
2342         uint8_t *opt_end = opt + len - DHCPV6_OPT_HDR_SIZE;
2343         retx->round_start = odhcp6c_get_milli_time();
2344         uint64_t elapsed = retx->round_start - retx->start;
2345 
2346         notice("Got a valid %s after %"PRIu64"ms",
2347                 dhcpv6_msg_to_str(hdr->msg_type), elapsed);
2348 
2349         if (retx->handler_reply) {
2350                 retx->reply_ret = retx->handler_reply(req_msg_type, retx->rc, opt, opt_end, &addr);
2351                 len = retx->reply_ret;
2352         }
2353 
2354         // Clamp round end (Round Trip Time) to 1s max wait after receiving a valid response (in milliseconds)
2355         if (len > 0 && retx->round_end - retx->round_start > 1000)
2356                 retx->round_end = 1000 + retx->round_start;
2357 
2358         return retx->reply_ret;
2359 }
2360 
2361 int dhcpv6_state_processing(enum dhcpv6_msg req_msg_type)
2362 {
2363         struct dhcpv6_retx *retx = &dhcpv6_retx[req_msg_type];
2364         int ret = retx->reply_ret;
2365         retx->round_start = odhcp6c_get_milli_time();
2366         uint64_t elapsed = retx->round_start - retx->start;
2367 
2368         if (retx->round_start >= retx->round_end || ret >=0 ) {
2369                 if (retx->handler_finish)
2370                         ret = retx->handler_finish();
2371 
2372                 if (ret < 0 && ((retx->timeout == UINT32_MAX) || (elapsed / 1000 < retx->timeout)) &&
2373                         (!retx->max_rc || retx->rc < retx->max_rc)) {
2374                                 retx->reply_ret = -1;
2375                                 dhcpv6_prev_state();
2376                 } else {
2377                         retx->is_retransmit = false;
2378                         dhcpv6_next_state();
2379                 }
2380         } else {
2381                 // This sets the response polling timeout (round_end - round_start) in milliseconds
2382                 dhcpv6_set_state_timeout(retx->round_end - retx->round_start);
2383         }
2384 
2385         return ret;
2386 }
2387 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt