udhcpc: emit maxsize option in all non-NAK type packets
authorDenys Vlasenko <vda.linux@googlemail.com>
Wed, 20 Oct 2010 19:37:23 +0000 (21:37 +0200)
committerDenys Vlasenko <vda.linux@googlemail.com>
Wed, 20 Oct 2010 19:37:23 +0000 (21:37 +0200)
Before, we were sending them only in DISCOVER packets.

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
networking/udhcp/dhcpc.c

index 9713e81..f685a1d 100644 (file)
@@ -346,31 +346,34 @@ static ALWAYS_INLINE uint32_t random_xid(void)
 /* Initialize the packet with the proper defaults */
 static void init_packet(struct dhcp_packet *packet, char type)
 {
+       /* Fill in: op, htype, hlen, cookie fields; message type option: */
        udhcp_init_header(packet, type);
+
+       packet->xid = random_xid();
+
        memcpy(packet->chaddr, client_config.client_mac, 6);
        if (client_config.clientid)
                udhcp_add_binary_option(packet, client_config.clientid);
+}
+
+static void add_client_options(struct dhcp_packet *packet)
+{
+       uint8_t c;
+       int i, end, len;
+
+       udhcp_add_simple_option(packet, DHCP_MAX_SIZE, htons(IP_UDP_DHCP_SIZE));
        if (client_config.hostname)
                udhcp_add_binary_option(packet, client_config.hostname);
        if (client_config.fqdn)
                udhcp_add_binary_option(packet, client_config.fqdn);
-       if (type != DHCPDECLINE
-        && type != DHCPRELEASE
-        && client_config.vendorclass
-       ) {
+       if (client_config.vendorclass)
                udhcp_add_binary_option(packet, client_config.vendorclass);
-       }
-}
 
