busybox/networking/udhcp/d6_dhcpc.c
<<
>>
Prefs
   1/* vi: set sw=4 ts=4: */
   2/*
   3 * DHCPv6 client.
   4 *
   5 * Copyright (C) 2011-2017 Denys Vlasenko.
   6 *
   7 * Licensed under GPLv2, see file LICENSE in this source tree.
   8 */
   9//config:config UDHCPC6
  10//config:       bool "udhcpc6 (21 kb)"
  11//config:       default y
  12//config:       depends on FEATURE_IPV6
  13//config:       help
  14//config:       udhcpc6 is a DHCPv6 client
  15//config:
  16//config:config FEATURE_UDHCPC6_RFC3646
  17//config:       bool "Support RFC 3646 (DNS server and search list)"
  18//config:       default y
  19//config:       depends on UDHCPC6
  20//config:       help
  21//config:       List of DNS servers and domain search list can be requested with
  22//config:       "-O dns" and "-O search". If server gives these values,
  23//config:       they will be set in environment variables "dns" and "search".
  24//config:
  25//config:config FEATURE_UDHCPC6_RFC4704
  26//config:       bool "Support RFC 4704 (Client FQDN)"
  27//config:       default y
  28//config:       depends on UDHCPC6
  29//config:       help
  30//config:       You can request FQDN to be given by server using "-O fqdn".
  31//config:
  32//config:config FEATURE_UDHCPC6_RFC4833
  33//config:       bool "Support RFC 4833 (Timezones)"
  34//config:       default y
  35//config:       depends on UDHCPC6
  36//config:       help
  37//config:       You can request POSIX timezone with "-O tz" and timezone name
  38//config:       with "-O timezone".
  39//config:
  40//config:config FEATURE_UDHCPC6_RFC5970
  41//config:       bool "Support RFC 5970 (Network Boot)"
  42//config:       default y
  43//config:       depends on UDHCPC6
  44//config:       help
  45//config:       You can request bootfile-url with "-O bootfile_url" and
  46//config:       bootfile-params with "-O bootfile_params".
  47
  48//applet:IF_UDHCPC6(APPLET(udhcpc6, BB_DIR_USR_BIN, BB_SUID_DROP))
  49
  50//kbuild:lib-$(CONFIG_UDHCPC6) += d6_dhcpc.o d6_packet.o d6_socket.o common.o socket.o signalpipe.o
  51//kbuild:lib-$(CONFIG_FEATURE_UDHCPC6_RFC3646) += domain_codec.o
  52//kbuild:lib-$(CONFIG_FEATURE_UDHCPC6_RFC4704) += domain_codec.o
  53
  54#include <syslog.h>
  55/* Override ENABLE_FEATURE_PIDFILE - ifupdown needs our pidfile to always exist */
  56#define WANT_PIDFILE 1
  57#include "common.h"
  58#include "dhcpd.h"
  59#include "dhcpc.h"
  60#include "d6_common.h"
  61
  62#include <netinet/if_ether.h>
  63#include <netpacket/packet.h>
  64#include <linux/filter.h>
  65
  66/* "struct client_data_t client_data" is in bb_common_bufsiz1 */
  67
  68static const struct dhcp_optflag d6_optflags[] = {
  69#if ENABLE_FEATURE_UDHCPC6_RFC3646
  70        { OPTION_6RD | OPTION_LIST        | OPTION_REQ, D6_OPT_DNS_SERVERS },
  71        { OPTION_DNS_STRING | OPTION_LIST | OPTION_REQ, D6_OPT_DOMAIN_LIST },
  72#endif
  73#if ENABLE_FEATURE_UDHCPC6_RFC4704
  74        { OPTION_DNS_STRING,                            D6_OPT_CLIENT_FQDN },
  75#endif
  76#if ENABLE_FEATURE_UDHCPC6_RFC4833
  77        { OPTION_STRING,                                D6_OPT_TZ_POSIX },
  78        { OPTION_STRING,                                D6_OPT_TZ_NAME },
  79#endif
  80#if ENABLE_FEATURE_UDHCPC6_RFC5970
  81        { OPTION_STRING,                                D6_OPT_BOOT_URL },
  82        { OPTION_STRING,                                D6_OPT_BOOT_PARAM },
  83#endif
  84        { OPTION_STRING,                                0xd1 }, /* DHCP_PXE_CONF_FILE */
  85        { OPTION_STRING,                                0xd2 }, /* DHCP_PXE_PATH_PREFIX */
  86        { 0, 0 }
  87};
  88/* Must match d6_optflags[] order */
  89static const char d6_option_strings[] ALIGN1 =
  90#if ENABLE_FEATURE_UDHCPC6_RFC3646
  91        "dns" "\0"      /* D6_OPT_DNS_SERVERS */
  92        "search" "\0"   /* D6_OPT_DOMAIN_LIST */
  93#endif
  94#if ENABLE_FEATURE_UDHCPC6_RFC4704
  95        "fqdn" "\0"     /* D6_OPT_CLIENT_FQDN */
  96#endif
  97#if ENABLE_FEATURE_UDHCPC6_RFC4833
  98        "tz" "\0"       /* D6_OPT_TZ_POSIX */
  99        "timezone" "\0" /* D6_OPT_TZ_NAME */
 100#endif
 101#if ENABLE_FEATURE_UDHCPC6_RFC5970
 102        "bootfile_url" "\0" /* D6_OPT_BOOT_URL */
 103        "bootfile_param" "\0" /* D6_OPT_BOOT_PARAM */
 104#endif
 105        "pxeconffile" "\0" /* DHCP_PXE_CONF_FILE  */
 106        "pxepathprefix" "\0" /* DHCP_PXE_PATH_PREFIX  */
 107        "\0";
 108
 109#if ENABLE_LONG_OPTS
 110static const char udhcpc6_longopts[] ALIGN1 =
 111        "interface\0"      Required_argument "i"
 112        "now\0"            No_argument       "n"
 113        "pidfile\0"        Required_argument "p"
 114        "quit\0"           No_argument       "q"
 115        "release\0"        No_argument       "R"
 116        "request\0"        Required_argument "r"
 117        "requestprefix\0"  No_argument       "d"
 118        "script\0"         Required_argument "s"
 119        "timeout\0"        Required_argument "T"
 120        "retries\0"        Required_argument "t"
 121        "tryagain\0"       Required_argument "A"
 122        "syslog\0"         No_argument       "S"
 123        "request-option\0" Required_argument "O"
 124        "no-default-options\0" No_argument   "o"
 125        "foreground\0"     No_argument       "f"
 126        USE_FOR_MMU(
 127        "background\0"     No_argument       "b"
 128        )
 129///     IF_FEATURE_UDHCPC_ARPING("arping\0"     No_argument       "a")
 130        IF_FEATURE_UDHCP_PORT("client-port\0"   Required_argument "P")
 131        ;
 132#endif
 133/* Must match getopt32 option string order */
 134enum {
 135        OPT_i = 1 << 0,
 136        OPT_n = 1 << 1,
 137        OPT_p = 1 << 2,
 138        OPT_q = 1 << 3,
 139        OPT_R = 1 << 4,
 140        OPT_r = 1 << 5,
 141        OPT_s = 1 << 6,
 142        OPT_T = 1 << 7,
 143        OPT_t = 1 << 8,
 144        OPT_S = 1 << 9,
 145        OPT_A = 1 << 10,
 146        OPT_O = 1 << 11,
 147        OPT_o = 1 << 12,
 148        OPT_x = 1 << 13,
 149        OPT_f = 1 << 14,
 150        OPT_d = 1 << 15,
 151/* The rest has variable bit positions, need to be clever */
 152        OPTBIT_d = 15,
 153        USE_FOR_MMU(             OPTBIT_b,)
 154        ///IF_FEATURE_UDHCPC_ARPING(OPTBIT_a,)
 155        IF_FEATURE_UDHCP_PORT(   OPTBIT_P,)
 156        USE_FOR_MMU(             OPT_b = 1 << OPTBIT_b,)
 157        ///IF_FEATURE_UDHCPC_ARPING(OPT_a = 1 << OPTBIT_a,)
 158        IF_FEATURE_UDHCP_PORT(   OPT_P = 1 << OPTBIT_P,)
 159};
 160
 161#if ENABLE_FEATURE_UDHCPC6_RFC4704
 162static const char opt_fqdn_req[] = {
 163        (D6_OPT_CLIENT_FQDN >> 8), (D6_OPT_CLIENT_FQDN & 0xff),
 164        0, 2, /* optlen */
 165        0, /* flags: */
 166        /* S=0: server SHOULD NOT perform AAAA RR updates */
 167        /* O=0: client MUST set this bit to 0 */
 168        /* N=0: server SHOULD perform updates (PTR RR only in our case, since S=0) */
 169        0 /* empty DNS-encoded name */
 170};
 171#endif
 172
 173/*** Utility functions ***/
 174
 175static void *d6_find_option(uint8_t *option, uint8_t *option_end, unsigned code)
 176{
 177        /* "length minus 4" */
 178        int len_m4 = option_end - option - 4;
 179        while (len_m4 >= 0) {
 180                /* Next option's len is too big? */
 181                if (option[3] > len_m4)
 182                        return NULL; /* yes. bogus packet! */
 183                /* So far we treat any opts with code >255
 184                 * or len >255 as bogus, and stop at once.
 185                 * This simplifies big-endian handling.
 186                 */
 187                if (option[0] != 0 || option[2] != 0)
 188                        return NULL;
 189                /* Option seems to be valid */
 190                /* Does its code match? */
 191                if (option[1] == code)
 192                        return option; /* yes! */
 193                len_m4 -= option[3] + 4;
 194                option += option[3] + 4;
 195        }
 196        return NULL;
 197}
 198
 199static void *d6_copy_option(uint8_t *option, uint8_t *option_end, unsigned code)
 200{
 201        uint8_t *opt = d6_find_option(option, option_end, code);
 202        if (!opt)
 203                return opt;
 204        return xmemdup(opt, opt[3] + 4);
 205}
 206
 207/*** Script execution code ***/
 208
 209static char** new_env(void)
 210{
 211        client6_data.env_ptr = xrealloc_vector(client6_data.env_ptr, 3, client6_data.env_idx);
 212        return &client6_data.env_ptr[client6_data.env_idx++];
 213}
 214
 215static char *string_option_to_env(const uint8_t *option,
 216                const uint8_t *option_end)
 217{
 218        const char *ptr, *name = NULL;
 219        unsigned val_len;
 220        int i;
 221
 222        ptr = d6_option_strings;
 223        i = 0;
 224        while (*ptr) {
 225                if (d6_optflags[i].code == option[1]) {
 226                        name = ptr;
 227                        goto found;
 228                }
 229                ptr += strlen(ptr) + 1;
 230                i++;
 231        }
 232        bb_error_msg("can't find option name for 0x%x, skipping", option[1]);
 233        return NULL;
 234
 235 found:
 236        val_len = (option[2] << 8) | option[3];
 237        if (val_len + &option[D6_OPT_DATA] > option_end) {
 238                bb_error_msg("option data exceeds option length");
 239                return NULL;
 240        }
 241        return xasprintf("%s=%.*s", name, val_len, (char*)option + 4);
 242}
 243
 244/* put all the parameters into the environment */
 245static void option_to_env(const uint8_t *option, const uint8_t *option_end)
 246{
 247#if ENABLE_FEATURE_UDHCPC6_RFC3646
 248        int addrs, option_offset;
 249#endif
 250        /* "length minus 4" */
 251        int len_m4 = option_end - option - 4;
 252
 253        while (len_m4 >= 0) {
 254                uint32_t v32;
 255                char ipv6str[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")];
 256
 257                if (option[0] != 0 || option[2] != 0)
 258                        break;
 259
 260                /* Check if option-length exceeds size of option */
 261                if (option[3] > len_m4)
 262                        break;
 263
 264                switch (option[1]) {
 265                //case D6_OPT_CLIENTID:
 266                //case D6_OPT_SERVERID:
 267                case D6_OPT_IA_NA:
 268                case D6_OPT_IA_PD:
 269                        option_to_env(option + 16, option + 4 + option[3]);
 270                        break;
 271                //case D6_OPT_IA_TA:
 272                case D6_OPT_IAADDR:
 273/*  0                   1                   2                   3
 274 *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 275 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 276 * |          OPTION_IAADDR        |          option-len           |
 277 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 278 * |                                                               |
 279 * |                         IPv6 address                          |
 280 * |                                                               |
 281 * |                                                               |
 282 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 283 * |                      preferred-lifetime                       |
 284 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 285 * |                        valid-lifetime                         |
 286 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 287 */
 288                        /* Make sure payload contains an address */
 289                        if (option[3] < 24)
 290                                break;
 291
 292                        sprint_nip6(ipv6str, option + 4);
 293                        *new_env() = xasprintf("ipv6=%s", ipv6str);
 294
 295                        move_from_unaligned32(v32, option + 4 + 16 + 4);
 296                        *new_env() = xasprintf("lease=%u", (unsigned)v32);
 297                        break;
 298
 299                //case D6_OPT_ORO:
 300                //case D6_OPT_PREFERENCE:
 301                //case D6_OPT_ELAPSED_TIME:
 302                //case D6_OPT_RELAY_MSG:
 303                //case D6_OPT_AUTH:
 304                //case D6_OPT_UNICAST:
 305                //case D6_OPT_STATUS_CODE:
 306                //case D6_OPT_RAPID_COMMIT:
 307                //case D6_OPT_USER_CLASS:
 308                //case D6_OPT_VENDOR_CLASS:
 309                //case D6_OPT_VENDOR_OPTS:
 310                //case D6_OPT_INTERFACE_ID:
 311                //case D6_OPT_RECONF_MSG:
 312                //case D6_OPT_RECONF_ACCEPT:
 313
 314                case D6_OPT_IAPREFIX:
 315/*  0                   1                   2                   3
 316 *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 317 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 318 * |        OPTION_IAPREFIX        |         option-length         |
 319 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 320 * |                      preferred-lifetime                       |
 321 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 322 * |                        valid-lifetime                         |
 323 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 324 * | prefix-length |                                               |
 325 * +-+-+-+-+-+-+-+-+          IPv6 prefix                          |
 326 * |                           (16 octets)                         |
 327 * |                                                               |
 328 * |               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 329 * |               |
 330 * +-+-+-+-+-+-+-+-+
 331 */
 332                        move_from_unaligned32(v32, option + 4 + 4);
 333                        *new_env() = xasprintf("ipv6prefix_lease=%u", (unsigned)v32);
 334
 335                        sprint_nip6(ipv6str, option + 4 + 4 + 4 + 1);
 336                        *new_env() = xasprintf("ipv6prefix=%s/%u", ipv6str, (unsigned)(option[4 + 4 + 4]));
 337                        break;
 338#if ENABLE_FEATURE_UDHCPC6_RFC3646
 339                case D6_OPT_DNS_SERVERS: {
 340                        char *dlist;
 341
 342                        /* Make sure payload-size is a multiple of 16 */
 343                        if ((option[3] & 0x0f) != 0)
 344                                break;
 345
 346                        /* Get the number of addresses on the option */
 347                        addrs = option[3] >> 4;
 348
 349                        /* Setup environment variable */
 350                        *new_env() = dlist = xmalloc(4 + addrs * 40 - 1);
 351                        dlist = stpcpy(dlist, "dns=");
 352                        option_offset = 0;
 353
 354                        while (addrs--) {
 355                                sprint_nip6(dlist, option + 4 + option_offset);
 356                                dlist += 39;
 357                                option_offset += 16;
 358                                if (addrs)
 359                                        *dlist++ = ' ';
 360                        }
 361
 362                        break;
 363                }
 364                case D6_OPT_DOMAIN_LIST: {
 365                        char *dlist;
 366
 367                        dlist = dname_dec(option + 4, (option[2] << 8) | option[3], "search=");
 368                        if (!dlist)
 369                                break;
 370                        *new_env() = dlist;
 371                        break;
 372                }
 373#endif
 374#if ENABLE_FEATURE_UDHCPC6_RFC4704
 375                case D6_OPT_CLIENT_FQDN: {
 376                        char *dlist;
 377
 378                        if (option[3] == 0)
 379                                break;
 380                        /* Work around broken ISC DHCPD6.
 381                         * ISC DHCPD6 does not implement RFC 4704 correctly: It says the first
 382                         * byte of option-payload should contain flags where the bits 7-3 are
 383                         * reserved for future use and MUST be zero. Instead ISC DHCPD6 just
 384                         * writes the entire FQDN as string to option-payload. We assume a
 385                         * broken server here if any of the reserved bits are set.
 386                         */
 387                        if (option[4] & 0xf8) {
 388                                *new_env() = xasprintf("fqdn=%.*s", (int)option[3], (char*)option + 4);
 389                                break;
 390                        }
 391                        dlist = dname_dec(option + 5, (/*(option[2] << 8) |*/ option[3]) - 1, "fqdn=");
 392                        if (!dlist)
 393                                break;
 394                        *new_env() = dlist;
 395                        break;
 396                }
 397#endif
 398#if ENABLE_FEATURE_UDHCPC6_RFC4833
 399                /* RFC 4833 Timezones */
 400                case D6_OPT_TZ_POSIX:
 401                        *new_env() = xasprintf("tz=%.*s", (int)option[3], (char*)option + 4);
 402                        break;
 403                case D6_OPT_TZ_NAME:
 404                        *new_env() = xasprintf("tz_name=%.*s", (int)option[3], (char*)option + 4);
 405                        break;
 406#endif
 407                case D6_OPT_BOOT_URL:
 408                case D6_OPT_BOOT_PARAM:
 409                case 0xd1: /* DHCP_PXE_CONF_FILE */
 410                case 0xd2: /* DHCP_PXE_PATH_PREFIX */
 411                        {
 412                        char *tmp = string_option_to_env(option, option_end);
 413                        if (tmp)
 414                                *new_env() = tmp;
 415                        break;
 416                        }
 417                }
 418                len_m4 -= 4 + option[3];
 419                option += 4 + option[3];
 420        }
 421}
 422
 423static char **fill_envp(const uint8_t *option, const uint8_t *option_end)
 424{
 425        char **envp, **curr;
 426
 427        client6_data.env_ptr = NULL;
 428        client6_data.env_idx = 0;
 429
 430        *new_env() = xasprintf("interface=%s", client_data.interface);
 431
 432        if (option)
 433                option_to_env(option, option_end);
 434
 435        envp = curr = client6_data.env_ptr;
 436        while (*curr)
 437                putenv(*curr++);
 438
 439        return envp;
 440}
 441
 442/* Call a script with a par file and env vars */
 443static void d6_run_script(const uint8_t *option, const uint8_t *option_end,
 444                const char *name)
 445{
 446        char **envp, **curr;
 447        char *argv[3];
 448
 449        envp = fill_envp(option, option_end);
 450
 451        /* call script */
 452        log1("executing %s %s", client_data.script, name);
 453        argv[0] = (char*) client_data.script;
 454        argv[1] = (char*) name;
 455        argv[2] = NULL;
 456        spawn_and_wait(argv);
 457
 458        for (curr = envp; *curr; curr++) {
 459                log2(" %s", *curr);
 460                bb_unsetenv_and_free(*curr);
 461        }
 462        free(envp);
 463}
 464
 465/* Call a script with a par file and no env var */
 466static void d6_run_script_no_option(const char *name)
 467{
 468        d6_run_script(NULL, NULL, name);
 469}
 470
 471/*** Sending/receiving packets ***/
 472
 473static ALWAYS_INLINE uint32_t random_xid(void)
 474{
 475        uint32_t t = rand() & htonl(0x00ffffff);
 476        return t;
 477}
 478
 479/* Initialize the packet with the proper defaults */
 480static uint8_t *init_d6_packet(struct d6_packet *packet, char type, uint32_t xid)
 481{
 482        struct d6_option *clientid;
 483
 484        memset(packet, 0, sizeof(*packet));
 485
 486        packet->d6_xid32 = xid;
 487        packet->d6_msg_type = type;
 488
 489        clientid = (void*)client_data.clientid;
 490        return mempcpy(packet->d6_options, clientid, clientid->len + 2+2);
 491}
 492
 493static uint8_t *add_d6_client_options(uint8_t *ptr)
 494{
 495        struct option_set *curr;
 496        uint8_t *start = ptr;
 497        unsigned option;
 498        uint16_t len;
 499
 500        ptr += 4;
 501        for (option = 1; option < 256; option++) {
 502                if (client_data.opt_mask[option >> 3] & (1 << (option & 7))) {
 503                        ptr[0] = (option >> 8);
 504                        ptr[1] = option;
 505                        ptr += 2;
 506                }
 507        }
 508
 509        if ((ptr - start - 4) != 0) {
 510                start[0] = (D6_OPT_ORO >> 8);
 511                start[1] = D6_OPT_ORO;
 512                start[2] = ((ptr - start - 4) >> 8);
 513                start[3] = (ptr - start - 4);
 514        } else
 515                ptr = start;
 516
 517#if ENABLE_FEATURE_UDHCPC6_RFC4704
 518        ptr = mempcpy(ptr, &opt_fqdn_req, sizeof(opt_fqdn_req));
 519#endif
 520        /* Add -x options if any */
 521        curr = client_data.options;
 522        while (curr) {
 523                len = (curr->data[D6_OPT_LEN] << 8) | curr->data[D6_OPT_LEN + 1];
 524                ptr = mempcpy(ptr, curr->data, D6_OPT_DATA + len);
 525                curr = curr->next;
 526        }
 527
 528        return ptr;
 529}
 530
 531static int d6_mcast_from_client_data_ifindex(struct d6_packet *packet, uint8_t *end)
 532{
 533        /* FF02::1:2 is "All_DHCP_Relay_Agents_and_Servers" address */
 534        static const uint8_t FF02__1_2[16] = {
 535                0xFF, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 536                0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02,
 537        };
 538
 539        return d6_send_raw_packet(
 540                packet, (end - (uint8_t*) packet),
 541                /*src*/ &client6_data.ll_ip6, CLIENT_PORT6,
 542                /*dst*/ (struct in6_addr*)FF02__1_2, SERVER_PORT6, MAC_BCAST_ADDR,
 543                client_data.ifindex
 544        );
 545}
 546
 547/* Milticast a DHCPv6 Solicit packet to the network, with an optionally requested IP.
 548 *
 549 * RFC 3315 17.1.1. Creation of Solicit Messages
 550 *
 551 * The client MUST include a Client Identifier option to identify itself
 552 * to the server.  The client includes IA options for any IAs to which
 553 * it wants the server to assign addresses.  The client MAY include
 554 * addresses in the IAs as a hint to the server about addresses for
 555 * which the client has a preference. ...
 556 *
 557 * The client uses IA_NA options to request the assignment of non-
 558 * temporary addresses and uses IA_TA options to request the assignment
 559 * of temporary addresses.  Either IA_NA or IA_TA options, or a
 560 * combination of both, can be included in DHCP messages.
 561 *
 562 * The client SHOULD include an Option Request option (see section 22.7)
 563 * to indicate the options the client is interested in receiving.  The
 564 * client MAY additionally include instances of those options that are
 565 * identified in the Option Request option, with data values as hints to
 566 * the server about parameter values the client would like to have
 567 * returned.
 568 *
 569 * The client includes a Reconfigure Accept option (see section 22.20)
 570 * if the client is willing to accept Reconfigure messages from the
 571 * server.
 572      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 573      |        OPTION_CLIENTID        |          option-len           |
 574      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 575      .                                                               .
 576      .                              DUID                             .
 577      .                        (variable length)                      .
 578      .                                                               .
 579      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 580
 581
 582      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 583      |          OPTION_IA_NA         |          option-len           |
 584      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 585      |                        IAID (4 octets)                        |
 586      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 587      |                              T1                               |
 588      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 589      |                              T2                               |
 590      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 591      |                                                               |
 592      .                         IA_NA-options                         .
 593      .                                                               .
 594      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 595
 596
 597      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 598      |          OPTION_IAADDR        |          option-len           |
 599      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 600      |                                                               |
 601      |                         IPv6 address                          |
 602      |                                                               |
 603      |                                                               |
 604      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 605      |                      preferred-lifetime                       |
 606      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 607      |                        valid-lifetime                         |
 608      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 609      .                                                               .
 610      .                        IAaddr-options                         .
 611      .                                                               .
 612      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 613
 614
 615      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 616      |           OPTION_ORO          |           option-len          |
 617      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 618      |    requested-option-code-1    |    requested-option-code-2    |
 619      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 620      |                              ...                              |
 621      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 622
 623
 624      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 625      |     OPTION_RECONF_ACCEPT      |               0               |
 626      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 627 */
 628/* NOINLINE: limit stack usage in caller */
 629static NOINLINE int send_d6_discover(uint32_t xid, struct in6_addr *requested_ipv6)
 630{
 631        struct d6_packet packet;
 632        uint8_t *opt_ptr;
 633        unsigned len;
 634
 635        /* Fill in: msg type, client id */
 636        opt_ptr = init_d6_packet(&packet, D6_MSG_SOLICIT, xid);
 637
 638        /* Create new IA_NA, optionally with included IAADDR with requested IP */
 639        free(client6_data.ia_na);
 640        client6_data.ia_na = NULL;
 641        if (option_mask32 & OPT_r) {
 642                len = requested_ipv6 ? 2+2+4+4+4 + 2+2+16+4+4 : 2+2+4+4+4;
 643                client6_data.ia_na = xzalloc(len);
 644                client6_data.ia_na->code = D6_OPT_IA_NA;
 645                client6_data.ia_na->len = len - 4;
 646                *(uint32_t*)client6_data.ia_na->data = rand(); /* IAID */
 647                if (requested_ipv6) {
 648                        struct d6_option *iaaddr = (void*)(client6_data.ia_na->data + 4+4+4);
 649                        iaaddr->code = D6_OPT_IAADDR;
 650                        iaaddr->len = 16+4+4;
 651                        memcpy(iaaddr->data, requested_ipv6, 16);
 652                }
 653                opt_ptr = mempcpy(opt_ptr, client6_data.ia_na, len);
 654        }
 655
 656        /* IA_PD */
 657        free(client6_data.ia_pd);
 658        client6_data.ia_pd = NULL;
 659        if (option_mask32 & OPT_d) {
 660                len = 2+2+4+4+4;
 661                client6_data.ia_pd = xzalloc(len);
 662                client6_data.ia_pd->code = D6_OPT_IA_PD;
 663                client6_data.ia_pd->len = len - 4;
 664                *(uint32_t*)client6_data.ia_pd->data = rand(); /* IAID */
 665                opt_ptr = mempcpy(opt_ptr, client6_data.ia_pd, len);
 666        }
 667
 668        /* Add options:
 669         * "param req" option according to -O, options specified with -x
 670         */
 671        opt_ptr = add_d6_client_options(opt_ptr);
 672
 673        bb_info_msg("sending %s", "discover");
 674        return d6_mcast_from_client_data_ifindex(&packet, opt_ptr);
 675}
 676
 677/* Multicast a DHCPv6 request message
 678 *
 679 * RFC 3315 18.1.1. Creation and Transmission of Request Messages
 680 *
 681 * The client uses a Request message to populate IAs with addresses and
 682 * obtain other configuration information.  The client includes one or
 683 * more IA options in the Request message.  The server then returns
 684 * addresses and other information about the IAs to the client in IA
 685 * options in a Reply message.
 686 *
 687 * The client generates a transaction ID and inserts this value in the
 688 * "transaction-id" field.
 689 *
 690 * The client places the identifier of the destination server in a
 691 * Server Identifier option.
 692 *
 693 * The client MUST include a Client Identifier option to identify itself
 694 * to the server.  The client adds any other appropriate options,
 695 * including one or more IA options (if the client is requesting that
 696 * the server assign it some network addresses).
 697 *
 698 * The client MUST include an Option Request option (see section 22.7)
 699 * to indicate the options the client is interested in receiving.  The
 700 * client MAY include options with data values as hints to the server
 701 * about parameter values the client would like to have returned.
 702 *
 703 * The client includes a Reconfigure Accept option (see section 22.20)
 704 * indicating whether or not the client is willing to accept Reconfigure
 705 * messages from the server.
 706 */
 707/* NOINLINE: limit stack usage in caller */
 708static NOINLINE int send_d6_select(uint32_t xid)
 709{
 710        struct d6_packet packet;
 711        uint8_t *opt_ptr;
 712
 713        /* Fill in: msg type, client id */
 714        opt_ptr = init_d6_packet(&packet, D6_MSG_REQUEST, xid);
 715
 716        /* server id */
 717        opt_ptr = mempcpy(opt_ptr, client6_data.server_id, client6_data.server_id->len + 2+2);
 718        /* IA NA (contains requested IP) */
 719        if (client6_data.ia_na)
 720                opt_ptr = mempcpy(opt_ptr, client6_data.ia_na, client6_data.ia_na->len + 2+2);
 721        /* IA PD */
 722        if (client6_data.ia_pd)
 723                opt_ptr = mempcpy(opt_ptr, client6_data.ia_pd, client6_data.ia_pd->len + 2+2);
 724
 725        /* Add options:
 726         * "param req" option according to -O, options specified with -x
 727         */
 728        opt_ptr = add_d6_client_options(opt_ptr);
 729
 730        bb_info_msg("sending %s", "select");
 731        return d6_mcast_from_client_data_ifindex(&packet, opt_ptr);
 732}
 733
 734/* Unicast or broadcast a DHCP renew message
 735 *
 736 * RFC 3315 18.1.3. Creation and Transmission of Renew Messages
 737 *
 738 * To extend the valid and preferred lifetimes for the addresses
 739 * associated with an IA, the client sends a Renew message to the server
 740 * from which the client obtained the addresses in the IA containing an
 741 * IA option for the IA.  The client includes IA Address options in the
 742 * IA option for the addresses associated with the IA.  The server
 743 * determines new lifetimes for the addresses in the IA according to the
 744 * administrative configuration of the server.  The server may also add
 745 * new addresses to the IA.  The server may remove addresses from the IA
 746 * by setting the preferred and valid lifetimes of those addresses to
 747 * zero.
 748 *
 749 * The server controls the time at which the client contacts the server
 750 * to extend the lifetimes on assigned addresses through the T1 and T2
 751 * parameters assigned to an IA.
 752 *
 753 * At time T1 for an IA, the client initiates a Renew/Reply message
 754 * exchange to extend the lifetimes on any addresses in the IA.  The
 755 * client includes an IA option with all addresses currently assigned to
 756 * the IA in its Renew message.
 757 *
 758 * If T1 or T2 is set to 0 by the server (for an IA_NA) or there are no
 759 * T1 or T2 times (for an IA_TA), the client may send a Renew or Rebind
 760 * message, respectively, at the client's discretion.
 761 *
 762 * The client sets the "msg-type" field to RENEW.  The client generates
 763 * a transaction ID and inserts this value in the "transaction-id"
 764 * field.
 765 *
 766 * The client places the identifier of the destination server in a
 767 * Server Identifier option.
 768 *
 769 * The client MUST include a Client Identifier option to identify itself
 770 * to the server.  The client adds any appropriate options, including
 771 * one or more IA options.  The client MUST include the list of
 772 * addresses the client currently has associated with the IAs in the
 773 * Renew message.
 774 *
 775 * The client MUST include an Option Request option (see section 22.7)
 776 * to indicate the options the client is interested in receiving.  The
 777 * client MAY include options with data values as hints to the server
 778 * about parameter values the client would like to have returned.
 779 */
 780/* NOINLINE: limit stack usage in caller */
 781static NOINLINE int send_d6_renew(uint32_t xid, struct in6_addr *server_ipv6, struct in6_addr *our_cur_ipv6)
 782{
 783        struct d6_packet packet;
 784        uint8_t *opt_ptr;
 785
 786        /* Fill in: msg type, client id */
 787        opt_ptr = init_d6_packet(&packet, DHCPREQUEST, xid);
 788
 789        /* server id */
 790        opt_ptr = mempcpy(opt_ptr, client6_data.server_id, client6_data.server_id->len + 2+2);
 791        /* IA NA (contains requested IP) */
 792        if (client6_data.ia_na)
 793                opt_ptr = mempcpy(opt_ptr, client6_data.ia_na, client6_data.ia_na->len + 2+2);
 794        /* IA PD */
 795        if (client6_data.ia_pd)
 796                opt_ptr = mempcpy(opt_ptr, client6_data.ia_pd, client6_data.ia_pd->len + 2+2);
 797
 798        /* Add options:
 799         * "param req" option according to -O, options specified with -x
 800         */
 801        opt_ptr = add_d6_client_options(opt_ptr);
 802
 803        bb_info_msg("sending %s", "renew");
 804        if (server_ipv6)
 805                return d6_send_kernel_packet(
 806                        &packet, (opt_ptr - (uint8_t*) &packet),
 807                        our_cur_ipv6, CLIENT_PORT6,
 808                        server_ipv6, SERVER_PORT6,
 809                        client_data.ifindex
 810                );
 811        return d6_mcast_from_client_data_ifindex(&packet, opt_ptr);
 812}
 813
 814/* Unicast a DHCP release message */
 815static
 816ALWAYS_INLINE /* one caller, help compiler to use this fact */
 817int send_d6_release(struct in6_addr *server_ipv6, struct in6_addr *our_cur_ipv6)
 818{
 819        struct d6_packet packet;
 820        uint8_t *opt_ptr;
 821
 822        /* Fill in: msg type, client id */
 823        opt_ptr = init_d6_packet(&packet, D6_MSG_RELEASE, random_xid());
 824        /* server id */
 825        opt_ptr = mempcpy(opt_ptr, client6_data.server_id, client6_data.server_id->len + 2+2);
 826        /* IA NA (contains our current IP) */
 827        if (client6_data.ia_na)
 828                opt_ptr = mempcpy(opt_ptr, client6_data.ia_na, client6_data.ia_na->len + 2+2);
 829        /* IA PD */
 830        if (client6_data.ia_pd)
 831                opt_ptr = mempcpy(opt_ptr, client6_data.ia_pd, client6_data.ia_pd->len + 2+2);
 832
 833        bb_info_msg("sending %s", "release");
 834        return d6_send_kernel_packet(
 835                &packet, (opt_ptr - (uint8_t*) &packet),
 836                our_cur_ipv6, CLIENT_PORT6,
 837                server_ipv6, SERVER_PORT6,
 838                client_data.ifindex
 839        );
 840}
 841
 842/* Returns -1 on errors that are fatal for the socket, -2 for those that aren't */
 843/* NOINLINE: limit stack usage in caller */
 844static NOINLINE int d6_recv_raw_packet(struct in6_addr *peer_ipv6, struct d6_packet *d6_pkt, int fd)
 845{
 846        int bytes;
 847        struct ip6_udp_d6_packet packet;
 848
 849        bytes = safe_read(fd, &packet, sizeof(packet));
 850        if (bytes < 0) {
 851                log1("packet read error, ignoring");
 852                /* NB: possible down interface, etc. Caller should pause. */
 853                return bytes; /* returns -1 */
 854        }
 855
 856        if (bytes < (int) (sizeof(packet.ip6) + sizeof(packet.udp))) {
 857                log1("packet is too short, ignoring");
 858                return -2;
 859        }
 860
 861        if (bytes < sizeof(packet.ip6) + ntohs(packet.ip6.ip6_plen)) {
 862                /* packet is bigger than sizeof(packet), we did partial read */
 863                log1("oversized packet, ignoring");
 864                return -2;
 865        }
 866
 867        /* ignore any extra garbage bytes */
 868        bytes = sizeof(packet.ip6) + ntohs(packet.ip6.ip6_plen);
 869
 870        /* make sure its the right packet for us, and that it passes sanity checks */
 871        if (packet.ip6.ip6_nxt != IPPROTO_UDP
 872         || (packet.ip6.ip6_vfc >> 4) != 6
 873         || packet.udp.dest != htons(CLIENT_PORT6)
 874        /* || bytes > (int) sizeof(packet) - can't happen */
 875         || packet.udp.len != packet.ip6.ip6_plen
 876        ) {
 877                log1("unrelated/bogus packet, ignoring");
 878                return -2;
 879        }
 880
 881//How to do this for ipv6?
 882//      /* verify UDP checksum. IP header has to be modified for this */
 883//      memset(&packet.ip, 0, offsetof(struct iphdr, protocol));
 884//      /* ip.xx fields which are not memset: protocol, check, saddr, daddr */
 885//      packet.ip.tot_len = packet.udp.len; /* yes, this is needed */
 886//      check = packet.udp.check;
 887//      packet.udp.check = 0;
 888//      if (check && check != inet_cksum((uint16_t *)&packet, bytes)) {
 889//              log1("packet with bad UDP checksum received, ignoring");
 890//              return -2;
 891//      }
 892
 893        if (peer_ipv6)
 894                *peer_ipv6 = packet.ip6.ip6_src; /* struct copy */
 895
 896        log1("received %s", "a packet");
 897        d6_dump_packet(&packet.data);
 898
 899        bytes -= sizeof(packet.ip6) + sizeof(packet.udp);
 900        memcpy(d6_pkt, &packet.data, bytes);
 901        return bytes;
 902}
 903
 904/*** Main ***/
 905
 906/* Values for client_data.listen_mode */
 907#define LISTEN_NONE   0
 908#define LISTEN_KERNEL 1
 909#define LISTEN_RAW    2
 910
 911/* Values for client_data.state */
 912/* initial state: (re)start DHCP negotiation */
 913#define INIT_SELECTING  0
 914/* discover was sent, DHCPOFFER reply received */
 915#define REQUESTING      1
 916/* select/renew was sent, DHCPACK reply received */
 917#define BOUND           2
 918/* half of lease passed, want to renew it by sending unicast renew requests */
 919#define RENEWING        3
 920/* renew requests were not answered, lease is almost over, send broadcast renew */
 921#define REBINDING       4
 922/* manually requested renew (SIGUSR1) */
 923#define RENEW_REQUESTED 5
 924/* release, possibly manually requested (SIGUSR2) */
 925#define RELEASED        6
 926
 927static int d6_raw_socket(int ifindex)
 928{
 929        int fd;
 930        struct sockaddr_ll sock;
 931
 932        /*
 933         * Comment:
 934         *
 935         *      I've selected not to see LL header, so BPF doesn't see it, too.
 936         *      The filter may also pass non-IP and non-ARP packets, but we do
 937         *      a more complete check when receiving the message in userspace.
 938         *
 939         * and filter shamelessly stolen from:
 940         *
 941         *      http://www.flamewarmaster.de/software/dhcpclient/
 942         *
 943         * There are a few other interesting ideas on that page (look under
 944         * "Motivation").  Use of netlink events is most interesting.  Think
 945         * of various network servers listening for events and reconfiguring.
 946         * That would obsolete sending HUP signals and/or make use of restarts.
 947         *
 948         * Copyright: 2006, 2007 Stefan Rompf <sux@loplof.de>.
 949         * License: GPL v2.
 950         *
 951         * TODO: make conditional?
 952         */
 953#if 0
 954        static const struct sock_filter filter_instr[] = {
 955                /* load 9th byte (protocol) */
 956                BPF_STMT(BPF_LD|BPF_B|BPF_ABS, 9),
 957                /* jump to L1 if it is IPPROTO_UDP, else to L4 */
 958                BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, IPPROTO_UDP, 0, 6),
 959                /* L1: load halfword from offset 6 (flags and frag offset) */
 960                BPF_STMT(BPF_LD|BPF_H|BPF_ABS, 6),
 961                /* jump to L4 if any bits in frag offset field are set, else to L2 */
 962                BPF_JUMP(BPF_JMP|BPF_JSET|BPF_K, 0x1fff, 4, 0),
 963                /* L2: skip IP header (load index reg with header len) */
 964                BPF_STMT(BPF_LDX|BPF_B|BPF_MSH, 0),
 965                /* load udp destination port from halfword[header_len + 2] */
 966                BPF_STMT(BPF_LD|BPF_H|BPF_IND, 2),
 967                /* jump to L3 if udp dport is CLIENT_PORT6, else to L4 */
 968                BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 68, 0, 1),
 969                /* L3: accept packet */
 970                BPF_STMT(BPF_RET|BPF_K, 0x7fffffff),
 971                /* L4: discard packet */
 972                BPF_STMT(BPF_RET|BPF_K, 0),
 973        };
 974        static const struct sock_fprog filter_prog = {
 975                .len = sizeof(filter_instr) / sizeof(filter_instr[0]),
 976                /* casting const away: */
 977                .filter = (struct sock_filter *) filter_instr,
 978        };
 979#endif
 980
 981        log2("opening raw socket on ifindex %d", ifindex);
 982
 983        fd = xsocket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IPV6));
 984        log3("got raw socket fd %d", fd);
 985
 986        memset(&sock, 0, sizeof(sock)); /* let's be deterministic */
 987        sock.sll_family = AF_PACKET;
 988        sock.sll_protocol = htons(ETH_P_IPV6);
 989        sock.sll_ifindex = ifindex;
 990        /*sock.sll_hatype = ARPHRD_???;*/
 991        /*sock.sll_pkttype = PACKET_???;*/
 992        /*sock.sll_halen = ???;*/
 993        /*sock.sll_addr[8] = ???;*/
 994        xbind(fd, (struct sockaddr *) &sock, sizeof(sock));
 995
 996#if 0
 997        if (CLIENT_PORT6 == 546) {
 998                /* Use only if standard port is in use */
 999                /* Ignoring error (kernel may lack support for this) */
1000                if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter_prog,
1001                                sizeof(filter_prog)) >= 0)
1002                        log1("attached filter to raw socket fd %d", fd); // log?
1003        }
1004#endif
1005
1006        log1("created raw socket");
1007
1008        return fd;
1009}
1010
1011static void change_listen_mode(int new_mode)
1012{
1013        log1("entering listen mode: %s",
1014                new_mode != LISTEN_NONE
1015                        ? (new_mode == LISTEN_KERNEL ? "kernel" : "raw")
1016                        : "none"
1017        );
1018
1019        client_data.listen_mode = new_mode;
1020        if (client_data.sockfd >= 0) {
1021                close(client_data.sockfd);
1022                client_data.sockfd = -1;
1023        }
1024        if (new_mode == LISTEN_KERNEL)
1025                client_data.sockfd = udhcp_listen_socket(/*INADDR_ANY,*/ CLIENT_PORT6, client_data.interface);
1026        else if (new_mode != LISTEN_NONE)
1027                client_data.sockfd = d6_raw_socket(client_data.ifindex);
1028        /* else LISTEN_NONE: client_data.sockfd stays closed */
1029}
1030
1031/* Called only on SIGUSR1 */
1032static void perform_renew(void)
1033{
1034        bb_info_msg("performing DHCP renew");
1035        switch (client_data.state) {
1036        case BOUND:
1037                change_listen_mode(LISTEN_KERNEL);
1038        case RENEWING:
1039        case REBINDING:
1040                client_data.state = RENEW_REQUESTED;
1041                break;
1042        case RENEW_REQUESTED: /* impatient are we? fine, square 1 */
1043                d6_run_script_no_option("deconfig");
1044        case REQUESTING:
1045        case RELEASED:
1046                change_listen_mode(LISTEN_RAW);
1047                client_data.state = INIT_SELECTING;
1048                break;
1049        case INIT_SELECTING:
1050                break;
1051        }
1052}
1053
1054static void perform_d6_release(struct in6_addr *server_ipv6, struct in6_addr *our_cur_ipv6)
1055{
1056        /* send release packet */
1057        if (client_data.state == BOUND
1058         || client_data.state == RENEWING
1059         || client_data.state == REBINDING
1060         || client_data.state == RENEW_REQUESTED
1061        ) {
1062                bb_info_msg("unicasting a release");
1063                send_d6_release(server_ipv6, our_cur_ipv6); /* unicast */
1064        }
1065        bb_info_msg("entering released state");
1066/*
1067 * We can be here on: SIGUSR2,
1068 * or on exit (SIGTERM) and -R "release on quit" is specified.
1069 * Users requested to be notified in all cases, even if not in one
1070 * of the states above.
1071 */
1072        d6_run_script_no_option("deconfig");
1073        change_listen_mode(LISTEN_NONE);
1074        client_data.state = RELEASED;
1075}
1076
1077///static uint8_t* alloc_dhcp_option(int code, const char *str, int extra)
1078///{
1079///     uint8_t *storage;
1080///     int len = strnlen(str, 255);
1081///     storage = xzalloc(len + extra + OPT_DATA);
1082///     storage[OPT_CODE] = code;
1083///     storage[OPT_LEN] = len + extra;
1084///     memcpy(storage + extra + OPT_DATA, str, len);
1085///     return storage;
1086///}
1087
1088#if BB_MMU
1089static void client_background(void)
1090{
1091        bb_daemonize(0);
1092        logmode &= ~LOGMODE_STDIO;
1093        /* rewrite pidfile, as our pid is different now */
1094        write_pidfile(client_data.pidfile);
1095}
1096#endif
1097
1098//usage:#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1
1099//usage:# define IF_UDHCP_VERBOSE(...) __VA_ARGS__
1100//usage:#else
1101//usage:# define IF_UDHCP_VERBOSE(...)
1102//usage:#endif
1103//usage:#define udhcpc6_trivial_usage
1104//usage:       "[-fbnq"IF_UDHCP_VERBOSE("v")"odR] [-i IFACE] [-r IPv6] [-s PROG] [-p PIDFILE]\n"
1105//usage:       "        [-x OPT:VAL]... [-O OPT]..." IF_FEATURE_UDHCP_PORT(" [-P N]")
1106//usage:#define udhcpc6_full_usage "\n"
1107//usage:     "\n        -i IFACE        Interface to use (default eth0)"
1108//usage:     "\n        -p FILE         Create pidfile"
1109//usage:     "\n        -s PROG         Run PROG at DHCP events (default "CONFIG_UDHCPC_DEFAULT_SCRIPT")"
1110//usage:     "\n        -B              Request broadcast replies"
1111//usage:     "\n        -t N            Send up to N discover packets"
1112//usage:     "\n        -T N            Pause between packets (default 3 seconds)"
1113//usage:     "\n        -A N            Wait N seconds (default 20) after failure"
1114//usage:     "\n        -f              Run in foreground"
1115//usage:        USE_FOR_MMU(
1116//usage:     "\n        -b              Background if lease is not obtained"
1117//usage:        )
1118//usage:     "\n        -n              Exit if lease is not obtained"
1119//usage:     "\n        -q              Exit after obtaining lease"
1120//usage:     "\n        -R              Release IP on exit"
1121//usage:     "\n        -S              Log to syslog too"
1122//usage:        IF_FEATURE_UDHCP_PORT(
1123//usage:     "\n        -P N            Use port N (default 546)"
1124//usage:        )
1125////usage:      IF_FEATURE_UDHCPC_ARPING(
1126////usage:     "\n      -a              Use arping to validate offered address"
1127////usage:      )
1128//usage:     "\n        -O OPT          Request option OPT from server (cumulative)"
1129//usage:     "\n        -o              Don't request any options (unless -O is given)"
1130//usage:     "\n        -r IPv6         Request this address ('no' to not request any IP)"
1131//usage:     "\n        -d              Request prefix"
1132//usage:     "\n        -x OPT:VAL      Include option OPT in sent packets (cumulative)"
1133//usage:     "\n                        Examples of string, numeric, and hex byte opts:"
1134//usage:     "\n                        -x hostname:bbox - option 12"
1135//usage:     "\n                        -x lease:3600 - option 51 (lease time)"
1136//usage:     "\n                        -x 0x3d:0100BEEFC0FFEE - option 61 (client id)"
1137//usage:     "\n                        -x 14:'\"dumpfile\"' - option 14 (shell-quoted)"
1138//usage:        IF_UDHCP_VERBOSE(
1139//usage:     "\n        -v              Verbose"
1140//usage:        )
1141//usage:     "\nSignals:"
1142//usage:     "\n        USR1    Renew lease"
1143//usage:     "\n        USR2    Release lease"
1144
1145int udhcpc6_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1146int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1147{
1148        const char *str_r;
1149        IF_FEATURE_UDHCP_PORT(char *str_P;)
1150        void *clientid_mac_ptr;
1151        llist_t *list_O = NULL;
1152        llist_t *list_x = NULL;
1153        int tryagain_timeout = 20;
1154        int discover_timeout = 3;
1155        int discover_retries = 3;
1156        struct in6_addr srv6_buf;
1157        struct in6_addr ipv6_buf;
1158        struct in6_addr *requested_ipv6;
1159        uint32_t xid = 0;
1160        int packet_num;
1161        int timeout; /* must be signed */
1162        unsigned already_waited_sec;
1163        unsigned opt;
1164        int retval;
1165
1166        setup_common_bufsiz();
1167        /* We want random_xid to be random */
1168        srand(monotonic_us());
1169
1170        /* Default options */
1171        IF_FEATURE_UDHCP_PORT(SERVER_PORT6 = 547;)
1172        IF_FEATURE_UDHCP_PORT(CLIENT_PORT6 = 546;)
1173        client_data.interface = "eth0";
1174        client_data.script = CONFIG_UDHCPC_DEFAULT_SCRIPT;
1175        client_data.sockfd = -1;
1176
1177        /* Make sure fd 0,1,2 are open */
1178        /* Set up the signal pipe on fds 3,4 - must be before openlog() */
1179        udhcp_sp_setup();
1180
1181        /* Parse command line */
1182        opt = getopt32long(argv, "^"
1183                /* O,x: list; -T,-t,-A take numeric param */
1184                "i:np:qRr:s:T:+t:+SA:+O:*ox:*fd"
1185                USE_FOR_MMU("b")
1186                ///IF_FEATURE_UDHCPC_ARPING("a")
1187                IF_FEATURE_UDHCP_PORT("P:")
1188                "v"
1189                "\0" IF_UDHCP_VERBOSE("vv") /* -v is a counter */
1190                , udhcpc6_longopts
1191                , &client_data.interface, &client_data.pidfile, &str_r /* i,p */
1192                , &client_data.script /* s */
1193                , &discover_timeout, &discover_retries, &tryagain_timeout /* T,t,A */
1194                , &list_O
1195                , &list_x
1196                IF_FEATURE_UDHCP_PORT(, &str_P)
1197                IF_UDHCP_VERBOSE(, &dhcp_verbose)
1198        );
1199        requested_ipv6 = NULL;
1200        option_mask32 |= OPT_r;
1201        if (opt & OPT_r) {
1202                if (strcmp(str_r, "no") == 0) {
1203                        option_mask32 -= OPT_r;
1204                } else {
1205                        if (inet_pton(AF_INET6, str_r, &ipv6_buf) <= 0)
1206                                bb_error_msg_and_die("bad IPv6 address '%s'", str_r);
1207                        requested_ipv6 = &ipv6_buf;
1208                }
1209        }
1210#if ENABLE_FEATURE_UDHCP_PORT
1211        if (opt & OPT_P) {
1212                CLIENT_PORT6 = xatou16(str_P);
1213                SERVER_PORT6 = CLIENT_PORT6 + 1;
1214        }
1215#endif
1216        while (list_O) {
1217                char *optstr = llist_pop(&list_O);
1218                unsigned n = bb_strtou(optstr, NULL, 0);
1219                if (errno || n > 254) {
1220                        n = udhcp_option_idx(optstr, d6_option_strings);
1221                        n = d6_optflags[n].code;
1222                }
1223                client_data.opt_mask[n >> 3] |= 1 << (n & 7);
1224        }
1225        if (!(opt & OPT_o)) {
1226                unsigned i, n;
1227                for (i = 0; (n = d6_optflags[i].code) != 0; i++) {
1228                        if (d6_optflags[i].flags & OPTION_REQ) {
1229                                client_data.opt_mask[n >> 3] |= 1 << (n & 7);
1230                        }
1231                }
1232        }
1233        while (list_x) {
1234                char *optstr = xstrdup(llist_pop(&list_x));
1235                udhcp_str2optset(optstr, &client_data.options,
1236                                d6_optflags, d6_option_strings,
1237                                /*dhcpv6:*/ 1
1238                );
1239                free(optstr);
1240        }
1241
1242        if (d6_read_interface(client_data.interface,
1243                        &client_data.ifindex,
1244                        &client6_data.ll_ip6,
1245                        client_data.client_mac)
1246        ) {
1247                return 1;
1248        }
1249
1250        /* Create client ID based on mac, set clientid_mac_ptr */
1251        {
1252                struct d6_option *clientid;
1253                clientid = xzalloc(2+2+2+2+6);
1254                clientid->code = D6_OPT_CLIENTID;
1255                clientid->len = 2+2+6;
1256                clientid->data[1] = 3; /* DUID-LL */
1257                clientid->data[3] = 1; /* ethernet */
1258                clientid_mac_ptr = clientid->data + 2+2;
1259                memcpy(clientid_mac_ptr, client_data.client_mac, 6);
1260                client_data.clientid = (void*)clientid;
1261        }
1262
1263#if !BB_MMU
1264        /* on NOMMU reexec (i.e., background) early */
1265        if (!(opt & OPT_f)) {
1266                bb_daemonize_or_rexec(0 /* flags */, argv);
1267                logmode = LOGMODE_NONE;
1268        }
1269#endif
1270        if (opt & OPT_S) {
1271                openlog(applet_name, LOG_PID, LOG_DAEMON);
1272                logmode |= LOGMODE_SYSLOG;
1273        }
1274
1275        /* Create pidfile */
1276        write_pidfile(client_data.pidfile);
1277        /* Goes to stdout (unless NOMMU) and possibly syslog */
1278        bb_info_msg("started, v"BB_VER);
1279
1280        client_data.state = INIT_SELECTING;
1281        d6_run_script_no_option("deconfig");
1282        change_listen_mode(LISTEN_RAW);
1283        packet_num = 0;
1284        timeout = 0;
1285        already_waited_sec = 0;
1286
1287        /* Main event loop. select() waits on signal pipe and possibly
1288         * on sockfd.
1289         * "continue" statements in code below jump to the top of the loop.
1290         */
1291        for (;;) {
1292                int tv;
1293                struct pollfd pfds[2];
1294                struct d6_packet packet;
1295                uint8_t *packet_end;
1296                /* silence "uninitialized!" warning */
1297                unsigned timestamp_before_wait = timestamp_before_wait;
1298
1299                //bb_error_msg("sockfd:%d, listen_mode:%d", client_data.sockfd, client_data.listen_mode);
1300
1301                /* Was opening raw or udp socket here
1302                 * if (client_data.listen_mode != LISTEN_NONE && client_data.sockfd < 0),
1303                 * but on fast network renew responses return faster
1304                 * than we open sockets. Thus this code is moved
1305                 * to change_listen_mode(). Thus we open listen socket
1306                 * BEFORE we send renew request (see "case BOUND:"). */
1307
1308                udhcp_sp_fd_set(pfds, client_data.sockfd);
1309
1310                tv = timeout - already_waited_sec;
1311                retval = 0;
1312                /* If we already timed out, fall through with retval = 0, else... */
1313                if (tv > 0) {
1314                        log1("waiting %u seconds", tv);
1315                        timestamp_before_wait = (unsigned)monotonic_sec();
1316                        retval = poll(pfds, 2, tv < INT_MAX/1000 ? tv * 1000 : INT_MAX);
1317                        if (retval < 0) {
1318                                /* EINTR? A signal was caught, don't panic */
1319                                if (errno == EINTR) {
1320                                        already_waited_sec += (unsigned)monotonic_sec() - timestamp_before_wait;
1321                                        continue;
1322                                }
1323                                /* Else: an error occured, panic! */
1324                                bb_perror_msg_and_die("poll");
1325                        }
1326                }
1327
1328                /* If timeout dropped to zero, time to become active:
1329                 * resend discover/renew/whatever
1330                 */
1331                if (retval == 0) {
1332                        /* When running on a bridge, the ifindex may have changed
1333                         * (e.g. if member interfaces were added/removed
1334                         * or if the status of the bridge changed).
1335                         * Refresh ifindex and client_mac:
1336                         */
1337                        if (d6_read_interface(client_data.interface,
1338                                        &client_data.ifindex,
1339                                        &client6_data.ll_ip6,
1340                                        client_data.client_mac)
1341                        ) {
1342                                goto ret0; /* iface is gone? */
1343                        }
1344
1345                        memcpy(clientid_mac_ptr, client_data.client_mac, 6);
1346
1347                        /* We will restart the wait in any case */
1348                        already_waited_sec = 0;
1349
1350                        switch (client_data.state) {
1351                        case INIT_SELECTING:
1352                                if (!discover_retries || packet_num < discover_retries) {
1353                                        if (packet_num == 0)
1354                                                xid = random_xid();
1355                                        /* multicast */
1356                                        send_d6_discover(xid, requested_ipv6);
1357                                        timeout = discover_timeout;
1358                                        packet_num++;
1359                                        continue;
1360                                }
1361 leasefail:
1362                                d6_run_script_no_option("leasefail");
1363#if BB_MMU /* -b is not supported on NOMMU */
1364                                if (opt & OPT_b) { /* background if no lease */
1365                                        bb_info_msg("no lease, forking to background");
1366                                        client_background();
1367                                        /* do not background again! */
1368                                        opt = ((opt & ~(OPT_b|OPT_n)) | OPT_f);
1369                                        /* ^^^ also disables -n (-b takes priority over -n):
1370                                         * ifup's default udhcpc options are -R -n,
1371                                         * and users want to be able to add -b
1372                                         * (in a config file) to make it background
1373                                         * _and not exit_.
1374                                         */
1375                                } else
1376#endif
1377                                if (opt & OPT_n) { /* abort if no lease */
1378                                        bb_info_msg("no lease, failing");
1379                                        retval = 1;
1380                                        goto ret;
1381                                }
1382                                /* wait before trying again */
1383                                timeout = tryagain_timeout;
1384                                packet_num = 0;
1385                                continue;
1386                        case REQUESTING:
1387                                if (!discover_retries || packet_num < discover_retries) {
1388                                        /* send multicast select packet */
1389                                        send_d6_select(xid);
1390                                        timeout = discover_timeout;
1391                                        packet_num++;
1392                                        continue;
1393                                }
1394                                /* Timed out, go back to init state.
1395                                 * "discover...select...discover..." loops
1396                                 * were seen in the wild. Treat them similarly
1397                                 * to "no response to discover" case */
1398                                change_listen_mode(LISTEN_RAW);
1399                                client_data.state = INIT_SELECTING;
1400                                goto leasefail;
1401                        case BOUND:
1402                                /* 1/2 lease passed, enter renewing state */
1403                                client_data.state = RENEWING;
1404                                client_data.first_secs = 0; /* make secs field count from 0 */
1405                                change_listen_mode(LISTEN_KERNEL);
1406                                log1("entering renew state");
1407                                /* fall right through */
1408                        case RENEW_REQUESTED: /* manual (SIGUSR1) renew */
1409                        case_RENEW_REQUESTED:
1410                        case RENEWING:
1411                                if (timeout >= 60) {
1412                                        /* send an unicast renew request */
1413                        /* Sometimes observed to fail (EADDRNOTAVAIL) to bind
1414                         * a new UDP socket for sending inside send_renew.
1415                         * I hazard to guess existing listening socket
1416                         * is somehow conflicting with it, but why is it
1417                         * not deterministic then?! Strange.
1418                         * Anyway, it does recover by eventually failing through
1419                         * into INIT_SELECTING state.
1420                         */
1421                                        send_d6_renew(xid, &srv6_buf, requested_ipv6);
1422                                        timeout >>= 1;
1423                                        continue;
1424                                }
1425                                /* Timed out, enter rebinding state */
1426                                log1("entering rebinding state");
1427                                client_data.state = REBINDING;
1428                                /* fall right through */
1429                        case REBINDING:
1430                                /* Switch to bcast receive */
1431                                change_listen_mode(LISTEN_RAW);
1432                                /* Lease is *really* about to run out,
1433                                 * try to find DHCP server using broadcast */
1434                                if (timeout > 0) {
1435                                        /* send a broadcast renew request */
1436                                        send_d6_renew(xid, /*server_ipv6:*/ NULL, requested_ipv6);
1437                                        timeout >>= 1;
1438                                        continue;
1439                                }
1440                                /* Timed out, enter init state */
1441                                bb_info_msg("lease lost, entering init state");
1442                                d6_run_script_no_option("deconfig");
1443                                client_data.state = INIT_SELECTING;
1444                                client_data.first_secs = 0; /* make secs field count from 0 */
1445                                /*timeout = 0; - already is */
1446                                packet_num = 0;
1447                                continue;
1448                        /* case RELEASED: */
1449                        }
1450                        /* yah, I know, *you* say it would never happen */
1451                        timeout = INT_MAX;
1452                        continue; /* back to main loop */
1453                } /* if poll timed out */
1454
1455                /* poll() didn't timeout, something happened */
1456
1457                /* Is it a signal? */
1458                switch (udhcp_sp_read()) {
1459                case SIGUSR1:
1460                        client_data.first_secs = 0; /* make secs field count from 0 */
1461                        already_waited_sec = 0;
1462                        perform_renew();
1463                        if (client_data.state == RENEW_REQUESTED) {
1464                                /* We might be either on the same network
1465                                 * (in which case renew might work),
1466                                 * or we might be on a completely different one
1467                                 * (in which case renew won't ever succeed).
1468                                 * For the second case, must make sure timeout
1469                                 * is not too big, or else we can send
1470                                 * futile renew requests for hours.
1471                                 */
1472                                if (timeout > 60)
1473                                        timeout = 60;
1474                                goto case_RENEW_REQUESTED;
1475                        }
1476                        /* Start things over */
1477                        packet_num = 0;
1478                        /* Kill any timeouts, user wants this to hurry along */
1479                        timeout = 0;
1480                        continue;
1481                case SIGUSR2:
1482                        perform_d6_release(&srv6_buf, requested_ipv6);
1483                        timeout = INT_MAX;
1484                        continue;
1485                case SIGTERM:
1486                        bb_info_msg("received %s", "SIGTERM");
1487                        goto ret0;
1488                }
1489
1490                /* Is it a packet? */
1491                if (!pfds[1].revents)
1492                        continue; /* no */
1493
1494                {
1495                        int len;
1496
1497                        /* A packet is ready, read it */
1498                        if (client_data.listen_mode == LISTEN_KERNEL)
1499                                len = d6_recv_kernel_packet(&srv6_buf, &packet, client_data.sockfd);
1500                        else
1501                                len = d6_recv_raw_packet(&srv6_buf, &packet, client_data.sockfd);
1502                        if (len == -1) {
1503                                /* Error is severe, reopen socket */
1504                                bb_error_msg("read error: "STRERROR_FMT", reopening socket" STRERROR_ERRNO);
1505                                sleep(discover_timeout); /* 3 seconds by default */
1506                                change_listen_mode(client_data.listen_mode); /* just close and reopen */
1507                        }
1508                        /* If this packet will turn out to be unrelated/bogus,
1509                         * we will go back and wait for next one.
1510                         * Be sure timeout is properly decreased. */
1511                        already_waited_sec += (unsigned)monotonic_sec() - timestamp_before_wait;
1512                        if (len < 0)
1513                                continue;
1514                        packet_end = (uint8_t*)&packet + len;
1515                }
1516
1517                if ((packet.d6_xid32 & htonl(0x00ffffff)) != xid) {
1518                        log1("xid %x (our is %x), ignoring packet",
1519                                (unsigned)(packet.d6_xid32 & htonl(0x00ffffff)), (unsigned)xid);
1520                        continue;
1521                }
1522
1523                switch (client_data.state) {
1524                case INIT_SELECTING:
1525                        if (packet.d6_msg_type == D6_MSG_ADVERTISE)
1526                                goto type_is_ok;
1527                        /* DHCPv6 has "Rapid Commit", when instead of Advertise,
1528                         * server sends Reply right away.
1529                         * Fall through to check for this case.
1530                         */
1531                case REQUESTING:
1532                case RENEWING:
1533                case RENEW_REQUESTED:
1534                case REBINDING:
1535                        if (packet.d6_msg_type == D6_MSG_REPLY) {
1536                                uint32_t lease_seconds;
1537                                struct d6_option *option;
1538                                unsigned address_timeout;
1539                                unsigned prefix_timeout;
1540 type_is_ok:
1541                                address_timeout = 0;
1542                                prefix_timeout = 0;
1543                                option = d6_find_option(packet.d6_options, packet_end, D6_OPT_STATUS_CODE);
1544                                if (option && (option->data[0] | option->data[1]) != 0) {
1545                                        /* return to init state */
1546                                        bb_info_msg("received DHCP NAK (%u)", option->data[4]);
1547                                        d6_run_script(packet.d6_options,
1548                                                        packet_end, "nak");
1549                                        if (client_data.state != REQUESTING)
1550                                                d6_run_script_no_option("deconfig");
1551                                        change_listen_mode(LISTEN_RAW);
1552                                        sleep(3); /* avoid excessive network traffic */
1553                                        client_data.state = INIT_SELECTING;
1554                                        client_data.first_secs = 0; /* make secs field count from 0 */
1555                                        requested_ipv6 = NULL;
1556                                        timeout = 0;
1557                                        packet_num = 0;
1558                                        already_waited_sec = 0;
1559                                        continue;
1560                                }
1561                                option = d6_copy_option(packet.d6_options, packet_end, D6_OPT_SERVERID);
1562                                if (!option) {
1563                                        bb_info_msg("no server ID, ignoring packet");
1564                                        continue;
1565                                        /* still selecting - this server looks bad */
1566                                }
1567//Note: we do not bother comparing server IDs in Advertise and Reply msgs.
1568//server_id variable is used solely for creation of proper server_id option
1569//in outgoing packets. (why DHCPv6 even introduced it is a mystery).
1570                                free(client6_data.server_id);
1571                                client6_data.server_id = option;
1572                                if (packet.d6_msg_type == D6_MSG_ADVERTISE) {
1573                                        /* enter requesting state */
1574                                        client_data.state = REQUESTING;
1575                                        timeout = 0;
1576                                        packet_num = 0;
1577                                        already_waited_sec = 0;
1578                                        continue;
1579                                }
1580                                /* It's a D6_MSG_REPLY */
1581/*
1582 * RFC 3315 18.1.8. Receipt of Reply Messages
1583 *
1584 * Upon the receipt of a valid Reply message in response to a Solicit
1585 * (with a Rapid Commit option), Request, Confirm, Renew, Rebind or
1586 * Information-request message, the client extracts the configuration
1587 * information contained in the Reply.  The client MAY choose to report
1588 * any status code or message from the status code option in the Reply
1589 * message.
1590 *
1591 * The client SHOULD perform duplicate address detection [17] on each of
1592 * the addresses in any IAs it receives in the Reply message before
1593 * using that address for traffic.  If any of the addresses are found to
1594 * be in use on the link, the client sends a Decline message to the
1595 * server as described in section 18.1.7.
1596 *
1597 * If the Reply was received in response to a Solicit (with a Rapid
1598 * Commit option), Request, Renew or Rebind message, the client updates
1599 * the information it has recorded about IAs from the IA options
1600 * contained in the Reply message:
1601 *
1602 * -  Record T1 and T2 times.
1603 *
1604 * -  Add any new addresses in the IA option to the IA as recorded by
1605 *    the client.
1606 *
1607 * -  Update lifetimes for any addresses in the IA option that the
1608 *    client already has recorded in the IA.
1609 *
1610 * -  Discard any addresses from the IA, as recorded by the client, that
1611 *    have a valid lifetime of 0 in the IA Address option.
1612 *
1613 * -  Leave unchanged any information about addresses the client has
1614 *    recorded in the IA but that were not included in the IA from the
1615 *    server.
1616 *
1617 * Management of the specific configuration information is detailed in
1618 * the definition of each option in section 22.
1619 *
1620 * If the client receives a Reply message with a Status Code containing
1621 * UnspecFail, the server is indicating that it was unable to process
1622 * the message due to an unspecified failure condition.  If the client
1623 * retransmits the original message to the same server to retry the
1624 * desired operation, the client MUST limit the rate at which it
1625 * retransmits the message and limit the duration of the time during
1626 * which it retransmits the message.
1627 *
1628 * When the client receives a Reply message with a Status Code option
1629 * with the value UseMulticast, the client records the receipt of the
1630 * message and sends subsequent messages to the server through the
1631 * interface on which the message was received using multicast.  The
1632 * client resends the original message using multicast.
1633 *
1634 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1635 * |          OPTION_IA_NA         |          option-len           |
1636 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1637 * |                        IAID (4 octets)                        |
1638 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1639 * |                              T1                               |
1640 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1641 * |                              T2                               |
1642 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1643 * |                                                               |
1644 * .                         IA_NA-options                         .
1645 * .                                                               .
1646 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1647 *
1648 *
1649 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1650 * |          OPTION_IAADDR        |          option-len           |
1651 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1652 * |                                                               |
1653 * |                         IPv6 address                          |
1654 * |                                                               |
1655 * |                                                               |
1656 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1657 * |                      preferred-lifetime                       |
1658 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1659 * |                        valid-lifetime                         |
1660 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1661 * .                                                               .
1662 * .                        IAaddr-options                         .
1663 * .                                                               .
1664 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1665 */
1666                                if (option_mask32 & OPT_r) {
1667                                        struct d6_option *iaaddr;
1668
1669                                        free(client6_data.ia_na);
1670                                        client6_data.ia_na = d6_copy_option(packet.d6_options, packet_end, D6_OPT_IA_NA);
1671                                        if (!client6_data.ia_na) {
1672                                                bb_info_msg("no %s option, ignoring packet", "IA_NA");
1673                                                continue;
1674                                        }
1675                                        if (client6_data.ia_na->len < (4 + 4 + 4) + (2 + 2 + 16 + 4 + 4)) {
1676                                                bb_info_msg("%s option is too short:%d bytes",
1677                                                        "IA_NA", client6_data.ia_na->len);
1678                                                continue;
1679                                        }
1680                                        iaaddr = d6_find_option(client6_data.ia_na->data + 4 + 4 + 4,
1681                                                        client6_data.ia_na->data + client6_data.ia_na->len,
1682                                                        D6_OPT_IAADDR
1683                                        );
1684                                        if (!iaaddr) {
1685                                                bb_info_msg("no %s option, ignoring packet", "IAADDR");
1686                                                continue;
1687                                        }
1688                                        if (iaaddr->len < (16 + 4 + 4)) {
1689                                                bb_info_msg("%s option is too short:%d bytes",
1690                                                        "IAADDR", iaaddr->len);
1691                                                continue;
1692                                        }
1693                                        /* Note: the address is sufficiently aligned for cast:
1694                                         * we _copied_ IA-NA, and copy is always well-aligned.
1695                                         */
1696                                        requested_ipv6 = (struct in6_addr*) iaaddr->data;
1697                                        move_from_unaligned32(lease_seconds, iaaddr->data + 16 + 4);
1698                                        lease_seconds = ntohl(lease_seconds);
1699/// TODO: check for 0 lease time?
1700                                        bb_info_msg("%s obtained, lease time %u",
1701                                                "IPv6", /*inet_ntoa(temp_addr),*/ (unsigned)lease_seconds);
1702                                        address_timeout = lease_seconds;
1703                                }
1704                                if (option_mask32 & OPT_d) {
1705                                        struct d6_option *iaprefix;
1706
1707                                        free(client6_data.ia_pd);
1708                                        client6_data.ia_pd = d6_copy_option(packet.d6_options, packet_end, D6_OPT_IA_PD);
1709                                        if (!client6_data.ia_pd) {
1710                                                bb_info_msg("no %s option, ignoring packet", "IA_PD");
1711                                                continue;
1712                                        }
1713                                        if (client6_data.ia_pd->len < (4 + 4 + 4) + (2 + 2 + 4 + 4 + 1 + 16)) {
1714                                                bb_info_msg("%s option is too short:%d bytes",
1715                                                        "IA_PD", client6_data.ia_pd->len);
1716                                                continue;
1717                                        }
1718                                        iaprefix = d6_find_option(client6_data.ia_pd->data + 4 + 4 + 4,
1719                                                        client6_data.ia_pd->data + client6_data.ia_pd->len,
1720                                                        D6_OPT_IAPREFIX
1721                                        );
1722                                        if (!iaprefix) {
1723                                                bb_info_msg("no %s option, ignoring packet", "IAPREFIX");
1724                                                continue;
1725                                        }
1726                                        if (iaprefix->len < (4 + 4 + 1 + 16)) {
1727                                                bb_info_msg("%s option is too short:%d bytes",
1728                                                        "IAPREFIX", iaprefix->len);
1729                                                continue;
1730                                        }
1731                                        move_from_unaligned32(lease_seconds, iaprefix->data + 4);
1732                                        lease_seconds = ntohl(lease_seconds);
1733                                        bb_info_msg("%s obtained, lease time %u",
1734                                                "prefix", /*inet_ntoa(temp_addr),*/ (unsigned)lease_seconds);
1735                                        prefix_timeout = lease_seconds;
1736                                }
1737                                if (!address_timeout)
1738                                        address_timeout = prefix_timeout;
1739                                if (!prefix_timeout)
1740                                        prefix_timeout = address_timeout;
1741                                /* note: "int timeout" will not overflow even with 0xffffffff inputs here: */
1742                                timeout = (prefix_timeout < address_timeout ? prefix_timeout : address_timeout) / 2;
1743                                /* paranoia: must not be too small */
1744                                /* timeout > 60 - ensures at least one unicast renew attempt */
1745                                if (timeout < 61)
1746                                        timeout = 61;
1747                                /* enter bound state */
1748                                d6_run_script(packet.d6_options, packet_end,
1749                                        (client_data.state == REQUESTING ? "bound" : "renew"));
1750
1751                                client_data.state = BOUND;
1752                                change_listen_mode(LISTEN_NONE);
1753                                if (opt & OPT_q) { /* quit after lease */
1754                                        goto ret0;
1755                                }
1756                                /* future renew failures should not exit (JM) */
1757                                opt &= ~OPT_n;
1758#if BB_MMU /* NOMMU case backgrounded earlier */
1759                                if (!(opt & OPT_f)) {
1760                                        client_background();
1761                                        /* do not background again! */
1762                                        opt = ((opt & ~OPT_b) | OPT_f);
1763                                }
1764#endif
1765                                already_waited_sec = 0;
1766                                continue; /* back to main loop */
1767                        }
1768                        continue;
1769                /* case BOUND: - ignore all packets */
1770                /* case RELEASED: - ignore all packets */
1771                }
1772                /* back to main loop */
1773        } /* for (;;) - main loop ends */
1774
1775 ret0:
1776        if (opt & OPT_R) /* release on quit */
1777                perform_d6_release(&srv6_buf, requested_ipv6);
1778        retval = 0;
1779 ret:
1780        /*if (client_data.pidfile) - remove_pidfile has its own check */
1781                remove_pidfile(client_data.pidfile);
1782        return retval;
1783}
1784