From b906997217b363c459fdbd2824bfe6c5ac69607e Mon Sep 17 00:00:00 2001
From: Sinan Kaya <ok...@kernel.org>
Date: Tue, 19 Apr 2022 13:47:19 +0000
Subject: [PATCH] udhcpc: add support for sending DHCPINFORM requests

It is useful for applications to be able to query DHCP options
without renewing IP address.

Tested-with: -I: for unknown DHCP server
             -I: for a specific DHCP server --server 1.2.3.4

Signed-off-by: Sinan Kaya <ok...@kernel.org>
---
 networking/udhcp/dhcpc.c | 68 ++++++++++++++++++++++++++++++----------
 1 file changed, 52 insertions(+), 16 deletions(-)

diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c
index c757fb37c..e788613fd 100644
--- a/networking/udhcp/dhcpc.c
+++ b/networking/udhcp/dhcpc.c
@@ -75,6 +75,8 @@ static const char udhcpc_longopts[] ALIGN1 =
        "background\0"     No_argument       "b"
        )
        "broadcast\0"      No_argument       "B"
+       "inform\0"         No_argument       "I"
+       "server\0"         Required_argument "e"
        IF_FEATURE_UDHCPC_ARPING("arping\0"   Optional_argument "a")
        IF_FEATURE_UDHCP_PORT("client-port\0" Required_argument "P")
        ;
@@ -100,8 +102,10 @@ enum {
        OPT_x = 1 << 16,
        OPT_f = 1 << 17,
        OPT_B = 1 << 18,
+       OPT_I = 1 << 19,
+       OPT_e = 1 << 20,
 /* The rest has variable bit positions, need to be clever */
-       OPTBIT_B = 18,
+       OPTBIT_e = 20,
        USE_FOR_MMU(             OPTBIT_b,)
        IF_FEATURE_UDHCPC_ARPING(OPTBIT_a,)
        IF_FEATURE_UDHCP_PORT(   OPTBIT_P,)
@@ -742,14 +746,15 @@ static NOINLINE int send_discover(uint32_t requested)

 /* Broadcast a DHCP request message */
 /* RFC 2131 3.1 paragraph 3:
- * "The client _broadcasts_ a DHCPREQUEST message..."
+ * "The client _broadcasts_ a DHCPREQUEST/INFORM message..."
  */
 /* NOINLINE: limit stack usage in caller */
-static NOINLINE int send_select(uint32_t server, uint32_t requested)
+static NOINLINE int send_select(uint32_t server, uint32_t requested, int inform)
 {
        struct dhcp_packet packet;
        struct in_addr temp_addr;
        char server_str[sizeof("255.255.255.255")];
+       const char *direction;

 /*
  * RFC 2131 4.3.2 DHCPREQUEST message
@@ -766,11 +771,12 @@ static NOINLINE int send_select(uint32_t server, uint32_t requested)
        /* Fill in: op, htype, hlen, cookie, chaddr fields,
         * xid field, message type option:
         */
-       init_packet(&packet, DHCPREQUEST);
+       init_packet(&packet, inform ? DHCPINFORM: DHCPREQUEST);

        udhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested);

-       udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server);
+       if (server)
+               udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server);

        /* Add options: maxsize,
         * "param req" option according to -O, options specified with -x
@@ -780,11 +786,19 @@ static NOINLINE int send_select(uint32_t server, uint32_t requested)
        temp_addr.s_addr = server;
        strcpy(server_str, inet_ntoa(temp_addr));
        temp_addr.s_addr = requested;
-       bb_info_msg("broadcasting select for %s, server %s",
-                       inet_ntoa(temp_addr),
-                       server_str
+       if (server)
+               direction = "unicasting";
+       else
+               direction = "broadcasting";
+
+       bb_info_msg("%s select for %s, server %s",
+               direction,
+               inet_ntoa(temp_addr),
+               server_str
        );
-       return raw_bcast_from_client_data_ifindex(&packet, INADDR_ANY);
+
+       // return raw_bcast_from_client_data_ifindex(&packet, INADDR_ANY);
+       return bcast_or_ucast(&packet, requested, server);
 }

 /* Unicast or broadcast a DHCP renew message */
@@ -1161,9 +1175,9 @@ static void client_background(void)
 //usage:# define IF_UDHCP_VERBOSE(...)
 //usage:#endif
 //usage:#define udhcpc_trivial_usage
-//usage: "[-fbq"IF_UDHCP_VERBOSE("v")"RB]"IF_FEATURE_UDHCPC_ARPING(" [-a[MSEC]]")" [-t N] [-T SEC] [-A SEC|-n]\n" +//usage: "[-fbq"IF_UDHCP_VERBOSE("v")"RBI]"IF_FEATURE_UDHCPC_ARPING(" [-a[MSEC]]")" [-t N] [-T SEC] [-A SEC|-n]\n" //usage: " [-i IFACE]"IF_FEATURE_UDHCP_PORT(" [-P PORT]")" [-s PROG] [-p PIDFILE]\n" -//usage: " [-oC] [-r IP] [-V VENDOR] [-F NAME] [-x OPT:VAL]... [-O OPT]..." +//usage: " [-oC] [-r IP] [-e IP] [-V VENDOR] [-F NAME] [-x OPT:VAL]... [-O OPT]..."
 //usage:#define udhcpc_full_usage "\n"
