summaryrefslogtreecommitdiff
path: root/cesar/ecos/packages/redboot/current/src/net
diff options
context:
space:
mode:
Diffstat (limited to 'cesar/ecos/packages/redboot/current/src/net')
-rw-r--r--cesar/ecos/packages/redboot/current/src/net/arp.c212
-rw-r--r--cesar/ecos/packages/redboot/current/src/net/bootp.c344
-rw-r--r--cesar/ecos/packages/redboot/current/src/net/cksum.c124
-rw-r--r--cesar/ecos/packages/redboot/current/src/net/dns.c287
-rw-r--r--cesar/ecos/packages/redboot/current/src/net/enet.c248
-rw-r--r--cesar/ecos/packages/redboot/current/src/net/http_client.c255
-rw-r--r--cesar/ecos/packages/redboot/current/src/net/icmp.c126
-rw-r--r--cesar/ecos/packages/redboot/current/src/net/inet_addr.c118
-rw-r--r--cesar/ecos/packages/redboot/current/src/net/ip.c216
-rw-r--r--cesar/ecos/packages/redboot/current/src/net/net_io.c899
-rw-r--r--cesar/ecos/packages/redboot/current/src/net/ping.c248
-rw-r--r--cesar/ecos/packages/redboot/current/src/net/pktbuf.c167
-rw-r--r--cesar/ecos/packages/redboot/current/src/net/tcp.c921
-rw-r--r--cesar/ecos/packages/redboot/current/src/net/tftp_client.c279
-rw-r--r--cesar/ecos/packages/redboot/current/src/net/timers.c135
-rw-r--r--cesar/ecos/packages/redboot/current/src/net/udp.c268
16 files changed, 4847 insertions, 0 deletions
diff --git a/cesar/ecos/packages/redboot/current/src/net/arp.c b/cesar/ecos/packages/redboot/current/src/net/arp.c
new file mode 100644
index 0000000000..58b3fd2291
--- /dev/null
+++ b/cesar/ecos/packages/redboot/current/src/net/arp.c
@@ -0,0 +1,212 @@
+//==========================================================================
+//
+// net/arp.c
+//
+// Stand-alone ARP support for RedBoot
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2002, 2003 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
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): gthomas
+// Contributors: gthomas
+// Date: 2000-07-14
+// Purpose:
+// Description:
+//
+// This code is part of RedBoot (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <net/net.h>
+
+static struct {
+ int waiting;
+ char *eth;
+ char *ip;
+} arp_req;
+
+/*
+ * Handle incoming ARP packets.
+ */
+void
+__arp_handler(pktbuf_t *pkt)
+{
+ arp_header_t *arp = pkt->arp_hdr;
+ int hw_type, protocol;
+
+ /*
+ * Only handle ethernet hardware and IP protocol.
+ */
+ protocol = ntohs(arp->protocol);
+ hw_type = ntohs(arp->hw_type);
+ if ((hw_type == ARP_HW_ETHER) && (protocol == ETH_TYPE_IP)) {
+ /*
+ * Handle requests for our ethernet address.
+ */
+ if (!memcmp(arp->target_ip, __local_ip_addr, 4)) {
+ if (ntohs(arp->opcode) == ARP_REQUEST) {
+ /* format response. */
+ arp->opcode = htons(ARP_REPLY);
+ memcpy(arp->target_ip, arp->sender_ip,
+ sizeof(ip_addr_t));
+ memcpy(arp->target_enet, arp->sender_enet,
+ sizeof(enet_addr_t));
+ memcpy(arp->sender_ip, __local_ip_addr,
+ sizeof(ip_addr_t));
+ memcpy(arp->sender_enet, __local_enet_addr,
+ sizeof(enet_addr_t));
+ pkt->pkt_bytes = sizeof(arp_header_t);
+ __enet_send(pkt, &arp->target_enet, ETH_TYPE_ARP);
+
+ } else if (ntohs(arp->opcode) == ARP_REPLY && arp_req.waiting) {
+ if (!memcmp(arp_req.ip, arp->sender_ip, sizeof(ip_addr_t))) {
+ memcpy(arp_req.eth, arp->sender_enet, sizeof(enet_addr_t));
+ arp_req.waiting = 0;
+ }
+ }
+ }
+ }
+ __pktbuf_free(pkt);
+}
+
+
+/*
+ * Find the ethernet address of the machine with the given
+ * ip address.
+ * Return 0 and fills in 'eth_addr' if successful,
+ * -1 if unsuccessful.
+ */
+int
+__arp_request(ip_addr_t *ip_addr, enet_addr_t *eth_addr, int allow_self)
+{
+ pktbuf_t *pkt;
+ arp_header_t *arp;
+ unsigned long retry_start;
+ enet_addr_t bcast_addr;
+ int retry;
+
+ if (!allow_self) {
+ // Special case request for self
+ if (!memcmp(ip_addr, __local_ip_addr, 4)) {
+ memcpy(eth_addr, __local_enet_addr, sizeof(enet_addr_t));
+ return 0;
+ }
+ }
+
+ /* just fail if can't get a buffer */
+ if ((pkt = __pktbuf_alloc(ARP_PKT_SIZE)) == NULL)
+ return -1;
+
+ arp = pkt->arp_hdr;
+ arp->opcode = htons(ARP_REQUEST);
+ arp->hw_type = htons(ARP_HW_ETHER);
+ arp->protocol = htons(0x800);
+ arp->hw_len = sizeof(enet_addr_t);
+ arp->proto_len = sizeof(ip_addr_t);
+
+ memcpy(arp->sender_ip, __local_ip_addr, sizeof(ip_addr_t));
+ memcpy(arp->sender_enet, __local_enet_addr, sizeof(enet_addr_t));
+ memcpy(arp->target_ip, ip_addr, sizeof(ip_addr_t));
+
+ bcast_addr[0] = 255;
+ bcast_addr[1] = 255;
+ bcast_addr[2] = 255;
+ bcast_addr[3] = 255;
+ bcast_addr[4] = 255;
+ bcast_addr[5] = 255;
+
+ arp_req.eth = (char *)eth_addr;
+ arp_req.ip = (char *)ip_addr;
+ arp_req.waiting = 1;
+
+ retry = 8;
+ while (retry-- > 0) {
+
+ /* send the packet */
+ pkt->pkt_bytes = sizeof(arp_header_t);
+ __enet_send(pkt, &bcast_addr, ETH_TYPE_ARP);
+
+ retry_start = MS_TICKS();
+ while ((MS_TICKS_DELAY() - retry_start) < 250) {
+ __enet_poll();
+ if (!arp_req.waiting) {
+ __pktbuf_free(pkt);
+ return 0;
+ }
+ }
+ }
+ __pktbuf_free(pkt);
+ return -1;
+}
+
+#define NUM_ARP 16
+static ip_route_t routes[NUM_ARP];
+
+int
+__arp_lookup(ip_addr_t *host, ip_route_t *rt)
+{
+ int i;
+ static int next_arp = 0;
+
+ for (i = 0; i < NUM_ARP; i++) {
+ if (memcmp(host, &routes[i].ip_addr, sizeof(*host)) == 0) {
+ // This is a known host
+ memcpy(rt, &routes[i], sizeof(*rt));
+ return 0;
+ }
+ }
+ 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) < 0) {
+ return -1;
+ } else {
+ memcpy(&routes[next_arp], rt, sizeof(*rt));
+ if (++next_arp == NUM_ARP) next_arp = 0;
+ return 0;
+ }
+}
+
diff --git a/cesar/ecos/packages/redboot/current/src/net/bootp.c b/cesar/ecos/packages/redboot/current/src/net/bootp.c
new file mode 100644
index 0000000000..046017f4b0
--- /dev/null
+++ b/cesar/ecos/packages/redboot/current/src/net/bootp.c
@@ -0,0 +1,344 @@
+//==========================================================================
+//
+// net/bootp.c
+//
+// Stand-alone minimal BOOTP support for RedBoot
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2002, 2003 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
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): gthomas
+// Contributors: gthomas
+// Date: 2000-07-14
+// Purpose:
+// Description:
+//
+// This code is part of RedBoot (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <redboot.h>
+#include <net/net.h>
+#include <net/bootp.h>
+
+#define SHOULD_BE_RANDOM 0x12345555
+
+/* How many milliseconds to wait before retrying the request */
+#define RETRY_TIME 2000
+#define MAX_RETRIES 8
+
+static bootp_header_t *bp_info;
+
+#ifdef CYGSEM_REDBOOT_NETWORKING_DHCP
+static const unsigned char dhcpCookie[] = {99,130,83,99};
+static const unsigned char dhcpEnd[] = {255};
+static const unsigned char dhcpDiscover[] = {53,1,1};
+static const unsigned char dhcpRequest[] = {53,1,3};
+static const unsigned char dhcpRequestIP[] = {50,4};
+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_DHCP
+ unsigned char *p, expected = 0;
+#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);
+ }
+
+ // 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;
+
+#ifdef CYGSEM_REDBOOT_NETWORKING_DHCP
+ p = b->bp_vend;
+ if (memcmp(p, dhcpCookie, sizeof(dhcpCookie)))
+ return;
+ p += 4;
+
+ // Find the DHCP Message Type tag
+ while (*p != TAG_DHCP_MESS_TYPE) {
+ p += p[1] + 2;
+ if (p >= (unsigned char*)b + sizeof(*bp_info))
+ return;
+ }
+
+ p += 2;
+
+ switch (dhcpState) {
+ case DHCP_DISCOVER:
+ // The discover message has been sent, only accept an offer reply
+ if (*p == DHCP_MESS_TYPE_OFFER) {
+ dhcpState = DHCP_OFFER;
+ return;
+ } else {
+ expected = DHCP_MESS_TYPE_OFFER;
+ }
+ break;
+ case DHCP_REQUEST:
+ // The request message has been sent, only accept an ack reply
+ if (*p == DHCP_MESS_TYPE_ACK) {
+ dhcpState = DHCP_ACK;
+ return;
+ } else {
+ expected = DHCP_MESS_TYPE_ACK;
+ }
+ break;
+ case DHCP_NONE:
+ case DHCP_OFFER:
+ case DHCP_ACK:
+ // Quitely ignore these - they indicate repeated message from server
+ return;
+ }
+ // See if we've been NAK'd - if so, give up and try again
+ if (*p == DHCP_MESS_TYPE_NAK) {
+ dhcpState = DHCP_NONE;
+ return;
+ }
+ diag_printf("DHCP reply: %d, not %d\n", (int)*p, (int)expected);
+ 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)
+
+/*
+ * 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;
+ ip_addr_t saved_ip_addr;
+#ifdef CYGSEM_REDBOOT_NETWORKING_DHCP
+ unsigned char *p;
+ int oldState;
+#endif
+ int txSize;
+ bool abort = false;
+ static int xid = SHOULD_BE_RANDOM;
+
+#ifdef CYGSEM_REDBOOT_NETWORKING_DHCP
+ dhcpState = DHCP_NONE;
+#endif
+
+ // 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
+ 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 = MAX_RETRIES;
+ do {
+ 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:
+ case DHCP_DISCOVER:
+ AddOption(p,dhcpCookie);
+ AddOption(p,dhcpDiscover);
+ AddOption(p,dhcpParamRequestList);
+ AddOption(p,dhcpEnd);
+ dhcpState = DHCP_DISCOVER;
+ break;
+ case DHCP_OFFER:
+ retry = MAX_RETRIES;
+ case DHCP_REQUEST:
+ b.bp_xid = bp_info->bp_xid; // Match what server sent
+ 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);
+ memset(&b.bp_yiaddr, 0x00, 4);
+ memset(&b.bp_siaddr, 0x00, 4);
+ break;
+ case DHCP_ACK:
+ // Ignore these states (they won't happen)
+ break;
+ }
+
+ // 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;
+ oldState = dhcpState;
+#else
+ txSize = sizeof(b);
+#endif
+
+ __udp_send((char *)&b, txSize, &r, IPPORT_BOOTPS, IPPORT_BOOTPC);
+
+ // If we're retrying, inform the user
+ if (retry == (MAX_RETRIES-1))
+ diag_printf("... waiting for BOOTP information\n");
+
+ do {
+ __enet_poll();
+#ifdef CYGSEM_REDBOOT_NETWORKING_DHCP
+ if (dhcpState != oldState) {
+ 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) {
+#ifdef CYGSEM_REDBOOT_NETWORKING_USE_GATEWAY
+ case TAG_SUBNET_MASK: // subnet mask
+ memcpy(__local_ip_mask,p,4);
+ break;
+ case TAG_GATEWAY: // router
+ memcpy(__local_ip_gate,p,4);
+ break;
+#endif
+#ifdef CYGPKG_REDBOOT_NETWORKING_DNS
+ case TAG_DOMAIN_SERVER:
+// diag_printf(" DNS server found!\n");
+ memcpy(&__bootp_dns_addr, p, 4);
+ __bootp_dns_set = 1;
+ break;
+#endif
+ default:
+ break;
+ }
+ }
+ p += optlen;
+ }
+ __udp_remove_listener(IPPORT_BOOTPC);
+ return 0;
+ } else {
+ break; // State changed, handle it
+ }
+ }
+#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;
+ }
+ MS_TICKS_DELAY(); // Count for ^C test
+ } while ((MS_TICKS_DELAY() - start) < RETRY_TIME);
+ } while (!abort && (retry-- > 0));
+
+ // timed out
+ __udp_remove_listener(IPPORT_BOOTPC);
+ // Restore any previous IP address
+ memcpy(__local_ip_addr, saved_ip_addr, sizeof(__local_ip_addr));
+ return -1;
+}
+
+
diff --git a/cesar/ecos/packages/redboot/current/src/net/cksum.c b/cesar/ecos/packages/redboot/current/src/net/cksum.c
new file mode 100644
index 0000000000..6ccf5894e8
--- /dev/null
+++ b/cesar/ecos/packages/redboot/current/src/net/cksum.c
@@ -0,0 +1,124 @@
+//==========================================================================
+//
+// net/cksum.c
+//
+// Stand-alone network checksum support for RedBoot
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): gthomas
+// Contributors: gthomas
+// Date: 2000-07-14
+// Purpose:
+// Description:
+//
+// This code is part of RedBoot (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <net/net.h>
+
+/*
+ * Do a one's complement checksum.
+ * The data being checksum'd is in network byte order.
+ * The returned checksum is in network byte order.
+ */
+unsigned short
+__sum(word *w, int len, int init_sum)
+{
+ int sum = init_sum;
+
+ union {
+ volatile unsigned char c[2];
+ volatile unsigned short s;
+ } su;
+
+ union {
+ volatile unsigned short s[2];
+ volatile int i;
+ } iu;
+
+ while ((len -= 2) >= 0)
+ sum += *w++;
+
+ if (len == -1) {
+ su.c[0] = *(char *)w;
+ su.c[1] = 0;
+ sum += su.s;
+ }
+
+ iu.i = sum;
+ sum = iu.s[0] + iu.s[1];
+ if (sum > 65535)
+ sum -= 65535;
+
+ su.s = ~sum;
+
+ return (su.c[0] << 8) | su.c[1];
+}
+
+
+/*
+ * Compute a partial checksum for the UDP/TCP pseudo header.
+ */
+int
+__pseudo_sum(ip_header_t *ip)
+{
+ int sum;
+ word *p;
+
+ union {
+ volatile unsigned char c[2];
+ volatile unsigned short s;
+ } su;
+
+ p = (word *)ip->source;
+ sum = *p++;
+ sum += *p++;
+ sum += *p++;
+ sum += *p++;
+
+ su.c[0] = 0;
+ su.c[1] = ip->protocol;
+ sum += su.s;
+
+ sum += ip->length;
+
+ return sum;
+}
diff --git a/cesar/ecos/packages/redboot/current/src/net/dns.c b/cesar/ecos/packages/redboot/current/src/net/dns.c
new file mode 100644
index 0000000000..c6cf392fbe
--- /dev/null
+++ b/cesar/ecos/packages/redboot/current/src/net/dns.c
@@ -0,0 +1,287 @@
+//=============================================================================
+//
+// dns.c
+//
+// DNS client code
+//
+//=============================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2003 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
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//=============================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): jskov
+// Contributors:jskov
+// Date: 2001-09-26
+// Description: Provides DNS lookup as per RFC 1034/1035.
+//
+// Note: This is a stripped down clone of dns.c from the CYGPKG_NS_DNS
+// package which does not use malloc/free and has been tweaked to
+// use UDP via RedBoot's network stack. Also adds commands
+// to set the DNS server IP at runtime.
+//
+//####DESCRIPTIONEND####
+//
+//=============================================================================
+
+#include <cyg/hal/drv_api.h>
+#include <cyg/infra/cyg_type.h>
+#include <cyg/infra/cyg_trac.h> /* Tracing support */
+
+#include <net/net.h>
+#include <redboot.h>
+/* #include <cyg/ns/dns/dns.h> - it's been moved to redboot.h */
+#include <cyg/ns/dns/dns_priv.h>
+
+#ifdef CYGSEM_REDBOOT_FLASH_CONFIG
+#include <flash_config.h>
+
+RedBoot_config_option("DNS server IP address",
+ dns_ip,
+ ALWAYS_ENABLED, true,
+ CONFIG_IP,
+ 0
+ );
+#endif
+
+/* So we remember which ports have been used */
+static int get_port = 7700;
+
+#define DOMAIN_PORT 53
+
+/* Some magic to make dns_impl.inl compile under RedBoot */
+#define sprintf diag_sprintf
+
+/* DNS server address possibly returned from bootp */
+struct in_addr __bootp_dns_addr;
+cyg_bool __bootp_dns_set = false;
+
+struct sockaddr_in server;
+
+/* static buffers so we can make do without malloc */
+static struct hostent _hent;
+static char* _h_addr_list[2];
+static struct in_addr _h_addr_list0;
+static int _hent_alloc = 0;
+
+#define _STRING_COUNT 2
+#define _STRING_LENGTH 64
+static char _strings[_STRING_COUNT][_STRING_LENGTH];
+static int _strings_alloc = 0;
+
+/* as in dns.c proper */
+static short id = 0; /* ID of the last query */
+static int s = -1; /* Socket to the DNS server */
+static cyg_drv_mutex_t dns_mutex; /* Mutex to stop multiple queries as once */
+static char * domainname=NULL; /* Domain name used for queries */
+
+
+/* Allocate space for string of length (len). Return NULL on
+ failure. */
+static char*
+alloc_string(int len)
+{
+ int i;
+
+ if (len > _STRING_LENGTH)
+ return NULL;
+
+ for (i = 0; i < _STRING_COUNT; i++) {
+ if (_strings_alloc & (1 << i)) continue;
+ _strings_alloc |= (1<<i);
+ return _strings[i];
+ }
+ return NULL;
+}
+
+static void
+free_string(char* s)
+{
+ int i;
+ for (i = 0; i < _STRING_COUNT; i++) {
+ if (_strings[i] == s) {
+ _strings_alloc &= ~(1<<i);
+ break;
+ }
+ }
+}
+
+/* Deallocate the memory taken to hold a hent structure */
+static void
+free_hent(struct hostent * hent)
+{
+ if (hent->h_name) {
+ free_string(hent->h_name);
+ }
+ _hent_alloc = 0;
+}
+
+/* Allocate hent structure with room for one in_addr. Returns NULL on
+ failure. */
+static struct hostent*
+alloc_hent(void)
+{
+ struct hostent *hent;
+
+ if (_hent_alloc) return NULL;
+
+ hent = &_hent;
+ memset(hent, 0, sizeof(struct hostent));
+ hent->h_addr_list = _h_addr_list;
+ hent->h_addr_list[0] = (char*)&_h_addr_list0;
+ hent->h_addr_list[1] = NULL;
+ _hent_alloc = 1;
+
+ return hent;
+}
+
+static __inline__ void
+free_stored_hent(void)
+{
+ free_hent( &_hent );
+}
+
+static __inline__ void
+store_hent(struct hostent *hent)
+{
+ hent=hent; // avoid warning
+}
+
+/* Send the query to the server and read the response back. Return -1
+ if it fails, otherwise put the response back in msg and return the
+ length of the response. */
+static int
+send_recv(char * msg, int len, int msglen)
+{
+ struct dns_header *dns_hdr;
+ int finished = false;
+ int read = 0;
+
+ dns_hdr = (struct dns_header *) msg;
+
+ do {
+ int len_togo = len;
+ struct timeval timeout;
+ struct sockaddr_in local_addr, from_addr;
+
+ memset((char *)&local_addr, 0, sizeof(local_addr));
+ local_addr.sin_family = AF_INET;
+ local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+ local_addr.sin_port = htons(get_port++);
+
+ if (__udp_sendto(msg, len_togo, &server, &local_addr) < 0)
+ return -1;
+
+ memset((char *)&from_addr, 0, sizeof(from_addr));
+
+ timeout.tv_sec = CYGNUM_REDBOOT_NETWORKING_DNS_TIMEOUT;
+ timeout.tv_usec = 0;
+
+ read = __udp_recvfrom(msg, len, &from_addr, &local_addr, &timeout);
+ if (read < 0)
+ return -1;
+
+ /* Reply to an old query. Ignore it */
+ if (ntohs(dns_hdr->id) != (id-1)) {
+ continue;
+ }
+ finished = true;
+ } while (!finished);
+
+ return read;
+}
+
+void
+set_dns(char* new_ip)
+{
+ in_addr_t dns_ip;
+
+ memset(&server.sin_addr, 0, sizeof(server.sin_addr));
+ if (!inet_aton(new_ip, &dns_ip)) {
+ diag_printf("Bad DNS server address: %s\n", new_ip);
+ } else {
+ memcpy(&server.sin_addr, &dns_ip, sizeof(dns_ip));
+ /* server config is valid */
+ s = 0;
+ }
+}
+
+void
+show_dns(void)
+{
+ diag_printf(", DNS server IP: %s", inet_ntoa((in_addr_t *)&server.sin_addr));
+ if (0 == server.sin_addr.s_addr) {
+ s = -1;
+ }
+}
+
+/* Initialise the resolver. Open a socket and bind it to the address
+ of the server. return -1 if something goes wrong, otherwise 0 */
+int
+redboot_dns_res_init(void)
+{
+ memset((char *)&server, 0, sizeof(server));
+ server.sin_len = sizeof(server);
+ server.sin_family = AF_INET;
+ server.sin_port = htons(DOMAIN_PORT);
+ cyg_drv_mutex_init(&dns_mutex);
+
+ /* If we got a DNS server address from the DHCP/BOOTP, then use that address */
+ if ( __bootp_dns_set ) {
+ memcpy(&server.sin_addr, &__bootp_dns_addr, sizeof(__bootp_dns_addr) );
+ s = 0;
+ }
+ else {
+#ifdef CYGSEM_REDBOOT_FLASH_CONFIG
+ {
+ ip_addr_t dns_ip;
+
+ flash_get_config("dns_ip", &dns_ip, CONFIG_IP);
+ if (dns_ip[0] == 0 && dns_ip[1] == 0 && dns_ip[2] == 0 && dns_ip[3] == 0)
+ return -1;
+ memcpy(&server.sin_addr, &dns_ip, sizeof(dns_ip));
+ /* server config is valid */
+ s = 0;
+ }
+#else
+ // Use static configuration
+ set_dns(__Xstr(CYGPKG_REDBOOT_NETWORKING_DNS_IP));
+#endif
+ }
+
+ return 0;
+}
+
+/* Include the DNS client implementation code */
+#include <cyg/ns/dns/dns_impl.inl>
diff --git a/cesar/ecos/packages/redboot/current/src/net/enet.c b/cesar/ecos/packages/redboot/current/src/net/enet.c
new file mode 100644
index 0000000000..6301c17ee6
--- /dev/null
+++ b/cesar/ecos/packages/redboot/current/src/net/enet.c
@@ -0,0 +1,248 @@
+//==========================================================================
+//
+// net/enet.c
+//
+// Stand-alone ethernet [link-layer] support for RedBoot
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): gthomas
+// Contributors: gthomas
+// Date: 2000-07-14
+// Purpose:
+// Description:
+//
+// This code is part of RedBoot (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <redboot.h>
+#include <net/net.h>
+#include <cyg/io/eth/eth_drv.h> // Logical driver interfaces
+
+//#define ENET_STATS 1
+
+#ifdef ENET_STATS
+static int num_ip = 0;
+static int num_arp = 0;
+#ifdef NET_SUPPORT_RARP
+static int num_rarp = 0;
+#endif
+static int num_received = 0;
+static int num_transmitted = 0;
+#endif
+
+//
+// Support for user handlers of additional ethernet packets (nonIP)
+//
+
+#define NUM_EXTRA_HANDLERS 4
+static struct {
+ int type;
+ pkt_handler_t handler;
+} eth_handlers[NUM_EXTRA_HANDLERS];
+
+pkt_handler_t
+__eth_install_listener(int eth_type, pkt_handler_t handler)
+{
+ int i, empty;
+ pkt_handler_t old;
+
+ if (eth_type > 0x800 || handler != (pkt_handler_t)0) {
+ empty = -1;
+ for (i = 0; i < NUM_EXTRA_HANDLERS; i++) {
+ if (eth_handlers[i].type == eth_type) {
+ // Replace existing handler
+ old = eth_handlers[i].handler;
+ eth_handlers[i].handler = handler;
+ return old;
+ }
+ if (eth_handlers[i].type == 0) {
+ empty = i;
+ }
+ }
+ if (empty >= 0) {
+ // Found a free slot
+ eth_handlers[empty].type = eth_type;
+ eth_handlers[empty].handler = handler;
+ return (pkt_handler_t)0;
+ }
+ }
+ diag_printf("** Warning: can't install listener for ethernet type 0x%02x\n", eth_type);
+ return (pkt_handler_t)0;
+}
+
+void
+__eth_remove_listener(int eth_type)
+{
+ int i;
+
+ for (i = 0; i < NUM_EXTRA_HANDLERS; i++) {
+ if (eth_handlers[i].type == eth_type) {
+ eth_handlers[i].type = 0;
+ }
+ }
+}
+
+/*
+ * Non-blocking poll of ethernet link. Process packets until no more
+ * are available.
+ */
+void
+__enet_poll(void)
+{
+ pktbuf_t *pkt;
+ eth_header_t eth_hdr;
+ int i, type;
+#ifdef DEBUG_PKT_EXHAUSTION
+ static bool was_exhausted = false;
+#endif
+
+ while (true) {
+ /*
+ * Try to get a free pktbuf and return if none
+ * are available.
+ */
+ if ((pkt = __pktbuf_alloc(ETH_MAX_PKTLEN)) == NULL) {
+#ifdef DEBUG_PKT_EXHAUSTION
+ if (!was_exhausted) {
+ int old = start_console(); // Force output to standard port
+ diag_printf("__enet_poll: no more buffers\n");
+ __pktbuf_dump();
+ was_exhausted = true;
+ end_console(old);
+ }
+#endif
+ return;
+ }
+#ifdef DEBUG_PKT_EXHAUSTION
+ was_exhausted = false; // Report the next time we're out of buffers
+#endif
+
+ if ((pkt->pkt_bytes = eth_drv_read((char *)&eth_hdr, (char *)pkt->buf,
+ ETH_MAX_PKTLEN)) > 0) {
+#ifdef ENET_STATS
+ ++num_received;
+#endif
+ switch (type = ntohs(eth_hdr.type)) {
+
+ case ETH_TYPE_IP:
+#ifdef ENET_STATS
+ ++num_ip;
+#endif
+ pkt->ip_hdr = (ip_header_t *)pkt->buf;
+ __ip_handler(pkt, &eth_hdr.source);
+ break;
+
+ case ETH_TYPE_ARP:
+#ifdef ENET_STATS
+ ++num_arp;
+#endif
+ pkt->arp_hdr = (arp_header_t *)pkt->buf;
+ __arp_handler(pkt);
+ break;
+
+#ifdef NET_SUPPORT_RARP
+ case ETH_TYPE_RARP:
+#ifdef ENET_STATS
+ ++num_rarp;
+#endif
+ pkt->arp_hdr = (arp_header_t *)pkt->buf;
+ __rarp_handler(pkt);
+ break;
+#endif
+
+ default:
+ if (type > 0x800) {
+ for (i = 0; i < NUM_EXTRA_HANDLERS; i++) {
+ if (eth_handlers[i].type == type) {
+ (eth_handlers[i].handler)(pkt, &eth_hdr);
+ }
+ }
+ }
+ __pktbuf_free(pkt);
+ break;
+ }
+ } else {
+ __pktbuf_free(pkt);
+ break;
+ }
+ }
+}
+
+
+
+/*
+ * Send an ethernet packet.
+ */
+void
+__enet_send(pktbuf_t *pkt, enet_addr_t *dest, int eth_type)
+{
+ eth_header_t eth_hdr;
+
+ // Set up ethernet header
+ memcpy(&eth_hdr.destination, dest, sizeof(enet_addr_t));
+ memcpy(&eth_hdr.source, __local_enet_addr, sizeof(enet_addr_t));
+ eth_hdr.type = htons(eth_type);
+
+ eth_drv_write((char *)&eth_hdr, (char *)pkt->buf, pkt->pkt_bytes);
+#ifdef ENET_STATS
+ ++num_transmitted;
+#endif
+}
+
+#ifdef __LITTLE_ENDIAN__
+
+unsigned long
+ntohl(unsigned long x)
+{
+ return (((x & 0x000000FF) << 24) |
+ ((x & 0x0000FF00) << 8) |
+ ((x & 0x00FF0000) >> 8) |
+ ((x & 0xFF000000) >> 24));
+}
+
+unsigned short
+ntohs(unsigned short x)
+{
+ return (((x & 0x00FF) << 8) |
+ ((x & 0xFF00) >> 8));
+}
+
+#endif
diff --git a/cesar/ecos/packages/redboot/current/src/net/http_client.c b/cesar/ecos/packages/redboot/current/src/net/http_client.c
new file mode 100644
index 0000000000..47bb480517
--- /dev/null
+++ b/cesar/ecos/packages/redboot/current/src/net/http_client.c
@@ -0,0 +1,255 @@
+//==========================================================================
+//
+// net/http_client.c
+//
+// Stand-alone HTTP support for RedBoot
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2002, 2003 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
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): gthomas
+// Contributors: gthomas
+// Date: 2002-05-22
+// Purpose:
+// Description:
+//
+// This code is part of RedBoot (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+// HTTP client support
+
+#include <redboot.h> // have_net
+#include <net/net.h>
+#include <net/http.h>
+
+// So we remember which ports have been used
+static int get_port = 7800;
+
+static struct _stream{
+ bool open;
+ int avail, actual_len, pos, filelen;
+ char data[4096];
+ char *bufp;
+ tcp_socket_t sock;
+} http_stream;
+
+static __inline__ int
+min(int a, int b)
+{
+ if (a < b)
+ return a;
+ else
+ return b;
+}
+
+int
+http_stream_open(connection_info_t *info, int *err)
+{
+ int res;
+ struct _stream *s = &http_stream;
+
+ if (!info->server->sin_port)
+ info->server->sin_port = 80; // HTTP port
+ if ((res = __tcp_open(&s->sock, info->server, get_port++, 5000, err)) < 0) {
+ *err = HTTP_OPEN;
+ return -1;
+ }
+ diag_sprintf(s->data, "GET %s HTTP/1.0\r\n\r\n", info->filename);
+ __tcp_write_block(&s->sock, s->data, strlen(s->data));
+ s->avail = 0;
+ s->open = true;
+ s->pos = 0;
+ return 0;
+}
+
+void
+http_stream_close(int *err)
+{
+ struct _stream *s = &http_stream;
+
+ if (s->open) {
+ __tcp_abort(&s->sock,1);
+ s->open = false;
+ }
+}
+
+int
+http_stream_read(char *buf,
+ int len,
+ int *err)
+{
+ struct _stream *s = &http_stream;
+ int total = 0;
+ int cnt, code;
+
+ if (!s->open) {
+ return -1; // Shouldn't happen, but...
+ }
+ while (len) {
+ while (s->avail == 0) {
+ // Need to wait for some data to arrive
+ __tcp_poll();
+ if (s->sock.state != _ESTABLISHED) {
+ if (s->sock.state == _CLOSE_WAIT) {
+ // This connection is breaking
+ if (s->sock.data_bytes == 0 && s->sock.rxcnt == 0) {
+ __tcp_close(&s->sock);
+ return total;
+ }
+ } else if (s->sock.state == _CLOSED) {
+ // The connection is gone
+ s->open = false;
+ return -1;
+ } else {
+ *err = HTTP_IO;
+ return -1;
+ }
+ }
+ s->actual_len = __tcp_read(&s->sock, s->data, sizeof(s->data));
+ if (s->actual_len > 0) {
+ s->bufp = s->data;
+ s->avail = s->actual_len;
+ if (s->pos == 0) {
+ // First data - need to scan HTTP response header
+ if (strncmp(s->bufp, "HTTP/", 5) == 0) {
+ // Should look like "HTTP/1.1 200 OK"
+ s->bufp += 5;
+ s->avail -= 5;
+ // Find first space
+ while ((s->avail > 0) && (*s->bufp != ' ')) {
+ s->bufp++;
+ s->avail--;
+ }
+ // Now the integer response
+ code = 0;
+ while ((s->avail > 0) && (*s->bufp == ' ')) {
+ s->bufp++;
+ s->avail--;
+ }
+ while ((s->avail > 0) && isdigit(*s->bufp)) {
+ code = (code * 10) + (*s->bufp - '0');
+ s->bufp++;
+ s->avail--;
+ }
+ // Make sure it says OK
+ while ((s->avail > 0) && (*s->bufp == ' ')) {
+ s->bufp++;
+ s->avail--;
+ }
+ if (strncmp(s->bufp, "OK", 2)) {
+ switch (code) {
+ case 400:
+ *err = HTTP_BADREQ;
+ break;
+ case 404:
+ *err = HTTP_NOFILE;
+ break;
+ default:
+ *err = HTTP_BADHDR;
+ break;
+ }
+ return -1;
+ }
+ // Find \r\n\r\n - end of HTTP preamble
+ while (s->avail >= 4) {
+ // This could be done faster, but not simpler
+ if (strncmp(s->bufp, "\r\n\r\n", 4) == 0) {
+ s->bufp += 4;
+ s->avail -= 4;
+#if 0 // DEBUG - show header
+ *(s->bufp-2) = '\0';
+ diag_printf(s->data);
+#endif
+ break;
+ }
+ s->avail--;
+ s->bufp++;
+ }
+ s->pos++;
+ } else {
+ // Unrecognized response
+ *err = HTTP_BADHDR;
+ return -1;
+ }
+ }
+ } else if (s->actual_len < 0) {
+ *err = HTTP_IO;
+ return -1;
+ }
+ }
+ cnt = min(len, s->avail);
+ memcpy(buf, s->bufp, cnt);
+ s->avail -= cnt;
+ s->bufp += cnt;
+ buf += cnt;
+ total += cnt;
+ len -= cnt;
+ }
+ return total;
+}
+
+char *
+http_error(int err)
+{
+ char *errmsg = "Unknown error";
+
+ switch (err) {
+ case HTTP_NOERR:
+ return "";
+ case HTTP_BADHDR:
+ return "Unrecognized HTTP response";
+ case HTTP_BADREQ:
+ return "Bad HTTP request (check file name)";
+ case HTTP_NOFILE:
+ return "No such file";
+ case HTTP_OPEN:
+ return "Can't connect to host";
+ case HTTP_IO:
+ return "I/O error";
+ }
+ return errmsg;
+}
+
+//
+// RedBoot interface
+//
+GETC_IO_FUNCS(http_io, http_stream_open, http_stream_close,
+ 0, http_stream_read, http_error);
+RedBoot_load(http, http_io, true, true, 0);
diff --git a/cesar/ecos/packages/redboot/current/src/net/icmp.c b/cesar/ecos/packages/redboot/current/src/net/icmp.c
new file mode 100644
index 0000000000..c5f5380d77
--- /dev/null
+++ b/cesar/ecos/packages/redboot/current/src/net/icmp.c
@@ -0,0 +1,126 @@
+//==========================================================================
+//
+// net/icmp.c
+//
+// Stand-alone ICMP networking support for RedBoot
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): gthomas
+// Contributors: gthomas
+// Date: 2000-07-14
+// Purpose:
+// Description:
+//
+// This code is part of RedBoot (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <net/net.h>
+
+/*
+ * Handle ICMP packets.
+ */
+static void default_icmp_handler(pktbuf_t *pkt, ip_route_t *dest);
+
+static icmp_handler_t icmp_handler = default_icmp_handler;
+
+/*
+ * Install a user defined user_handler for incoming icmp packets.
+ * Returns zero if successful, -1 if the user_handler is already used.
+ */
+int
+__icmp_install_listener(icmp_handler_t user_handler)
+{
+ if (icmp_handler == user_handler) {
+ return -1;
+ }
+ icmp_handler = user_handler;
+ return 0;
+}
+
+
+/*
+ * Replace a user defined handler by the default handler.
+ */
+void
+__icmp_remove_listener(void)
+{
+ if (icmp_handler != default_icmp_handler) {
+ icmp_handler = default_icmp_handler;
+ }
+}
+
+/*
+ * ICMP entry point with an IP packet pkt and the destination dest a reply
+ * should be sent to.
+ */
+void
+__icmp_handler(pktbuf_t *pkt, ip_route_t *dest)
+{
+ (*icmp_handler)(pkt, dest);
+
+ BSPLOG(bsp_log("icmp: dest[%s] type[%d] seq[%d]\n",
+ inet_ntoa(pkt->ip_hdr->destination),
+ pkt->icmp_hdr->type,
+ pkt->icmp_hdr->seqnum));
+ __pktbuf_free(pkt);
+}
+
+
+/*
+ * The default ICMP handler only handles ICMP incoming echo request and
+ * outgoing echo reply.
+ */
+static void
+default_icmp_handler(pktbuf_t *pkt, ip_route_t *dest)
+{
+ word cksum;
+
+ if (pkt->icmp_hdr->type == ICMP_TYPE_ECHOREQUEST
+ && pkt->icmp_hdr->code == 0
+ && __sum((word *)pkt->icmp_hdr, pkt->pkt_bytes, 0) == 0) {
+
+ pkt->icmp_hdr->type = ICMP_TYPE_ECHOREPLY;
+ pkt->icmp_hdr->checksum = 0;
+ cksum = __sum((word *)pkt->icmp_hdr, pkt->pkt_bytes, 0);
+ pkt->icmp_hdr->checksum = htons(cksum);
+ __ip_send(pkt, IP_PROTO_ICMP, dest);
+ }
+}
diff --git a/cesar/ecos/packages/redboot/current/src/net/inet_addr.c b/cesar/ecos/packages/redboot/current/src/net/inet_addr.c
new file mode 100644
index 0000000000..0d4d8f1db0
--- /dev/null
+++ b/cesar/ecos/packages/redboot/current/src/net/inet_addr.c
@@ -0,0 +1,118 @@
+//==========================================================================
+//
+// net/inet_addr.c
+//
+// Stand-alone IP address parsing for RedBoot
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): gthomas
+// Contributors: gthomas
+// Date: 2000-07-14
+// Purpose:
+// Description:
+//
+// This code is part of RedBoot (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <redboot.h>
+#include <net/net.h>
+
+bool
+inet_aton(const char *s, in_addr_t *addr)
+{
+ int i, val, radix, digit;
+ unsigned long res = 0;
+ bool first;
+ char c;
+
+ for (i = 0; i < 4; i++) {
+ // Parse next digit string
+ first = true;
+ val = 0;
+ radix = 10;
+ while ((c = *s++) != '\0') {
+ if (first && (c == '0') && (_tolower(*s) == 'x')) {
+ radix = 16;
+ s++; // Skip over 0x
+ c = *s++;
+ }
+ first = false;
+ if (_is_hex(c) && ((digit = _from_hex(c)) < radix)) {
+ // Valid digit
+ val = (val * radix) + digit;
+ } else if (c == '.' && i < 3) { // all but last terminate by '.'
+ break;
+ } else {
+ return false;
+ }
+ }
+ // merge result
+#ifdef __LITTLE_ENDIAN__
+ res |= val << ((3-i)*8); // 24, 16, 8, 0
+#else
+ res = (res << 8) | val;
+#endif
+ if ('\0' == c) {
+ if (0 == i) { // first field found end of string
+ res = val; // no shifting, use it as the whole thing
+ break; // permit entering a single number
+ }
+ if (3 > i) // we found end of string before getting 4 fields
+ return false;
+ }
+ // after that we check that it was 0..255 only
+ if (val &~0xff) return false;
+ }
+ addr->s_addr = htonl(res);
+ return true;
+}
+
+// Assumes address is in network byte order
+char *
+inet_ntoa(in_addr_t *addr)
+{
+ static char str[32];
+ unsigned char *ap;
+
+ ap = (unsigned char *)addr;
+ diag_sprintf(str, "%d.%d.%d.%d", ap[0], ap[1], ap[2], ap[3]);
+ return str;
+}
diff --git a/cesar/ecos/packages/redboot/current/src/net/ip.c b/cesar/ecos/packages/redboot/current/src/net/ip.c
new file mode 100644
index 0000000000..0e26591248
--- /dev/null
+++ b/cesar/ecos/packages/redboot/current/src/net/ip.c
@@ -0,0 +1,216 @@
+//==========================================================================
+//
+// net/ip.c
+//
+// Stand-alone IP networking support for RedBoot
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// 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
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): gthomas
+// Contributors: gthomas
+// Date: 2000-07-14
+// Purpose:
+// Description:
+//
+// This code is part of RedBoot (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <net/net.h>
+
+#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.
+ * 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)
+ return 1;
+
+ if (!memcmp(addr, __local_ip_addr, sizeof(ip_addr_t)))
+ return 1;
+
+ /*
+ * Consider it an address match if we haven't gotten our IP address yet.
+ * Some DHCP servers will address IP packets to the assigned address
+ * instead of a IP broadcast address.
+ */
+ if (__local_ip_addr[0] == 0 && __local_ip_addr[1] == 0 &&
+ __local_ip_addr[2] == 0 && __local_ip_addr[3] == 0)
+ return 1;
+
+ return 0;
+}
+
+
+extern void __tcp_handler(pktbuf_t *, ip_route_t *);
+
+/*
+ * Handle IP packets coming from the polled ethernet interface.
+ */
+void
+__ip_handler(pktbuf_t *pkt, enet_addr_t *src_enet_addr)
+{
+ ip_header_t *ip = pkt->ip_hdr;
+ ip_route_t r;
+ int hdr_bytes;
+
+ /* first make sure its ours and has a good checksum. */
+ if (!ip_addr_match(ip->destination) ||
+ __sum((word *)ip, ip->hdr_len << 2, 0) != 0) {
+ __pktbuf_free(pkt);
+ return;
+ }
+
+ memcpy(r.ip_addr, ip->source, sizeof(ip_addr_t));
+ memcpy(r.enet_addr, src_enet_addr, sizeof(enet_addr_t));
+
+ hdr_bytes = ip->hdr_len << 2;
+ pkt->pkt_bytes = ntohs(ip->length) - hdr_bytes;
+
+ switch (ip->protocol) {
+
+#if NET_SUPPORT_ICMP
+ case IP_PROTO_ICMP:
+ pkt->icmp_hdr = (icmp_header_t *)(((char *)ip) + hdr_bytes);
+ __icmp_handler(pkt, &r);
+ break;
+#endif
+
+#if NET_SUPPORT_TCP
+ case IP_PROTO_TCP:
+ pkt->tcp_hdr = (tcp_header_t *)(((char *)ip) + hdr_bytes);
+ __tcp_handler(pkt, &r);
+ break;
+#endif
+
+#if NET_SUPPORT_UDP
+ case IP_PROTO_UDP:
+ pkt->udp_hdr = (udp_header_t *)(((char *)ip) + hdr_bytes);
+ __udp_handler(pkt, &r);
+ break;
+#endif
+
+ default:
+ __pktbuf_free(pkt);
+ break;
+ }
+}
+
+
+/*
+ * 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.
+ */
+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;
+
+ /*
+ * 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;
+
+ ip->version = 4;
+ ip->hdr_len = hdr_bytes >> 2;
+ ip->tos = 0;
+ ip->length = htons(pkt->pkt_bytes);
+ ip->ident = htons(ip_ident);
+ ip_ident++;
+ ip->fragment = 0;
+ 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);
+ return 0;
+}
+
+
diff --git a/cesar/ecos/packages/redboot/current/src/net/net_io.c b/cesar/ecos/packages/redboot/current/src/net/net_io.c
new file mode 100644
index 0000000000..a8cd8ed35a
--- /dev/null
+++ b/cesar/ecos/packages/redboot/current/src/net/net_io.c
@@ -0,0 +1,899 @@
+//==========================================================================
+//
+// net/net_io.c
+//
+// Stand-alone network logical I/O support for RedBoot
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 Red Hat, Inc.
+// Copyright (C) 2002, 2003, 2004 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
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): gthomas
+// Contributors: gthomas
+// Date: 2000-07-14
+// Purpose:
+// Description:
+//
+// This code is part of RedBoot (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <redboot.h>
+#include <net/net.h>
+#include <cyg/hal/hal_misc.h> // Helper functions
+#include <cyg/hal/hal_if.h> // HAL I/O interfaces
+#include <cyg/hal/drv_api.h>
+#include <cyg/hal/hal_intr.h>
+#include <cyg/infra/cyg_ass.h> // assertion macros
+
+#ifdef CYGSEM_REDBOOT_FLASH_CONFIG
+#include <flash_config.h>
+
+RedBoot_config_option("GDB connection port",
+ gdb_port,
+ ALWAYS_ENABLED, true,
+ CONFIG_INT,
+ CYGNUM_REDBOOT_NETWORKING_TCP_PORT
+ );
+RedBoot_config_option("Network debug at boot time",
+ net_debug,
+ ALWAYS_ENABLED, true,
+ CONFIG_BOOL,
+ false
+ );
+#if defined(CYGHWR_NET_DRIVERS) && (CYGHWR_NET_DRIVERS > 1)
+RedBoot_config_option("Default network device",
+ net_device,
+ ALWAYS_ENABLED, true,
+ CONFIG_NETPORT,
+ CYGDAT_REDBOOT_DEFAULT_NETWORK_DEVICE
+ );
+#endif
+// Note: the following options are related. If 'bootp' is false, then
+// the other values are used in the configuration. Because of the way
+// that configuration tables are generated, they should have names which
+// are related. The configuration options will show up lexicographically
+// ordered, thus the peculiar naming. In this case, the 'use' option is
+// negated (if false, the others apply) which makes the names even more
+// confusing.
+
+#ifndef CYGSEM_REDBOOT_DEFAULT_NO_BOOTP
+#define CYGSEM_REDBOOT_DEFAULT_NO_BOOTP 0
+#endif
+RedBoot_config_option("Use BOOTP for network configuration",
+ bootp,
+ ALWAYS_ENABLED, true,
+ CONFIG_BOOL,
+ !CYGSEM_REDBOOT_DEFAULT_NO_BOOTP
+ );
+RedBoot_config_option("Local IP address",
+ bootp_my_ip,
+ "bootp", false,
+ 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,
+ ALWAYS_ENABLED, true,
+ CONFIG_IP,
+ 0
+ );
+
+// Note: the following options are related too.
+RedBoot_config_option("Force console for special debug messages",
+ info_console_force,
+ ALWAYS_ENABLED, true,
+ CONFIG_BOOL,
+ false
+ );
+RedBoot_config_option("Console number for special debug messages",
+ info_console_number,
+ "info_console_force", true,
+ CONFIG_INT,
+ 0
+ );
+#endif
+
+#define TCP_CHANNEL CYGNUM_HAL_VIRTUAL_VECTOR_COMM_CHANNELS
+
+#ifdef DEBUG_TCP
+int show_tcp = 0;
+#endif
+
+static tcp_socket_t tcp_sock;
+static int state;
+static int _timeout = 500;
+static int orig_console, orig_debug;
+
+static int in_buflen = 0;
+static unsigned char in_buf[64];
+static unsigned char *in_bufp;
+static int out_buflen = 0;
+static unsigned char out_buf[1024];
+static unsigned char *out_bufp;
+static bool flush_output_lines = false;
+
+// Functions in this module
+static void net_io_flush(void);
+static void net_io_revert_console(void);
+static void net_io_putc(void*, cyg_uint8);
+
+// Special characters used by Telnet - must be interpretted here
+#define TELNET_IAC 0xFF // Interpret as command (escape)
+#define TELNET_IP 0xF4 // Interrupt process
+#define TELNET_WONT 0xFC // I Won't do it
+#define TELNET_DO 0xFD // Will you XXX
+#define TELNET_TM 0x06 // Time marker (special DO/WONT after IP)
+
+static cyg_bool
+_net_io_getc_nonblock(void* __ch_data, cyg_uint8* ch)
+{
+ if (in_buflen == 0) {
+ __tcp_poll();
+ if (tcp_sock.state == _CLOSE_WAIT) {
+ // This connection is breaking
+ if (tcp_sock.data_bytes == 0 && tcp_sock.rxcnt == 0) {
+ __tcp_close(&tcp_sock);
+ return false;
+ }
+ }
+ if (tcp_sock.state == _CLOSED) {
+ // The connection is gone
+ net_io_revert_console();
+ *ch = '\n';
+ return true;
+ }
+ in_buflen = __tcp_read(&tcp_sock, in_buf, sizeof(in_buf));
+ in_bufp = in_buf;
+#ifdef DEBUG_TCP
+ if (show_tcp && (in_buflen > 0)) {
+ int old_console;
+ old_console = start_console();
+ diag_printf("%s:%d\n", __FUNCTION__, __LINE__);
+ diag_dump_buf(in_buf, in_buflen);
+ end_console(old_console);
+ }
+#endif // DEBUG_TCP
+ }
+ if (in_buflen) {
+ *ch = *in_bufp++;
+ in_buflen--;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+static cyg_bool
+net_io_getc_nonblock(void* __ch_data, cyg_uint8* ch)
+{
+ cyg_uint8 esc;
+
+ if (!_net_io_getc_nonblock(__ch_data, ch))
+ return false;
+
+ if (gdb_active || *ch != TELNET_IAC)
+ return true;
+
+ // Telnet escape - need to read/handle more
+ while (!_net_io_getc_nonblock(__ch_data, &esc)) ;
+
+ switch (esc) {
+ case TELNET_IAC:
+ // The other special case - escaped escape
+ return true;
+ case TELNET_IP:
+ // Special case for ^C == Interrupt Process
+ *ch = 0x03;
+ // Just in case the other end needs synchronizing
+ net_io_putc(__ch_data, TELNET_IAC);
+ net_io_putc(__ch_data, TELNET_WONT);
+ net_io_putc(__ch_data, TELNET_TM);
+ net_io_flush();
+ return true;
+ case TELNET_DO:
+ // Telnet DO option
+ while (!_net_io_getc_nonblock(__ch_data, &esc)) ;
+ // Respond with WONT option
+ net_io_putc(__ch_data, TELNET_IAC);
+ net_io_putc(__ch_data, TELNET_WONT);
+ net_io_putc(__ch_data, esc);
+ return false; // Ignore this whole thing!
+ default:
+ return false;
+ }
+}
+
+static cyg_uint8
+net_io_getc(void* __ch_data)
+{
+ cyg_uint8 ch;
+ int idle_timeout = 10; // 10ms
+
+ CYGARC_HAL_SAVE_GP();
+ while (true) {
+ if (net_io_getc_nonblock(__ch_data, &ch)) break;
+ if (--idle_timeout == 0) {
+ net_io_flush();
+ idle_timeout = 10;
+ }
+ }
+ CYGARC_HAL_RESTORE_GP();
+ return ch;
+}
+
+static void
+net_io_flush(void)
+{
+ int n;
+ char *bp = out_buf;
+
+#ifdef DEBUG_TCP
+ if (show_tcp) {
+ int old_console;
+ old_console = start_console();
+ diag_printf("%s.%d\n", __FUNCTION__, __LINE__);
+ diag_dump_buf(out_buf, out_buflen);
+ end_console(old_console);
+ }
+#endif // SHOW_TCP
+ n = __tcp_write_block(&tcp_sock, bp, out_buflen);
+ if (n < 0) {
+ // The connection is gone!
+ net_io_revert_console();
+ } else {
+ out_buflen -= n;
+ bp += n;
+ }
+ out_bufp = out_buf; out_buflen = 0;
+ // Check interrupt flag
+ if (CYGACC_CALL_IF_CONSOLE_INTERRUPT_FLAG()) {
+ CYGACC_CALL_IF_CONSOLE_INTERRUPT_FLAG_SET(0);
+ cyg_hal_user_break(0);
+ }
+}
+
+static void
+net_io_putc(void* __ch_data, cyg_uint8 c)
+{
+ static bool have_dollar, have_hash;
+ static int hash_count;
+
+ CYGARC_HAL_SAVE_GP();
+ *out_bufp++ = c;
+ if (c == '$') have_dollar = true;
+ if (have_dollar && (c == '#')) {
+ have_hash = true;
+ hash_count = 0;
+ }
+ if ((++out_buflen == sizeof(out_buf)) ||
+ (flush_output_lines && c == '\n') ||
+ (have_hash && (++hash_count == 3))) {
+ net_io_flush();
+ have_dollar = false;
+ }
+ CYGARC_HAL_RESTORE_GP();
+}
+
+static void
+net_io_write(void* __ch_data, const cyg_uint8* __buf, cyg_uint32 __len)
+{
+ int old_console;
+
+ old_console = start_console();
+ diag_printf("%s.%d\n", __FUNCTION__, __LINE__);
+ end_console(old_console);
+#if 0
+ CYGARC_HAL_SAVE_GP();
+
+ while(__len-- > 0)
+ net_io_putc(__ch_data, *__buf++);
+
+ CYGARC_HAL_RESTORE_GP();
+#endif
+}
+
+static void
+net_io_read(void* __ch_data, cyg_uint8* __buf, cyg_uint32 __len)
+{
+ int old_console;
+
+ old_console = start_console();
+ diag_printf("%s.%d\n", __FUNCTION__, __LINE__);
+ end_console(old_console);
+#if 0
+ CYGARC_HAL_SAVE_GP();
+
+ while(__len-- > 0)
+ *__buf++ = net_io_getc(__ch_data);
+
+ CYGARC_HAL_RESTORE_GP();
+#endif
+}
+
+static cyg_bool
+net_io_getc_timeout(void* __ch_data, cyg_uint8* ch)
+{
+ int delay_count;
+ cyg_bool res;
+
+ CYGARC_HAL_SAVE_GP();
+ net_io_flush(); // Make sure any output has been sent
+ delay_count = _timeout;
+
+ for(;;) {
+ res = net_io_getc_nonblock(__ch_data, ch);
+ if (res || 0 == delay_count--)
+ break;
+ }
+
+ CYGARC_HAL_RESTORE_GP();
+
+ return res;
+}
+
+static int
+net_io_control(void *__ch_data, __comm_control_cmd_t __func, ...)
+{
+ static int vector = 0;
+ int ret = 0;
+ static int irq_state = 0;
+
+ CYGARC_HAL_SAVE_GP();
+
+ switch (__func) {
+ case __COMMCTL_IRQ_ENABLE:
+ irq_state = 1;
+ if (vector == 0) {
+ vector = eth_drv_int_vector();
+ }
+ HAL_INTERRUPT_UNMASK(vector);
+ break;
+ case __COMMCTL_IRQ_DISABLE:
+ ret = irq_state;
+ irq_state = 0;
+ if (vector == 0) {
+ vector = eth_drv_int_vector();
+ }
+ HAL_INTERRUPT_MASK(vector);
+ break;
+ case __COMMCTL_DBG_ISR_VECTOR:
+ ret = vector;
+ break;
+ case __COMMCTL_SET_TIMEOUT:
+ {
+ va_list ap;
+
+ va_start(ap, __func);
+
+ ret = _timeout;
+ _timeout = va_arg(ap, cyg_uint32);
+
+ va_end(ap);
+ break;
+ }
+ case __COMMCTL_FLUSH_OUTPUT:
+ net_io_flush();
+ break;
+ case __COMMCTL_ENABLE_LINE_FLUSH:
+ flush_output_lines = true;
+ break;
+ case __COMMCTL_DISABLE_LINE_FLUSH:
+ flush_output_lines = false;
+ break;
+ default:
+ break;
+ }
+ CYGARC_HAL_RESTORE_GP();
+ return ret;
+}
+
+static int
+net_io_isr(void *__ch_data, int* __ctrlc,
+ CYG_ADDRWORD __vector, CYG_ADDRWORD __data)
+{
+ char ch;
+
+ CYGARC_HAL_SAVE_GP();
+ *__ctrlc = 0;
+ if (net_io_getc_nonblock(__ch_data, &ch)) {
+ if (ch == 0x03) {
+ *__ctrlc = 1;
+ }
+ }
+ CYGARC_HAL_RESTORE_GP();
+ return CYG_ISR_HANDLED;
+}
+
+// TEMP
+
+int
+start_console(void)
+{
+ int cur_console =
+ CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
+
+#ifdef CYGSEM_REDBOOT_FLASH_CONFIG
+ int i = 0;
+ if ( flash_get_config( "info_console_force", &i, CONFIG_BOOL) )
+ if ( i )
+ if ( ! flash_get_config( "info_console_number", &i, CONFIG_INT) )
+ i = 0; // the default, if that call failed.
+ if ( i )
+ CYGACC_CALL_IF_SET_CONSOLE_COMM(i);
+ else
+#endif
+ CYGACC_CALL_IF_SET_CONSOLE_COMM(0);
+
+ return cur_console;
+}
+
+void
+end_console(int old_console)
+{
+ // Restore original console
+ CYGACC_CALL_IF_SET_CONSOLE_COMM(old_console);
+}
+// TEMP
+
+static void
+net_io_revert_console(void)
+{
+#ifdef CYGPKG_REDBOOT_ANY_CONSOLE
+ console_selected = false;
+#endif
+ CYGACC_CALL_IF_SET_CONSOLE_COMM(orig_console);
+ CYGACC_CALL_IF_SET_DEBUG_COMM(orig_debug);
+ console_echo = true;
+}
+
+static void
+net_io_assume_console(void)
+{
+#ifdef CYGPKG_REDBOOT_ANY_CONSOLE
+ console_selected = true;
+#endif
+ console_echo = false;
+ orig_console = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
+ CYGACC_CALL_IF_SET_CONSOLE_COMM(TCP_CHANNEL);
+ orig_debug = CYGACC_CALL_IF_SET_DEBUG_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
+ CYGACC_CALL_IF_SET_DEBUG_COMM(TCP_CHANNEL);
+}
+
+static void
+net_io_init(void)
+{
+ static int init = 0;
+ if (!init) {
+ hal_virtual_comm_table_t* comm;
+ int cur = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
+
+ // Setup procs in the vector table
+ CYGACC_CALL_IF_SET_CONSOLE_COMM(TCP_CHANNEL);
+ comm = CYGACC_CALL_IF_CONSOLE_PROCS();
+ //CYGACC_COMM_IF_CH_DATA_SET(*comm, chan);
+ CYGACC_COMM_IF_WRITE_SET(*comm, net_io_write);
+ CYGACC_COMM_IF_READ_SET(*comm, net_io_read);
+ CYGACC_COMM_IF_PUTC_SET(*comm, net_io_putc);
+ CYGACC_COMM_IF_GETC_SET(*comm, net_io_getc);
+ CYGACC_COMM_IF_CONTROL_SET(*comm, net_io_control);
+ CYGACC_COMM_IF_DBG_ISR_SET(*comm, net_io_isr);
+ CYGACC_COMM_IF_GETC_TIMEOUT_SET(*comm, net_io_getc_timeout);
+
+ // Disable interrupts via this interface to set static
+ // state into correct state.
+ net_io_control( comm, __COMMCTL_IRQ_DISABLE );
+
+ // Restore original console
+ CYGACC_CALL_IF_SET_CONSOLE_COMM(cur);
+
+ init = 1;
+ gdb_active = false;
+ }
+ __tcp_listen(&tcp_sock, gdb_port);
+ state = tcp_sock.state;
+#ifdef DEBUG_TCP
+ diag_printf("show tcp = %p\n", (void *)&show_tcp);
+#endif
+}
+
+// Check for incoming TCP debug connection
+void
+net_io_test(bool is_idle)
+{
+ if (!is_idle) return; // Only care about idle case
+ if (!have_net) return;
+ __tcp_poll();
+ if (state != tcp_sock.state) {
+ // Something has changed
+ if (tcp_sock.state == _ESTABLISHED) {
+ // A new connection has arrived
+ net_io_assume_console();
+ in_bufp = in_buf; in_buflen = 1; *in_bufp = '\r';
+ out_bufp = out_buf; out_buflen = 0;
+ }
+ if (tcp_sock.state == _CLOSED) {
+ net_io_init(); // Get ready for another connection
+ }
+ }
+ state = tcp_sock.state;
+}
+
+// This schedules the 'net_io_test()' function to be run by RedBoot's
+// main command loop when idle (i.e. when no input arrives after some
+// period of time).
+RedBoot_idle(net_io_test, RedBoot_IDLE_NETIO);
+
+//
+// Network initialization
+//
+#include <cyg/io/eth/eth_drv.h>
+#include <cyg/io/eth/netdev.h>
+#include <cyg/hal/hal_tables.h>
+
+// Define table boundaries
+CYG_HAL_TABLE_BEGIN( __NETDEVTAB__, netdev );
+CYG_HAL_TABLE_END( __NETDEVTAB_END__, netdev );
+
+RedBoot_init(net_init, RedBoot_INIT_LAST);
+
+static void
+show_addrs(void)
+{
+ diag_printf("IP: %s", inet_ntoa((in_addr_t *)&__local_ip_addr));
+#ifdef CYGSEM_REDBOOT_NETWORKING_USE_GATEWAY
+ diag_printf("/%s", inet_ntoa((in_addr_t *)&__local_ip_mask));
+ diag_printf(", Gateway: %s\n", inet_ntoa((in_addr_t *)&__local_ip_gate));
+#else
+ diag_printf(", ");
+#endif
+ diag_printf("Default server: %s", inet_ntoa(&my_bootp_info.bp_siaddr));
+#ifdef CYGPKG_REDBOOT_NETWORKING_DNS
+ show_dns();
+#endif
+ diag_printf("\n");
+}
+
+#ifdef CYGSEM_REDBOOT_FLASH_CONFIG
+static void
+flash_get_IP(char *id, ip_addr_t *val)
+{
+ ip_addr_t my_ip;
+ int i;
+
+ if (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];
+ }
+ }
+}
+#endif
+
+static cyg_netdevtab_entry_t *
+net_devtab_entry(unsigned index)
+{
+ cyg_netdevtab_entry_t *t = &__NETDEVTAB__[index];
+
+ if (t < &__NETDEVTAB__[0] || t >= &__NETDEVTAB_END__)
+ return NULL;
+
+ return t;
+}
+
+const char *
+net_devname(unsigned index)
+{
+ cyg_netdevtab_entry_t *t = net_devtab_entry(index);
+ if (t)
+ return t->name;
+ return NULL;
+}
+
+int
+net_devindex(char *name)
+{
+ const char *devname;
+ int index;
+
+ for (index = 0; (devname = net_devname(index)) != NULL; index++)
+ if (!strcmp(name, devname))
+ return index;
+ return -1;
+}
+
+static void
+show_eth_info(void)
+{
+ diag_printf("Ethernet %s: MAC address %02x:%02x:%02x:%02x:%02x:%02x\n",
+ __local_enet_sc->dev_name,
+ __local_enet_addr[0],
+ __local_enet_addr[1],
+ __local_enet_addr[2],
+ __local_enet_addr[3],
+ __local_enet_addr[4],
+ __local_enet_addr[5]);
+}
+
+void
+net_init(void)
+{
+ cyg_netdevtab_entry_t *t;
+ unsigned index;
+ struct eth_drv_sc *primary_net = (struct eth_drv_sc *)0;
+#if defined(CYGHWR_NET_DRIVERS) && (CYGHWR_NET_DRIVERS > 1)
+ char *default_devname;
+ int default_index;
+#endif
+#ifdef CYGDAT_REDBOOT_DEFAULT_BOOTP_SERVER_IP_ADDR
+ char ip_addr[16];
+#endif
+
+ // Set defaults as appropriate
+#ifdef CYGSEM_REDBOOT_DEFAULT_NO_BOOTP
+ use_bootp = false;
+#else
+ use_bootp = true;
+#endif
+#ifdef CYGDBG_REDBOOT_NET_DEBUG
+ net_debug = true;
+#else
+ net_debug = false;
+#endif
+ gdb_port = CYGNUM_REDBOOT_NETWORKING_TCP_PORT;
+#ifdef CYGSEM_REDBOOT_FLASH_CONFIG
+ // Fetch values from saved config data, if available
+#if defined(CYGHWR_NET_DRIVERS) && (CYGHWR_NET_DRIVERS > 1)
+ flash_get_config("net_device", &default_devname, CONFIG_NETPORT);
+#endif
+ flash_get_config("net_debug", &net_debug, CONFIG_BOOL);
+ flash_get_config("gdb_port", &gdb_port, CONFIG_INT);
+ flash_get_config("bootp", &use_bootp, CONFIG_BOOL);
+ if (!use_bootp) {
+ 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
+ }
+#endif
+# ifdef CYGDBG_IO_ETH_DRIVERS_DEBUG
+ // Don't override if the user has deliberately set something more
+ // verbose.
+ if (0 == cyg_io_eth_net_debug)
+ cyg_io_eth_net_debug = net_debug;
+# endif
+ have_net = false;
+ // Make sure the recv buffers are set up
+ eth_drv_buffers_init();
+ __pktbuf_init();
+
+ // Initialize network device(s).
+#if defined(CYGHWR_NET_DRIVERS) && (CYGHWR_NET_DRIVERS > 1)
+ default_index = net_devindex(default_devname);
+ if (default_index < 0)
+ default_index = 0;
+#ifdef CYGSEM_REDBOOT_NETWORK_INIT_ONE_DEVICE
+ if ((t = net_devtab_entry(default_index)) != NULL && t->init(t)) {
+ t->status = CYG_NETDEVTAB_STATUS_AVAIL;
+ primary_net = __local_enet_sc;
+ } else
+#endif
+#endif
+ for (index = 0; (t = net_devtab_entry(index)) != NULL; index++) {
+#ifdef CYGSEM_REDBOOT_NETWORK_INIT_ONE_DEVICE
+ if (index == default_index)
+ continue;
+#endif
+ if (t->init(t)) {
+ t->status = CYG_NETDEVTAB_STATUS_AVAIL;
+ if (primary_net == (struct eth_drv_sc *)0) {
+ primary_net = __local_enet_sc;
+ }
+#if defined(CYGHWR_NET_DRIVERS) && (CYGHWR_NET_DRIVERS > 1)
+ if (index == default_index) {
+ primary_net = __local_enet_sc;
+ }
+#endif
+ }
+ }
+ __local_enet_sc = primary_net;
+
+ if (!__local_enet_sc) {
+ diag_printf("No network interfaces found\n");
+ return;
+ }
+ // Initialize the network [if present]
+ if (use_bootp) {
+ if (__bootp_find_local_ip(&my_bootp_info) == 0) {
+ have_net = true;
+ } else {
+ // Is it an unset address, or has it been set to a static addr
+ if (__local_ip_addr[0] == 0 && __local_ip_addr[1] == 0 &&
+ __local_ip_addr[2] == 0 && __local_ip_addr[3] == 0) {
+ show_eth_info();
+ diag_printf("Can't get BOOTP info for device!\n");
+ } else {
+ diag_printf("Can't get BOOTP info, using default IP address\n");
+ have_net = true;
+ }
+ }
+ } else {
+ if (__local_ip_addr[0] == 0 && __local_ip_addr[1] == 0 &&
+ __local_ip_addr[2] == 0 && __local_ip_addr[3] == 0) {
+ show_eth_info();
+ diag_printf("No IP info for device!\n");
+ } else {
+ enet_addr_t enet_addr;
+ have_net = true; // Assume values in FLASH were OK
+ // Tell the world that we are using this fixed IP address
+ if (__arp_request((ip_addr_t *)__local_ip_addr, &enet_addr, 1) >= 0) {
+ diag_printf("Warning: IP address %s in use\n", inet_ntoa((in_addr_t *)&__local_ip_addr));
+ }
+ }
+ }
+ if (have_net) {
+ show_eth_info();
+#ifdef CYGDAT_REDBOOT_DEFAULT_BOOTP_SERVER_IP_ADDR
+ diag_sprintf(ip_addr, "%d.%d.%d.%d",
+ CYGDAT_REDBOOT_DEFAULT_BOOTP_SERVER_IP_ADDR);
+ inet_aton(ip_addr, &my_bootp_info.bp_siaddr);
+#endif
+#ifdef CYGSEM_REDBOOT_FLASH_CONFIG
+ flash_get_IP("bootp_server_ip", (ip_addr_t *)&my_bootp_info.bp_siaddr);
+#endif
+#ifdef CYGPKG_REDBOOT_NETWORKING_DNS
+ redboot_dns_res_init();
+#endif
+ show_addrs();
+ net_io_init();
+ }
+}
+
+static char usage[] = "[-b] [-l <local_ip_address>[/<mask_len>]] [-h <server_address>]"
+#ifdef CYGPKG_REDBOOT_NETWORKING_DNS
+ " [-d <dns_server_address]"
+#endif
+ ;
+
+// Exported CLI function
+static void do_ip_addr(int argc, char *argv[]);
+RedBoot_cmd("ip_address",
+ "Set/change IP addresses",
+ usage,
+ do_ip_addr
+ );
+
+void
+do_ip_addr(int argc, char *argv[])
+{
+ struct option_info opts[4];
+ char *ip_addr, *host_addr;
+ bool ip_addr_set, host_addr_set;
+ bool do_bootp = false;
+ struct sockaddr_in host;
+#ifdef CYGPKG_REDBOOT_NETWORKING_DNS
+ char *dns_addr;
+ bool dns_addr_set;
+#endif
+ int num_opts;
+
+ init_opts(&opts[0], 'l', true, OPTION_ARG_TYPE_STR,
+ (void *)&ip_addr, (bool *)&ip_addr_set, "local IP address");
+ init_opts(&opts[1], 'h', true, OPTION_ARG_TYPE_STR,
+ (void *)&host_addr, (bool *)&host_addr_set, "default server address");
+ init_opts(&opts[2], 'b', false, OPTION_ARG_TYPE_FLG,
+ &do_bootp, 0, "use BOOTP");
+ num_opts = 3;
+#ifdef CYGPKG_REDBOOT_NETWORKING_DNS
+ init_opts(&opts[num_opts], 'd', true, OPTION_ARG_TYPE_STR,
+ (void *)&dns_addr, (bool *)&dns_addr_set, "DNS server address");
+ num_opts++;
+#endif
+
+ CYG_ASSERT(num_opts <= NUM_ELEMS(opts), "Too many options");
+
+ if (!scan_opts(argc, argv, 1, opts, num_opts, 0, 0, "")) {
+ return;
+ }
+ if (do_bootp) {
+ if (__bootp_find_local_ip(&my_bootp_info) != 0) {
+ diag_printf("Failed to get BOOTP address\n");
+ }
+ }
+ if (ip_addr_set) {
+#ifdef CYGSEM_REDBOOT_NETWORKING_USE_GATEWAY
+ char *slash_pos;
+ /* see if the (optional) mask length was given */
+ if( (slash_pos = strchr(ip_addr, '/')) ) {
+ int mask_len;
+ unsigned long mask;
+ *slash_pos = '\0';
+ slash_pos++;
+ if( !parse_num(slash_pos, (unsigned long *)&mask_len, 0, 0) ||
+ mask_len <= 0 || mask_len > 32 ) {
+ diag_printf("Invalid mask length: %s\n", slash_pos);
+ return;
+ }
+ mask = htonl((0xffffffff << (32-mask_len))&0xffffffff);
+ memcpy(&__local_ip_mask, &mask, 4);
+ }
+#endif
+ if (!_gethostbyname(ip_addr, (in_addr_t *)&host)) {
+ diag_printf("Invalid local IP address: %s\n", ip_addr);
+ return;
+ }
+ // Of course, each address goes in its own place :-)
+ memcpy(&__local_ip_addr, &host.sin_addr, sizeof(host.sin_addr));
+ }
+ if (host_addr_set) {
+ if (!_gethostbyname(host_addr, (in_addr_t *)&host)) {
+ diag_printf("Invalid server address: %s\n", host_addr);
+ return;
+ }
+ my_bootp_info.bp_siaddr = host.sin_addr;
+ }
+#ifdef CYGPKG_REDBOOT_NETWORKING_DNS
+ if (dns_addr_set) {
+ set_dns(dns_addr);
+ }
+#endif
+ show_addrs();
+ if (!have_net) {
+ have_net = true;
+ net_io_init();
+ }
+}
+
+// EOF net_io.c
diff --git a/cesar/ecos/packages/redboot/current/src/net/ping.c b/cesar/ecos/packages/redboot/current/src/net/ping.c
new file mode 100644
index 0000000000..74dcb0712a
--- /dev/null
+++ b/cesar/ecos/packages/redboot/current/src/net/ping.c
@@ -0,0 +1,248 @@
+//==========================================================================
+//
+// ping.c
+//
+// Network utility - ping
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2003 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
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): gthomas
+// Contributors: gthomas
+// Date: 2001-01-22
+// Purpose:
+// Description:
+//
+// This code is part of RedBoot (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <redboot.h>
+#include <net/net.h>
+
+#ifndef CYGPKG_REDBOOT_NETWORKING
+#error CYGPKG_REDBOOT_NETWORKING required!
+#else
+
+static void do_ping(int argc, char *argv[]);
+RedBoot_cmd("ping",
+ "Network connectivity test",
+ "[-v] [-n <count>] [-l <length>] [-t <timeout>] [-r <rate>]\n"
+ " [-i <IP_addr>] -h <IP_addr>",
+ do_ping
+ );
+
+static bool icmp_received;
+static icmp_header_t hold_hdr;
+
+static void
+handle_icmp(pktbuf_t *pkt, ip_route_t *src_route)
+{
+ icmp_header_t *icmp;
+ unsigned short cksum;
+
+ icmp = pkt->icmp_hdr;
+ if (icmp->type == ICMP_TYPE_ECHOREQUEST
+ && icmp->code == 0
+ && __sum((word *)icmp, pkt->pkt_bytes, 0) == 0) {
+
+ icmp->type = ICMP_TYPE_ECHOREPLY;
+ icmp->checksum = 0;
+ cksum = __sum((word *)icmp, pkt->pkt_bytes, 0);
+ icmp->checksum = htons(cksum);
+ __ip_send(pkt, IP_PROTO_ICMP, src_route);
+ } else if (icmp->type == ICMP_TYPE_ECHOREPLY) {
+ memcpy(&hold_hdr, icmp, sizeof(*icmp));
+ icmp_received = true;
+ }
+}
+
+static void
+do_ping(int argc, char *argv[])
+{
+ struct option_info opts[7];
+ long count, timeout, length, rate, start_time, end_time, timer, received, tries;
+ char *local_ip_addr, *host_ip_addr;
+ bool local_ip_addr_set, host_ip_addr_set, count_set,
+ timeout_set, length_set, rate_set, verbose;
+ struct sockaddr_in local_addr, host_addr;
+ ip_addr_t hold_addr;
+ icmp_header_t *icmp;
+ pktbuf_t *pkt;
+ ip_header_t *ip;
+ unsigned short cksum;
+ ip_route_t dest_ip;
+
+ init_opts(&opts[0], 'n', true, OPTION_ARG_TYPE_NUM,
+ (void *)&count, (bool *)&count_set, "<count> - number of packets to test");
+ init_opts(&opts[1], 't', true, OPTION_ARG_TYPE_NUM,
+ (void *)&timeout, (bool *)&timeout_set, "<timeout> - max #ms per packet [rount trip]");
+ init_opts(&opts[2], 'i', true, OPTION_ARG_TYPE_STR,
+ (void *)&local_ip_addr, (bool *)&local_ip_addr_set, "local IP address");
+ init_opts(&opts[3], 'h', true, OPTION_ARG_TYPE_STR,
+ (void *)&host_ip_addr, (bool *)&host_ip_addr_set, "host name or IP address");
+ init_opts(&opts[4], 'l', true, OPTION_ARG_TYPE_NUM,
+ (void *)&length, (bool *)&length_set, "<length> - size of payload");
+ init_opts(&opts[5], 'v', false, OPTION_ARG_TYPE_FLG,
+ (void *)&verbose, (bool *)0, "verbose operation");
+ init_opts(&opts[6], 'r', true, OPTION_ARG_TYPE_NUM,
+ (void *)&rate, (bool *)&rate_set, "<rate> - time between packets");
+ if (!scan_opts(argc, argv, 1, opts, 7, (void **)0, 0, "")) {
+ diag_printf("PING - Invalid option specified\n");
+ return;
+ }
+ // Set defaults; this has to be done _after_ the scan, since it will
+ // have destroyed all values not explicitly set.
+ if (local_ip_addr_set) {
+ if (!_gethostbyname(local_ip_addr, (in_addr_t *)&local_addr)) {
+ diag_printf("PING - Invalid local name: %s\n", local_ip_addr);
+ return;
+ }
+ } else {
+ memcpy((in_addr_t *)&local_addr, __local_ip_addr, sizeof(__local_ip_addr));
+ }
+ if (host_ip_addr_set) {
+ if (!_gethostbyname(host_ip_addr, (in_addr_t *)&host_addr)) {
+ diag_printf("PING - Invalid host name: %s\n", host_ip_addr);
+ return;
+ }
+ if (__arp_lookup((ip_addr_t *)&host_addr.sin_addr, &dest_ip) < 0) {
+ diag_printf("PING: Cannot reach server '%s' (%s)\n",
+ host_ip_addr, inet_ntoa((in_addr_t *)&host_addr));
+ return;
+ }
+ } else {
+ diag_printf("PING - host name or IP address required\n");
+ return;
+ }
+#define DEFAULT_LENGTH 64
+#define DEFAULT_COUNT 10
+#define DEFAULT_TIMEOUT 1000
+#define DEFAULT_RATE 1000
+ if (!rate_set) {
+ rate = DEFAULT_RATE;
+ }
+ if (!length_set) {
+ length = DEFAULT_LENGTH;
+ }
+ if ((length < 64) || (length > 1400)) {
+ diag_printf("Invalid length specified: %ld\n", length);
+ return;
+ }
+ if (!count_set) {
+ count = DEFAULT_COUNT;
+ }
+ if (!timeout_set) {
+ timeout = DEFAULT_TIMEOUT;
+ }
+ // Note: two prints here because 'inet_ntoa' returns a static pointer
+ diag_printf("Network PING - from %s",
+ inet_ntoa((in_addr_t *)&local_addr));
+ diag_printf(" to %s\n",
+ inet_ntoa((in_addr_t *)&host_addr));
+ received = 0;
+ __icmp_install_listener(handle_icmp);
+ // Save default "local" address
+ memcpy(hold_addr, __local_ip_addr, sizeof(hold_addr));
+ for (tries = 0; tries < count; tries++) {
+ // The network stack uses the global variable '__local_ip_addr'
+ memcpy(__local_ip_addr, &local_addr, sizeof(__local_ip_addr));
+ // Build 'ping' request
+ if ((pkt = __pktbuf_alloc(ETH_MAX_PKTLEN)) == NULL) {
+ // Give up if no packets - something is wrong
+ break;
+ }
+
+ icmp = pkt->icmp_hdr;
+ ip = pkt->ip_hdr;
+ pkt->pkt_bytes = length + sizeof(icmp_header_t);
+
+ icmp->type = ICMP_TYPE_ECHOREQUEST;
+ icmp->code = 0;
+ icmp->checksum = 0;
+ icmp->seqnum = htons(tries+1);
+ cksum = __sum((word *)icmp, pkt->pkt_bytes, 0);
+ icmp->checksum = htons(cksum);
+
+ memcpy(ip->source, (in_addr_t *)&local_addr, sizeof(ip_addr_t));
+ memcpy(ip->destination, (in_addr_t *)&host_addr, sizeof(ip_addr_t));
+ ip->protocol = IP_PROTO_ICMP;
+ ip->length = htons(pkt->pkt_bytes);
+
+ __ip_send(pkt, IP_PROTO_ICMP, &dest_ip);
+ __pktbuf_free(pkt);
+
+ start_time = MS_TICKS();
+ timer = start_time + timeout;
+ icmp_received = false;
+ while (!icmp_received && (MS_TICKS_DELAY() < timer)) {
+ if (_rb_break(1)) {
+ goto abort;
+ }
+ MS_TICKS_DELAY();
+ __enet_poll();
+ }
+ end_time = MS_TICKS();
+
+ timer = MS_TICKS() + rate;
+ while (MS_TICKS_DELAY() < timer) {
+ if (_rb_break(1)) {
+ goto abort;
+ }
+ MS_TICKS_DELAY();
+ __enet_poll();
+ }
+
+ if (icmp_received) {
+ received++;
+ if (verbose) {
+ diag_printf(" seq: %d, time: %ld (ticks)\n",
+ ntohs(hold_hdr.seqnum), end_time-start_time);
+ }
+ }
+ }
+ abort:
+ __icmp_remove_listener();
+ // Clean up
+ memcpy(__local_ip_addr, &hold_addr, sizeof(__local_ip_addr));
+ // Report
+ diag_printf("PING - received %ld of %ld expected\n", received, count);
+}
+
+#endif //CYGPKG_REDBOOT_NETWORKING
diff --git a/cesar/ecos/packages/redboot/current/src/net/pktbuf.c b/cesar/ecos/packages/redboot/current/src/net/pktbuf.c
new file mode 100644
index 0000000000..584e84befa
--- /dev/null
+++ b/cesar/ecos/packages/redboot/current/src/net/pktbuf.c
@@ -0,0 +1,167 @@
+//==========================================================================
+//
+// net/pktbuf.c
+//
+// Stand-alone network packet support for RedBoot
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): gthomas
+// Contributors: gthomas
+// Date: 2000-07-14
+// Purpose:
+// Description:
+//
+// This code is part of RedBoot (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <redboot.h>
+#include <net/net.h>
+
+#define MAX_PKTBUF CYGNUM_REDBOOT_NETWORKING_MAX_PKTBUF
+
+#define BUFF_STATS 1
+
+#if BUFF_STATS
+int max_alloc = 0;
+int num_alloc = 0;
+int num_free = 0;
+#endif
+
+static pktbuf_t pktbuf_list[MAX_PKTBUF];
+static word bufdata[MAX_PKTBUF][ETH_MAX_PKTLEN/2 + 1];
+static pktbuf_t *free_list;
+
+
+/*
+ * Initialize the free list.
+ */
+void
+__pktbuf_init(void)
+{
+ int i;
+ word *p;
+ static int init = 0;
+
+ if (init) return;
+ init = 1;
+
+ for (i = 0; i < MAX_PKTBUF; i++) {
+ p = bufdata[i];
+ if ((((unsigned long)p) & 2) != 0)
+ ++p;
+ pktbuf_list[i].buf = p;
+ pktbuf_list[i].bufsize = ETH_MAX_PKTLEN;
+ pktbuf_list[i].next = free_list;
+ free_list = &pktbuf_list[i];
+ }
+}
+
+void
+__pktbuf_dump(void)
+{
+ int i;
+ for (i = 0; i < MAX_PKTBUF; i++) {
+ diag_printf("Buf[%d]/%p: buf: %p, len: %d/%d, next: %p\n",
+ i,
+ (void*)&pktbuf_list[i],
+ (void*)pktbuf_list[i].buf,
+ pktbuf_list[i].bufsize,
+ pktbuf_list[i].pkt_bytes,
+ (void*)pktbuf_list[i].next);
+ }
+ diag_printf("Free list = %p\n", (void*)free_list);
+}
+
+/*
+ * simple pktbuf allocation
+ */
+pktbuf_t *
+__pktbuf_alloc(int nbytes)
+{
+ pktbuf_t *p = free_list;
+
+ if (p) {
+ free_list = p->next;
+ p->ip_hdr = (ip_header_t *)p->buf;
+ p->tcp_hdr = (tcp_header_t *)(p->ip_hdr + 1);
+ p->pkt_bytes = 0;
+#if BUFF_STATS
+ ++num_alloc;
+ if ((num_alloc - num_free) > max_alloc)
+ max_alloc = num_alloc - num_free;
+#endif
+ }
+ return p;
+}
+
+
+/*
+ * free a pktbuf.
+ */
+void
+__pktbuf_free(pktbuf_t *pkt)
+{
+#if BUFF_STATS
+ --num_alloc;
+#endif
+#ifdef BSP_LOG
+ {
+ int i;
+ word *p;
+
+ for (i = 0; i < MAX_PKTBUF; i++) {
+ p = bufdata[i];
+ if ((((unsigned long)p) & 2) == 0)
+ ++p;
+ if (p == (word *)pkt)
+ break;
+ }
+ if (i < MAX_PKTBUF) {
+ BSPLOG(bsp_log("__pktbuf_free: bad pkt[%x].\n", pkt));
+ BSPLOG(while(1));
+ }
+ }
+#endif
+ pkt->next = free_list;
+ free_list = pkt;
+}
+
+
diff --git a/cesar/ecos/packages/redboot/current/src/net/tcp.c b/cesar/ecos/packages/redboot/current/src/net/tcp.c
new file mode 100644
index 0000000000..44fde44d08
--- /dev/null
+++ b/cesar/ecos/packages/redboot/current/src/net/tcp.c
@@ -0,0 +1,921 @@
+//==========================================================================
+//
+// net/tcp.c
+//
+// Stand-alone TCP networking support for RedBoot
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2003 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
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): gthomas
+// Contributors: gthomas
+// Date: 2000-07-14
+// Purpose:
+// Description:
+//
+// This code is part of RedBoot (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <net/net.h>
+#include <cyg/infra/diag.h>
+#include <cyg/hal/hal_if.h>
+
+#define MAX_TCP_SEGMENT (ETH_MAX_PKTLEN - (sizeof(eth_header_t) + sizeof(ip_header_t)))
+#define MAX_TCP_DATA (MAX_TCP_SEGMENT - sizeof(tcp_header_t))
+
+
+/* sequence number comparison macros */
+#define SEQ_LT(a,b) ((int)((a)-(b)) < 0)
+#define SEQ_LE(a,b) ((int)((a)-(b)) <= 0)
+#define SEQ_GT(a,b) ((int)((a)-(b)) > 0)
+#define SEQ_GE(a,b) ((int)((a)-(b)) >= 0)
+
+/* Set a timer which will send an RST and abort a connection. */
+static timer_t abort_timer;
+
+static void do_retrans(void *p);
+static void do_close(void *p);
+
+#ifdef BSP_LOG
+static char *
+flags_to_str(octet f)
+{
+ static char str[7], *p;
+
+ p = str;
+
+ if (f & TCP_FLAG_FIN)
+ *p++ = 'F';
+ if (f & TCP_FLAG_SYN)
+ *p++ = 'S';
+ if (f & TCP_FLAG_RST)
+ *p++ = 'R';
+ if (f & TCP_FLAG_PSH)
+ *p++ = 'P';
+ if (f & TCP_FLAG_ACK)
+ *p++ = 'A';
+ if (f & TCP_FLAG_URG)
+ *p++ = 'U';
+ *p = '\0';
+ return str;
+}
+#endif
+
+/*
+ * 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 tcp_socket_t *tcp_list;
+
+/*
+ * Format and send an outgoing segment.
+ */
+static void
+tcp_send(tcp_socket_t *s, int flags, int resend)
+{
+ tcp_header_t *tcp;
+ ip_header_t *ip;
+ pktbuf_t *pkt = &s->pkt;
+ unsigned short cksum;
+ dword tcp_magic;
+ int tcp_magic_size = sizeof(tcp_magic);
+
+ ip = pkt->ip_hdr;
+ tcp = pkt->tcp_hdr;
+
+ if (flags & TCP_FLAG_SYN) {
+ /* If SYN, assume no data and send MSS option in tcp header */
+ pkt->pkt_bytes = sizeof(tcp_header_t) + 4;
+ tcp->hdr_len = 6;
+ tcp_magic = htonl(0x02040000 | MAX_TCP_DATA);
+ memcpy((unsigned char *)(tcp+1), &tcp_magic, tcp_magic_size);
+ s->data_bytes = 0;
+ } else {
+ pkt->pkt_bytes = s->data_bytes + sizeof(tcp_header_t);
+ tcp->hdr_len = 5;
+ }
+
+ /* tcp header */
+ tcp->reserved = 0;
+ tcp->seqnum = htonl(s->seq);
+ tcp->acknum = htonl(s->ack);
+ tcp->checksum = 0;
+
+ if (!resend) {
+ tcp->src_port = htons(s->our_port);
+ tcp->dest_port = htons(s->his_port);
+ tcp->flags = flags;
+ /* always set PUSH flag if sending data */
+ if (s->data_bytes)
+ tcp->flags |= TCP_FLAG_PSH;
+ tcp->window = htons(MAX_TCP_DATA);
+ tcp->urgent = 0;
+
+ /* fill in some pseudo-header fields */
+ memcpy(ip->source, __local_ip_addr, sizeof(ip_addr_t));
+ memcpy(ip->destination, s->his_addr.ip_addr, sizeof(ip_addr_t));
+ ip->protocol = IP_PROTO_TCP;
+ }
+
+ /* another pseudo-header field */
+ ip->length = htons(pkt->pkt_bytes);
+
+ /* compute tcp checksum */
+ cksum = __sum((word *)tcp, pkt->pkt_bytes, __pseudo_sum(ip));
+ tcp->checksum = htons(cksum);
+
+ __ip_send(pkt, IP_PROTO_TCP, &s->his_addr);
+
+ // HACK! If this delay is not present, then if the target system sends
+ // back data (not just an ACK), then somehow we miss it :-(
+ CYGACC_CALL_IF_DELAY_US(2*1000);
+
+ BSPLOG(bsp_log("tcp_send: state[%d] flags[%s] ack[%x] data[%d].\n",
+ s->state, flags_to_str(tcp->flags), s->ack, s->data_bytes));
+
+ if (s->state == _TIME_WAIT) {
+ // If 'reuse' is set on socket, close after 1 second, otherwise 2 minutes
+ __timer_set(&s->timer, s->reuse ? 1000 : 120000, do_close, s);
+ }
+ else if ((tcp->flags & (TCP_FLAG_FIN | TCP_FLAG_SYN)) || s->data_bytes)
+ __timer_set(&s->timer, 1000, do_retrans, s);
+}
+
+static pktbuf_t ack_pkt;
+static word ack_buf[ETH_MIN_PKTLEN/sizeof(word)];
+
+/*
+ * Send an ack.
+ */
+static void
+send_ack(tcp_socket_t *s)
+{
+ tcp_header_t *tcp;
+ ip_header_t *ip;
+ unsigned short cksum;
+
+ ack_pkt.buf = ack_buf;
+ ack_pkt.bufsize = sizeof(ack_buf);
+ ack_pkt.ip_hdr = ip = (ip_header_t *)ack_buf;
+ ack_pkt.tcp_hdr = tcp = (tcp_header_t *)(ip + 1);
+ ack_pkt.pkt_bytes = sizeof(tcp_header_t);
+
+ /* tcp header */
+ tcp->hdr_len = 5;
+ tcp->reserved = 0;
+ tcp->seqnum = htonl(s->seq);
+ tcp->acknum = htonl(s->ack);
+ tcp->checksum = 0;
+
+ tcp->src_port = htons(s->our_port);
+ tcp->dest_port = htons(s->his_port);
+ tcp->flags = TCP_FLAG_ACK;
+
+ tcp->window = htons(MAX_TCP_DATA);
+ tcp->urgent = 0;
+
+ /* fill in some pseudo-header fields */
+ memcpy(ip->source, __local_ip_addr, sizeof(ip_addr_t));
+ memcpy(ip->destination, s->his_addr.ip_addr, sizeof(ip_addr_t));
+ ip->protocol = IP_PROTO_TCP;
+
+ /* another pseudo-header field */
+ ip->length = htons(sizeof(tcp_header_t));
+
+ /* compute tcp checksum */
+ cksum = __sum((word *)tcp, sizeof(*tcp), __pseudo_sum(ip));
+ tcp->checksum = htons(cksum);
+
+ __ip_send(&ack_pkt, IP_PROTO_TCP, &s->his_addr);
+}
+
+
+/*
+ * Send a reset for a bogus incoming segment.
+ */
+static void
+send_reset(pktbuf_t *pkt, ip_route_t *r)
+{
+ ip_header_t *ip = pkt->ip_hdr;
+ tcp_header_t *tcp = pkt->tcp_hdr;
+ dword seq, ack;
+ word src, dest;
+ word cksum;
+
+ seq = ntohl(tcp->acknum);
+ ack = ntohl(tcp->seqnum);
+ src = ntohs(tcp->dest_port);
+ dest = ntohs(tcp->src_port);
+
+ tcp = (tcp_header_t *)(ip + 1);
+ pkt->pkt_bytes = sizeof(tcp_header_t);
+
+ /* tcp header */
+ tcp->hdr_len = 5;
+ tcp->reserved = 0;
+ tcp->seqnum = htonl(seq);
+ tcp->acknum = htonl(ack);
+ tcp->window = htons(1024);
+ tcp->urgent = 0;
+ tcp->checksum = 0;
+ tcp->src_port = htons(src);
+ tcp->dest_port = htons(dest);
+ tcp->flags = TCP_FLAG_RST | TCP_FLAG_ACK;
+
+ /* fill in some pseudo-header fields */
+ memcpy(ip->source, __local_ip_addr, sizeof(ip_addr_t));
+ memcpy(ip->destination, r->ip_addr, sizeof(ip_addr_t));
+ ip->protocol = IP_PROTO_TCP;
+ ip->length = htons(pkt->pkt_bytes);
+
+ /* compute tcp checksum */
+ cksum = __sum((word *)tcp, pkt->pkt_bytes, __pseudo_sum(ip));
+ tcp->checksum = htons(cksum);
+
+ __ip_send(pkt, IP_PROTO_TCP, r);
+}
+
+
+
+/*
+ * Remove given socket from socket list.
+ */
+static void
+unlink_socket(tcp_socket_t *s)
+{
+ tcp_socket_t *prev, *tp;
+
+ for (prev = NULL, tp = tcp_list; tp; prev = tp, tp = tp->next)
+ if (tp == s) {
+ BSPLOG(bsp_log("unlink tcp socket.\n"));
+ if (prev)
+ prev->next = s->next;
+ else
+ tcp_list = s->next;
+ }
+}
+
+/*
+ * Retransmit last packet.
+ */
+static void
+do_retrans(void *p)
+{
+ BSPLOG(bsp_log("tcp do_retrans.\n"));
+ tcp_send((tcp_socket_t *)p, 0, 1);
+}
+
+
+static void
+do_close(void *p)
+{
+ BSPLOG(bsp_log("tcp do_close.\n"));
+ /* close connection */
+ ((tcp_socket_t *)p)->state = _CLOSED;
+ unlink_socket(p);
+}
+
+
+static void
+free_rxlist(tcp_socket_t *s)
+{
+ pktbuf_t *p;
+
+ BSPLOG(bsp_log("tcp free_rxlist.\n"));
+
+ while ((p = s->rxlist) != NULL) {
+ s->rxlist = p->next;
+ __pktbuf_free(p);
+ }
+}
+
+
+/*
+ * Handle a conection reset.
+ */
+static void
+do_reset(tcp_socket_t *s)
+{
+ /* close connection */
+ s->state = _CLOSED;
+ __timer_cancel(&s->timer);
+ free_rxlist(s);
+ unlink_socket(s);
+}
+
+
+/*
+ * Extract data from incoming tcp segment.
+ * Returns true if packet is queued on rxlist, false otherwise.
+ */
+static int
+handle_data(tcp_socket_t *s, pktbuf_t *pkt)
+{
+ tcp_header_t *tcp = pkt->tcp_hdr;
+ unsigned int diff, seq;
+ int data_len;
+ char *data_ptr;
+ pktbuf_t *p;
+
+ data_len = pkt->pkt_bytes - (tcp->hdr_len << 2);
+ data_ptr = ((char *)tcp) + (tcp->hdr_len << 2);
+
+ seq = ntohl(tcp->seqnum);
+
+ BSPLOG(bsp_log("tcp data: seq[%x] len[%d].\n", seq, data_len));
+
+ if (SEQ_LE(seq, s->ack)) {
+ /*
+ * Figure difference between which byte we're expecting and which byte
+ * is sent first. Adjust data length and data pointer accordingly.
+ */
+ diff = s->ack - seq;
+ data_len -= diff;
+ data_ptr += diff;
+
+ if (data_len > 0) {
+ /* queue the new data */
+ s->ack += data_len;
+ pkt->next = NULL;
+ if ((p = s->rxlist) != NULL) {
+ while (p->next)
+ p = p->next;
+ p->next = pkt;
+ BSPLOG(bsp_log("tcp data: Add pkt[%x] len[%d].\n",
+ pkt, data_len));
+ } else {
+ s->rxlist = pkt;
+ s->rxcnt = data_len;
+ s->rxptr = data_ptr;
+ BSPLOG(bsp_log("tcp data: pkt[%x] len[%d].\n",
+ pkt, data_len));
+ }
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+static void
+handle_ack(tcp_socket_t *s, pktbuf_t *pkt)
+{
+ tcp_header_t *tcp = pkt->tcp_hdr;
+ dword ack;
+ int advance;
+ char *dp;
+
+ /* process ack value in packet */
+ ack = ntohl(tcp->acknum);
+
+ BSPLOG(bsp_log("Rcvd tcp ACK %x\n", ack));
+
+ if (SEQ_GT(ack, s->seq)) {
+ __timer_cancel(&s->timer);
+ advance = ack - s->seq;
+ if (advance > s->data_bytes)
+ advance = s->data_bytes;
+
+ BSPLOG(bsp_log("seq advance %d", advance));
+
+ if (advance > 0) {
+ s->seq += advance;
+ s->data_bytes -= advance;
+ if (s->data_bytes) {
+ /* other end ack'd only part of the pkt */
+ BSPLOG(bsp_log(" %d bytes left", s->data_bytes));
+ dp = (char *)(s->pkt.tcp_hdr + 1);
+ memcpy(dp, dp + advance, s->data_bytes);
+ }
+ }
+ }
+ BSPLOG(bsp_log("\n"));
+}
+
+
+/*
+ * Handle incoming TCP packets.
+ */
+void
+__tcp_handler(pktbuf_t *pkt, ip_route_t *r)
+{
+ tcp_header_t *tcp = pkt->tcp_hdr;
+ ip_header_t *ip = pkt->ip_hdr;
+ tcp_socket_t *prev,*s;
+ dword ack;
+ int queued = 0;
+
+ /* set length for pseudo sum calculation */
+ ip->length = htons(pkt->pkt_bytes);
+
+ if (__sum((word *)tcp, pkt->pkt_bytes, __pseudo_sum(ip)) == 0) {
+ for (prev = NULL, s = tcp_list; s; prev = s, s = s->next) {
+ if (s->our_port == ntohs(tcp->dest_port)) {
+ if (s->his_port == 0)
+ break;
+ if (s->his_port == ntohs(tcp->src_port) &&
+ !memcmp(r->ip_addr, s->his_addr.ip_addr, sizeof(ip_addr_t)))
+ break;
+ }
+ }
+
+ if (s) {
+ /* found the socket this packet belongs to */
+
+ /* refresh his ethernet address */
+ memcpy(s->his_addr.enet_addr, r->enet_addr, sizeof(enet_addr_t));
+
+ if (s->state != _SYN_RCVD && tcp->flags & TCP_FLAG_RST) {
+ BSPLOG(bsp_log("TCP_FLAG_RST rcvd\n"));
+ do_reset(s);
+ __pktbuf_free(pkt);
+ return;
+ }
+
+ switch (s->state) {
+
+ case _SYN_SENT:
+ /* active open not supported */
+ if (tcp->flags != (TCP_FLAG_SYN | TCP_FLAG_ACK)) {
+ do_reset(s);
+ __pktbuf_free(pkt);
+ return;
+ }
+ s->state = _ESTABLISHED;
+ s->ack = ntohl(tcp->seqnum) + 1;
+ s->seq = ntohl(tcp->acknum);
+ __timer_cancel(&s->timer);
+ send_ack(s);
+ break;
+
+ case _LISTEN:
+ if (tcp->flags & TCP_FLAG_SYN) {
+ s->state = _SYN_RCVD;
+ s->ack = ntohl(tcp->seqnum) + 1;
+ s->his_port = ntohs(tcp->src_port);
+ memcpy(s->his_addr.ip_addr, r->ip_addr, sizeof(ip_addr_t));
+ s->data_bytes = 0;
+
+ BSPLOG(bsp_log("SYN from %d.%d.%d.%d:%d (seq %x)\n",
+ s->his_addr.ip_addr[0],s->his_addr.ip_addr[1],
+ s->his_addr.ip_addr[2],s->his_addr.ip_addr[3],
+ s->his_port, ntohl(tcp->seqnum)));
+
+ tcp_send(s, TCP_FLAG_SYN | TCP_FLAG_ACK, 0);
+ }
+ else
+ send_reset(pkt, r);
+ break;
+
+ case _SYN_RCVD:
+ BSPLOG(bsp_log("_SYN_RCVD timer cancel.\n"));
+ __timer_cancel(&s->timer);
+
+ /* go back to _LISTEN state if reset */
+ if (tcp->flags & TCP_FLAG_RST) {
+ s->state = _LISTEN;
+
+ BSPLOG(bsp_log("_SYN_RCVD --> _LISTEN\n"));
+
+ } else if (tcp->flags & TCP_FLAG_SYN) {
+ /* apparently our SYN/ACK was lost? */
+ tcp_send(s, 0, 1);
+
+ BSPLOG(bsp_log("retransmitting SYN/ACK\n"));
+
+ } else if ((tcp->flags & TCP_FLAG_ACK) &&
+ ntohl(tcp->acknum) == (s->seq + 1)) {
+ /* we've established the connection */
+ s->state = _ESTABLISHED;
+ s->seq++;
+
+ BSPLOG(bsp_log("ACK received - connection established\n"));
+ }
+ break;
+
+ case _ESTABLISHED:
+ case _CLOSE_WAIT:
+ ack = s->ack; /* save original ack */
+ if (tcp->flags & TCP_FLAG_ACK)
+ handle_ack(s, pkt);
+
+ queued = handle_data(s, pkt);
+
+ if ((tcp->flags & TCP_FLAG_FIN) &&
+ ntohl(tcp->seqnum) == s->ack) {
+
+ BSPLOG(bsp_log("FIN received - going to _CLOSE_WAIT\n"));
+
+ s->ack++;
+ s->state = _CLOSE_WAIT;
+ }
+ /*
+ * Send an ack if neccessary.
+ */
+ if (s->ack != ack || pkt->pkt_bytes > (tcp->hdr_len << 2))
+ send_ack(s);
+ break;
+
+ case _LAST_ACK:
+ if (tcp->flags & TCP_FLAG_ACK) {
+ handle_ack(s, pkt);
+ if (ntohl(tcp->acknum) == (s->seq + 1)) {
+ BSPLOG(bsp_log("_LAST_ACK --> _CLOSED\n"));
+ s->state = _CLOSED;
+ unlink_socket(s);
+ }
+ }
+ break;
+
+ case _FIN_WAIT_1:
+ if (tcp->flags & TCP_FLAG_ACK) {
+ handle_ack(s, pkt);
+ if (ntohl(tcp->acknum) == (s->seq + 1)) {
+ /* got ACK for FIN packet */
+ s->seq++;
+ if (tcp->flags & TCP_FLAG_FIN) {
+ BSPLOG(bsp_log("_FIN_WAIT_1 --> _TIME_WAIT\n"));
+ s->ack++;
+ s->state = _TIME_WAIT;
+ send_ack(s);
+ } else {
+ s->state = _FIN_WAIT_2;
+ BSPLOG(bsp_log("_FIN_WAIT_1 --> _FIN_WAIT_2\n"));
+ }
+ break; /* All done for now */
+ }
+ }
+ /* At this point, no ACK for FIN has been seen, so check for
+ simultaneous close */
+ if (tcp->flags & TCP_FLAG_FIN) {
+ BSPLOG(bsp_log("_FIN_WAIT_1 --> _CLOSING\n"));
+ __timer_cancel(&s->timer);
+ s->ack++;
+ s->state = _CLOSING;
+ /* FIN is resent so the timeout and retry for this packet
+ will also take care of timeout and resend of the
+ previously sent FIN (which got us to FIN_WAIT_1). While
+ not technically correct, resending FIN only causes a
+ duplicate FIN (same sequence number) which should be
+ ignored by the other end. */
+ tcp_send(s, TCP_FLAG_FIN | TCP_FLAG_ACK, 0);
+ }
+ break;
+
+ case _FIN_WAIT_2:
+ queued = handle_data(s, pkt);
+ if (tcp->flags & TCP_FLAG_FIN) {
+ BSPLOG(bsp_log("_FIN_WAIT_2 --> _TIME_WAIT\n"));
+ s->ack++;
+ s->state = _TIME_WAIT;
+ send_ack(s);
+ }
+ break;
+
+ case _CLOSING:
+ if (tcp->flags & TCP_FLAG_ACK) {
+ handle_ack(s, pkt);
+ if (ntohl(tcp->acknum) == (s->seq + 1)) {
+ /* got ACK for FIN packet */
+ BSPLOG(bsp_log("_CLOSING --> _TIME_WAIT\n"));
+ __timer_cancel(&s->timer);
+ s->state = _TIME_WAIT;
+ }
+ }
+ break;
+
+ case _TIME_WAIT:
+ BSPLOG(bsp_log("_TIME_WAIT resend.\n"));
+ if (tcp->flags & TCP_FLAG_FIN)
+ tcp_send(s, 0, 1); /* just resend ack */
+ break;
+ }
+ } else {
+ BSPLOG(bsp_log("Unexpected segment from: %d.%d.%d.%d:%d\n",
+ r->ip_addr[0], r->ip_addr[1], r->ip_addr[3],
+ r->ip_addr[4], ntohs(tcp->src_port)));
+ send_reset(pkt, r);
+ }
+ }
+ if (!queued)
+ __pktbuf_free(pkt);
+}
+
+
+void
+__tcp_poll(void)
+{
+ __enet_poll();
+ __timer_poll();
+}
+
+
+int
+__tcp_listen(tcp_socket_t *s, word port)
+{
+ BSPLOG(bsp_log("tcp_listen: s[%p] port[%x]\n", s, port));
+
+ memset(s, 0, sizeof(tcp_socket_t));
+ s->state = _LISTEN;
+ s->our_port = port;
+ s->pkt.buf = (word *)s->pktbuf;
+ s->pkt.bufsize = ETH_MAX_PKTLEN;
+ s->pkt.ip_hdr = (ip_header_t *)s->pkt.buf;
+ s->pkt.tcp_hdr = (tcp_header_t *)(s->pkt.ip_hdr + 1);
+
+ s->next = tcp_list;
+
+#if 0
+ /* limit to one open socket at a time */
+ if (s->next) {
+ BSPLOG(bsp_log("tcp_listen: recursion error\n"));
+ BSPLOG(while(1));
+ }
+#endif
+
+ tcp_list = s;
+
+ return 0;
+}
+
+/*
+ * SO_REUSEADDR, no 2MSL.
+ */
+void
+__tcp_so_reuseaddr(tcp_socket_t *s)
+{
+// BSPLOG(bsp_log("__tcp_so_reuseaddr.\n"));
+ s->reuse = 0x01;
+}
+
+/*
+ * Block while waiting for all data to be transmitted.
+ */
+void
+__tcp_drain(tcp_socket_t *s)
+{
+// BSPLOG(bsp_log("__tcp_drain.\n"));
+ while (s->state != _CLOSED && s->data_bytes)
+ __tcp_poll();
+// BSPLOG(bsp_log("__tcp_drain done.\n"));
+}
+
+
+/*
+ * Close the tcp connection.
+ */
+static void
+do_abort(void *s)
+{
+ BSPLOG(bsp_log("do_abort: send RST\n"));
+ tcp_send((tcp_socket_t *)s, TCP_FLAG_ACK | TCP_FLAG_RST, 0);
+ __timer_cancel(&abort_timer);
+ ((tcp_socket_t *)s)->state = _CLOSED;
+ free_rxlist((tcp_socket_t *)s);
+ unlink_socket((tcp_socket_t *)s);
+}
+
+void
+__tcp_abort(tcp_socket_t *s, unsigned long delay)
+{
+ __timer_set(&abort_timer, delay, do_abort, s);
+}
+
+/*
+ * Close the tcp connection.
+ */
+void
+__tcp_close(tcp_socket_t *s)
+{
+ __tcp_drain(s);
+ if (s->state == _ESTABLISHED || s->state == _SYN_RCVD) {
+ BSPLOG(bsp_log("__tcp_close: going to _FIN_WAIT_1\n"));
+ s->state = _FIN_WAIT_1;
+ tcp_send(s, TCP_FLAG_ACK | TCP_FLAG_FIN, 0);
+ } else if (s->state == _CLOSE_WAIT) {
+
+ BSPLOG(bsp_log("__tcp_close: going to _LAST_ACK\n"));
+
+ s->state = _LAST_ACK;
+ tcp_send(s, TCP_FLAG_ACK | TCP_FLAG_FIN, 0);
+ }
+ free_rxlist(s);
+}
+
+
+/*
+ * Wait for connection to be fully closed.
+ */
+void
+__tcp_close_wait(tcp_socket_t *s)
+{
+ BSPLOG(bsp_log("__tcp_close_wait.\n"));
+ while (s->state != _CLOSED)
+ __tcp_poll();
+ BSPLOG(bsp_log("__tcp_close_wait done.\n"));
+}
+
+
+/*
+ * Read up to 'len' bytes without blocking.
+ */
+int
+__tcp_read(tcp_socket_t *s, char *buf, int len)
+{
+ int nread;
+ pktbuf_t *pkt;
+ tcp_header_t *tcp;
+
+ if (len <= 0 || s->rxcnt == 0)
+ return 0;
+
+ if (s->state != _ESTABLISHED && s->rxcnt == 0)
+ return -1;
+
+ nread = 0;
+ while (len) {
+ if (len < s->rxcnt) {
+ memcpy(buf, s->rxptr, len);
+ BSPLOG(bsp_log("tcp_read: read %d bytes.\n", len));
+ s->rxptr += len;
+ s->rxcnt -= len;
+ nread += len;
+
+ BSPLOG(bsp_log("tcp_read: %d bytes left in rxlist head.\n",
+ s->rxcnt));
+
+ break;
+ } else {
+ memcpy(buf, s->rxptr, s->rxcnt);
+ BSPLOG(bsp_log("tcp_read: read %d bytes. pkt[%x] freed.\n",
+ s->rxcnt, s->rxlist));
+ nread += s->rxcnt;
+ buf += s->rxcnt;
+ len -= s->rxcnt;
+
+ /* setup for next packet in list */
+ pkt = s->rxlist;
+ s->rxlist = pkt->next;
+ __pktbuf_free(pkt);
+
+ if ((pkt = s->rxlist) != NULL) {
+ tcp = pkt->tcp_hdr;
+ s->rxcnt = pkt->pkt_bytes - (tcp->hdr_len << 2);
+ s->rxptr = ((char *)tcp) + (tcp->hdr_len << 2);
+
+ BSPLOG(bsp_log("tcp_read: next pkt[%x] has %d bytes.\n",
+ s->rxlist, s->rxcnt));
+ } else {
+
+ BSPLOG(bsp_log("tcp_read: no more data.\n"));
+
+ s->rxcnt = 0;
+ break;
+ }
+ }
+ }
+ return nread;
+}
+
+
+/*
+ * Write up to 'len' bytes without blocking
+ */
+int
+__tcp_write(tcp_socket_t *s, char *buf, int len)
+{
+ tcp_header_t *tcp = s->pkt.tcp_hdr;
+
+ if (len <= 0)
+ return 0;
+
+ if (s->state != _ESTABLISHED && s->state != _CLOSE_WAIT)
+ return -1;
+
+ if (s->data_bytes)
+ return 0;
+
+ if (len > MAX_TCP_DATA)
+ len = MAX_TCP_DATA;
+
+ memcpy(tcp + 1, buf, len);
+ s->data_bytes = len;
+
+ tcp_send(s, TCP_FLAG_ACK, 0);
+
+ return len;
+}
+
+/*
+ * Write 'len' bytes from 'buf', blocking until sent.
+ * If connection collapses, return -1
+ */
+int
+__tcp_write_block(tcp_socket_t *s, char *buf, int len)
+{
+ int total = 0;
+ int n;
+
+ while (len) {
+ if (s->state == _CLOSE_WAIT) {
+ // This connection is tring to close
+ // This connection is breaking
+ if (s->data_bytes == 0 && s->rxcnt == 0)
+ __tcp_close(s);
+ }
+ if (s->state == _CLOSED) {
+ // The connection is gone!
+ return -1;
+ }
+ n = __tcp_write(s, buf, len);
+ if (n > 0) {
+ len -= n;
+ buf += n;
+ }
+ __tcp_poll();
+ }
+ __tcp_drain(s);
+ return total;
+}
+
+/*
+ * Establish a new [outgoing] connection, with a timeout.
+ */
+int
+__tcp_open(tcp_socket_t *s, struct sockaddr_in *host,
+ word port, int timeout, int *err)
+{
+ // Fill in socket details
+ memset(s, 0, sizeof(tcp_socket_t));
+ s->state = _SYN_SENT;
+ s->our_port = port;
+ s->his_port = host->sin_port;
+ s->pkt.buf = (word *)s->pktbuf;
+ s->pkt.bufsize = ETH_MAX_PKTLEN;
+ s->pkt.ip_hdr = (ip_header_t *)s->pkt.buf;
+ s->pkt.tcp_hdr = (tcp_header_t *)(s->pkt.ip_hdr + 1);
+ s->seq = (port << 16) | 0xDE77;
+ s->ack = 0;
+ if (__arp_lookup((ip_addr_t *)&host->sin_addr, &s->his_addr) < 0) {
+ diag_printf("%s: Can't find address of server\n", __FUNCTION__);
+ return -1;
+ }
+ s->next = tcp_list;
+ tcp_list = s;
+
+ // Send off the SYN packet to open the connection
+ tcp_send(s, TCP_FLAG_SYN, 0);
+ // Wait for connection to establish
+ while (s->state != _ESTABLISHED) {
+ if (s->state == _CLOSED) {
+ diag_printf("TCP open - host closed connection\n");
+ return -1;
+ }
+ if (--timeout <= 0) {
+ diag_printf("TCP open - connection timed out\n");
+ return -1;
+ }
+ MS_TICKS_DELAY();
+ __tcp_poll();
+ }
+ return 0;
+}
+
+
diff --git a/cesar/ecos/packages/redboot/current/src/net/tftp_client.c b/cesar/ecos/packages/redboot/current/src/net/tftp_client.c
new file mode 100644
index 0000000000..d4213bfeaa
--- /dev/null
+++ b/cesar/ecos/packages/redboot/current/src/net/tftp_client.c
@@ -0,0 +1,279 @@
+//==========================================================================
+//
+// net/tftp_client.c
+//
+// Stand-alone TFTP support for RedBoot
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2002, 2003 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
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): gthomas
+// Contributors: gthomas
+// Date: 2000-07-14
+// Purpose:
+// Description:
+//
+// This code is part of RedBoot (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+// TFTP client support
+
+#include <redboot.h> // have_net
+#include <net/net.h>
+#include <net/tftp.h>
+#include <net/tftp_support.h>
+
+// So we remember which ports have been used
+static int get_port = 7700;
+
+static struct {
+ bool open;
+ int total_timeouts, packets_received;
+ unsigned long last_good_block;
+ int avail, actual_len;
+ struct sockaddr_in local_addr, from_addr;
+ char data[SEGSIZE+sizeof(struct tftphdr)];
+ char *bufp;
+} tftp_stream;
+
+int
+tftp_stream_open(connection_info_t *info,
+ int *err)
+{
+ struct tftphdr *hdr = (struct tftphdr *)tftp_stream.data;
+ char *cp, *fp;
+ char test_buf;
+
+ if (!have_net || tftp_stream.open) {
+ *err = TFTP_INVALID; // Already open
+ return -1;
+ }
+
+ // Create initial request
+ hdr->th_opcode = htons(RRQ); // Read file
+ cp = (char *)&hdr->th_stuff;
+ fp = info->filename;
+ while (*fp) *cp++ = *fp++;
+ *cp++ = '\0';
+ // Since this is used for downloading data, OCTET (binary) is the
+ // only mode that makes sense.
+ fp = "OCTET";
+ while (*fp) *cp++ = *fp++;
+ *cp++ = '\0';
+
+ memset((char *)&tftp_stream.local_addr, 0, sizeof(tftp_stream.local_addr));
+ tftp_stream.local_addr.sin_family = AF_INET;
+ tftp_stream.local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+ tftp_stream.local_addr.sin_port = htons(get_port++);
+
+ if (info->server->sin_port == 0) {
+ info->server->sin_port = htons(TFTP_PORT);
+ } else {
+ info->server->sin_port = htons(info->server->sin_port);
+ }
+
+ // Send request - note: RFC 1350 (TFTP rev 2) indicates that this should be
+ // only as long as required to hold the request, with the nul terminator.
+ // Some servers silently go to lunch if the request is not the correct size.
+ if (__udp_sendto(tftp_stream.data, cp-(char *)hdr,
+ info->server, &tftp_stream.local_addr) < 0) {
+ // Problem sending request
+ *err = TFTP_NETERR;
+ return -1;
+ }
+
+ tftp_stream.open = true;
+ tftp_stream.avail = 0;
+ tftp_stream.actual_len = -1;
+ tftp_stream.last_good_block = 0;
+ tftp_stream.total_timeouts = 0;
+ tftp_stream.from_addr.sin_port = 0;
+ tftp_stream.packets_received = 0;
+
+ // Try and read the first byte [block] since no errors are
+ // reported until then.
+ if (tftp_stream_read(&test_buf, 1, err) == 1) {
+ // Back up [rewind] over this datum
+ tftp_stream.bufp--;
+ tftp_stream.avail++;
+ return 0; // Open and first read successful
+ } else {
+ tftp_stream.open = false;
+ return -1; // Couldn't read
+ }
+}
+
+static int
+tftp_ack(int *err)
+{
+ struct tftphdr *hdr = (struct tftphdr *)tftp_stream.data;
+ // ACK last packet so server can shut down
+ if (tftp_stream.packets_received > 0) {
+ hdr->th_opcode = htons(ACK);
+ hdr->th_block = htons((cyg_uint16)tftp_stream.last_good_block & 0xFFFF);
+ if (__udp_sendto(tftp_stream.data, 4 /* FIXME */,
+ &tftp_stream.from_addr, &tftp_stream.local_addr) < 0) {
+ // Problem sending ACK
+ *err = TFTP_NETERR;
+ return -1;
+ }
+ }
+ return 0;
+}
+
+void
+tftp_stream_close(int *err)
+{
+ tftp_ack(err);
+ tftp_stream.open = false;
+}
+
+int
+tftp_stream_read(char *buf,
+ int len,
+ int *err)
+{
+ int total_bytes = 0;
+ int size, recv_len, data_len;
+ struct timeval timeout;
+ struct tftphdr *hdr = (struct tftphdr *)tftp_stream.data;
+
+ while (total_bytes < len) {
+ // Move any bytes which we've already read/buffered
+ if (tftp_stream.avail > 0) {
+ size = tftp_stream.avail;
+ if (size > (len - total_bytes)) size = len - total_bytes;
+ memcpy(buf, tftp_stream.bufp, size);
+ buf += size;
+ tftp_stream.bufp += size;
+ tftp_stream.avail -= size;
+ total_bytes += size;
+ } else {
+ if (tftp_ack(err) < 0) {
+ return -1;
+ }
+ if ((tftp_stream.actual_len >= 0) && (tftp_stream.actual_len < SEGSIZE)) {
+ // Out of data
+ break;
+ }
+ timeout.tv_sec = (tftp_stream.last_good_block == 0) ? 10*TFTP_TIMEOUT_PERIOD : TFTP_TIMEOUT_PERIOD;
+ timeout.tv_usec = 0;
+ recv_len = sizeof(tftp_stream.data);
+ if ((data_len = __udp_recvfrom(&tftp_stream.data[0], recv_len, &tftp_stream.from_addr,
+ &tftp_stream.local_addr, &timeout)) < 0) {
+ // No data, try again
+ diag_printf("TFTP timed out %d/%d\n", tftp_stream.total_timeouts+1, TFTP_TIMEOUT_MAX);
+ if ((++tftp_stream.total_timeouts > TFTP_TIMEOUT_MAX) ||
+ (tftp_stream.last_good_block == 0)) {
+ // Timeout - no data received
+ *err = TFTP_TIMEOUT;
+ return -1;
+ }
+ // Send out the ACK for the last block - maybe server will retry
+ if (tftp_ack(err) < 0) {
+ return -1;
+ }
+ } else {
+ tftp_stream.packets_received++;
+ if (ntohs(hdr->th_opcode) == DATA) {
+ if (ntohs(hdr->th_block) == (cyg_uint16)((tftp_stream.last_good_block+1) & 0xFFFF)) {
+ // Consume this data
+ data_len -= 4; /* Sizeof TFTP header */
+ tftp_stream.avail = tftp_stream.actual_len = data_len;
+ tftp_stream.bufp = hdr->th_data;
+ tftp_stream.last_good_block++;
+ }
+ } else {
+ if (ntohs(hdr->th_opcode) == ERROR) {
+ *err = ntohs(hdr->th_code);
+ return -1;
+ } else {
+ // What kind of packet is this?
+ *err = TFTP_PROTOCOL;
+ return -1;
+ }
+ }
+ }
+ }
+ }
+ return total_bytes;
+}
+
+char *
+tftp_error(int err)
+{
+ char *errmsg = "Unknown error";
+
+ switch (err) {
+ case TFTP_ENOTFOUND:
+ return "file not found";
+ case TFTP_EACCESS:
+ return "access violation";
+ case TFTP_ENOSPACE:
+ return "disk full or allocation exceeded";
+ case TFTP_EBADOP:
+ return "illegal TFTP operation";
+ case TFTP_EBADID:
+ return "unknown transfer ID";
+ case TFTP_EEXISTS:
+ return "file already exists";
+ case TFTP_ENOUSER:
+ return "no such user";
+ case TFTP_TIMEOUT:
+ return "operation timed out";
+ case TFTP_NETERR:
+ return "some sort of network error";
+ case TFTP_INVALID:
+ return "invalid parameter";
+ case TFTP_PROTOCOL:
+ return "protocol violation";
+ case TFTP_TOOLARGE:
+ return "file is larger than buffer";
+ }
+ return errmsg;
+}
+
+//
+// RedBoot interface
+//
+GETC_IO_FUNCS(tftp_io, tftp_stream_open, tftp_stream_close,
+ 0, tftp_stream_read, tftp_error);
+RedBoot_load(tftp, tftp_io, true, true, 0);
+
diff --git a/cesar/ecos/packages/redboot/current/src/net/timers.c b/cesar/ecos/packages/redboot/current/src/net/timers.c
new file mode 100644
index 0000000000..79523eda85
--- /dev/null
+++ b/cesar/ecos/packages/redboot/current/src/net/timers.c
@@ -0,0 +1,135 @@
+//==========================================================================
+//
+// net/timers.c
+//
+// Stand-alone networking support for RedBoot
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): gthomas
+// Contributors: gthomas
+// Date: 2000-07-14
+// Purpose:
+// Description:
+//
+// This code is part of RedBoot (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <net/net.h>
+
+static timer_t *tmr_list;
+
+
+/*
+ * Set a timer. Caller is responsible for providing the timer_t struct.
+ */
+void
+__timer_set(timer_t *t, unsigned long delay,
+ tmr_handler_t handler, void *user_data)
+{
+ timer_t *p;
+
+ t->delay = delay;
+ t->start = MS_TICKS();
+ t->handler = handler;
+ t->user_data = user_data;
+
+ for (p = tmr_list; p; p = p->next)
+ if (p == t) {
+ return;
+ }
+
+ t->next = tmr_list;
+ tmr_list = t;
+}
+
+
+/*
+ * Remove a given timer from timer list.
+ */
+void
+__timer_cancel(timer_t *t)
+{
+ timer_t *prev, *p;
+
+ for (prev = NULL, p = tmr_list; p; prev = p, p = p->next)
+ if (p == t) {
+ if (prev)
+ prev->next = p->next;
+ else
+ tmr_list = p->next;
+ return;
+ }
+}
+
+
+/*
+ * Poll timer list for timer expirations.
+ */
+void
+__timer_poll(void)
+{
+ timer_t *prev, *t;
+
+ prev = NULL;
+ t = tmr_list;
+ while (t) {
+ if ((MS_TICKS_DELAY() - t->start) >= t->delay) {
+
+ /* remove it before calling handler */
+ if (prev)
+ prev->next = t->next;
+ else
+ tmr_list = t->next;
+ /* now, call the handler */
+ t->handler(t->user_data);
+
+ /*
+ * handler may be time consuming, so start
+ * from beginning of list.
+ */
+ prev = NULL;
+ t = tmr_list;
+ } else {
+ prev = t;
+ t = t->next;
+ }
+ }
+}
diff --git a/cesar/ecos/packages/redboot/current/src/net/udp.c b/cesar/ecos/packages/redboot/current/src/net/udp.c
new file mode 100644
index 0000000000..1ea50529a4
--- /dev/null
+++ b/cesar/ecos/packages/redboot/current/src/net/udp.c
@@ -0,0 +1,268 @@
+//==========================================================================
+//
+// net/udp.c
+//
+// Stand-alone UDP networking support for RedBoot
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004 Red Hat, Inc.
+// Copyright (C) 2002, 2003 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
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): gthomas
+// Contributors: gthomas
+// Date: 2000-07-14
+// Purpose:
+// Description:
+//
+// This code is part of RedBoot (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <redboot.h>
+#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 - (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;
+
+
+/*
+ * Install a handler for incoming udp packets.
+ * Caller provides the udp_socket_t structure.
+ * Returns zero if successful, -1 if socket is already used.
+ */
+int
+__udp_install_listener(udp_socket_t *s, word port, udp_handler_t handler)
+{
+ udp_socket_t *p;
+
+ /*
+ * Make sure we only have one handler per port.
+ */
+ for (p = udp_list; p; p = p->next)
+ if (p->our_port == port)
+ return -1;
+
+ s->our_port = htons(port);
+ s->handler = handler;
+ s->next = udp_list;
+ udp_list = s;
+
+ return 0;
+}
+
+
+/*
+ * Remove the handler for the given socket.
+ */
+void
+__udp_remove_listener(word port)
+{
+ udp_socket_t *prev, *s;
+
+ for (prev = NULL, s = udp_list; s; prev = s, s = s->next)
+ if (s->our_port == htons(port)) {
+ if (prev)
+ prev->next = s->next;
+ else
+ udp_list = s->next;
+ }
+}
+
+
+/*
+ * Handle incoming UDP packets.
+ */
+void
+__udp_handler(pktbuf_t *pkt, ip_route_t *r)
+{
+ udp_header_t *udp = pkt->udp_hdr;
+ ip_header_t *ip = pkt->ip_hdr;
+ udp_socket_t *s;
+
+ if (udp->checksum == 0xffff)
+ udp->checksum = 0;
+
+ /* copy length for pseudo sum calculation */
+ ip->length = udp->length;
+
+ if (__sum((word *)udp, ntohs(udp->length), __pseudo_sum(ip)) == 0) {
+ for (s = udp_list; s; s = s->next) {
+ if (s->our_port == udp->dest_port) {
+ (*s->handler)(s, ((char *)udp) + sizeof(udp_header_t),
+ ntohs(udp->length) - sizeof(udp_header_t),
+ r, ntohs(udp->src_port));
+ __pktbuf_free(pkt);
+ return;
+ }
+ }
+ }
+ __pktbuf_free(pkt);
+}
+
+
+/*
+ * Send a UDP packet.
+ */
+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 -1;
+
+ /* just drop it if can't get a buffer */
+ if ((pkt = __pktbuf_alloc(ETH_MAX_PKTLEN)) == NULL)
+ 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);
+ udp->checksum = 0;
+
+ memcpy(((char *)udp) + sizeof(udp_header_t), buf, len);
+
+ /* 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);
+
+ 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) {
+ 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;
+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)
+{
+ if (recvfrom_server == NULL || recvfrom_buf == NULL)
+ return;
+
+ if (recvfrom_server->sin_port && recvfrom_server->sin_port != htons(src_port))
+ return;
+
+ // Move data to waiting buffer
+ recvfrom_len = len;
+ memcpy(recvfrom_buf, buf, len);
+ if (recvfrom_server) {
+ recvfrom_server->sin_port = htons(src_port);
+ memcpy(&recvfrom_server->sin_addr, &src_route->ip_addr, sizeof(src_route->ip_addr));
+ recvfrom_buf = (char *)0; // Tell reader we got a packet
+ } else {
+ diag_printf("udp_recvfrom - dropped packet of %d bytes\n", len);
+ }
+}
+
+int
+__udp_recvfrom(char *data, int len, struct sockaddr_in *server,
+ struct sockaddr_in *local, struct timeval *timo)
+{
+ int res, my_port, total_ms;
+ udp_socket_t skt;
+ unsigned long start;
+
+ my_port = ntohs(local->sin_port);
+ if (__udp_install_listener(&skt, my_port, __udp_recvfrom_handler) < 0) {
+ return -1;
+ }
+ recvfrom_buf = data;
+ recvfrom_len = len;
+ recvfrom_server = server;
+ total_ms = (timo->tv_sec * 1000) + (timo->tv_usec / 1000);
+ start = MS_TICKS();
+ res = -1;
+ do {
+ __enet_poll(); // Handle the hardware
+ if (!recvfrom_buf) {
+ // Data have arrived
+ res = recvfrom_len;
+ break;
+ }
+ } while ((MS_TICKS_DELAY() - start) < total_ms);
+ __udp_remove_listener(my_port);
+ return res;
+}