udhcpc[6]: show select timeout in log
[oweals/busybox.git] / networking / udhcp / d6_dhcpc.c
index 62d79b363b6901ea66905d0376608c9dde5e2489..d9d8b9b565f4e0fd4a2c871a66e4981def962021 100644 (file)
  */
 
 //config:config UDHCPC6
-//config:       bool "udhcp client for DHCPv6 (udhcpc6)"
-//config:       default n  # not yet ready
-//config:       help
-//config:         udhcpc6 is a DHCPv6 client
+//config:      bool "udhcp client for DHCPv6 (udhcpc6)"
+//config:      default n  # not yet ready
+//config:      depends on FEATURE_IPV6
+//config:      help
+//config:        udhcpc6 is a DHCPv6 client
 
 //applet:IF_UDHCPC6(APPLET(udhcpc6, BB_DIR_USR_BIN, BB_SUID_DROP))
 
-//kbuild:lib-$(CONFIG_UDHCPC6) += d6_dhcpc.o d6_packet.o d6_socket.o common.o
+//kbuild:lib-$(CONFIG_UDHCPC6) += d6_dhcpc.o d6_packet.o d6_socket.o common.o socket.o signalpipe.o
 
 
 #include <syslog.h>
@@ -38,7 +39,7 @@
 
 
 #if ENABLE_LONG_OPTS
-static const char udhcpc_longopts[] ALIGN1 =
+static const char udhcpc6_longopts[] ALIGN1 =
        "interface\0"      Required_argument "i"
        "now\0"            No_argument       "n"
        "pidfile\0"        Required_argument "p"
@@ -47,7 +48,6 @@ static const char udhcpc_longopts[] ALIGN1 =
        "request\0"        Required_argument "r"
        "script\0"         Required_argument "s"
        "timeout\0"        Required_argument "T"
-       "version\0"        No_argument       "v"
        "retries\0"        Required_argument "t"
        "tryagain\0"       Required_argument "A"
        "syslog\0"         No_argument       "S"
@@ -55,7 +55,6 @@ static const char udhcpc_longopts[] ALIGN1 =
        "no-default-options\0" No_argument   "o"
        "foreground\0"     No_argument       "f"
        "background\0"     No_argument       "b"
-       "broadcast\0"      No_argument       "B"
 ///    IF_FEATURE_UDHCPC_ARPING("arping\0"     No_argument       "a")
        IF_FEATURE_UDHCP_PORT("client-port\0"   Required_argument "P")
        ;
