This is the mail archive of the ecos-patches@sources.redhat.com mailing list for the eCos project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

RedBoot - complete DHCP


Fix for BUG #1000053

-- 
Gary Thomas <gary@mlbassoc.com>
MLB Associates
Index: redboot/current/ChangeLog
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/redboot/current/ChangeLog,v
retrieving revision 1.130
diff -u -5 -p -r1.130 ChangeLog
--- redboot/current/ChangeLog	20 Sep 2003 13:28:30 -0000	1.130
+++ redboot/current/ChangeLog	20 Sep 2003 14:25:47 -0000
@@ -1,5 +1,12 @@
+2003-09-20  Gary Thomas  <gary@mlbassoc.com>
+
+	* src/net/bootp.c: Rework to use full DHCP protocol.  Previously,
+	once an offer came in, RedBoot was happy, without actually making
+	the address reservation and waiting for the final acknowledgement.
+	Also, added CDL to enable/disable DHCP.  BUG #1000053
+
 2003-09-20  Chris Garry  <cgarry@sweeneydesign.co.uk>
 	
 	* src/main.c: Modified the way multiple "RAM" segments are reported.
 
 	* src/fconfig.c: Variables 'stat' and '*err_addr' in function
Index: redboot/current/cdl/redboot.cdl
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/redboot/current/cdl/redboot.cdl,v
retrieving revision 1.52
diff -u -5 -p -r1.52 redboot.cdl
--- redboot/current/cdl/redboot.cdl	19 Sep 2003 17:11:33 -0000	1.52
+++ redboot/current/cdl/redboot.cdl	20 Sep 2003 14:32:30 -0000
@@ -313,14 +313,24 @@ cdl_package CYGPKG_REDBOOT {
                          timeout. This option is overriden by the
                          configuration stored in flash."
                 }
             }
     
