[ECOS] Redboot DHCP and gateway support

Grant Edwards grante@visi.com
Mon Jul 8 11:47:00 GMT 2002


> I am also interested in DHCP/Gateway support for Redboot.
> I would like to get your patch or have support added to
> the Redboot source if it is not already there.

I've attached patches containing my DHCP and default route
changes.

Disclaimer:

These patches are against a rather old version of Redboot
(circa December 2000).  Though I've tried to cull out
extraneous diffs, I've made a lot of changes unrelated to
DHCP/gateway, and these patches may contain unrelated changes
that may or may not have already been incorporated into the CVS
source tree (changes that you may or may not want).

IOW, don't apply the patches blindly.

-- 
Grant Edwards
grante@visi.com
-------------- next part --------------
Index: bootp.h
===================================================================
RCS file: /cvs/ecos/ecos/packages/redboot/current/include/net/bootp.h,v
retrieving revision 1.1
diff -U8 -r1.1 bootp.h
--- bootp.h	25 Aug 2000 17:33:46 -0000	1.1
+++ bootp.h	8 Jul 2002 18:36:22 -0000
@@ -74,17 +74,17 @@
  * This file specifies the "implementation-independent" BOOTP protocol
  * information which is common to both client and server.
  *
  */
 
 #define BP_CHADDR_LEN	 16
 #define BP_SNAME_LEN	 64
 #define BP_FILE_LEN	128
-#define BP_VEND_LEN	 64
+#define BP_VEND_LEN	312
 #define BP_MINPKTSZ	300	/* to check sizeof(struct bootp) */
 
 typedef struct bootp {
     unsigned char    bp_op;			/* packet opcode type */
     unsigned char    bp_htype;			/* hardware addr type */
     unsigned char    bp_hlen;			/* hardware addr length */
     unsigned char    bp_hops;			/* gateway hops */
     unsigned int     bp_xid;			/* transaction ID */
-------------- next part --------------
Index: net.h
===================================================================
RCS file: /cvs/ecos/ecos/packages/redboot/current/include/net/net.h,v
retrieving revision 1.3
diff -U8 -r1.3 net.h
--- net.h	8 Dec 2000 03:30:08 -0000	1.3
+++ net.h	8 Jul 2002 18:39:49 -0000
@@ -48,17 +48,19 @@
 
 #include <pkgconf/redboot.h>
 #include <cyg/hal/hal_arch.h>
 #include <cyg/hal/basetype.h>
 
 extern bool net_debug;
 
 extern unsigned long do_ms_tick(void);
-#define MS_TICKS() do_ms_tick()
+extern unsigned long get_ms_ticks(void);
+#define MS_TICKS() get_ms_ticks()
+#define MS_TICKS_DELAY() do_ms_tick()
 
 /* #define NET_SUPPORT_RARP  1 */
 #define NET_SUPPORT_ICMP 1
 #define NET_SUPPORT_UDP  1
 #define NET_SUPPORT_TCP  1
 
 #if (CYG_BYTEORDER == CYG_LSBFIRST)
 #ifndef __LITTLE_ENDIAN__
@@ -74,16 +76,17 @@
 #define	htonl(x)	ntohl(x)
 #define	htons(x)	ntohs(x)
 
 /*
  * Minimum ethernet packet length.
  */
 #define ETH_MIN_PKTLEN  60
 #define ETH_MAX_PKTLEN  1514
+#define ETH_HDR_SIZE    14
 
 typedef unsigned char enet_addr_t[6];
 typedef unsigned char ip_addr_t[4];
 
 typedef unsigned char  octet;
 typedef unsigned short word;
 typedef unsigned int   dword;
 
@@ -160,17 +163,17 @@
 #define	RARP_REPLY	4
     enet_addr_t	sender_enet;
     ip_addr_t	sender_ip;
     enet_addr_t	target_enet;
     ip_addr_t	target_ip;
 } arp_header_t;
 
 
