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