+            cdl_component CYGSEM_REDBOOT_NETWORKING_DHCP {
+                display          "Use DHCP to get IP information"
+                flavor           bool
+                default_value    1
+                description      "
+                    Use DHCP protocol to obtain pertinent IP addresses, such as
+                    the client, server, gateway, etc."
+            }
+    
             cdl_component CYGSEM_REDBOOT_NETWORKING_USE_GATEWAY {
                 display          "Use a gateway for non-local IP traffic"
                 flavor           bool
                 default_value    1
+                requires         CYGSEM_REDBOOT_NETWORKING_DHCP
                 description      "
                   Enabling this option will allow the RedBoot networking
                 stack to use a \[single\] gateway to reach a non-local
                 IP address.  If disabled, RedBoot will only be able to
                 reach nodes on the same subnet."
Index: redboot/current/src/net/bootp.c
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/redboot/current/src/net/bootp.c,v
retrieving revision 1.13
diff -u -5 -p -r1.13 bootp.c
--- redboot/current/src/net/bootp.c	14 Sep 2003 13:41:58 -0000	1.13
+++ redboot/current/src/net/bootp.c	20 Sep 2003 14:32:28 -0000
@@ -55,35 +55,43 @@
 
 #include <redboot.h>
 #include <net/net.h>
 #include <net/bootp.h>
 
-extern int net_debug;
-
 #define SHOULD_BE_RANDOM  0x12345555
 
 /* How many milliseconds to wait before retrying the request */
 #define RETRY_TIME   500
 #define MAX_RETRIES   30
 
 static bootp_header_t *bp_info;
   
-#ifdef CYGSEM_REDBOOT_NETWORKING_USE_GATEWAY
+#ifdef CYGSEM_REDBOOT_NETWORKING_DHCP
 static const unsigned char dhcpCookie[] = {99,130,83,99};
-static const unsigned char dhcpEndOption[] = {255};
-static const unsigned char dhcpDiscoverOption[] = {53,1,1};
+static const unsigned char dhcpEnd[] = {255};
+static const unsigned char dhcpDiscover[] = {53,1,1};
+static const unsigned char dhcpOffer[] = {53,1,2};
+static const unsigned char dhcpRequest[] = {53,1,3};
+static const unsigned char dhcpRequestIP[] = {50,4};
+static const unsigned char dhcpAck[] = {53,1,5};
 static const unsigned char dhcpParamRequestList[] = {55,3,1,3,6};
+static enum {
+    DHCP_NONE = 0,
+    DHCP_DISCOVER,
+    DHCP_OFFER,
+    DHCP_REQUEST,
+    DHCP_ACK
+} dhcpState;
 #endif
 
 static void
 bootp_handler(udp_socket_t *skt, char *buf, int len,
 	      ip_route_t *src_route, word src_port)
 {
     bootp_header_t *b;
-#ifdef CYGSEM_REDBOOT_NETWORKING_USE_GATEWAY
-    unsigned char *p,*end;
-    int optlen;
+#ifdef CYGSEM_REDBOOT_NETWORKING_DHCP
+    unsigned char *p, *expected = 0;
 #endif
 
     b = (bootp_header_t *)buf;
     if (bp_info) {
         memset(bp_info,0,sizeof *bp_info);
@@ -98,44 +106,49 @@ bootp_handler(udp_socket_t *skt, char *b
     
     // Must be sent to me, as well!
     if (memcmp(b->bp_chaddr, __local_enet_addr, 6))
       return;
         
-    memcpy(__local_ip_addr, &b->bp_yiaddr, 4);
-#ifdef CYGSEM_REDBOOT_NETWORKING_USE_GATEWAY
-    memcpy(__local_ip_gate, &b->bp_giaddr, 4);
-    
-    if (memcmp(b->bp_vend, dhcpCookie, sizeof(dhcpCookie)))
+#ifdef CYGSEM_REDBOOT_NETWORKING_DHCP
+    p = b->bp_vend;
+    if (memcmp(p, dhcpCookie, sizeof(dhcpCookie)))
       return;
-                
-    optlen = len - (b->bp_vend - ((unsigned char*)b));
-    
-    p = b->bp_vend+4;
-    end = ((unsigned char*)b) + len;
-    
-    while (p < end) {
-        unsigned char tag = *p;
-        if (tag == TAG_END)
-          break;
-        if (tag == TAG_PAD)
-          optlen = 1;
-        else {
-            optlen = p[1];
-            p += 2;
-            switch (tag) {
-             case TAG_SUBNET_MASK:  // subnet mask
-                memcpy(__local_ip_mask,p,4); 
-                break;
-             case TAG_GATEWAY:  // router
-                memcpy(__local_ip_gate,p,4); 
-                break;
-             default:
-                break;
-            }
+    p += 4;
+                    
+    switch (dhcpState) {
+    case DHCP_DISCOVER:
+        // The discover message has been sent, only accept an offer reply
+        if (memcmp(p, dhcpOffer, sizeof(dhcpOffer)) == 0) {
+            dhcpState = DHCP_OFFER;
+            return;
+        } else {
+            expected = (unsigned char *)dhcpOffer;
+        }
+        break;
+    case DHCP_REQUEST:
+        // The request message has been sent, only accept an ack reply
+        if (memcmp(p, dhcpAck, sizeof(dhcpAck)) == 0) {
+            dhcpState = DHCP_ACK;
+            return;
+        } else {
+            expected = (unsigned char *)dhcpAck;
         }
-        p += optlen;
+        break;
+    case DHCP_NONE:
+    case DHCP_OFFER:
+    case DHCP_ACK:
+        diag_printf("Invalid DHCP reply state: %d\n", dhcpState);
+        dhcpState = DHCP_NONE;  // Reset state machine
+        return;
     }
+    diag_printf("DHCP reply: %d/%d/%d, not %d/%d/%d\n",
+                p[0], p[1], p[2], expected[0], expected[1], expected[2]);
+    dhcpState = DHCP_NONE;  // Reset state machine
+    return;
+#else
+    // Simple BOOTP - this is all there is!
+    memcpy(__local_ip_addr, &b->bp_yiaddr, 4);
 #endif
 }
 
 #define AddOption(p,d) do {memcpy(p,d,sizeof d); p += sizeof d;} while (0)
 
@@ -150,46 +163,27 @@ __bootp_find_local_ip(bootp_header_t *in
     bootp_header_t b;
     ip_route_t     r;
     int            retry;
     unsigned long  start;
     ip_addr_t saved_ip_addr;
-#ifdef CYGSEM_REDBOOT_NETWORKING_USE_GATEWAY
+#ifdef CYGSEM_REDBOOT_NETWORKING_DHCP
     unsigned char *p;
 #endif
     int txSize;
     bool abort = false;
+    static int xid = SHOULD_BE_RANDOM;
 
-    bp_info = info;
-
-    memset(&b, 0, sizeof(b));
-
-    b.bp_op = BOOTREQUEST;
-    b.bp_htype = HTYPE_ETHERNET;
-    b.bp_hlen = 6;
-    b.bp_xid = SHOULD_BE_RANDOM;
-         
-#ifdef CYGSEM_REDBOOT_NETWORKING_USE_GATEWAY
-    p = b.bp_vend;
-     
-    AddOption(p,dhcpCookie);
-    AddOption(p,dhcpDiscoverOption);
-    AddOption(p,dhcpParamRequestList);
-    AddOption(p,dhcpEndOption);
-
-    // Some servers insist on a minimum amount of "vendor" data
-    if (p < &b.bp_vend[BP_MIN_VEND_SIZE]) p = &b.bp_vend[BP_MIN_VEND_SIZE];
-    txSize = p - (unsigned char*)&b;
-#else
-    txSize = sizeof(b);
+#ifdef CYGSEM_REDBOOT_NETWORKING_DHCP
+    dhcpState = DHCP_NONE;
 #endif
 
-    memcpy( saved_ip_addr, __local_ip_addr, sizeof(__local_ip_addr) );
-    memset( __local_ip_addr, 0, sizeof(__local_ip_addr) );
-
-    memcpy(b.bp_chaddr, __local_enet_addr, 6);
+    // Where we want the results saved
+    bp_info = info;
+    // Preserve any IP address we currently have, just in case
+    memcpy(saved_ip_addr, __local_ip_addr, sizeof(__local_ip_addr));
 
-    /* fill out route for a broadcast */
+    // fill out route for a broadcast
     r.ip_addr[0] = 255;
     r.ip_addr[1] = 255;
     r.ip_addr[2] = 255;
     r.ip_addr[3] = 255;
     r.enet_addr[0] = 255;
@@ -197,27 +191,114 @@ __bootp_find_local_ip(bootp_header_t *in
     r.enet_addr[2] = 255;
     r.enet_addr[3] = 255;
     r.enet_addr[4] = 255;
     r.enet_addr[5] = 255;
 
-    /* setup a socket listener for bootp replies */
+    // setup a socket listener for bootp replies
     __udp_install_listener(&udp_skt, IPPORT_BOOTPC, bootp_handler);
 
     retry = MAX_RETRIES;  
     while (!abort && (retry-- > 0)) {
 	start = MS_TICKS();
 
+        // Build up the BOOTP/DHCP request
+        memset(&b, 0, sizeof(b));
+        b.bp_op = BOOTREQUEST;
+        b.bp_htype = HTYPE_ETHERNET;
+        b.bp_hlen = 6;
+        b.bp_xid = xid++;
+        memcpy(b.bp_chaddr, __local_enet_addr, 6);
+        memset(__local_ip_addr, 0, sizeof(__local_ip_addr));
+         
+#ifdef CYGSEM_REDBOOT_NETWORKING_DHCP
+        p = b.bp_vend;
+        switch (dhcpState) {
+        case DHCP_NONE:
+            AddOption(p,dhcpCookie);
+            AddOption(p,dhcpDiscover);
+            AddOption(p,dhcpParamRequestList);
+            AddOption(p,dhcpEnd);
+            dhcpState = DHCP_DISCOVER;
+            break;
+        case DHCP_OFFER:
+            retry = MAX_RETRIES;
+            AddOption(p,dhcpCookie);
+            AddOption(p,dhcpRequest);
+            AddOption(p,dhcpRequestIP);
+            memcpy(p, &bp_info->bp_yiaddr, 4);  p += 4;  // Ask for the address just given
+            AddOption(p,dhcpParamRequestList);
+            AddOption(p,dhcpEnd);
+            dhcpState = DHCP_REQUEST;
+            memset(&b.bp_yiaddr, 0xFF, 4);
+            memset(&b.bp_siaddr, 0xFF, 4);
+            break;
+        case DHCP_DISCOVER:
+        case DHCP_REQUEST:
+        case DHCP_ACK:
+            // These states should never occur here!
+            diag_printf("Invalid DHCP state: %d\n", dhcpState);
+            abort = true;
+        }
+        if (abort) break;  // From while loop
+     
+        // Some servers insist on a minimum amount of "vendor" data
+        if (p < &b.bp_vend[BP_MIN_VEND_SIZE]) p = &b.bp_vend[BP_MIN_VEND_SIZE];
+        txSize = p - (unsigned char*)&b;
+#else
+        txSize = sizeof(b);
+#endif
+
 	__udp_send((char *)&b, txSize, &r, IPPORT_BOOTPS, IPPORT_BOOTPC);
 
 	do {
 	    __enet_poll();
+#ifdef CYGSEM_REDBOOT_NETWORKING_DHCP
+            if (dhcpState == DHCP_ACK) {
+                unsigned char *end;
+                int optlen;
+                // Address information has now arrived!
+                memcpy(__local_ip_addr, &bp_info->bp_yiaddr, 4);
+#ifdef CYGSEM_REDBOOT_NETWORKING_USE_GATEWAY
+                memcpy(__local_ip_gate, &bp_info->bp_giaddr, 4);
+#endif
+                p = bp_info->bp_vend+4;
+                end = (unsigned char *)bp_info+sizeof(*bp_info);
+                while (p < end) {
+                    unsigned char tag = *p;
+                    if (tag == TAG_END)
+                        break;
+                    if (tag == TAG_PAD)
+                        optlen = 1;
+                    else {
+                        optlen = p[1];
+                        p += 2;
+                        switch (tag) {
+                        case TAG_SUBNET_MASK:  // subnet mask
+                            memcpy(__local_ip_mask,p,4); 
+                            break;
+#ifdef CYGSEM_REDBOOT_NETWORKING_USE_GATEWAY
+                        case TAG_GATEWAY:  // router
+                            memcpy(__local_ip_gate,p,4); 
+                            break;
+#endif
+                        default:
+                            break;
+                        }
+                    }
+                    p += optlen;
+                }
+                return 0;
+            }
+#else
+            // All done, if address response has arrived
 	    if (__local_ip_addr[0] || __local_ip_addr[1] ||
 		__local_ip_addr[2] || __local_ip_addr[3]) {
 		/* success */
 		__udp_remove_listener(IPPORT_BOOTPC);
 		return 0;
 	    }
+#endif
             if (_rb_break(1)) {
                 // The user typed ^C on the console
                 abort = true;
                 break;
             }
@@ -228,13 +309,13 @@ __bootp_find_local_ip(bootp_header_t *in
         if (retry == (MAX_RETRIES-1)) {
             diag_printf("... waiting for BOOTP information\n");
         }
     }
 
-    /* timed out */
+    // timed out
     __udp_remove_listener(IPPORT_BOOTPC);
-    net_debug = 0;
-    memcpy( __local_ip_addr, saved_ip_addr, sizeof(__local_ip_addr));
+    // Restore any previous IP address
+    memcpy(__local_ip_addr, saved_ip_addr, sizeof(__local_ip_addr));
     return -1;
 }
 
 

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]