-#define ARP_PKT_SIZE  (sizeof(arp_header_t) + sizeof(eth_header_t))
+#define ARP_PKT_SIZE  (sizeof(arp_header_t) + ETH_HDR_SIZE)
 
 /*
  * Internet Protocol header.
  */
 typedef struct {
 #ifdef __LITTLE_ENDIAN__
     octet       hdr_len:4,
                 version:4;
@@ -188,17 +191,17 @@
 #define IP_PROTO_TCP   6
 #define IP_PROTO_UDP  17
     word        checksum;
     ip_addr_t   source;
     ip_addr_t   destination;
 } ip_header_t;
 
 
-#define IP_PKT_SIZE (60 + sizeof(eth_header_t))
+#define IP_PKT_SIZE (60 + ETH_HDR_SIZE)
 
 
 /*
  * A IP<->ethernet address mapping.
  */
 typedef struct {
     ip_addr_t    ip_addr;
     enet_addr_t  enet_addr;
@@ -255,19 +258,17 @@
     word	checksum;
     word	ident;
     word	seqnum;
 } icmp_header_t;
 
 
 typedef struct _pktbuf {
     struct _pktbuf *next;
-#if 0
     eth_header_t   *eth_hdr;		/* pointer to ethernet header */
-#endif
     union {
 	ip_header_t *__iphdr;		/* pointer to IP header */
 	arp_header_t *__arphdr;		/* pointer to ARP header */
     } u1;
 #define ip_hdr u1.__iphdr
 #define arp_hdr u1.__arphdr
     union {
 	udp_header_t *__udphdr;		/* pointer to UDP header */
@@ -330,17 +331,18 @@
     char               pktbuf[ETH_MAX_PKTLEN];
 } tcp_socket_t;
 
 /*
  * Our address.
  */
 extern enet_addr_t __local_enet_addr;
 extern ip_addr_t   __local_ip_addr;
-
+extern ip_addr_t   __local_ip_gate;
+extern ip_addr_t   __local_ip_mask;
 
 /*
  * Set a timer. Caller is responsible for providing the timer_t struct.
  */
 extern void __timer_set(timer_t *t, unsigned long delay,
 			tmr_handler_t handler, void *user_data);
 
 /*
@@ -393,16 +395,21 @@
  */
 extern void __enet_poll(void);
 
 /*
  * Send an ethernet packet.
  */
 extern void __enet_send(pktbuf_t *pkt, enet_addr_t *dest, int eth_type);
 
+/*
+ * return true if addr is on local subnet
+ */
+extern int __ip_addr_local(ip_addr_t *addr);
+
 
 /*
  * Handle incoming ARP packets.
  */
 extern void __arp_handler(pktbuf_t *pkt);
 
 /* 
  * Find the ethernet address of the machine with the given
@@ -437,19 +444,19 @@
 extern void __ip_handler(pktbuf_t *pkt, enet_addr_t *src_enet_addr);
 
 /*
  * Send an IP packet.
  *
  * The IP data field should contain pkt->pkt_bytes of data.
  * pkt->[udp|tcp|icmp]_hdr points to the IP data field. Any
  * IP options are assumed to be already in place in the IP
- * options field.
+ * options field.  Returns 0 for success.
  */
-extern void __ip_send(pktbuf_t *pkt, int protocol, ip_route_t *dest);
+extern int __ip_send(pktbuf_t *pkt, int protocol, ip_route_t *dest);
 
 
 /*
  * Handle incoming ICMP packets.
  */
 extern void __icmp_handler(pktbuf_t *pkt, ip_route_t *r);
 
 /*
@@ -468,17 +475,17 @@
 /*
  * Remove the handler for the given socket.
  */
 extern void __udp_remove_listener(word port);
 
 /*
  * Send a UDP packet.
  */
-extern void __udp_send(char *buf, int len, ip_route_t *dest_ip,
+extern int __udp_send(char *buf, int len, ip_route_t *dest_ip,
 		       word dest_port, word src_port);
 
 // Send a UDP packet
 extern int __udp_sendto(char *buf, int len, 
                         struct sockaddr_in *server, struct sockaddr_in *local);
 
 // Receive a UDP packet
 extern int __udp_recvfrom(char *buf, int len, 
-------------- next part --------------
Index: bootp.c
===================================================================
RCS file: /cvs/ecos/ecos/packages/redboot/current/src/net/bootp.c,v
retrieving revision 1.1
diff -U9 -r1.1 bootp.c
--- bootp.c	25 Aug 2000 17:33:47 -0000	1.1
+++ bootp.c	8 Jul 2002 18:17:17 -0000
@@ -49,95 +49,147 @@
 extern int net_debug;
 
 #define SHOULD_BE_RANDOM  0x12345555
 
 /* How many milliseconds to wait before retrying the request */
 #define RETRY_TIME  2000
 
 static bootp_header_t *bp_info;
 
+static const unsigned char dhcpCookie[] = {99,130,83,99};
+static const unsigned char dhcpEndOption[] = {255};
+static const unsigned char dhcpRequestOption[] = {52,1,3};
+
+void dump_buf(void *p, CYG_ADDRWORD s);
+
 static void
 bootp_handler(udp_socket_t *skt, char *buf, int len,
-	      ip_route_t *src_route, word src_port)
+              ip_route_t *src_route, word src_port)
 {
     bootp_header_t *b;
-
+    unsigned char *p,*end;
+    int optlen;
+    
     b = (bootp_header_t *)buf;
+    
     if (bp_info) {
+        memset(bp_info,0,sizeof *bp_info);
+        if (len > sizeof *bp_info)
+          len = sizeof *bp_info;
         memcpy(bp_info, b, len);
     }
-
-    if (b->bp_op == BOOTREPLY && 
-	!memcmp(b->bp_chaddr, __local_enet_addr, 6)) {
-	memcpy(__local_ip_addr, &b->bp_yiaddr, 4);
+    
+    if (b->bp_op != BOOTREPLY)
+      return;
+    
+    if (memcmp(b->bp_chaddr, __local_enet_addr, 6))
+      return;
+        
+    memcpy(__local_ip_addr, &b->bp_yiaddr, 4);
+    memcpy(__local_ip_gate, &b->bp_giaddr, 4);
+    
+    if (memcmp(b->bp_vend,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 == 255)
+          break;
+        if (tag == 0)
+          optlen = 1;
+        else {
+            optlen = p[1];
+            p += 2;
+            switch (tag) {
+             case 1:  // subnet mask
+                memcpy(__local_ip_mask,p,4); 
+                break;
+             case 3:  // router
+                memcpy(__local_ip_gate,p,4); 
+                break;
+             default:
+                break;
+            }
+        }
+        p += optlen;
     }
 }
 
+#define AddOption(p,d) do {memcpy(p,d,sizeof d); p += sizeof d;} while (0)
 
 /*
  * Find our IP address and copy to __local_ip_addr.
  * Return zero if successful, -1 if not.
  */
 int
 __bootp_find_local_ip(bootp_header_t *info)
 {
     udp_socket_t udp_skt;
     bootp_header_t b;
     ip_route_t     r;
     int            retry;
     unsigned long  start;
+    unsigned char *p;
+    int txSize;
 
     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;
-
+        
+    p = b.bp_vend;
+    
+    AddOption(p,dhcpCookie);
+    AddOption(p,dhcpRequestOption);
+    AddOption(p,dhcpEndOption);
+          
+    txSize = p - (unsigned char*)&b;
+  
     __local_ip_addr[0] = 0;
     __local_ip_addr[1] = 0;
     __local_ip_addr[2] = 0;
     __local_ip_addr[3] = 0;
 
     memcpy(b.bp_chaddr, __local_enet_addr, 6);
 
     /* 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;
-    r.enet_addr[1] = 255;
-    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 */
     __udp_install_listener(&udp_skt, IPPORT_BOOTPC, bootp_handler);
 
     retry = 3;
     while (retry-- > 0) {
-	start = MS_TICKS();
-
-	__udp_send((char *)&b, sizeof(b), &r, IPPORT_BOOTPS, IPPORT_BOOTPC);
-
-	do {
-	    __enet_poll();
-	    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;
-	    }
-	} while ((MS_TICKS() - start) < RETRY_TIME);
+        start = MS_TICKS();
+        
+        __udp_send((char *)&b, txSize, &r, IPPORT_BOOTPS, IPPORT_BOOTPC);
+        
+        do {
+            __enet_poll();
+            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;
+            }
+        } while ((MS_TICKS_DELAY() - start) < RETRY_TIME);
     }
-
+    
     /* timed out */
     __udp_remove_listener(IPPORT_BOOTPC);
     net_debug = 0;
     return -1;
 }
 
 
-------------- next part --------------
Index: ip.c
===================================================================
RCS file: /cvs/ecos/ecos/packages/redboot/current/src/net/ip.c,v
retrieving revision 1.1
diff -U9 -r1.1 ip.c
--- ip.c	25 Aug 2000 17:33:47 -0000	1.1
+++ ip.c	8 Jul 2002 18:18:36 -0000
@@ -37,24 +37,38 @@
 // Purpose:      
 // Description:  
 //              
 // This code is part of RedBoot (tm).
 //
 //####DESCRIPTIONEND####
 //
 //==========================================================================
 
+#include <redboot.h>
 #include <net/net.h>
 
 ip_addr_t __local_ip_addr = { 0, 0, 0, 0 };
+ip_addr_t __local_ip_mask = { 0, 0, 0, 0 };
+ip_addr_t __local_ip_gate = { 0, 0, 0, 0 };
+
+extern int terseMode;
 
 static word ip_ident;
 
+int __ip_addr_local(ip_addr_t *addr)
+{
+  return !(
+           ((__local_ip_addr[0] ^ (*addr)[0]) & __local_ip_mask[0]) |
+           ((__local_ip_addr[1] ^ (*addr)[1]) & __local_ip_mask[1]) |
+           ((__local_ip_addr[2] ^ (*addr)[2]) & __local_ip_mask[2]) |
+           ((__local_ip_addr[3] ^ (*addr)[3]) & __local_ip_mask[3]));
+}
+
 
 /*
  * Match given IP address to our address.
  * Check for broadcast matches as well.
  */
 static int
 ip_addr_match(ip_addr_t addr)
 {
     if (addr[0] == 255 && addr[1] == 255 && addr[2] == 255 && addr[3] == 255)
@@ -133,24 +147,25 @@
 
 /*
  * Send an IP packet.
  *
  * The IP data field should contain pkt->pkt_bytes of data.
  * pkt->[udp|tcp|icmp]_hdr points to the IP data field. Any
  * IP options are assumed to be already in place in the IP
  * options field.
  */
-void
+int
 __ip_send(pktbuf_t *pkt, int protocol, ip_route_t *dest)
 {
     ip_header_t *ip = pkt->ip_hdr;
     int         hdr_bytes;
     unsigned short cksum;
+    ip_route_t  destrt;
     
     /*
      * Figure out header length. The use udp_hdr is
      * somewhat arbitrary, but works because it is
      * a union with other IP protocol headers.
      */
     hdr_bytes = (((char *)pkt->udp_hdr) - ((char *)ip));
 
     pkt->pkt_bytes += hdr_bytes;
@@ -165,13 +180,30 @@
     ip->ttl = 255;
     ip->ttl = 64;
     ip->protocol = protocol;
     ip->checksum = 0;
     memcpy(ip->source, __local_ip_addr, sizeof(ip_addr_t));
     memcpy(ip->destination, dest->ip_addr, sizeof(ip_addr_t));
     cksum = __sum((word *)ip, hdr_bytes, 0);
     ip->checksum = htons(cksum);
 
-    __enet_send(pkt, &dest->enet_addr, ETH_TYPE_IP);    
+    if ((dest->ip_addr[0] & dest->ip_addr[1] & dest->ip_addr[2]) == 255) {
+        memset(destrt.enet_addr,0xff,sizeof destrt.enet_addr);
+    } else if (__ip_addr_local((ip_addr_t *)&dest->ip_addr)) {
+        // local IP address -- look up Ethernet address in ARP cache
+        if (__arp_lookup(&dest->ip_addr, &destrt) < 0) {
+            if (!terseMode) printf("%s: Can't find address of server\n", __FUNCTION__);
+            return -1;
+        }
+	} else {
+		// non-local IP address -- look up Gateway's Ethernet address
+		if (__arp_lookup(&__local_ip_gate, &destrt) < 0) {
+			if (!terseMode) printf("%s: Can't find address of gateway\n", __FUNCTION__);
+			return -1;
+		}
+    }
+    
+    __enet_send(pkt, &destrt.enet_addr, ETH_TYPE_IP);
+    return 0;
 }
 
 
-------------- next part --------------
Index: udp.c
===================================================================
RCS file: /cvs/ecos/ecos/packages/redboot/current/src/net/udp.c,v
retrieving revision 1.2
diff -U9 -r1.2 udp.c
--- udp.c	31 Oct 2000 20:53:15 -0000	1.2
+++ udp.c	8 Jul 2002 18:19:33 -0000
@@ -47,19 +47,19 @@
 #include <net/net.h>
 
 #ifdef UDP_STATS
 static int udp_rx_total;
 static int udp_rx_handled;
 static int udp_rx_cksum;
 static int udp_rx_dropped;
 #endif
 
-#define MAX_UDP_DATA (ETH_MAX_PKTLEN - (sizeof(eth_header_t) + \
+#define MAX_UDP_DATA (ETH_MAX_PKTLEN - (ETH_HDR_SIZE + \
 					sizeof(ip_header_t)  + \
 					sizeof(udp_header_t)))
 
 /*
  * A major assumption is that only a very small number of sockets will
  * active, so a simple linear search of those sockets is acceptible.
  */
 static udp_socket_t *udp_list;
 
