changeset 231:4ebdd3788c30

Merge gateway support from Grant Edwards
author gthomas
date Tue, 09 Jul 2002 20:23:47 +0000
parents 20314171555b
children 4316e167c83b
files packages/redboot/current/ChangeLog packages/redboot/current/cdl/redboot.cdl packages/redboot/current/include/net/bootp.h packages/redboot/current/include/net/net.h packages/redboot/current/src/net/arp.c packages/redboot/current/src/net/bootp.c packages/redboot/current/src/net/ip.c packages/redboot/current/src/net/net_io.c packages/redboot/current/src/net/udp.c
diffstat 9 files changed, 227 insertions(+), 36 deletions(-) [+]
line wrap: on
line diff
--- a/packages/redboot/current/ChangeLog
+++ b/packages/redboot/current/ChangeLog
@@ -1,3 +1,16 @@
+2002-07-09  Gary Thomas  <gary@chez-thomas.org>
+2002-07-09  Grant Edwards <grante@visi.com>
+
+	* src/net/udp.c: 
+	* src/net/net_io.c: 
+	* src/net/ip.c: 
+	* src/net/bootp.c: 
+	* src/net/arp.c: 
+	* include/net/net.h: 
+	* include/net/bootp.h: 
+	* cdl/redboot.cdl: Add basic support for non-local networking
+	using a single gateway.  Based on contribution from Grant Edwards.
+
 2002-07-01  Gary Thomas  <gary@chez-thomas.org>
 
 	* src/net/tftp_client.c: 
--- a/packages/redboot/current/cdl/redboot.cdl
+++ b/packages/redboot/current/cdl/redboot.cdl
@@ -218,6 +218,41 @@ cdl_package CYGPKG_REDBOOT {
             }
         }
 