-static void add_client_options(struct dhcp_packet *packet)
-{
        /* Add a "param req" option with the list of options we'd like to have
         * from stubborn DHCP servers. Pull the data from the struct in common.c.
         * No bounds checking because it goes towards the head of the packet. */
-       uint8_t c;
-       int end = udhcp_end_option(packet->options);
-       int i, len = 0;
-
+       end = udhcp_end_option(packet->options);
+       len = 0;
        for (i = 0; (c = dhcp_optflags[i].code) != 0; i++) {
                if ((   (dhcp_optflags[i].flags & OPTION_REQ)
                     && !client_config.no_default_options
@@ -432,13 +435,20 @@ static int send_discover(uint32_t xid, uint32_t requested)
 {
        struct dhcp_packet packet;
 
+       /* Fill in: op, htype, hlen, cookie, chaddr fields,
+        * random xid field (we override it below),
+        * client-id option (unless -C), message type option:
+        */
        init_packet(&packet, DHCPDISCOVER);
+
        packet.xid = xid;
        if (requested)
                udhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested);
-       /* Explicitly saying that we want RFC-compliant packets helps
-        * some buggy DHCP servers to NOT send bigger packets */
-       udhcp_add_simple_option(&packet, DHCP_MAX_SIZE, htons(576));
+
+       /* Add options: maxsize,
+        * optionally: hostname, fqdn, vendorclass,
+        * "param req" option according to -O, options specified with -x
+        */
        add_client_options(&packet);
 
        bb_info_msg("Sending discover...");
@@ -454,10 +464,33 @@ static int send_select(uint32_t xid, uint32_t server, uint32_t requested)
        struct dhcp_packet packet;
        struct in_addr addr;
 
+/*
+ * RFC 2131 4.3.2 DHCPREQUEST message
+ * ...
+ * If the DHCPREQUEST message contains a 'server identifier'
+ * option, the message is in response to a DHCPOFFER message.
+ * Otherwise, the message is a request to verify or extend an
+ * existing lease. If the client uses a 'client identifier'
+ * in a DHCPREQUEST message, it MUST use that same 'client identifier'
+ * in all subsequent messages. If the client included a list
+ * of requested parameters in a DHCPDISCOVER message, it MUST
+ * include that list in all subsequent messages.
+ */
+       /* Fill in: op, htype, hlen, cookie, chaddr fields,
+        * random xid field (we override it below),
+        * client-id option (unless -C), message type option:
+        */
        init_packet(&packet, DHCPREQUEST);
+
        packet.xid = xid;
        udhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested);
+
        udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server);
+
+       /* Add options: maxsize,
+        * optionally: hostname, fqdn, vendorclass,
+        * "param req" option according to -O, and options specified with -x
+        */
        add_client_options(&packet);
 
        addr.s_addr = requested;
@@ -470,9 +503,33 @@ static int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr)
 {
        struct dhcp_packet packet;
 
+/*
+ * RFC 2131 4.3.2 DHCPREQUEST message
+ * ...
+ * DHCPREQUEST generated during RENEWING state:
+ *
+ * 'server identifier' MUST NOT be filled in, 'requested IP address'
+ * option MUST NOT be filled in, 'ciaddr' MUST be filled in with
+ * client's IP address. In this situation, the client is completely
+ * configured, and is trying to extend its lease. This message will
+ * be unicast, so no relay agents will be involved in its
+ * transmission.  Because 'giaddr' is therefore not filled in, the
+ * DHCP server will trust the value in 'ciaddr', and use it when
+ * replying to the client.
+ */
+       /* Fill in: op, htype, hlen, cookie, chaddr fields,
+        * random xid field (we override it below),
+        * client-id option (unless -C), message type option:
+        */
        init_packet(&packet, DHCPREQUEST);
+
        packet.xid = xid;
        packet.ciaddr = ciaddr;
+
+       /* Add options: maxsize,
+        * optionally: hostname, fqdn, vendorclass,
+        * "param req" option according to -O, and options specified with -x
+        */
        add_client_options(&packet);
 
        bb_info_msg("Sending renew...");
@@ -489,9 +546,20 @@ static int send_decline(uint32_t xid, uint32_t server, uint32_t requested)
 {
        struct dhcp_packet packet;
 
+       /* Fill in: op, htype, hlen, cookie, chaddr, random xid fields,
+        * client-id option (unless -C), message type option:
+        */
        init_packet(&packet, DHCPDECLINE);
+
+       /* RFC 2131 says DHCPDECLINE's xid is randomly selected by client,
+        * but in case the server is buggy and wants DHCPDECLINE's xid
+        * to match the xid which started entire handshake,
+        * we use the same xid we used in initial DHCPDISCOVER:
+        */
        packet.xid = xid;
+       /* DHCPDECLINE uses "requested ip", not ciaddr, to store offered IP */
        udhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested);
+
        udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server);
 
        bb_info_msg("Sending decline...");
@@ -504,8 +572,12 @@ static int send_release(uint32_t server, uint32_t ciaddr)
 {
        struct dhcp_packet packet;
 
+       /* Fill in: op, htype, hlen, cookie, chaddr, random xid fields,
+        * client-id option (unless -C), message type option:
+        */
        init_packet(&packet, DHCPRELEASE);
-       packet.xid = random_xid();
+
+       /* DHCPRELEASE uses ciaddr, not "requested ip", to store IP being released */
        packet.ciaddr = ciaddr;
 
        udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server);
@@ -1254,7 +1326,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
 
                /* Ignore packets that aren't for us */
                if (packet.hlen != 6
-                || memcmp(packet.chaddr, client_config.client_mac, 6)
+                || memcmp(packet.chaddr, client_config.client_mac, 6) != 0
                ) {
 //FIXME: need to also check that last 10 bytes are zero
                        log1("chaddr does not match, ignoring packet"); // log2?
@@ -1280,7 +1352,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
                                }
                                /* it IS unaligned sometimes, don't "optimize" */
                                move_from_unaligned32(server_addr, temp);
-                               xid = packet.xid;
+                               /*xid = packet.xid; - already is */
                                requested_ip = packet.yiaddr;
 
                                /* enter requesting state */