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

This page was automatically generated by LXR 0.3.1.  •  OpenWrt