Mercurial > ecos
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;
