[dhcp] Append new DHCP options versus prepend
authorShao Miller <shao.miller@yrdsb.edu.on.ca>
Thu, 22 Oct 2009 20:51:43 +0000 (16:51 -0400)
committerMarty Connor <mdc@etherboot.org>
Thu, 14 Jan 2010 16:14:24 +0000 (11:14 -0500)
Change the behaviour for adding DHCP options into a DHCP packet so
that we now append options, rather than insert them in front of
whatever options might already be present.

Apparently, the DHCP relay logic on a Nortel 470-48T layer 2 switch
cares about the order of DHCP options.  If we build a DHCP packet
pre-populated with some options, their order will now be preserved,
except for encapsulated options.

Signed-off-by: Marty Connor <mdc@etherboot.org>
src/net/dhcpopts.c

index c1940f1..6482c62 100644 (file)
@@ -103,7 +103,7 @@ static unsigned int dhcp_option_len ( struct dhcp_option *option ) {
  * DHCP option block.  Encapsulated options may be searched for by
  * using DHCP_ENCAP_OPT() to construct the tag value.
  *
- * If the option is encapsulated, and @c encapsulator is non-NULL, it
+ * If the option is encapsulated, and @c encap_offset is non-NULL, it
  * will be filled in with the offset of the encapsulating option.
  *
  * This routine is designed to be paranoid.  It does not assume that
@@ -136,8 +136,15 @@ static int find_dhcp_option_with_encap ( struct dhcp_options *options,
                if ( remaining < 0 )
                        break;
                /* Check for explicit end marker */
-               if ( option->tag == DHCP_END )
-                       break;
+               if ( option->tag == DHCP_END ) {
+                       if ( tag == DHCP_END )
+                               /* Special case where the caller is interested
+                                * in whether we have this marker or not.
+                                */
+                               return offset;
+                       else
+                               break;
+               }
                /* Check for matching tag */
                if ( option->tag == tag ) {
                        DBGC ( options, "DHCPOPT %p found %s (length %d)\n",
@@ -256,7 +263,7 @@ static int set_dhcp_option ( struct dhcp_options *options, unsigned int tag,
        static const uint8_t empty_encapsulator[] = { DHCP_END };
        int offset;
        int encap_offset = -1;
-       int creation_offset = 0;
+       int creation_offset;
        struct dhcp_option *option;
        unsigned int encap_tag = DHCP_ENCAPSULATOR ( tag );
        size_t old_len = 0;
@@ -267,6 +274,10 @@ static int set_dhcp_option ( struct dhcp_options *options, unsigned int tag,
        if ( tag == DHCP_PAD )
                return -ENOTTY;
 
+       creation_offset = find_dhcp_option_with_encap ( options, DHCP_END,
+                                                       NULL );
+       if ( creation_offset < 0 )
+               creation_offset = options->len;
        /* Find old instance of this option, if any */
        offset = find_dhcp_option_with_encap ( options, tag, &encap_offset );
        if ( offset >= 0 ) {