@@ -136,35 +136,35 @@
 	}
     }
     __pktbuf_free(pkt);
 }
 
 
 /*
  * Send a UDP packet.
  */
-void
+int
 __udp_send(char *buf, int len, ip_route_t *dest_ip,
 	   word dest_port, word src_port)
 {
     pktbuf_t *pkt;
     udp_header_t *udp;
     ip_header_t *ip;
     unsigned short cksum;
-
+    int ret;
 
     /* dumb */
     if (len > MAX_UDP_DATA)
-	return;
+	return -1;
 
     /* just drop it if can't get a buffer */
     if ((pkt = __pktbuf_alloc(ETH_MAX_PKTLEN)) == NULL)
-	return;
+	return -1;
 
     udp = pkt->udp_hdr;
     ip = pkt->ip_hdr;
 
     pkt->pkt_bytes = len + sizeof(udp_header_t);
 
     udp->src_port = htons(src_port);
     udp->dest_port = htons(dest_port);
     udp->length = htons(pkt->pkt_bytes);
@@ -175,36 +175,31 @@
     /* fill in some pseudo-header fields */
     memcpy(ip->source, __local_ip_addr, sizeof(ip_addr_t));
     memcpy(ip->destination, dest_ip->ip_addr, sizeof(ip_addr_t));
     ip->protocol = IP_PROTO_UDP;
     ip->length = udp->length;
 
     cksum = __sum((word *)udp, pkt->pkt_bytes, __pseudo_sum(ip));
     udp->checksum = htons(cksum);
 
-    __ip_send(pkt, IP_PROTO_UDP, dest_ip);
-
+    ret = __ip_send(pkt, IP_PROTO_UDP, dest_ip);
     __pktbuf_free(pkt);
+  
+    return ret;
 }
 
 int
 __udp_sendto(char *data, int len, struct sockaddr_in *server, 
              struct sockaddr_in *local)
 {
     ip_route_t rt;
-
-    if (__arp_lookup((ip_addr_t *)&server->sin_addr, &rt) < 0) {
-        printf("%s: Can't find address of server\n", __FUNCTION__);
-        return -1;
-    } else {
-	__udp_send(data, len, &rt, ntohs(server->sin_port), ntohs(local->sin_port));
-        return 0;
-    }
+    memcpy(rt.ip_addr,&(server->sin_addr),sizeof rt.ip_addr);
+    return __udp_send(data, len, &rt, ntohs(server->sin_port), ntohs(local->sin_port));
 }
 
 static char               *recvfrom_buf;
 static int                 recvfrom_len;
 static struct sockaddr_in *recvfrom_server;
 
 static void
 __udp_recvfrom_handler(udp_socket_t *skt, char *buf, int len,
                        ip_route_t *src_route, word src_port)

-------------- next part --------------
-- 
Before posting, please read the FAQ: http://sources.redhat.com/fom/ecos
and search the list archive: http://sources.redhat.com/ml/ecos-discuss


More information about the Ecos-discuss mailing list