@@ -77,9 +76,8 @@ enum {
        OPT_o = 1 << 12,
        OPT_x = 1 << 13,
        OPT_f = 1 << 14,
-       OPT_B = 1 << 15,
 /* The rest has variable bit positions, need to be clever */
-       OPTBIT_B = 15,
+       OPTBIT_f = 14,
        USE_FOR_MMU(             OPTBIT_b,)
        ///IF_FEATURE_UDHCPC_ARPING(OPTBIT_a,)
        IF_FEATURE_UDHCP_PORT(   OPTBIT_P,)
@@ -132,32 +130,114 @@ static void *d6_store_blob(void *dst, const void *src, unsigned len)
 
 /*** Script execution code ***/
 
+static char** new_env(void)
+{
+       client6_data.env_ptr = xrealloc_vector(client6_data.env_ptr, 3, client6_data.env_idx);
+       return &client6_data.env_ptr[client6_data.env_idx++];
+}
+
 /* put all the parameters into the environment */
-static char **fill_envp(struct d6_packet *packet
-    UNUSED_PARAM
-)
+static void option_to_env(uint8_t *option, uint8_t *option_end)
 {
-       int envc;
-       char **envp, **curr;
+       /* "length minus 4" */
+       int len_m4 = option_end - option - 4;
+       while (len_m4 >= 0) {
+               uint32_t v32;
+               char ipv6str[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")];
 
-#define BITMAP unsigned
-#define BBITS (sizeof(BITMAP) * 8)
-#define BMASK(i) (1 << (i & (sizeof(BITMAP) * 8 - 1)))
-#define FOUND_OPTS(i) (found_opts[(unsigned)i / BBITS])
-       ///BITMAP found_opts[256 / BBITS];
+               if (option[0] != 0 || option[2] != 0)
+                       break;
+
+               switch (option[1]) {
+               //case D6_OPT_CLIENTID:
+               //case D6_OPT_SERVERID:
+               case D6_OPT_IA_NA:
+               case D6_OPT_IA_PD:
+                       option_to_env(option + 16, option + 4 + option[3]);
+                       break;
+               //case D6_OPT_IA_TA:
+               case D6_OPT_IAADDR:
+/*   0                   1                   2                   3
+ *  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
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |          OPTION_IAADDR        |          option-len           |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                                                               |
+ * |                         IPv6 address                          |
+ * |                                                               |
+ * |                                                               |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                      preferred-lifetime                       |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                        valid-lifetime                         |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+                       sprint_nip6(ipv6str, option + 4);
+                       *new_env() = xasprintf("ipv6=%s", ipv6str);
+
+                       move_from_unaligned32(v32, option + 4 + 16 + 4);
+                       *new_env() = xasprintf("lease=%u", (unsigned)v32);
+                       break;
+
+               //case D6_OPT_ORO:
+               //case D6_OPT_PREFERENCE:
+               //case D6_OPT_ELAPSED_TIME:
+               //case D6_OPT_RELAY_MSG:
+               //case D6_OPT_AUTH:
+               //case D6_OPT_UNICAST:
+               //case D6_OPT_STATUS_CODE:
+               //case D6_OPT_RAPID_COMMIT:
+               //case D6_OPT_USER_CLASS:
+               //case D6_OPT_VENDOR_CLASS:
+               //case D6_OPT_VENDOR_OPTS:
+               //case D6_OPT_INTERFACE_ID:
+               //case D6_OPT_RECONF_MSG:
+               //case D6_OPT_RECONF_ACCEPT:
+
+               case D6_OPT_IAPREFIX:
+/*  0                   1                   2                   3
+ *  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
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |        OPTION_IAPREFIX        |         option-length         |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                      preferred-lifetime                       |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                        valid-lifetime                         |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | prefix-length |                                               |
+ * +-+-+-+-+-+-+-+-+          IPv6 prefix                          |
+ * |                           (16 octets)                         |
+ * |                                                               |
+ * |               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |               |
+ * +-+-+-+-+-+-+-+-+
+ */
+                       //move_from_unaligned32(v32, option + 4 + 4);
+                       //*new_env() = xasprintf("lease=%u", (unsigned)v32);
 
-       ///memset(found_opts, 0, sizeof(found_opts));
+                       sprint_nip6(ipv6str, option + 4 + 4 + 1);
+                       *new_env() = xasprintf("ipv6prefix=%s/%u", ipv6str, (unsigned)(option[4 + 4]));
+               }
+               option += 4 + option[3];
+               len_m4 -= 4 + option[3];
+       }
+}
 
-       /* We need 2 elements for:
-        * "interface=IFACE"
-        * terminating NULL
-        */
-       envc = 2;
+static char **fill_envp(struct d6_packet *packet)
+{
+       char **envp, **curr;
 
-       curr = envp = xzalloc(sizeof(envp[0]) * envc);
+       client6_data.env_ptr = NULL;
+       client6_data.env_idx = 0;
 
-       *curr = xasprintf("interface=%s", client_config.interface);
-       putenv(*curr++);
+       *new_env() = xasprintf("interface=%s", client_config.interface);
+
+       if (packet)
+               option_to_env(packet->d6_options, packet->d6_options + sizeof(packet->d6_options));
+
+       envp = curr = client6_data.env_ptr;
+       while (*curr)
+               putenv(*curr++);
 
        return envp;
 }
@@ -751,7 +831,7 @@ static void client_background(void)
 //usage:# define IF_UDHCP_VERBOSE(...)
 //usage:#endif
 //usage:#define udhcpc6_trivial_usage
-//usage:       "[-fbnq"IF_UDHCP_VERBOSE("v")"oRB] [-i IFACE] [-r IP] [-s PROG] [-p PIDFILE]\n"
+//usage:       "[-fbnq"IF_UDHCP_VERBOSE("v")"oR] [-i IFACE] [-r IP] [-s PROG] [-p PIDFILE]\n"
 //usage:       "       [-x OPT:VAL]... [-O OPT]..." IF_FEATURE_UDHCP_PORT(" [-P N]")
 //usage:#define udhcpc6_full_usage "\n"
 //usage:       IF_LONG_OPTS(
@@ -771,7 +851,7 @@ static void client_background(void)
 //usage:     "\n       -R,--release            Release IP on exit"
 //usage:     "\n       -S,--syslog             Log to syslog too"
 //usage:       IF_FEATURE_UDHCP_PORT(
-//usage:     "\n       -P,--client-port N      Use port N (default 68)"
+//usage:     "\n       -P,--client-port N      Use port N (default 546)"
 //usage:       )
 ////usage:     IF_FEATURE_UDHCPC_ARPING(
 ////usage:     "\n     -a,--arping             Use arping to validate offered address"
@@ -805,7 +885,7 @@ static void client_background(void)
 //usage:     "\n       -R              Release IP on exit"
 //usage:     "\n       -S              Log to syslog too"
 //usage:       IF_FEATURE_UDHCP_PORT(
-//usage:     "\n       -P N            Use port N (default 68)"
+//usage:     "\n       -P N            Use port N (default 546)"
 //usage:       )
 ////usage:     IF_FEATURE_UDHCPC_ARPING(
 ////usage:     "\n     -a              Use arping to validate offered address"
@@ -859,8 +939,8 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
        /* Parse command line */
        /* O,x: list; -T,-t,-A take numeric param */
        opt_complementary = "O::x::T+:t+:A+" IF_UDHCP_VERBOSE(":vv") ;
-       IF_LONG_OPTS(applet_long_options = udhcpc_longopts;)
-       opt = getopt32(argv, "i:np:qRr:s:T:t:SA:O:ox:fB"
+       IF_LONG_OPTS(applet_long_options = udhcpc6_longopts;)
+       opt = getopt32(argv, "i:np:qRr:s:T:t:SA:O:ox:f"
                USE_FOR_MMU("b")
                ///IF_FEATURE_UDHCPC_ARPING("a")
                IF_FEATURE_UDHCP_PORT("P:")
@@ -872,7 +952,7 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
                , &list_x
                IF_FEATURE_UDHCP_PORT(, &str_P)
                IF_UDHCP_VERBOSE(, &dhcp_verbose)
-               );
+       );
        requested_ipv6 = NULL;
        if (opt & OPT_r) {
                if (inet_pton(AF_INET6, str_r, &ipv6_buf) <= 0)
@@ -986,8 +1066,8 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
                retval = 0;
                /* If we already timed out, fall through with retval = 0, else... */
                if ((int)tv.tv_sec > 0) {
+                       log1("Waiting on select %u seconds", (int)tv.tv_sec);
                        timestamp_before_wait = (unsigned)monotonic_sec();
-                       log1("Waiting on select...");
                        retval = select(max_fd + 1, &rfds, NULL, NULL, &tv);
                        if (retval < 0) {
                                /* EINTR? A signal was caught, don't panic */
@@ -1332,19 +1412,19 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
                                free(client6_data.ia_na);
                                client6_data.ia_na = d6_copy_option(packet.d6_options, packet_end, D6_OPT_IA_NA);
                                if (!client6_data.ia_na) {
-                                       bb_error_msg("no lease time, ignoring packet");
+                                       bb_error_msg("no %s option, ignoring packet", "IA_NA");
                                        continue;
                                }
                                if (client6_data.ia_na->len < (4 + 4 + 4) + (2 + 2 + 16 + 4 + 4)) {
                                        bb_error_msg("IA_NA option is too short:%d bytes", client6_data.ia_na->len);
                                        continue;
                                }
-                               iaaddr = d6_find_option(client6_data.ia_na->data,
+                               iaaddr = d6_find_option(client6_data.ia_na->data + 4 + 4 + 4,
                                                client6_data.ia_na->data + client6_data.ia_na->len,
                                                D6_OPT_IAADDR
                                );
                                if (!iaaddr) {
-                                       bb_error_msg("no lease time, ignoring packet");
+                                       bb_error_msg("no %s option, ignoring packet", "IAADDR");
                                        continue;
                                }
                                if (iaaddr->len < (16 + 4 + 4)) {