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