Home | History | Annotate | Download | only in pending
      1 /* dhcp6.c - DHCP6 client for dynamic network configuration.
      2  *
      3  * Copyright 2015 Rajni Kant <rajnikant12345 (at) gmail.com>
      4  *
      5  * Not in SUSv4.
      6 USE_DHCP6(NEWTOY(dhcp6, "r:A#<0T#<0t#<0s:p:i:SRvqnbf", TOYFLAG_SBIN|TOYFLAG_ROOTONLY))
      7 
      8 config DHCP6
      9   bool "dhcp6"
     10   default n
     11   help
     12   usage: dhcp6 [-fbnqvR] [-i IFACE] [-r IP] [-s PROG] [-p PIDFILE]
     13 
     14         Configure network dynamicaly using DHCP.
     15 
     16       -i Interface to use (default eth0)
     17       -p Create pidfile
     18       -s Run PROG at DHCP events
     19       -t Send up to N Solicit packets
     20       -T Pause between packets (default 3 seconds)
     21       -A Wait N seconds after failure (default 20)
     22       -f Run in foreground
     23       -b Background if lease is not obtained
     24       -n Exit if lease is not obtained
     25       -q Exit after obtaining lease
     26       -R Release IP on exit
     27       -S Log to syslog too
     28       -r Request this IP address
     29       -v Verbose
     30 
     31       Signals:
     32       USR1  Renew current lease
     33       USR2  Release current lease
     34 */
     35 #define FOR_dhcp6
     36 #include "toys.h"
     37 #include <linux/sockios.h>
     38 #include <linux/if_ether.h>
     39 #include <netinet/ip.h>
     40 #include <netinet/ip6.h>
     41 #include <netinet/udp.h>
     42 #include <linux/if_packet.h>
     43 #include <syslog.h>
     44 
     45 GLOBALS(
     46   char *interface_name, *pidfile, *script;
     47   long retry, timeout, errortimeout;
     48   char *req_ip;
     49   int length, state, request_length, sock, sock1, status, retval, retries;
     50   struct timeval tv;
     51   uint8_t transction_id[3];
     52   struct sockaddr_in6 input_socket6;
     53 )
     54 
     55 #define DHCP6SOLICIT        1
     56 #define DHCP6ADVERTISE      2   // server -> client
     57 #define DHCP6REQUEST        3
     58 #define DHCP6CONFIRM        4
     59 #define DHCP6RENEW          5
     60 #define DHCP6REBIND         6
     61 #define DHCP6REPLY          7   // server -> client
     62 #define DHCP6RELEASE        8
     63 #define DHCP6DECLINE        9
     64 #define DHCP6RECONFIGURE    10  // server -> client
     65 #define DHCP6INFOREQUEST    11
     66 #define DHCP6RELAYFLOW      12  // relay -> relay/server
     67 #define DHCP6RELAYREPLY     13  // server/relay -> relay
     68 
     69 // DHCPv6 option codes (partial). See RFC 3315
     70 #define DHCP6_OPT_CLIENTID      1
     71 #define DHCP6_OPT_SERVERID      2
     72 #define DHCP6_OPT_IA_NA         3
     73 #define DHCP6_OPT_IA_ADDR       5
     74 #define DHCP6_OPT_ORO           6
     75 #define DHCP6_OPT_PREFERENCE    7
     76 #define DHCP6_OPT_ELAPSED_TIME  8
     77 #define DHCP6_OPT_RELAY_MSG     9
     78 #define DHCP6_OPT_STATUS_CODE   13
     79 #define DHCP6_OPT_IA_PD         25
     80 #define DHCP6_OPT_IA_PREFIX     26
     81 
     82 #define DHCP6_STATUS_SUCCESS        0
     83 #define DHCP6_STATUS_NOADDRSAVAIL   2
     84 
     85 #define DHCP6_DUID_LLT    1
     86 #define DHCP6_DUID_EN     2
     87 #define DHCP6_DUID_LL     3
     88 #define DHCP6_DUID_UUID   4
     89 
     90 #define DHCPC_SERVER_PORT     547
     91 #define DHCPC_CLIENT_PORT     546
     92 
     93 #define LOG_SILENT          0x0
     94 #define LOG_CONSOLE         0x1
     95 #define LOG_SYSTEM          0x2
     96 
     97 typedef struct __attribute__((packed)) dhcp6_msg_s {
     98   uint8_t msgtype, transaction_id[3], options[524];
     99 } dhcp6_msg_t;
    100 
    101 typedef struct __attribute__((packed)) optval_duid_llt {
    102   uint16_t type;
    103   uint16_t hwtype;
    104   uint32_t time;
    105   uint8_t lladdr[6];
    106 } DUID;
    107 
    108 typedef struct __attribute__((packed)) optval_ia_na {
    109   uint32_t iaid, t1, t2;
    110 } IA_NA;
    111 
    112 typedef struct __attribute__((packed)) dhcp6_raw_s {
    113   struct ip6_hdr iph;
    114   struct udphdr udph;
    115   dhcp6_msg_t dhcp6;
    116 } dhcp6_raw_t;
    117 
    118 typedef struct __attribute__((packed)) dhcp_data_client {
    119   uint16_t  status_code;
    120   uint32_t iaid , t1,t2, pf_lf, va_lf;
    121   uint8_t ipaddr[17] ;
    122 } DHCP_DATA;
    123 
    124 static DHCP_DATA dhcp_data;
    125 static dhcp6_raw_t *mymsg;
    126 static dhcp6_msg_t mesg;
    127 static DUID *duid;
    128 
    129 static void (*dbg)(char *format, ...);
    130 static void dummy(char *format, ...)
    131 {
    132   return;
    133 }
    134 
    135 static void logit(char *format, ...)
    136 {
    137   int used;
    138   char *msg;
    139   va_list p, t;
    140   uint8_t infomode = LOG_SILENT;
    141 
    142   if (toys.optflags & FLAG_S) infomode |= LOG_SYSTEM;
    143   if(toys.optflags & FLAG_v) infomode |= LOG_CONSOLE;
    144   va_start(p, format);
    145   va_copy(t, p);
    146   used = vsnprintf(NULL, 0, format, t);
    147   used++;
    148   va_end(t);
    149 
    150   msg = xmalloc(used);
    151   vsnprintf(msg, used, format, p);
    152   va_end(p);
    153 
    154   if (infomode & LOG_SYSTEM) syslog(LOG_INFO, "%s", msg);
    155   if (infomode & LOG_CONSOLE) printf("%s", msg);
    156   free(msg);
    157   return;
    158 }
    159 
    160 static void get_mac(uint8_t *mac, char *interface)
    161 {
    162   int fd;
    163   struct ifreq req;
    164 
    165   if (!mac) return;
    166   fd = xsocket(AF_INET6, SOCK_RAW, IPPROTO_RAW);
    167   req.ifr_addr.sa_family = AF_INET6;
    168   xstrncpy(req.ifr_name, interface, IFNAMSIZ);
    169   xioctl(fd, SIOCGIFHWADDR, &req);
    170   memcpy(mac, req.ifr_hwaddr.sa_data, 6);
    171   xclose(fd);
    172 }
    173 
    174 static void fill_option(uint16_t option_id, uint16_t option_len, uint8_t **dhmesg)
    175 {
    176   uint8_t *tmp = *dhmesg;
    177 
    178   *((uint16_t*)tmp) = htons(option_id);
    179   *(uint16_t*)(tmp+2) = htons(option_len);
    180   *dhmesg += 4;
    181   TT.length += 4;
    182 }
    183 
    184 static void fill_clientID()
    185 {
    186   uint8_t *tmp = &mesg.options[TT.length];
    187 
    188   if(!duid) {
    189     uint8_t mac[7] = {0,};
    190     duid = (DUID*)malloc(sizeof(DUID));
    191     duid->type = htons(1);
    192     duid->hwtype = htons(1);
    193     duid->time = htonl((uint32_t)(time(NULL) - 946684800) & 0xffffffff);
    194     fill_option(DHCP6_OPT_CLIENTID,14,&tmp);
    195     get_mac(mac, TT.interface_name);
    196     memcpy(duid->lladdr,mac, 6);
    197     memcpy(tmp,(uint8_t*)duid,sizeof(DUID));
    198   }
    199   else {
    200     fill_option(DHCP6_OPT_CLIENTID,14,&tmp);
    201     memcpy(tmp,(uint8_t*)duid,sizeof(DUID));
    202   }
    203   TT.length += sizeof(DUID);
    204 }
    205 
    206 // TODO: make it generic for multiple options.
    207 static void fill_optionRequest()
    208 {
    209   uint8_t *tmp = &mesg.options[TT.length];
    210 
    211   fill_option(DHCP6_OPT_ORO,4,&tmp);
    212   *(uint16_t*)(tmp+4) = htons(23);
    213   *(uint16_t*)(tmp+6) = htons(24);
    214   TT.length += 4;
    215 }
    216 
    217 static void fill_elapsedTime()
    218 {
    219   uint8_t *tmp = &mesg.options[TT.length];
    220 
    221   fill_option(DHCP6_OPT_ELAPSED_TIME, 2, &tmp);
    222   *(uint16_t*)(tmp+6) = htons(0);
    223   TT.length += 2;
    224 }
    225 
    226 static void fill_iaid()
    227 {
    228   IA_NA iana;
    229   uint8_t *tmp = &mesg.options[TT.length];
    230 
    231   fill_option(DHCP6_OPT_IA_NA, 12, &tmp);
    232   iana.iaid = rand();
    233   iana.t1 = 0xffffffff;
    234   iana.t2 = 0xffffffff;
    235   memcpy(tmp, (uint8_t*)&iana, sizeof(IA_NA));
    236   TT.length += sizeof(IA_NA);
    237 }
    238 
    239 //static void mode_raw(int *sock_t)
    240 static void mode_raw()
    241 {
    242   int constone = 1;
    243   struct sockaddr_ll sockll;
    244 
    245   if (TT.sock > 0) xclose(TT.sock);
    246   TT.sock = xsocket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IPV6));
    247 
    248   memset(&sockll, 0, sizeof(sockll));
    249   sockll.sll_family = AF_PACKET;
    250   sockll.sll_protocol = htons(ETH_P_IPV6);
    251   sockll.sll_ifindex = if_nametoindex(TT.interface_name);
    252   if (bind(TT.sock, (struct sockaddr *) &sockll, sizeof(sockll))) {
    253     xclose(TT.sock);
    254     error_exit("MODE RAW : Bind fail.\n");
    255   }
    256   if (setsockopt(TT.sock, SOL_PACKET, PACKET_HOST,&constone, sizeof(int)) < 0) {
    257 		if (errno != ENOPROTOOPT) error_exit("MODE RAW : Bind fail.\n");
    258 	}
    259 }
    260 
    261 static void generate_transection_id()
    262 {
    263   int i, r = rand() % 0xffffff;
    264 
    265   for (i=0; i<3; i++) {
    266     TT.transction_id[i] = r%0xff;
    267     r = r/10;
    268   }
    269 }
    270 
    271 static void set_timeout(int seconds)
    272 {
    273   TT.tv.tv_sec = seconds;
    274   TT.tv.tv_usec = 100000;
    275 }
    276 
    277 static void  send_msg(int type)
    278 {
    279   struct sockaddr_in6 addr6;
    280   int sendlength = 0;
    281 
    282   memset(&addr6, 0, sizeof(addr6));
    283   addr6.sin6_family = AF_INET6;
    284   addr6.sin6_port = htons(DHCPC_SERVER_PORT); //SERVER_PORT
    285   inet_pton(AF_INET6, "ff02::1:2", &addr6.sin6_addr);
    286   mesg.msgtype = type;
    287   generate_transection_id();
    288   memcpy(mesg.transaction_id, TT.transction_id, 3);
    289 
    290   if (type  == DHCP6SOLICIT) {
    291     TT.length = 0;
    292     fill_clientID();
    293     fill_optionRequest();
    294     fill_elapsedTime();
    295     fill_iaid();
    296     sendlength = sizeof(dhcp6_msg_t) - 524 + TT.length;
    297   } else if (type == DHCP6REQUEST || type == DHCP6RELEASE || type == DHCP6RENEW)
    298     sendlength = TT.request_length;
    299   dbg("Sending message type: %d\n", type);
    300   sendlength = sendto(TT.sock1, &mesg, sendlength , 0,(struct sockaddr *)&addr6,
    301           sizeof(struct sockaddr_in6 ));
    302   if (sendlength <= 0) dbg("Error in sending message type: %d\n", type);
    303 }
    304 
    305 uint8_t *get_msg_ptr(uint8_t *data, int data_length, int msgtype)
    306 {
    307   uint16_t type =  *((uint16_t*)data), length = *((uint16_t*)(data+2));
    308 
    309   type = ntohs(type);
    310   if (type == msgtype) return data;
    311   length = ntohs(length);
    312   while (type != msgtype) {
    313     data_length -= (4 + length);
    314     if (data_length <= 0) break;
    315     data = data + 4 + length;
    316     type = ntohs(*((uint16_t*)data));
    317     length = ntohs(*((uint16_t*)(data+2)));
    318     if (type == msgtype) return data;
    319   }
    320   return NULL;
    321 }
    322 
    323 static uint8_t *check_server_id(uint8_t *data, int data_length)
    324 {
    325   return get_msg_ptr(data,  data_length, DHCP6_OPT_SERVERID);
    326 }
    327 
    328 static int check_client_id(uint8_t *data, int data_length)
    329 {
    330   if ((data = get_msg_ptr(data,  data_length, DHCP6_OPT_CLIENTID))) {
    331     DUID one = *((DUID*)(data+4));
    332     DUID two = *((DUID*)&mesg.options[4]);
    333 
    334     if (!memcmp(&one, &two, sizeof(DUID))) return 1;
    335   }
    336   return 0;
    337 }
    338 
    339 static int validate_ids()
    340 {
    341   if (!check_server_id(mymsg->dhcp6.options,
    342     TT.status - ((char*)&mymsg->dhcp6.options[0] - (char*)mymsg) )) {
    343     dbg("Invalid server id: %d\n");
    344     return 0;
    345   }
    346   if (!check_client_id(mymsg->dhcp6.options,
    347     TT.status - ((char*)&mymsg->dhcp6.options[0] - (char*)mymsg) )) {
    348     dbg("Invalid client id: %d\n");
    349     return 0;
    350   }
    351   return 1;
    352 }
    353 
    354 static void parse_ia_na(uint8_t *data, int data_length)
    355 {
    356   uint8_t *t = get_msg_ptr(data, data_length, DHCP6_OPT_IA_NA);
    357   uint16_t iana_len, content_len = 0;
    358 
    359   memset(&dhcp_data,0,sizeof(dhcp_data));
    360   if (!t) return;
    361 
    362   iana_len = ntohs(*((uint16_t*)(t+2)));
    363   dhcp_data.iaid = ntohl(*((uint32_t*)(t+4)));
    364   dhcp_data.t1 = ntohl(*((uint32_t*)(t+8)));
    365   dhcp_data.t2 = ntohl(*((uint32_t*)(t+12)));
    366   t += 16;
    367   iana_len -= 12;
    368 
    369   while(iana_len > 0) {
    370     uint16_t sub_type = ntohs(*((uint16_t*)(t)));
    371 
    372     switch (sub_type) {
    373       case DHCP6_OPT_IA_ADDR:
    374         content_len = ntohs(*((uint16_t*)(t+2)));
    375         memcpy(dhcp_data.ipaddr,t+4,16);
    376         if (TT.state == DHCP6SOLICIT) {
    377           if (TT.req_ip) {
    378             struct addrinfo *res = NULL;
    379 
    380             if(!getaddrinfo(TT.req_ip, NULL, NULL,&res)) {
    381               dbg("Requesting IP: %s\n", TT.req_ip);
    382               memcpy (&TT.input_socket6, res->ai_addr, res->ai_addrlen);
    383               memcpy(t+4, TT.input_socket6.sin6_addr.__in6_u.__u6_addr8, 16);
    384             } else xprintf("Invalid IP: %s\n",TT.req_ip);
    385             freeaddrinfo(res);
    386           }
    387         }
    388         dhcp_data.pf_lf = ntohl(*((uint32_t*)(t+20)));
    389         dhcp_data.va_lf = ntohl(*((uint32_t*)(t+24)));
    390         iana_len -= (content_len + 4);
    391         t += (content_len + 4);
    392         break;
    393       case DHCP6_OPT_STATUS_CODE:
    394         content_len = ntohs(*((uint16_t*)(t+2)));
    395         dhcp_data.status_code = ntohs(*((uint16_t*)(t+4)));
    396         iana_len -= (content_len + 4);
    397         t += (content_len + 4);
    398         break;
    399       default:
    400         content_len = ntohs(*((uint16_t*)(t+2)));
    401         iana_len -= (content_len + 4);
    402         t += (content_len + 4);
    403         break;
    404     }
    405   }
    406 }
    407 
    408 static void write_pid(char *path)
    409 {
    410   int pidfile = open(path, O_CREAT | O_WRONLY | O_TRUNC, 0666);
    411 
    412   if (pidfile > 0) {
    413     char pidbuf[12];
    414 
    415     sprintf(pidbuf, "%u", (unsigned)getpid());
    416     write(pidfile, pidbuf, strlen(pidbuf));
    417     close(pidfile);
    418   }
    419 }
    420 
    421 // Creates environment pointers from RES to use in script
    422 static int fill_envp(DHCP_DATA *res)
    423 {
    424   int ret = setenv("interface", TT.interface_name, 1);
    425 
    426   if (ret) return ret;
    427   inet_ntop(AF_INET6, res->ipaddr, toybuf, INET6_ADDRSTRLEN);
    428   ret = setenv("ip",(const char*)toybuf , 1);
    429   return ret;
    430 }
    431 
    432 // Executes Script NAME.
    433 static void run_script(DHCP_DATA *res,  char *name)
    434 {
    435   volatile int error = 0;
    436   struct stat sts;
    437   pid_t pid;
    438   char *argv[3];
    439   char *script = (toys.optflags & FLAG_s) ? TT.script
    440     : "/usr/share/dhcp/default.script";
    441 
    442   if (stat(script, &sts) == -1 && errno == ENOENT) return;
    443   if (!res || fill_envp(res)) {
    444     dbg("Failed to create environment variables.\n");
    445     return;
    446   }
    447   dbg("Executing %s %s\n", script, name);
    448   argv[0] = (char*)script;
    449   argv[1] = (char*)name;
    450   argv[2] = NULL;
    451   fflush(NULL);
    452 
    453   pid = vfork();
    454   if (pid < 0) {
    455     dbg("Fork failed.\n");
    456     return;
    457   }
    458   if (!pid) {
    459     execvp(argv[0], argv);
    460     error = errno;
    461     _exit(111);
    462   }
    463   if (error) {
    464     waitpid(pid, NULL, 0);
    465     errno = error;
    466     perror_msg("script exec failed");
    467   }
    468   dbg("script complete.\n");
    469 }
    470 
    471 static void lease_fail()
    472 {
    473   dbg("Lease failed.\n");
    474   run_script(NULL, "leasefail");
    475   if (toys.optflags & FLAG_n) {
    476     xclose(TT.sock);
    477     xclose(TT.sock1);
    478     error_exit("Lease Failed, Exiting.");
    479   }
    480   if (toys.optflags & FLAG_b) {
    481     dbg("Lease failed. Going to daemon mode.\n");
    482     if (daemon(0,0)) perror_exit("daemonize");
    483     if (toys.optflags & FLAG_p) write_pid(TT.pidfile);
    484     toys.optflags &= ~FLAG_b;
    485     toys.optflags |= FLAG_f;
    486   }
    487 }
    488 
    489 // Generic signal handler real handling is done in main funcrion.
    490 static void signal_handler(int sig)
    491 {
    492     dbg("Caught signal: %d\n", sig);
    493     switch (sig) {
    494     case SIGUSR1:
    495       dbg("SIGUSR1.\n");
    496       if (TT.state == DHCP6RELEASE || TT.state == DHCP6REQUEST ) {
    497         TT.state = DHCP6SOLICIT;
    498         set_timeout(0);
    499         return;
    500       }
    501       dbg("SIGUSR1 sending renew.\n");
    502       send_msg(DHCP6RENEW);
    503       TT.state = DHCP6RENEW;
    504       TT.retries = 0;
    505       set_timeout(0);
    506       break;
    507     case SIGUSR2:
    508       dbg("SIGUSR2.\n");
    509       if (TT.state == DHCP6RELEASE) return;
    510       if (TT.state != DHCP6CONFIRM ) return;
    511       dbg("SIGUSR2 sending release.\n");
    512       send_msg(DHCP6RELEASE);
    513       TT.state = DHCP6RELEASE;
    514       TT.retries = 0;
    515       set_timeout(0);
    516       break;
    517     case SIGTERM:
    518     case SIGINT:
    519       dbg((sig == SIGTERM)?"SIGTERM.\n":"SIGINT.\n");
    520       if ((toys.optflags & FLAG_R) && TT.state == DHCP6CONFIRM)
    521         send_msg(DHCP6RELEASE);
    522       if(sig == SIGINT) exit(0);
    523       break;
    524     default: break;
    525   }
    526 }
    527 
    528 // signal setup for SIGUSR1 SIGUSR2 SIGTERM
    529 static int setup_signal()
    530 {
    531   signal(SIGUSR1, signal_handler);
    532   signal(SIGUSR2, signal_handler);
    533   signal(SIGTERM, signal_handler);
    534   signal(SIGINT, signal_handler);
    535   return 0;
    536 }
    537 
    538 void dhcp6_main(void)
    539 {
    540   struct sockaddr_in6  sinaddr6;
    541   int constone = 1;
    542   fd_set rfds;
    543 
    544   srand(time(NULL));
    545   setlinebuf(stdout);
    546   dbg = dummy;
    547   TT.state = DHCP6SOLICIT;
    548 
    549   if (toys.optflags & FLAG_v) dbg = logit;
    550   if (!TT.interface_name) TT.interface_name = "eth0";
    551   if (toys.optflags & FLAG_p) write_pid(TT.pidfile);
    552   if (!TT.retry) TT.retry = 3;
    553   if (!TT.timeout) TT.timeout = 3;
    554   if (!TT.errortimeout) TT.errortimeout = 20;
    555   if (toys.optflags & FLAG_S) {
    556     openlog("DHCP6 :", LOG_PID, LOG_DAEMON);
    557     dbg = logit;
    558   }
    559 
    560   dbg("Interface: %s\n", TT.interface_name);
    561   dbg("pid file: %s\n", TT.pidfile);
    562   dbg("Retry count: %d\n", TT.retry);
    563   dbg("Timeout : %d\n", TT.timeout);
    564   dbg("Error timeout: %d\n", TT.errortimeout);
    565 
    566 
    567 
    568   setup_signal();
    569   TT.sock1 = xsocket(PF_INET6, SOCK_DGRAM, 0);
    570   memset(&sinaddr6, 0, sizeof(sinaddr6));
    571   sinaddr6.sin6_family = AF_INET6;
    572   sinaddr6.sin6_port = htons(DHCPC_CLIENT_PORT);
    573   sinaddr6.sin6_scope_id = if_nametoindex(TT.interface_name);
    574   sinaddr6.sin6_addr = in6addr_any ;
    575 
    576   xsetsockopt(TT.sock1, SOL_SOCKET, SO_REUSEADDR, &constone, sizeof(constone));
    577 
    578   if (bind(TT.sock1, (struct sockaddr *)&sinaddr6, sizeof(sinaddr6))) {
    579     xclose(TT.sock1);
    580     error_exit("bind failed");
    581   }
    582 
    583   mode_raw();
    584   set_timeout(0);
    585   for (;;) {
    586     int maxfd = TT.sock;
    587 
    588     if (TT.sock >= 0) FD_SET(TT.sock, &rfds);
    589     TT.retval = 0;
    590     if ((TT.retval = select(maxfd + 1, &rfds, NULL, NULL, &TT.tv)) < 0) {
    591       if(errno == EINTR) continue;
    592       perror_exit("Error in select");
    593     }
    594     if (!TT.retval) {
    595       if (TT.state == DHCP6SOLICIT || TT.state == DHCP6CONFIRM) {
    596         dbg("State is solicit, sending solicit packet\n");
    597         run_script(NULL, "deconfig");
    598         send_msg(DHCP6SOLICIT);
    599         TT.state = DHCP6SOLICIT;
    600         TT.retries++;
    601         if(TT.retries > TT.retry) set_timeout(TT.errortimeout);
    602         else if (TT.retries == TT.retry) {
    603           dbg("State is solicit, retry count is max.\n");
    604           lease_fail();
    605           set_timeout(TT.errortimeout);
    606         } else set_timeout(TT.timeout);
    607         continue;
    608       } else if (TT.state == DHCP6REQUEST || TT.state == DHCP6RENEW ||
    609               TT.state == DHCP6RELEASE) {
    610         dbg("State is %d , sending packet\n", TT.state);
    611         send_msg(TT.state);
    612         TT.retries++;
    613         if (TT.retries > TT.retry) set_timeout(TT.errortimeout);
    614         else if (TT.retries == TT.retry) {
    615           lease_fail();
    616           set_timeout(TT.errortimeout);
    617         } else set_timeout(TT.timeout);
    618         continue;
    619       }
    620     } else if (FD_ISSET(TT.sock, &rfds)) {
    621       if ((TT.status = read(TT.sock, toybuf, sizeof(toybuf))) <= 0) continue;
    622       mymsg = (dhcp6_raw_t*)toybuf;
    623       if (ntohs(mymsg->udph.dest) == 546 &&
    624               !memcmp(mymsg->dhcp6.transaction_id, TT.transction_id, 3)) {
    625         if (TT.state == DHCP6SOLICIT) {
    626           if (mymsg->dhcp6.msgtype == DHCP6ADVERTISE ) {
    627             if (!validate_ids()) {
    628               dbg("Invalid id recieved, solicit.\n");
    629               TT.state = DHCP6SOLICIT;
    630               continue;
    631             }
    632             dbg("Got reply to request or solicit.\n");
    633             TT.retries = 0;
    634             set_timeout(0);
    635             TT.request_length = TT.status - ((char*)&mymsg->dhcp6 - (char*)mymsg);
    636             memcpy((uint8_t*)&mesg, &mymsg->dhcp6, TT.request_length);
    637             parse_ia_na(mesg.options, TT.request_length);
    638             dbg("Status code:%d\n", dhcp_data.status_code);
    639             inet_ntop(AF_INET6, dhcp_data.ipaddr, toybuf, INET6_ADDRSTRLEN);
    640             dbg("Advertiesed IP: %s\n", toybuf);
    641             TT.state = DHCP6REQUEST;
    642           } else {
    643             dbg("Invalid solicit.\n");
    644             continue;
    645           }
    646         } else if (TT.state == DHCP6REQUEST || TT.state == DHCP6RENEW ) {
    647           if (mymsg->dhcp6.msgtype == DHCP6REPLY) {
    648             if (!validate_ids()) {
    649               dbg("Invalid id recieved, %d.\n", TT.state);
    650               TT.state = DHCP6REQUEST;
    651               continue;
    652             }
    653             dbg("Got reply to request or renew.\n");
    654             TT.request_length = TT.status - ((char*)&mymsg->dhcp6 - (char*)mymsg);
    655             memcpy((uint8_t*)&mesg, &mymsg->dhcp6, TT.request_length);
    656             parse_ia_na(mymsg->dhcp6.options, TT.request_length);
    657             dbg("Status code:%d\n", dhcp_data.status_code);
    658             inet_ntop(AF_INET6, dhcp_data.ipaddr, toybuf, INET6_ADDRSTRLEN);
    659             dbg("Got IP: %s\n", toybuf);
    660             TT.retries = 0;
    661             run_script(&dhcp_data, (TT.state == DHCP6REQUEST) ?
    662               "request" : "renew");
    663             if (toys.optflags & FLAG_q) {
    664               if (toys.optflags & FLAG_R) send_msg(DHCP6RELEASE);
    665               break;
    666             }
    667             TT.state = DHCP6CONFIRM;
    668             set_timeout((dhcp_data.va_lf)?dhcp_data.va_lf:INT_MAX);
    669             dbg("Setting timeout to intmax.");
    670             if (TT.state == DHCP6REQUEST || !(toys.optflags & FLAG_f)) {
    671               dbg("Making it a daemon\n");
    672               if (daemon(0,0)) perror_exit("daemonize");
    673               toys.optflags |= FLAG_f;
    674               if (toys.optflags & FLAG_p) write_pid(TT.pidfile);
    675             }
    676             dbg("Making it a foreground.\n");
    677             continue;
    678           } else {
    679             dbg("Invalid reply.\n");
    680             continue;
    681           }
    682         } else if (TT.state == DHCP6RELEASE) {
    683           dbg("Got reply to release.\n");
    684           run_script(NULL, "release");
    685           set_timeout(INT_MAX);
    686         }
    687       }
    688     }
    689   }
    690   xclose(TT.sock1);
    691   xclose(TT.sock);
    692 }
    693