//usage: "\n -i IFACE Interface to use (default "CONFIG_UDHCPC_DEFAULT_INTERFACE")"
 //usage:       IF_FEATURE_UDHCP_PORT(
@@ -1172,6 +1186,7 @@ static void client_background(void)
//usage: "\n -s PROG Run PROG at DHCP events (default "CONFIG_UDHCPC_DEFAULT_SCRIPT")"
 //usage:     "\n  -p FILE         Create pidfile"
 //usage:     "\n  -B              Request broadcast replies"
+//usage:     "\n  -I              Request using inform"
 //usage:     "\n  -t N            Send up to N discover packets (default 3)"
 //usage:     "\n  -T SEC          Pause between packets (default 3)"
 //usage:     "\n  -A SEC          Wait if lease is not obtained (default 20)"
@@ -1187,6 +1202,7 @@ static void client_background(void)
 //usage:     "\n  -a[MSEC]        Validate offered address with ARP ping"
 //usage:       )
 //usage:     "\n  -r IP           Request this IP address"
+//usage:     "\n  -e IP           Request this server IP address"
 //usage:     "\n  -o              Don't request any options (unless -O is 
given)"
 //usage:     "\n  -O OPT          Request option OPT from server (cumulative)"
//usage: "\n -x OPT:VAL Include option OPT in sent packets (cumulative)" @@ -1209,7 +1225,7 @@ int udhcpc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 int udhcpc_main(int argc UNUSED_PARAM, char **argv)
 {
        uint8_t *message;
-       const char *str_V, *str_F, *str_r;
+       const char *str_V, *str_F, *str_r, *str_e;
        IF_FEATURE_UDHCPC_ARPING(const char *str_a = "2000";)
        IF_FEATURE_UDHCP_PORT(char *str_P;)
        uint8_t *clientid_mac_ptr;
@@ -1218,7 +1234,8 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
        int tryagain_timeout = 20;
        int discover_timeout = 3;
        int discover_retries = 3;
-       uint32_t server_id = server_id; /* for compiler */
+       int use_inform = 0;
+       uint32_t server_id = 0;
        uint32_t requested_ip = 0;
        int packet_num;
        int timeout; /* must be signed */
@@ -1244,7 +1261,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
        /* Parse command line */
        opt = getopt32long(argv, "^"
                /* O,x: list; -T,-t,-A take numeric param */
-               "CV:F:i:np:qRr:s:T:+t:+SA:+O:*ox:*fB"
+               "CV:F:i:np:qRr:s:T:+t:+SA:+O:*ox:*fBIe:"
                USE_FOR_MMU("b")
                IF_FEATURE_UDHCPC_ARPING("a::")
                IF_FEATURE_UDHCP_PORT("P:")
@@ -1258,10 +1275,15 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
                , &discover_timeout, &discover_retries, &tryagain_timeout /* 
T,t,A */
                , &list_O
                , &list_x
+               , &str_e /* e */
                IF_FEATURE_UDHCPC_ARPING(, &str_a)
                IF_FEATURE_UDHCP_PORT(, &str_P)
                IF_UDHCP_VERBOSE(, &dhcp_verbose)
        );
+
+       if (opt & OPT_I)
+               use_inform = 1;
+
        if (opt & OPT_F) {
                char *p;
                unsigned len;
@@ -1283,6 +1305,9 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
                /*p[OPT_DATA + 2] = 0; */
                memcpy(p + OPT_DATA + 3, str_F, len); /* do not store NUL byte 
*/
        }
+       if (opt & OPT_e)
+               if (!inet_aton(str_e, (void*)&server_id))
+                       bb_show_usage();
        if (opt & OPT_r)
                if (!inet_aton(str_r, (void*)&requested_ip))
                        bb_show_usage();
@@ -1368,12 +1393,23 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
        /* We want random_xid to be random... */
        srand(monotonic_us());

-       client_data.state = INIT_SELECTING;
+       if (use_inform) {
+               bb_simple_info_msg("using inform");
+               client_data.state = REQUESTING;
+       } else {
+               client_data.state = INIT_SELECTING;
+       }
+
        d4_run_script_deconfig();
        packet_num = 0;
        timeout = 0;
        lease_remaining = 0;

+       if (use_inform) {
+               change_listen_mode(LISTEN_RAW);
+               client_data.xid = random_xid();
+       }
+
        /* Main event loop. select() waits on signal pipe and possibly
         * on sockfd.
         * "continue" statements in code below jump to the top of the loop.
@@ -1482,7 +1518,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
                        case REQUESTING:
                                if (packet_num < 3) {
                                        /* send broadcast select packet */
-                                       send_select(server_id, requested_ip);
+                                       send_select(server_id, requested_ip, 
use_inform);
                                        timeout = discover_timeout;
                                        packet_num++;
                                        continue;
--
2.17.1

_______________________________________________
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox

Reply via email to