10f66f451Sopenharmony_ci/* dhcp6.c - DHCP6 client for dynamic network configuration.
20f66f451Sopenharmony_ci *
30f66f451Sopenharmony_ci * Copyright 2015 Rajni Kant <rajnikant12345@gmail.com>
40f66f451Sopenharmony_ci *
50f66f451Sopenharmony_ci * Not in SUSv4.
60f66f451Sopenharmony_ciUSE_DHCP6(NEWTOY(dhcp6, "r:A#<0T#<0t#<0s:p:i:SRvqnbf", TOYFLAG_SBIN|TOYFLAG_ROOTONLY))
70f66f451Sopenharmony_ci
80f66f451Sopenharmony_ciconfig DHCP6
90f66f451Sopenharmony_ci  bool "dhcp6"
100f66f451Sopenharmony_ci  default n
110f66f451Sopenharmony_ci  help
120f66f451Sopenharmony_ci  usage: dhcp6 [-fbnqvR] [-i IFACE] [-r IP] [-s PROG] [-p PIDFILE]
130f66f451Sopenharmony_ci
140f66f451Sopenharmony_ci        Configure network dynamically using DHCP.
150f66f451Sopenharmony_ci
160f66f451Sopenharmony_ci      -i Interface to use (default eth0)
170f66f451Sopenharmony_ci      -p Create pidfile
180f66f451Sopenharmony_ci      -s Run PROG at DHCP events
190f66f451Sopenharmony_ci      -t Send up to N Solicit packets
200f66f451Sopenharmony_ci      -T Pause between packets (default 3 seconds)
210f66f451Sopenharmony_ci      -A Wait N seconds after failure (default 20)
220f66f451Sopenharmony_ci      -f Run in foreground
230f66f451Sopenharmony_ci      -b Background if lease is not obtained
240f66f451Sopenharmony_ci      -n Exit if lease is not obtained
250f66f451Sopenharmony_ci      -q Exit after obtaining lease
260f66f451Sopenharmony_ci      -R Release IP on exit
270f66f451Sopenharmony_ci      -S Log to syslog too
280f66f451Sopenharmony_ci      -r Request this IP address
290f66f451Sopenharmony_ci      -v Verbose
300f66f451Sopenharmony_ci
310f66f451Sopenharmony_ci      Signals:
320f66f451Sopenharmony_ci      USR1  Renew current lease
330f66f451Sopenharmony_ci      USR2  Release current lease
340f66f451Sopenharmony_ci*/
350f66f451Sopenharmony_ci#define FOR_dhcp6
360f66f451Sopenharmony_ci#include "toys.h"
370f66f451Sopenharmony_ci#include <linux/sockios.h>
380f66f451Sopenharmony_ci#include <linux/if_ether.h>
390f66f451Sopenharmony_ci#include <netinet/ip.h>
400f66f451Sopenharmony_ci#include <netinet/ip6.h>
410f66f451Sopenharmony_ci#include <netinet/udp.h>
420f66f451Sopenharmony_ci#include <linux/if_packet.h>
430f66f451Sopenharmony_ci#include <syslog.h>
440f66f451Sopenharmony_ci
450f66f451Sopenharmony_ciGLOBALS(
460f66f451Sopenharmony_ci  char *interface_name, *pidfile, *script;
470f66f451Sopenharmony_ci  long retry, timeout, errortimeout;
480f66f451Sopenharmony_ci  char *req_ip;
490f66f451Sopenharmony_ci  int length, state, request_length, sock, sock1, status, retval, retries;
500f66f451Sopenharmony_ci  struct timeval tv;
510f66f451Sopenharmony_ci  uint8_t transction_id[3];
520f66f451Sopenharmony_ci  struct sockaddr_in6 input_socket6;
530f66f451Sopenharmony_ci)
540f66f451Sopenharmony_ci
550f66f451Sopenharmony_ci#define DHCP6SOLICIT        1
560f66f451Sopenharmony_ci#define DHCP6ADVERTISE      2   // server -> client
570f66f451Sopenharmony_ci#define DHCP6REQUEST        3
580f66f451Sopenharmony_ci#define DHCP6CONFIRM        4
590f66f451Sopenharmony_ci#define DHCP6RENEW          5
600f66f451Sopenharmony_ci#define DHCP6REBIND         6
610f66f451Sopenharmony_ci#define DHCP6REPLY          7   // server -> client
620f66f451Sopenharmony_ci#define DHCP6RELEASE        8
630f66f451Sopenharmony_ci#define DHCP6DECLINE        9
640f66f451Sopenharmony_ci#define DHCP6RECONFIGURE    10  // server -> client
650f66f451Sopenharmony_ci#define DHCP6INFOREQUEST    11
660f66f451Sopenharmony_ci#define DHCP6RELAYFLOW      12  // relay -> relay/server
670f66f451Sopenharmony_ci#define DHCP6RELAYREPLY     13  // server/relay -> relay
680f66f451Sopenharmony_ci
690f66f451Sopenharmony_ci// DHCPv6 option codes (partial). See RFC 3315
700f66f451Sopenharmony_ci#define DHCP6_OPT_CLIENTID      1
710f66f451Sopenharmony_ci#define DHCP6_OPT_SERVERID      2
720f66f451Sopenharmony_ci#define DHCP6_OPT_IA_NA         3
730f66f451Sopenharmony_ci#define DHCP6_OPT_IA_ADDR       5
740f66f451Sopenharmony_ci#define DHCP6_OPT_ORO           6
750f66f451Sopenharmony_ci#define DHCP6_OPT_PREFERENCE    7
760f66f451Sopenharmony_ci#define DHCP6_OPT_ELAPSED_TIME  8
770f66f451Sopenharmony_ci#define DHCP6_OPT_RELAY_MSG     9
780f66f451Sopenharmony_ci#define DHCP6_OPT_STATUS_CODE   13
790f66f451Sopenharmony_ci#define DHCP6_OPT_IA_PD         25
800f66f451Sopenharmony_ci#define DHCP6_OPT_IA_PREFIX     26
810f66f451Sopenharmony_ci
820f66f451Sopenharmony_ci#define DHCP6_STATUS_SUCCESS        0
830f66f451Sopenharmony_ci#define DHCP6_STATUS_NOADDRSAVAIL   2
840f66f451Sopenharmony_ci
850f66f451Sopenharmony_ci#define DHCP6_DUID_LLT    1
860f66f451Sopenharmony_ci#define DHCP6_DUID_EN     2
870f66f451Sopenharmony_ci#define DHCP6_DUID_LL     3
880f66f451Sopenharmony_ci#define DHCP6_DUID_UUID   4
890f66f451Sopenharmony_ci
900f66f451Sopenharmony_ci#define DHCPC_SERVER_PORT     547
910f66f451Sopenharmony_ci#define DHCPC_CLIENT_PORT     546
920f66f451Sopenharmony_ci
930f66f451Sopenharmony_ci#define LOG_SILENT          0x0
940f66f451Sopenharmony_ci#define LOG_CONSOLE         0x1
950f66f451Sopenharmony_ci#define LOG_SYSTEM          0x2
960f66f451Sopenharmony_ci
970f66f451Sopenharmony_citypedef struct __attribute__((packed)) dhcp6_msg_s {
980f66f451Sopenharmony_ci  uint8_t msgtype, transaction_id[3], options[524];
990f66f451Sopenharmony_ci} dhcp6_msg_t;
1000f66f451Sopenharmony_ci
1010f66f451Sopenharmony_citypedef struct __attribute__((packed)) optval_duid_llt {
1020f66f451Sopenharmony_ci  uint16_t type;
1030f66f451Sopenharmony_ci  uint16_t hwtype;
1040f66f451Sopenharmony_ci  uint32_t time;
1050f66f451Sopenharmony_ci  uint8_t lladdr[6];
1060f66f451Sopenharmony_ci} DUID;
1070f66f451Sopenharmony_ci
1080f66f451Sopenharmony_citypedef struct __attribute__((packed)) optval_ia_na {
1090f66f451Sopenharmony_ci  uint32_t iaid, t1, t2;
1100f66f451Sopenharmony_ci} IA_NA;
1110f66f451Sopenharmony_ci
1120f66f451Sopenharmony_citypedef struct __attribute__((packed)) dhcp6_raw_s {
1130f66f451Sopenharmony_ci  struct ip6_hdr iph;
1140f66f451Sopenharmony_ci  struct udphdr udph;
1150f66f451Sopenharmony_ci  dhcp6_msg_t dhcp6;
1160f66f451Sopenharmony_ci} dhcp6_raw_t;
1170f66f451Sopenharmony_ci
1180f66f451Sopenharmony_citypedef struct __attribute__((packed)) dhcp_data_client {
1190f66f451Sopenharmony_ci  uint16_t  status_code;
1200f66f451Sopenharmony_ci  uint32_t iaid , t1,t2, pf_lf, va_lf;
1210f66f451Sopenharmony_ci  uint8_t ipaddr[17] ;
1220f66f451Sopenharmony_ci} DHCP_DATA;
1230f66f451Sopenharmony_ci
1240f66f451Sopenharmony_cistatic DHCP_DATA dhcp_data;
1250f66f451Sopenharmony_cistatic dhcp6_raw_t *mymsg;
1260f66f451Sopenharmony_cistatic dhcp6_msg_t mesg;
1270f66f451Sopenharmony_cistatic DUID *duid;
1280f66f451Sopenharmony_ci
1290f66f451Sopenharmony_cistatic void (*dbg)(char *format, ...);
1300f66f451Sopenharmony_cistatic void dummy(char *format, ...)
1310f66f451Sopenharmony_ci{
1320f66f451Sopenharmony_ci  return;
1330f66f451Sopenharmony_ci}
1340f66f451Sopenharmony_ci
1350f66f451Sopenharmony_cistatic void logit(char *format, ...)
1360f66f451Sopenharmony_ci{
1370f66f451Sopenharmony_ci  int used;
1380f66f451Sopenharmony_ci  char *msg;
1390f66f451Sopenharmony_ci  va_list p, t;
1400f66f451Sopenharmony_ci  uint8_t infomode = LOG_SILENT;
1410f66f451Sopenharmony_ci
1420f66f451Sopenharmony_ci  if (toys.optflags & FLAG_S) infomode |= LOG_SYSTEM;
1430f66f451Sopenharmony_ci  if(toys.optflags & FLAG_v) infomode |= LOG_CONSOLE;
1440f66f451Sopenharmony_ci  va_start(p, format);
1450f66f451Sopenharmony_ci  va_copy(t, p);
1460f66f451Sopenharmony_ci  used = vsnprintf(NULL, 0, format, t);
1470f66f451Sopenharmony_ci  used++;
1480f66f451Sopenharmony_ci  va_end(t);
1490f66f451Sopenharmony_ci
1500f66f451Sopenharmony_ci  msg = xmalloc(used);
1510f66f451Sopenharmony_ci  vsnprintf(msg, used, format, p);
1520f66f451Sopenharmony_ci  va_end(p);
1530f66f451Sopenharmony_ci
1540f66f451Sopenharmony_ci  if (infomode & LOG_SYSTEM) syslog(LOG_INFO, "%s", msg);
1550f66f451Sopenharmony_ci  if (infomode & LOG_CONSOLE) printf("%s", msg);
1560f66f451Sopenharmony_ci  free(msg);
1570f66f451Sopenharmony_ci  return;
1580f66f451Sopenharmony_ci}
1590f66f451Sopenharmony_ci
1600f66f451Sopenharmony_cistatic void get_mac(uint8_t *mac, char *interface)
1610f66f451Sopenharmony_ci{
1620f66f451Sopenharmony_ci  int fd;
1630f66f451Sopenharmony_ci  struct ifreq req;
1640f66f451Sopenharmony_ci
1650f66f451Sopenharmony_ci  if (!mac) return;
1660f66f451Sopenharmony_ci  fd = xsocket(AF_INET6, SOCK_RAW, IPPROTO_RAW);
1670f66f451Sopenharmony_ci  req.ifr_addr.sa_family = AF_INET6;
1680f66f451Sopenharmony_ci  xstrncpy(req.ifr_name, interface, IFNAMSIZ);
1690f66f451Sopenharmony_ci  xioctl(fd, SIOCGIFHWADDR, &req);
1700f66f451Sopenharmony_ci  memcpy(mac, req.ifr_hwaddr.sa_data, 6);
1710f66f451Sopenharmony_ci  xclose(fd);
1720f66f451Sopenharmony_ci}
1730f66f451Sopenharmony_ci
1740f66f451Sopenharmony_cistatic void fill_option(uint16_t option_id, uint16_t option_len, uint8_t **dhmesg)
1750f66f451Sopenharmony_ci{
1760f66f451Sopenharmony_ci  uint8_t *tmp = *dhmesg;
1770f66f451Sopenharmony_ci
1780f66f451Sopenharmony_ci  *((uint16_t*)tmp) = htons(option_id);
1790f66f451Sopenharmony_ci  *(uint16_t*)(tmp+2) = htons(option_len);
1800f66f451Sopenharmony_ci  *dhmesg += 4;
1810f66f451Sopenharmony_ci  TT.length += 4;
1820f66f451Sopenharmony_ci}
1830f66f451Sopenharmony_ci
1840f66f451Sopenharmony_cistatic void fill_clientID()
1850f66f451Sopenharmony_ci{
1860f66f451Sopenharmony_ci  uint8_t *tmp = &mesg.options[TT.length];
1870f66f451Sopenharmony_ci
1880f66f451Sopenharmony_ci  if(!duid) {
1890f66f451Sopenharmony_ci    uint8_t mac[7] = {0,};
1900f66f451Sopenharmony_ci    duid = (DUID*)malloc(sizeof(DUID));
1910f66f451Sopenharmony_ci    duid->type = htons(1);
1920f66f451Sopenharmony_ci    duid->hwtype = htons(1);
1930f66f451Sopenharmony_ci    duid->time = htonl((uint32_t)(time(NULL) - 946684800) & 0xffffffff);
1940f66f451Sopenharmony_ci    fill_option(DHCP6_OPT_CLIENTID,14,&tmp);
1950f66f451Sopenharmony_ci    get_mac(mac, TT.interface_name);
1960f66f451Sopenharmony_ci    memcpy(duid->lladdr,mac, 6);
1970f66f451Sopenharmony_ci    memcpy(tmp,(uint8_t*)duid,sizeof(DUID));
1980f66f451Sopenharmony_ci  }
1990f66f451Sopenharmony_ci  else {
2000f66f451Sopenharmony_ci    fill_option(DHCP6_OPT_CLIENTID,14,&tmp);
2010f66f451Sopenharmony_ci    memcpy(tmp,(uint8_t*)duid,sizeof(DUID));
2020f66f451Sopenharmony_ci  }
2030f66f451Sopenharmony_ci  TT.length += sizeof(DUID);
2040f66f451Sopenharmony_ci}
2050f66f451Sopenharmony_ci
2060f66f451Sopenharmony_ci// TODO: make it generic for multiple options.
2070f66f451Sopenharmony_cistatic void fill_optionRequest()
2080f66f451Sopenharmony_ci{
2090f66f451Sopenharmony_ci  uint8_t *tmp = &mesg.options[TT.length];
2100f66f451Sopenharmony_ci
2110f66f451Sopenharmony_ci  fill_option(DHCP6_OPT_ORO,4,&tmp);
2120f66f451Sopenharmony_ci  *(uint16_t*)(tmp+4) = htons(23);
2130f66f451Sopenharmony_ci  *(uint16_t*)(tmp+6) = htons(24);
2140f66f451Sopenharmony_ci  TT.length += 4;
2150f66f451Sopenharmony_ci}
2160f66f451Sopenharmony_ci
2170f66f451Sopenharmony_cistatic void fill_elapsedTime()
2180f66f451Sopenharmony_ci{
2190f66f451Sopenharmony_ci  uint8_t *tmp = &mesg.options[TT.length];
2200f66f451Sopenharmony_ci
2210f66f451Sopenharmony_ci  fill_option(DHCP6_OPT_ELAPSED_TIME, 2, &tmp);
2220f66f451Sopenharmony_ci  *(uint16_t*)(tmp+6) = htons(0);
2230f66f451Sopenharmony_ci  TT.length += 2;
2240f66f451Sopenharmony_ci}
2250f66f451Sopenharmony_ci
2260f66f451Sopenharmony_cistatic void fill_iaid()
2270f66f451Sopenharmony_ci{
2280f66f451Sopenharmony_ci  IA_NA iana;
2290f66f451Sopenharmony_ci  uint8_t *tmp = &mesg.options[TT.length];
2300f66f451Sopenharmony_ci
2310f66f451Sopenharmony_ci  fill_option(DHCP6_OPT_IA_NA, 12, &tmp);
2320f66f451Sopenharmony_ci  iana.iaid = rand();
2330f66f451Sopenharmony_ci  iana.t1 = 0xffffffff;
2340f66f451Sopenharmony_ci  iana.t2 = 0xffffffff;
2350f66f451Sopenharmony_ci  memcpy(tmp, (uint8_t*)&iana, sizeof(IA_NA));
2360f66f451Sopenharmony_ci  TT.length += sizeof(IA_NA);
2370f66f451Sopenharmony_ci}
2380f66f451Sopenharmony_ci
2390f66f451Sopenharmony_ci//static void mode_raw(int *sock_t)
2400f66f451Sopenharmony_cistatic void mode_raw()
2410f66f451Sopenharmony_ci{
2420f66f451Sopenharmony_ci  int constone = 1;
2430f66f451Sopenharmony_ci  struct sockaddr_ll sockll;
2440f66f451Sopenharmony_ci
2450f66f451Sopenharmony_ci  if (TT.sock > 0) xclose(TT.sock);
2460f66f451Sopenharmony_ci  TT.sock = xsocket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IPV6));
2470f66f451Sopenharmony_ci
2480f66f451Sopenharmony_ci  memset(&sockll, 0, sizeof(sockll));
2490f66f451Sopenharmony_ci  sockll.sll_family = AF_PACKET;
2500f66f451Sopenharmony_ci  sockll.sll_protocol = htons(ETH_P_IPV6);
2510f66f451Sopenharmony_ci  sockll.sll_ifindex = if_nametoindex(TT.interface_name);
2520f66f451Sopenharmony_ci  xbind(TT.sock, (struct sockaddr *) &sockll, sizeof(sockll));
2530f66f451Sopenharmony_ci  if (setsockopt(TT.sock, SOL_PACKET, PACKET_HOST,&constone, sizeof(int)) < 0) {
2540f66f451Sopenharmony_ci    if (errno != ENOPROTOOPT) error_exit("MODE RAW : Bind fail.\n");
2550f66f451Sopenharmony_ci  }
2560f66f451Sopenharmony_ci}
2570f66f451Sopenharmony_ci
2580f66f451Sopenharmony_cistatic void generate_transection_id()
2590f66f451Sopenharmony_ci{
2600f66f451Sopenharmony_ci  int i, r = rand() % 0xffffff;
2610f66f451Sopenharmony_ci
2620f66f451Sopenharmony_ci  for (i=0; i<3; i++) {
2630f66f451Sopenharmony_ci    TT.transction_id[i] = r%0xff;
2640f66f451Sopenharmony_ci    r = r/10;
2650f66f451Sopenharmony_ci  }
2660f66f451Sopenharmony_ci}
2670f66f451Sopenharmony_ci
2680f66f451Sopenharmony_cistatic void set_timeout(int seconds)
2690f66f451Sopenharmony_ci{
2700f66f451Sopenharmony_ci  TT.tv.tv_sec = seconds;
2710f66f451Sopenharmony_ci  TT.tv.tv_usec = 100000;
2720f66f451Sopenharmony_ci}
2730f66f451Sopenharmony_ci
2740f66f451Sopenharmony_cistatic void  send_msg(int type)
2750f66f451Sopenharmony_ci{
2760f66f451Sopenharmony_ci  struct sockaddr_in6 addr6;
2770f66f451Sopenharmony_ci  int sendlength = 0;
2780f66f451Sopenharmony_ci
2790f66f451Sopenharmony_ci  memset(&addr6, 0, sizeof(addr6));
2800f66f451Sopenharmony_ci  addr6.sin6_family = AF_INET6;
2810f66f451Sopenharmony_ci  addr6.sin6_port = htons(DHCPC_SERVER_PORT); //SERVER_PORT
2820f66f451Sopenharmony_ci  inet_pton(AF_INET6, "ff02::1:2", &addr6.sin6_addr);
2830f66f451Sopenharmony_ci  mesg.msgtype = type;
2840f66f451Sopenharmony_ci  generate_transection_id();
2850f66f451Sopenharmony_ci  memcpy(mesg.transaction_id, TT.transction_id, 3);
2860f66f451Sopenharmony_ci
2870f66f451Sopenharmony_ci  if (type  == DHCP6SOLICIT) {
2880f66f451Sopenharmony_ci    TT.length = 0;
2890f66f451Sopenharmony_ci    fill_clientID();
2900f66f451Sopenharmony_ci    fill_optionRequest();
2910f66f451Sopenharmony_ci    fill_elapsedTime();
2920f66f451Sopenharmony_ci    fill_iaid();
2930f66f451Sopenharmony_ci    sendlength = sizeof(dhcp6_msg_t) - 524 + TT.length;
2940f66f451Sopenharmony_ci  } else if (type == DHCP6REQUEST || type == DHCP6RELEASE || type == DHCP6RENEW)
2950f66f451Sopenharmony_ci    sendlength = TT.request_length;
2960f66f451Sopenharmony_ci  dbg("Sending message type: %d\n", type);
2970f66f451Sopenharmony_ci  sendlength = sendto(TT.sock1, &mesg, sendlength , 0,(struct sockaddr *)&addr6,
2980f66f451Sopenharmony_ci          sizeof(struct sockaddr_in6 ));
2990f66f451Sopenharmony_ci  if (sendlength <= 0) dbg("Error in sending message type: %d\n", type);
3000f66f451Sopenharmony_ci}
3010f66f451Sopenharmony_ci
3020f66f451Sopenharmony_ciuint8_t *get_msg_ptr(uint8_t *data, int data_length, int msgtype)
3030f66f451Sopenharmony_ci{
3040f66f451Sopenharmony_ci  uint16_t type =  *((uint16_t*)data), length = *((uint16_t*)(data+2));
3050f66f451Sopenharmony_ci
3060f66f451Sopenharmony_ci  type = ntohs(type);
3070f66f451Sopenharmony_ci  if (type == msgtype) return data;
3080f66f451Sopenharmony_ci  length = ntohs(length);
3090f66f451Sopenharmony_ci  while (type != msgtype) {
3100f66f451Sopenharmony_ci    data_length -= (4 + length);
3110f66f451Sopenharmony_ci    if (data_length <= 0) break;
3120f66f451Sopenharmony_ci    data = data + 4 + length;
3130f66f451Sopenharmony_ci    type = ntohs(*((uint16_t*)data));
3140f66f451Sopenharmony_ci    length = ntohs(*((uint16_t*)(data+2)));
3150f66f451Sopenharmony_ci    if (type == msgtype) return data;
3160f66f451Sopenharmony_ci  }
3170f66f451Sopenharmony_ci  return NULL;
3180f66f451Sopenharmony_ci}
3190f66f451Sopenharmony_ci
3200f66f451Sopenharmony_cistatic uint8_t *check_server_id(uint8_t *data, int data_length)
3210f66f451Sopenharmony_ci{
3220f66f451Sopenharmony_ci  return get_msg_ptr(data,  data_length, DHCP6_OPT_SERVERID);
3230f66f451Sopenharmony_ci}
3240f66f451Sopenharmony_ci
3250f66f451Sopenharmony_cistatic int check_client_id(uint8_t *data, int data_length)
3260f66f451Sopenharmony_ci{
3270f66f451Sopenharmony_ci  if ((data = get_msg_ptr(data,  data_length, DHCP6_OPT_CLIENTID))) {
3280f66f451Sopenharmony_ci    DUID one = *((DUID*)(data+4));
3290f66f451Sopenharmony_ci    DUID two = *((DUID*)&mesg.options[4]);
3300f66f451Sopenharmony_ci
3310f66f451Sopenharmony_ci    if (!memcmp(&one, &two, sizeof(DUID))) return 1;
3320f66f451Sopenharmony_ci  }
3330f66f451Sopenharmony_ci  return 0;
3340f66f451Sopenharmony_ci}
3350f66f451Sopenharmony_ci
3360f66f451Sopenharmony_cistatic int validate_ids()
3370f66f451Sopenharmony_ci{
3380f66f451Sopenharmony_ci  if (!check_server_id(mymsg->dhcp6.options,
3390f66f451Sopenharmony_ci    TT.status - ((char*)&mymsg->dhcp6.options[0] - (char*)mymsg) )) {
3400f66f451Sopenharmony_ci    dbg("Invalid server id: %d\n");
3410f66f451Sopenharmony_ci    return 0;
3420f66f451Sopenharmony_ci  }
3430f66f451Sopenharmony_ci  if (!check_client_id(mymsg->dhcp6.options,
3440f66f451Sopenharmony_ci    TT.status - ((char*)&mymsg->dhcp6.options[0] - (char*)mymsg) )) {
3450f66f451Sopenharmony_ci    dbg("Invalid client id: %d\n");
3460f66f451Sopenharmony_ci    return 0;
3470f66f451Sopenharmony_ci  }
3480f66f451Sopenharmony_ci  return 1;
3490f66f451Sopenharmony_ci}
3500f66f451Sopenharmony_ci
3510f66f451Sopenharmony_cistatic void parse_ia_na(uint8_t *data, int data_length)
3520f66f451Sopenharmony_ci{
3530f66f451Sopenharmony_ci  uint8_t *t = get_msg_ptr(data, data_length, DHCP6_OPT_IA_NA);
3540f66f451Sopenharmony_ci  uint16_t iana_len, content_len = 0;
3550f66f451Sopenharmony_ci
3560f66f451Sopenharmony_ci  memset(&dhcp_data,0,sizeof(dhcp_data));
3570f66f451Sopenharmony_ci  if (!t) return;
3580f66f451Sopenharmony_ci
3590f66f451Sopenharmony_ci  iana_len = ntohs(*((uint16_t*)(t+2)));
3600f66f451Sopenharmony_ci  dhcp_data.iaid = ntohl(*((uint32_t*)(t+4)));
3610f66f451Sopenharmony_ci  dhcp_data.t1 = ntohl(*((uint32_t*)(t+8)));
3620f66f451Sopenharmony_ci  dhcp_data.t2 = ntohl(*((uint32_t*)(t+12)));
3630f66f451Sopenharmony_ci  t += 16;
3640f66f451Sopenharmony_ci  iana_len -= 12;
3650f66f451Sopenharmony_ci
3660f66f451Sopenharmony_ci  while(iana_len > 0) {
3670f66f451Sopenharmony_ci    uint16_t sub_type = ntohs(*((uint16_t*)(t)));
3680f66f451Sopenharmony_ci
3690f66f451Sopenharmony_ci    switch (sub_type) {
3700f66f451Sopenharmony_ci      case DHCP6_OPT_IA_ADDR:
3710f66f451Sopenharmony_ci        content_len = ntohs(*((uint16_t*)(t+2)));
3720f66f451Sopenharmony_ci        memcpy(dhcp_data.ipaddr,t+4,16);
3730f66f451Sopenharmony_ci        if (TT.state == DHCP6SOLICIT) {
3740f66f451Sopenharmony_ci          if (TT.req_ip) {
3750f66f451Sopenharmony_ci            struct addrinfo *res = NULL;
3760f66f451Sopenharmony_ci
3770f66f451Sopenharmony_ci            if(!getaddrinfo(TT.req_ip, NULL, NULL,&res)) {
3780f66f451Sopenharmony_ci              dbg("Requesting IP: %s\n", TT.req_ip);
3790f66f451Sopenharmony_ci              memcpy (&TT.input_socket6, res->ai_addr, res->ai_addrlen);
3800f66f451Sopenharmony_ci              memcpy(t+4, TT.input_socket6.sin6_addr.s6_addr, 16);
3810f66f451Sopenharmony_ci            } else xprintf("Invalid IP: %s\n",TT.req_ip);
3820f66f451Sopenharmony_ci            freeaddrinfo(res);
3830f66f451Sopenharmony_ci          }
3840f66f451Sopenharmony_ci        }
3850f66f451Sopenharmony_ci        dhcp_data.pf_lf = ntohl(*((uint32_t*)(t+20)));
3860f66f451Sopenharmony_ci        dhcp_data.va_lf = ntohl(*((uint32_t*)(t+24)));
3870f66f451Sopenharmony_ci        iana_len -= (content_len + 4);
3880f66f451Sopenharmony_ci        t += (content_len + 4);
3890f66f451Sopenharmony_ci        break;
3900f66f451Sopenharmony_ci      case DHCP6_OPT_STATUS_CODE:
3910f66f451Sopenharmony_ci        content_len = ntohs(*((uint16_t*)(t+2)));
3920f66f451Sopenharmony_ci        dhcp_data.status_code = ntohs(*((uint16_t*)(t+4)));
3930f66f451Sopenharmony_ci        iana_len -= (content_len + 4);
3940f66f451Sopenharmony_ci        t += (content_len + 4);
3950f66f451Sopenharmony_ci        break;
3960f66f451Sopenharmony_ci      default:
3970f66f451Sopenharmony_ci        content_len = ntohs(*((uint16_t*)(t+2)));
3980f66f451Sopenharmony_ci        iana_len -= (content_len + 4);
3990f66f451Sopenharmony_ci        t += (content_len + 4);
4000f66f451Sopenharmony_ci        break;
4010f66f451Sopenharmony_ci    }
4020f66f451Sopenharmony_ci  }
4030f66f451Sopenharmony_ci}
4040f66f451Sopenharmony_ci
4050f66f451Sopenharmony_cistatic void write_pid(char *path)
4060f66f451Sopenharmony_ci{
4070f66f451Sopenharmony_ci  int pidfile = open(path, O_CREAT | O_WRONLY | O_TRUNC, 0666);
4080f66f451Sopenharmony_ci
4090f66f451Sopenharmony_ci  if (pidfile > 0) {
4100f66f451Sopenharmony_ci    char pidbuf[12];
4110f66f451Sopenharmony_ci
4120f66f451Sopenharmony_ci    sprintf(pidbuf, "%u", (unsigned)getpid());
4130f66f451Sopenharmony_ci    write(pidfile, pidbuf, strlen(pidbuf));
4140f66f451Sopenharmony_ci    close(pidfile);
4150f66f451Sopenharmony_ci  }
4160f66f451Sopenharmony_ci}
4170f66f451Sopenharmony_ci
4180f66f451Sopenharmony_ci// Creates environment pointers from RES to use in script
4190f66f451Sopenharmony_cistatic int fill_envp(DHCP_DATA *res)
4200f66f451Sopenharmony_ci{
4210f66f451Sopenharmony_ci  int ret = setenv("interface", TT.interface_name, 1);
4220f66f451Sopenharmony_ci
4230f66f451Sopenharmony_ci  if (ret) return ret;
4240f66f451Sopenharmony_ci  inet_ntop(AF_INET6, res->ipaddr, toybuf, INET6_ADDRSTRLEN);
4250f66f451Sopenharmony_ci  ret = setenv("ip",(const char*)toybuf , 1);
4260f66f451Sopenharmony_ci  return ret;
4270f66f451Sopenharmony_ci}
4280f66f451Sopenharmony_ci
4290f66f451Sopenharmony_ci// Executes Script NAME.
4300f66f451Sopenharmony_cistatic void run_script(DHCP_DATA *res,  char *name)
4310f66f451Sopenharmony_ci{
4320f66f451Sopenharmony_ci  volatile int error = 0;
4330f66f451Sopenharmony_ci  struct stat sts;
4340f66f451Sopenharmony_ci  pid_t pid;
4350f66f451Sopenharmony_ci  char *argv[3];
4360f66f451Sopenharmony_ci  char *script = (toys.optflags & FLAG_s) ? TT.script
4370f66f451Sopenharmony_ci    : "/usr/share/dhcp/default.script";
4380f66f451Sopenharmony_ci
4390f66f451Sopenharmony_ci  if (stat(script, &sts) == -1 && errno == ENOENT) return;
4400f66f451Sopenharmony_ci  if (!res || fill_envp(res)) {
4410f66f451Sopenharmony_ci    dbg("Failed to create environment variables.\n");
4420f66f451Sopenharmony_ci    return;
4430f66f451Sopenharmony_ci  }
4440f66f451Sopenharmony_ci  dbg("Executing %s %s\n", script, name);
4450f66f451Sopenharmony_ci  argv[0] = (char*)script;
4460f66f451Sopenharmony_ci  argv[1] = (char*)name;
4470f66f451Sopenharmony_ci  argv[2] = NULL;
4480f66f451Sopenharmony_ci  fflush(NULL);
4490f66f451Sopenharmony_ci
4500f66f451Sopenharmony_ci  pid = vfork();
4510f66f451Sopenharmony_ci  if (pid < 0) {
4520f66f451Sopenharmony_ci    dbg("Fork failed.\n");
4530f66f451Sopenharmony_ci    return;
4540f66f451Sopenharmony_ci  }
4550f66f451Sopenharmony_ci  if (!pid) {
4560f66f451Sopenharmony_ci    execvp(argv[0], argv);
4570f66f451Sopenharmony_ci    error = errno;
4580f66f451Sopenharmony_ci    _exit(111);
4590f66f451Sopenharmony_ci  }
4600f66f451Sopenharmony_ci  if (error) {
4610f66f451Sopenharmony_ci    waitpid(pid, NULL, 0);
4620f66f451Sopenharmony_ci    errno = error;
4630f66f451Sopenharmony_ci    perror_msg("script exec failed");
4640f66f451Sopenharmony_ci  }
4650f66f451Sopenharmony_ci  dbg("script complete.\n");
4660f66f451Sopenharmony_ci}
4670f66f451Sopenharmony_ci
4680f66f451Sopenharmony_cistatic void lease_fail()
4690f66f451Sopenharmony_ci{
4700f66f451Sopenharmony_ci  dbg("Lease failed.\n");
4710f66f451Sopenharmony_ci  run_script(NULL, "leasefail");
4720f66f451Sopenharmony_ci  if (toys.optflags & FLAG_n) {
4730f66f451Sopenharmony_ci    xclose(TT.sock);
4740f66f451Sopenharmony_ci    xclose(TT.sock1);
4750f66f451Sopenharmony_ci    error_exit("Lease Failed, Exiting.");
4760f66f451Sopenharmony_ci  }
4770f66f451Sopenharmony_ci  if (toys.optflags & FLAG_b) {
4780f66f451Sopenharmony_ci    dbg("Lease failed. Going to daemon mode.\n");
4790f66f451Sopenharmony_ci    if (daemon(0,0)) perror_exit("daemonize");
4800f66f451Sopenharmony_ci    if (toys.optflags & FLAG_p) write_pid(TT.pidfile);
4810f66f451Sopenharmony_ci    toys.optflags &= ~FLAG_b;
4820f66f451Sopenharmony_ci    toys.optflags |= FLAG_f;
4830f66f451Sopenharmony_ci  }
4840f66f451Sopenharmony_ci}
4850f66f451Sopenharmony_ci
4860f66f451Sopenharmony_ci// Generic signal handler real handling is done in main funcrion.
4870f66f451Sopenharmony_cistatic void signal_handler(int sig)
4880f66f451Sopenharmony_ci{
4890f66f451Sopenharmony_ci    dbg("Caught signal: %d\n", sig);
4900f66f451Sopenharmony_ci    switch (sig) {
4910f66f451Sopenharmony_ci    case SIGUSR1:
4920f66f451Sopenharmony_ci      dbg("SIGUSR1.\n");
4930f66f451Sopenharmony_ci      if (TT.state == DHCP6RELEASE || TT.state == DHCP6REQUEST ) {
4940f66f451Sopenharmony_ci        TT.state = DHCP6SOLICIT;
4950f66f451Sopenharmony_ci        set_timeout(0);
4960f66f451Sopenharmony_ci        return;
4970f66f451Sopenharmony_ci      }
4980f66f451Sopenharmony_ci      dbg("SIGUSR1 sending renew.\n");
4990f66f451Sopenharmony_ci      send_msg(DHCP6RENEW);
5000f66f451Sopenharmony_ci      TT.state = DHCP6RENEW;
5010f66f451Sopenharmony_ci      TT.retries = 0;
5020f66f451Sopenharmony_ci      set_timeout(0);
5030f66f451Sopenharmony_ci      break;
5040f66f451Sopenharmony_ci    case SIGUSR2:
5050f66f451Sopenharmony_ci      dbg("SIGUSR2.\n");
5060f66f451Sopenharmony_ci      if (TT.state == DHCP6RELEASE) return;
5070f66f451Sopenharmony_ci      if (TT.state != DHCP6CONFIRM ) return;
5080f66f451Sopenharmony_ci      dbg("SIGUSR2 sending release.\n");
5090f66f451Sopenharmony_ci      send_msg(DHCP6RELEASE);
5100f66f451Sopenharmony_ci      TT.state = DHCP6RELEASE;
5110f66f451Sopenharmony_ci      TT.retries = 0;
5120f66f451Sopenharmony_ci      set_timeout(0);
5130f66f451Sopenharmony_ci      break;
5140f66f451Sopenharmony_ci    case SIGTERM:
5150f66f451Sopenharmony_ci    case SIGINT:
5160f66f451Sopenharmony_ci      dbg((sig == SIGTERM)?"SIGTERM.\n":"SIGINT.\n");
5170f66f451Sopenharmony_ci      if ((toys.optflags & FLAG_R) && TT.state == DHCP6CONFIRM)
5180f66f451Sopenharmony_ci        send_msg(DHCP6RELEASE);
5190f66f451Sopenharmony_ci      if(sig == SIGINT) exit(0);
5200f66f451Sopenharmony_ci      break;
5210f66f451Sopenharmony_ci    default: break;
5220f66f451Sopenharmony_ci  }
5230f66f451Sopenharmony_ci}
5240f66f451Sopenharmony_ci
5250f66f451Sopenharmony_ci// signal setup for SIGUSR1 SIGUSR2 SIGTERM
5260f66f451Sopenharmony_cistatic int setup_signal()
5270f66f451Sopenharmony_ci{
5280f66f451Sopenharmony_ci  signal(SIGUSR1, signal_handler);
5290f66f451Sopenharmony_ci  signal(SIGUSR2, signal_handler);
5300f66f451Sopenharmony_ci  signal(SIGTERM, signal_handler);
5310f66f451Sopenharmony_ci  signal(SIGINT, signal_handler);
5320f66f451Sopenharmony_ci  return 0;
5330f66f451Sopenharmony_ci}
5340f66f451Sopenharmony_ci
5350f66f451Sopenharmony_civoid dhcp6_main(void)
5360f66f451Sopenharmony_ci{
5370f66f451Sopenharmony_ci  struct sockaddr_in6  sinaddr6;
5380f66f451Sopenharmony_ci  int constone = 1;
5390f66f451Sopenharmony_ci  fd_set rfds;
5400f66f451Sopenharmony_ci
5410f66f451Sopenharmony_ci  srand(time(NULL));
5420f66f451Sopenharmony_ci  setlinebuf(stdout);
5430f66f451Sopenharmony_ci  dbg = dummy;
5440f66f451Sopenharmony_ci  TT.state = DHCP6SOLICIT;
5450f66f451Sopenharmony_ci
5460f66f451Sopenharmony_ci  if (toys.optflags & FLAG_v) dbg = logit;
5470f66f451Sopenharmony_ci  if (!TT.interface_name) TT.interface_name = "eth0";
5480f66f451Sopenharmony_ci  if (toys.optflags & FLAG_p) write_pid(TT.pidfile);
5490f66f451Sopenharmony_ci  if (!TT.retry) TT.retry = 3;
5500f66f451Sopenharmony_ci  if (!TT.timeout) TT.timeout = 3;
5510f66f451Sopenharmony_ci  if (!TT.errortimeout) TT.errortimeout = 20;
5520f66f451Sopenharmony_ci  if (toys.optflags & FLAG_S) {
5530f66f451Sopenharmony_ci    openlog("DHCP6 :", LOG_PID, LOG_DAEMON);
5540f66f451Sopenharmony_ci    dbg = logit;
5550f66f451Sopenharmony_ci  }
5560f66f451Sopenharmony_ci
5570f66f451Sopenharmony_ci  dbg("Interface: %s\n", TT.interface_name);
5580f66f451Sopenharmony_ci  dbg("pid file: %s\n", TT.pidfile);
5590f66f451Sopenharmony_ci  dbg("Retry count: %d\n", TT.retry);
5600f66f451Sopenharmony_ci  dbg("Timeout : %d\n", TT.timeout);
5610f66f451Sopenharmony_ci  dbg("Error timeout: %d\n", TT.errortimeout);
5620f66f451Sopenharmony_ci
5630f66f451Sopenharmony_ci
5640f66f451Sopenharmony_ci
5650f66f451Sopenharmony_ci  setup_signal();
5660f66f451Sopenharmony_ci  TT.sock1 = xsocket(PF_INET6, SOCK_DGRAM, 0);
5670f66f451Sopenharmony_ci  memset(&sinaddr6, 0, sizeof(sinaddr6));
5680f66f451Sopenharmony_ci  sinaddr6.sin6_family = AF_INET6;
5690f66f451Sopenharmony_ci  sinaddr6.sin6_port = htons(DHCPC_CLIENT_PORT);
5700f66f451Sopenharmony_ci  sinaddr6.sin6_scope_id = if_nametoindex(TT.interface_name);
5710f66f451Sopenharmony_ci  sinaddr6.sin6_addr = in6addr_any ;
5720f66f451Sopenharmony_ci
5730f66f451Sopenharmony_ci  xsetsockopt(TT.sock1, SOL_SOCKET, SO_REUSEADDR, &constone, sizeof(constone));
5740f66f451Sopenharmony_ci
5750f66f451Sopenharmony_ci  xbind(TT.sock1, (struct sockaddr *)&sinaddr6, sizeof(sinaddr6));
5760f66f451Sopenharmony_ci
5770f66f451Sopenharmony_ci  mode_raw();
5780f66f451Sopenharmony_ci  set_timeout(0);
5790f66f451Sopenharmony_ci  for (;;) {
5800f66f451Sopenharmony_ci    int maxfd = TT.sock;
5810f66f451Sopenharmony_ci
5820f66f451Sopenharmony_ci    if (TT.sock >= 0) FD_SET(TT.sock, &rfds);
5830f66f451Sopenharmony_ci    TT.retval = 0;
5840f66f451Sopenharmony_ci    if ((TT.retval = select(maxfd + 1, &rfds, NULL, NULL, &TT.tv)) < 0) {
5850f66f451Sopenharmony_ci      if(errno == EINTR) continue;
5860f66f451Sopenharmony_ci      perror_exit("Error in select");
5870f66f451Sopenharmony_ci    }
5880f66f451Sopenharmony_ci    if (!TT.retval) {
5890f66f451Sopenharmony_ci      if (TT.state == DHCP6SOLICIT || TT.state == DHCP6CONFIRM) {
5900f66f451Sopenharmony_ci        dbg("State is solicit, sending solicit packet\n");
5910f66f451Sopenharmony_ci        run_script(NULL, "deconfig");
5920f66f451Sopenharmony_ci        send_msg(DHCP6SOLICIT);
5930f66f451Sopenharmony_ci        TT.state = DHCP6SOLICIT;
5940f66f451Sopenharmony_ci        TT.retries++;
5950f66f451Sopenharmony_ci        if(TT.retries > TT.retry) set_timeout(TT.errortimeout);
5960f66f451Sopenharmony_ci        else if (TT.retries == TT.retry) {
5970f66f451Sopenharmony_ci          dbg("State is solicit, retry count is max.\n");
5980f66f451Sopenharmony_ci          lease_fail();
5990f66f451Sopenharmony_ci          set_timeout(TT.errortimeout);
6000f66f451Sopenharmony_ci        } else set_timeout(TT.timeout);
6010f66f451Sopenharmony_ci        continue;
6020f66f451Sopenharmony_ci      } else if (TT.state == DHCP6REQUEST || TT.state == DHCP6RENEW ||
6030f66f451Sopenharmony_ci              TT.state == DHCP6RELEASE) {
6040f66f451Sopenharmony_ci        dbg("State is %d , sending packet\n", TT.state);
6050f66f451Sopenharmony_ci        send_msg(TT.state);
6060f66f451Sopenharmony_ci        TT.retries++;
6070f66f451Sopenharmony_ci        if (TT.retries > TT.retry) set_timeout(TT.errortimeout);
6080f66f451Sopenharmony_ci        else if (TT.retries == TT.retry) {
6090f66f451Sopenharmony_ci          lease_fail();
6100f66f451Sopenharmony_ci          set_timeout(TT.errortimeout);
6110f66f451Sopenharmony_ci        } else set_timeout(TT.timeout);
6120f66f451Sopenharmony_ci        continue;
6130f66f451Sopenharmony_ci      }
6140f66f451Sopenharmony_ci    } else if (FD_ISSET(TT.sock, &rfds)) {
6150f66f451Sopenharmony_ci      if ((TT.status = read(TT.sock, toybuf, sizeof(toybuf))) <= 0) continue;
6160f66f451Sopenharmony_ci      mymsg = (dhcp6_raw_t*)toybuf;
6170f66f451Sopenharmony_ci      if (ntohs(mymsg->udph.dest) == 546 &&
6180f66f451Sopenharmony_ci              !memcmp(mymsg->dhcp6.transaction_id, TT.transction_id, 3)) {
6190f66f451Sopenharmony_ci        if (TT.state == DHCP6SOLICIT) {
6200f66f451Sopenharmony_ci          if (mymsg->dhcp6.msgtype == DHCP6ADVERTISE ) {
6210f66f451Sopenharmony_ci            if (!validate_ids()) {
6220f66f451Sopenharmony_ci              dbg("Invalid id received, solicit.\n");
6230f66f451Sopenharmony_ci              TT.state = DHCP6SOLICIT;
6240f66f451Sopenharmony_ci              continue;
6250f66f451Sopenharmony_ci            }
6260f66f451Sopenharmony_ci            dbg("Got reply to request or solicit.\n");
6270f66f451Sopenharmony_ci            TT.retries = 0;
6280f66f451Sopenharmony_ci            set_timeout(0);
6290f66f451Sopenharmony_ci            TT.request_length = TT.status - ((char*)&mymsg->dhcp6 - (char*)mymsg);
6300f66f451Sopenharmony_ci            memcpy((uint8_t*)&mesg, &mymsg->dhcp6, TT.request_length);
6310f66f451Sopenharmony_ci            parse_ia_na(mesg.options, TT.request_length);
6320f66f451Sopenharmony_ci            dbg("Status code:%d\n", dhcp_data.status_code);
6330f66f451Sopenharmony_ci            inet_ntop(AF_INET6, dhcp_data.ipaddr, toybuf, INET6_ADDRSTRLEN);
6340f66f451Sopenharmony_ci            dbg("Advertiesed IP: %s\n", toybuf);
6350f66f451Sopenharmony_ci            TT.state = DHCP6REQUEST;
6360f66f451Sopenharmony_ci          } else {
6370f66f451Sopenharmony_ci            dbg("Invalid solicit.\n");
6380f66f451Sopenharmony_ci            continue;
6390f66f451Sopenharmony_ci          }
6400f66f451Sopenharmony_ci        } else if (TT.state == DHCP6REQUEST || TT.state == DHCP6RENEW ) {
6410f66f451Sopenharmony_ci          if (mymsg->dhcp6.msgtype == DHCP6REPLY) {
6420f66f451Sopenharmony_ci            if (!validate_ids()) {
6430f66f451Sopenharmony_ci              dbg("Invalid id received, %d.\n", TT.state);
6440f66f451Sopenharmony_ci              TT.state = DHCP6REQUEST;
6450f66f451Sopenharmony_ci              continue;
6460f66f451Sopenharmony_ci            }
6470f66f451Sopenharmony_ci            dbg("Got reply to request or renew.\n");
6480f66f451Sopenharmony_ci            TT.request_length = TT.status - ((char*)&mymsg->dhcp6 - (char*)mymsg);
6490f66f451Sopenharmony_ci            memcpy((uint8_t*)&mesg, &mymsg->dhcp6, TT.request_length);
6500f66f451Sopenharmony_ci            parse_ia_na(mymsg->dhcp6.options, TT.request_length);
6510f66f451Sopenharmony_ci            dbg("Status code:%d\n", dhcp_data.status_code);
6520f66f451Sopenharmony_ci            inet_ntop(AF_INET6, dhcp_data.ipaddr, toybuf, INET6_ADDRSTRLEN);
6530f66f451Sopenharmony_ci            dbg("Got IP: %s\n", toybuf);
6540f66f451Sopenharmony_ci            TT.retries = 0;
6550f66f451Sopenharmony_ci            run_script(&dhcp_data, (TT.state == DHCP6REQUEST) ?
6560f66f451Sopenharmony_ci              "request" : "renew");
6570f66f451Sopenharmony_ci            if (toys.optflags & FLAG_q) {
6580f66f451Sopenharmony_ci              if (toys.optflags & FLAG_R) send_msg(DHCP6RELEASE);
6590f66f451Sopenharmony_ci              break;
6600f66f451Sopenharmony_ci            }
6610f66f451Sopenharmony_ci            TT.state = DHCP6CONFIRM;
6620f66f451Sopenharmony_ci            set_timeout((dhcp_data.va_lf)?dhcp_data.va_lf:INT_MAX);
6630f66f451Sopenharmony_ci            dbg("Setting timeout to intmax.");
6640f66f451Sopenharmony_ci            if (TT.state == DHCP6REQUEST || !(toys.optflags & FLAG_f)) {
6650f66f451Sopenharmony_ci              dbg("Making it a daemon\n");
6660f66f451Sopenharmony_ci              if (daemon(0,0)) perror_exit("daemonize");
6670f66f451Sopenharmony_ci              toys.optflags |= FLAG_f;
6680f66f451Sopenharmony_ci              if (toys.optflags & FLAG_p) write_pid(TT.pidfile);
6690f66f451Sopenharmony_ci            }
6700f66f451Sopenharmony_ci            dbg("Making it a foreground.\n");
6710f66f451Sopenharmony_ci            continue;
6720f66f451Sopenharmony_ci          } else {
6730f66f451Sopenharmony_ci            dbg("Invalid reply.\n");
6740f66f451Sopenharmony_ci            continue;
6750f66f451Sopenharmony_ci          }
6760f66f451Sopenharmony_ci        } else if (TT.state == DHCP6RELEASE) {
6770f66f451Sopenharmony_ci          dbg("Got reply to release.\n");
6780f66f451Sopenharmony_ci          run_script(NULL, "release");
6790f66f451Sopenharmony_ci          set_timeout(INT_MAX);
6800f66f451Sopenharmony_ci        }
6810f66f451Sopenharmony_ci      }
6820f66f451Sopenharmony_ci    }
6830f66f451Sopenharmony_ci  }
6840f66f451Sopenharmony_ci  xclose(TT.sock1);
6850f66f451Sopenharmony_ci  xclose(TT.sock);
6860f66f451Sopenharmony_ci}
687