+        cdl_component CYGSEM_REDBOOT_NETWORKING_USE_GATEWAY {
+            display          "Use a gateway for non-local IP traffic"
+            flavor           bool
+            default_value    1
+            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."
+
+            cdl_component CYGDAT_REDBOOT_DEFAULT_GATEWAY_IP_ADDR {
+                display          "Default gateway IP address"
+                flavor           booldata
+                default_value    CYGSEM_REDBOOT_FLASH_CONFIG ? 0 : \
+                                    { "0, 0, 0, 0" }
+                description      "
+                    This IP address is the default used by RedBoot if a BOOTP/DHCP
+                    server does not respond. The numbers should be separated by
+                    *commas*, and not dots. If an IP address is configured into
+                    the Flash configuration, that will be used in preference."
+            }
+
+            cdl_component CYGDAT_REDBOOT_DEFAULT_IP_ADDR_MASK {
+                display          "Default IP address mask"
+                flavor           booldata
+                default_value    CYGSEM_REDBOOT_FLASH_CONFIG ? 0 : \
+                                    { "255, 255, 255, 0" }
+                description      "
+                    This IP address mask is the default used by RedBoot if a BOOTP/DHCP
+                    server does not respond. The numbers should be separated by
+                    *commas*, and not dots. If an IP address is configured into
+                    the Flash configuration, that will be used in preference."
+            }
+        }
+
         cdl_option CYGNUM_REDBOOT_NETWORKING_TCP_PORT {
             display          "TCP port to listen for incoming connections"
             flavor           data
--- a/packages/redboot/current/include/net/bootp.h
+++ b/packages/redboot/current/include/net/bootp.h
@@ -9,6 +9,7 @@
 // -------------------------------------------
 // This file is part of eCos, the Embedded Configurable Operating System.
 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2002 Gary Thomas
 //
 // eCos is free software; you can redistribute it and/or modify it under
 // the terms of the GNU General Public License as published by the Free
@@ -88,7 +89,7 @@ SOFTWARE.
 #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 {
--- a/packages/redboot/current/include/net/net.h
+++ b/packages/redboot/current/include/net/net.h
@@ -9,6 +9,7 @@
 // -------------------------------------------
 // This file is part of eCos, the Embedded Configurable Operating System.
 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2002 Gary Thomas
 //
 // eCos is free software; you can redistribute it and/or modify it under
 // the terms of the GNU General Public License as published by the Free
@@ -98,6 +99,7 @@ extern unsigned long  ntohs(unsigned sho
  */
 #define ETH_MIN_PKTLEN  60
 #define ETH_MAX_PKTLEN  (1540-14)
+#define ETH_HDR_SIZE    14
 
 typedef unsigned char enet_addr_t[6];
 typedef unsigned char ip_addr_t[4];
@@ -184,7 +186,7 @@ typedef struct {
 } 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.
@@ -212,7 +214,7 @@ typedef struct {
 } ip_header_t;
 
 
-#define IP_PKT_SIZE (60 + sizeof(eth_header_t))
+#define IP_PKT_SIZE (60 + ETH_HDR_SIZE)
 
 
 /*
@@ -351,7 +353,10 @@ typedef struct _tcp_socket {
  */
 extern enet_addr_t __local_enet_addr;
 extern ip_addr_t   __local_ip_addr;
-
+#ifdef CYGSEM_REDBOOT_NETWORKING_USE_GATEWAY
+extern ip_addr_t   __local_ip_gate;
+extern ip_addr_t   __local_ip_mask;
+#endif
 
 /*
  * Set a timer. Caller is responsible for providing the timer_t struct.
@@ -410,6 +415,12 @@ extern void __enet_poll(void);
  */
 extern void __enet_send(pktbuf_t *pkt, enet_addr_t *dest, int eth_type);
 
+#ifdef CYGSEM_REDBOOT_NETWORKING_USE_GATEWAY
+/*
+ * return true if addr is on local subnet
+ */
+extern int __ip_addr_local(ip_addr_t *addr);
+#endif
 
 /*
  * Handle incoming ARP packets.
@@ -454,9 +465,9 @@ extern void __ip_handler(pktbuf_t *pkt, 
  * 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);
 
 
 /*
@@ -487,7 +498,7 @@ extern void __udp_remove_listener(word p
 /*
  * 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
--- a/packages/redboot/current/src/net/arp.c
+++ b/packages/redboot/current/src/net/arp.c
@@ -9,6 +9,7 @@
 // -------------------------------------------
 // This file is part of eCos, the Embedded Configurable Operating System.
 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2002 Gary Thomas
 //
 // eCos is free software; you can redistribute it and/or modify it under
 // the terms of the GNU General Public License as published by the Free
@@ -189,6 +190,15 @@ int
         }
     }
     memcpy(&rt->ip_addr, host, sizeof(*host));
+    if (((*host)[0] == 0xFF) && ((*host)[1] == 0xFF) && ((*host)[2] == 0xFF)) {
+        memset(&rt->enet_addr, 0xFF, sizeof(&rt->enet_addr));
+        return 0;
+#ifdef CYGSEM_REDBOOT_NETWORKING_USE_GATEWAY
+    } else if (!__ip_addr_local(host)) {
+        // non-local IP address -- look up Gateway's Ethernet address
+        host = &__local_ip_gate;
+#endif
+    }
     if (__arp_request(host, &rt->enet_addr) < 0) {
         return -1;
     } else {
--- a/packages/redboot/current/src/net/bootp.c
+++ b/packages/redboot/current/src/net/bootp.c
@@ -9,6 +9,7 @@
 // -------------------------------------------
 // This file is part of eCos, the Embedded Configurable Operating System.
 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2002 Gary Thomas
 //
 // eCos is free software; you can redistribute it and/or modify it under
 // the terms of the GNU General Public License as published by the Free
@@ -65,26 +66,77 @@ extern int net_debug;
 #define MAX_RETRIES   30
 
 static bootp_header_t *bp_info;
+  
+#ifdef CYGSEM_REDBOOT_NETWORKING_USE_GATEWAY
+static const unsigned char dhcpCookie[] = {99,130,83,99};
+static const unsigned char dhcpEndOption[] = {255};
+static const unsigned char dhcpRequestOption[] = {52,1,3};
+#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;
+#endif
 
     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);
+    // Only accept pure REPLY responses
+    if (b->bp_op != BOOTREPLY)
+      return;
+    
+    // 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)))
+      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 += optlen;
     }
+#endif
 }
 
+#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.
@@ -99,6 +151,10 @@ int
     int            retry;
     unsigned long  start;
     ip_addr_t saved_ip_addr;
+#ifdef CYGSEM_REDBOOT_NETWORKING_USE_GATEWAY
+    unsigned char *p;
+#endif
+    int txSize;
 
     bp_info = info;
 
@@ -108,6 +164,18 @@ int
     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,dhcpRequestOption);
+    AddOption(p,dhcpEndOption);
+
+    txSize = p - (unsigned char*)&b;
+#else
+    txSize = sizeof(b);
+#endif
 
     memcpy( saved_ip_addr, __local_ip_addr, sizeof(__local_ip_addr) );
     memset( __local_ip_addr, 0, sizeof(__local_ip_addr) );
@@ -133,7 +201,7 @@ int
     while (retry-- > 0) {
 	start = MS_TICKS();
 
-	__udp_send((char *)&b, sizeof(b), &r, IPPORT_BOOTPS, IPPORT_BOOTPC);
+	__udp_send((char *)&b, txSize, &r, IPPORT_BOOTPS, IPPORT_BOOTPC);
 
 	do {
 	    __enet_poll();
@@ -149,7 +217,7 @@ int
     /* timed out */
     __udp_remove_listener(IPPORT_BOOTPC);
     net_debug = 0;
-    memcpy( __local_ip_addr, saved_ip_addr, sizeof(__local_ip_addr) );
+    memcpy( __local_ip_addr, saved_ip_addr, sizeof(__local_ip_addr));
     return -1;
 }
 
--- a/packages/redboot/current/src/net/ip.c
+++ b/packages/redboot/current/src/net/ip.c
@@ -13,6 +13,7 @@
 // eCos is free software; you can redistribute it and/or modify it under
 // the terms of the GNU General Public License as published by the Free
 // Software Foundation; either version 2 or (at your option) any later version.
+// Copyright (C) 2002 Gary Thomas
 //
 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
@@ -57,11 +58,35 @@
 #ifndef CYGDAT_REDBOOT_DEFAULT_IP_ADDR
 # define CYGDAT_REDBOOT_DEFAULT_IP_ADDR 0, 0, 0, 0
 #endif
+#ifndef CYGDAT_REDBOOT_DEFAULT_IP_ADDR_MASK
+# define CYGDAT_REDBOOT_DEFAULT_IP_ADDR_MASK 255, 255, 255, 0
+#endif
+#ifndef CYGDAT_REDBOOT_DEFAULT_GATEWAY_IP_ADDR
+# define CYGDAT_REDBOOT_DEFAULT_GATEWAY_IP_ADDR 0, 0, 0, 0
+#endif
 
 ip_addr_t __local_ip_addr = { CYGDAT_REDBOOT_DEFAULT_IP_ADDR };
+#ifdef CYGSEM_REDBOOT_NETWORKING_USE_GATEWAY
+ip_addr_t __local_ip_mask = { CYGDAT_REDBOOT_DEFAULT_IP_ADDR_MASK };
+ip_addr_t __local_ip_gate = { CYGDAT_REDBOOT_DEFAULT_GATEWAY_IP_ADDR };
+#endif
 
 static word ip_ident;
 
+#ifdef CYGSEM_REDBOOT_NETWORKING_USE_GATEWAY
+/*
+ * See if an address is on the local network
+ */
+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]));
+}
+#endif
 
 /*
  * Match given IP address to our address.
@@ -152,7 +177,7 @@ void
  * 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;
@@ -185,6 +210,7 @@ void
     ip->checksum = htons(cksum);
 
     __enet_send(pkt, &dest->enet_addr, ETH_TYPE_IP);    
+    return 0;
 }
 
 
--- a/packages/redboot/current/src/net/net_io.c
+++ b/packages/redboot/current/src/net/net_io.c
@@ -9,6 +9,7 @@
 // -------------------------------------------
 // This file is part of eCos, the Embedded Configurable Operating System.
 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2002 Gary Thomas
 //
 // eCos is free software; you can redistribute it and/or modify it under
 // the terms of the GNU General Public License as published by the Free
@@ -94,6 +95,20 @@ RedBoot_config_option("Local IP address"
                       CONFIG_IP,
                       0
     );
+#ifdef CYGSEM_REDBOOT_NETWORKING_USE_GATEWAY
+RedBoot_config_option("Local IP address mask",
+                      bootp_my_ip_mask,
+                      "bootp", false,
+                      CONFIG_IP,
+                      0
+    );
+RedBoot_config_option("Gateway IP address",
+                      bootp_my_gateway_ip,
+                      "bootp", false,
+                      CONFIG_IP,
+                      0
+    );
+#endif
 RedBoot_config_option("Default server IP address",
                       bootp_server_ip,
                       "bootp", false,
@@ -562,6 +577,21 @@ show_addrs(void)
     diag_printf("\n");
 }
 
+static void
+flash_get_IP(char *id, ip_addr_t *val)
+{
+    ip_addr_t my_ip;
+    int i;
+    
+    flash_get_config(id, &my_ip, CONFIG_IP);
+    if (my_ip[0] != 0 || my_ip[1] != 0 ||
+        my_ip[2] != 0 || my_ip[3] != 0) {
+        // 'id' is set to something so let it override any static IP
+        for (i=0; i<4; i++)
+            (*val)[i] = my_ip[i];
+    }        
+}
+
 void
 net_init(void)
 {
@@ -586,15 +616,11 @@ net_init(void)
     flash_get_config("bootp", &use_bootp, CONFIG_BOOL);
     if (!use_bootp)
     {
-        ip_addr_t bootp_my_ip;
-        int i;
-        flash_get_config("bootp_my_ip", &bootp_my_ip, CONFIG_IP);
-        if (bootp_my_ip[0] != 0 || bootp_my_ip[1] != 0 ||
-            bootp_my_ip[2] != 0 || bootp_my_ip[3] != 0) {
-            // bootp_my_ip is set to something so let it override any static IP
-            for (i=0; i<4; i++)
-                __local_ip_addr[i] = bootp_my_ip[i];
-        }        
+        flash_get_IP("bootp_my_ip", &__local_ip_addr);
+#ifdef CYGSEM_REDBOOT_NETWORKING_USE_GATEWAY
+        flash_get_IP("bootp_my_ip_mask", &__local_ip_mask);
+        flash_get_IP("bootp_my_gateway_ip", &__local_ip_gate);
+#endif
         flash_get_config("bootp_server_ip", &my_bootp_info.bp_siaddr,
                          CONFIG_IP);
     }
--- a/packages/redboot/current/src/net/udp.c
+++ b/packages/redboot/current/src/net/udp.c
@@ -9,6 +9,7 @@
 // -------------------------------------------
 // This file is part of eCos, the Embedded Configurable Operating System.
 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2002 Gary Thomas
 //
 // eCos is free software; you can redistribute it and/or modify it under
 // the terms of the GNU General Public License as published by the Free
@@ -62,7 +63,7 @@ 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)))
 
@@ -151,7 +152,7 @@ void
 /*
  * Send a UDP packet.
  */
-void
+int
 __udp_send(char *buf, int len, ip_route_t *dest_ip,
 	   word dest_port, word src_port)
 {
@@ -159,15 +160,15 @@ void
     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;
@@ -190,9 +191,9 @@ void
     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
@@ -201,13 +202,13 @@ int
 {
     ip_route_t rt;
 
-    if (__arp_lookup((ip_addr_t *)&server->sin_addr, &rt) < 0) {
-        diag_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;
-    }
+   if (__arp_lookup((ip_addr_t *)&server->sin_addr, &rt) < 0) {
+       diag_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;
+   }
 }
 
 static char               *recvfrom_buf;