OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /or1k/trunk/ecos-2.0/packages/redboot/v2_0/src/net
    from Rev 1254 to Rev 1765
    Reverse comparison

Rev 1254 → Rev 1765

/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() - 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;
}
}
}
/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;
}
 
 
/tftp_client.c
0,0 → 1,259
//==========================================================================
//
// 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 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;
unsigned short 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);
}
 
// 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;
 
// 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
}
}
 
void
tftp_stream_close(int *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_stream.last_good_block != 0) {
// Send out the ACK
hdr->th_opcode = htons(ACK);
hdr->th_block = htons(tftp_stream.last_good_block);
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;
}
}
if ((tftp_stream.actual_len >= 0) && (tftp_stream.actual_len < SEGSIZE)) {
// Out of data
break;
}
timeout.tv_sec = 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
if ((++tftp_stream.total_timeouts > TFTP_TIMEOUT_MAX) ||
(tftp_stream.last_good_block == 0)) {
// Timeout - no data received
*err = TFTP_TIMEOUT;
return -1;
}
} else {
if (ntohs(hdr->th_opcode) == DATA) {
if (ntohs(hdr->th_block) == (tftp_stream.last_good_block+1)) {
// 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);
 
/net_io.c
0,0 → 1,774
//==========================================================================
//
// 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 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 <redboot.h>
#include <cyg/io/eth/eth_drv.h> // Logical driver interfaces
#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>
 
#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
);
// 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.
RedBoot_config_option("Use BOOTP for network configuration",
bootp,
ALWAYS_ENABLED, true,
CONFIG_BOOL,
true
);
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,
"bootp", false,
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
 
void
net_init(void)
{
cyg_netdevtab_entry_t *t;
 
// 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
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
flash_get_config("bootp_server_ip", &my_bootp_info.bp_siaddr,
CONFIG_IP);
}
#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 all network devices
for (t = &__NETDEVTAB__[0]; t != &__NETDEVTAB_END__; t++) {
if (t->init(t)) {
t->status = CYG_NETDEVTAB_STATUS_AVAIL;
} else {
// What to do if device init fails?
t->status = 0; // Device not [currently] available
}
}
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) {
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]);
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 {
have_net = true; // Assume values in FLASH were OK
}
if (have_net) {
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]);
 
#ifdef CYGPKG_REDBOOT_NETWORKING_DNS
redboot_dns_res_init();
#endif
show_addrs();
net_io_init();
}
}
 
static char usage[] = "[-l <local_ip_address>] [-h <server_address>]";
 
// 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[3];
char *ip_addr, *host_addr;
bool ip_addr_set, host_addr_set;
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");
num_opts = 2;
#ifdef CYGPKG_REDBOOT_NETWORKING_DNS
init_opts(&opts[2], 'd', true, OPTION_ARG_TYPE_STR,
(void **)&dns_addr, (bool *)&dns_addr_set, "DNS server address");
num_opts++;
#endif
if (!scan_opts(argc, argv, 1, opts, num_opts, 0, 0, "")) {
return;
}
if (ip_addr_set) {
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
/http_client.c
0,0 → 1,240
//==========================================================================
//
// 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 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;
 
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_close(&s->sock);
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)) {
*err = HTTP_BADHDR;
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_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);
/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;
}
/arp.c
0,0 → 1,210
//==========================================================================
//
// 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 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)
{
pktbuf_t *pkt;
arp_header_t *arp;
unsigned long retry_start;
enet_addr_t bcast_addr;
int retry;
 
// 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) {
return -1;
} else {
memcpy(&routes[next_arp], rt, sizeof(*rt));
if (++next_arp == NUM_ARP) next_arp = 0;
return 0;
}
}
 
/bootp.c
0,0 → 1,226
//==========================================================================
//
// 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 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>
 
extern int net_debug;
 
#define SHOULD_BE_RANDOM 0x12345555
 
/* How many milliseconds to wait before retrying the request */
#define RETRY_TIME 1000
#define MAX_RETRIES 30
 
static bootp_header_t *bp_info;
#ifdef CYGSEM_REDBOOT_NETWORKING_USE_GATEWAY
static const unsigned char dhcpCookie[] = {99,130,83,99};
static const unsigned char dhcpEndOption[] = {255};
static const unsigned char dhcpRequestOption[] = {52,1,3};
#endif
 
static void
bootp_handler(udp_socket_t *skt, char *buf, int len,
ip_route_t *src_route, word src_port)
{
bootp_header_t *b;
#ifdef CYGSEM_REDBOOT_NETWORKING_USE_GATEWAY
unsigned char *p,*end;
int optlen;
#endif
 
b = (bootp_header_t *)buf;
if (bp_info) {
memset(bp_info,0,sizeof *bp_info);
if (len > sizeof *bp_info)
len = sizeof *bp_info;
memcpy(bp_info, b, len);
}
 
// Only accept pure REPLY responses
if (b->bp_op != BOOTREPLY)
return;
// Must be sent to me, as well!
if (memcmp(b->bp_chaddr, __local_enet_addr, 6))
return;
memcpy(__local_ip_addr, &b->bp_yiaddr, 4);
#ifdef CYGSEM_REDBOOT_NETWORKING_USE_GATEWAY
memcpy(__local_ip_gate, &b->bp_giaddr, 4);
if (memcmp(b->bp_vend, dhcpCookie, sizeof(dhcpCookie)))
return;
optlen = len - (b->bp_vend - ((unsigned char*)b));
p = b->bp_vend+4;
end = ((unsigned char*)b) + len;
while (p < end) {
unsigned char tag = *p;
if (tag == TAG_END)
break;
if (tag == TAG_PAD)
optlen = 1;
else {
optlen = p[1];
p += 2;
switch (tag) {
case TAG_SUBNET_MASK: // subnet mask
memcpy(__local_ip_mask,p,4);
break;
case TAG_GATEWAY: // router
memcpy(__local_ip_gate,p,4);
break;
default:
break;
}
}
p += optlen;
}
#endif
}
 
#define AddOption(p,d) do {memcpy(p,d,sizeof d); p += sizeof d;} while (0)
 
/*
* Find our IP address and copy to __local_ip_addr.
* 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_USE_GATEWAY
unsigned char *p;
#endif
int txSize;
 
bp_info = info;
 
memset(&b, 0, sizeof(b));
 
b.bp_op = BOOTREQUEST;
b.bp_htype = HTYPE_ETHERNET;
b.bp_hlen = 6;
b.bp_xid = SHOULD_BE_RANDOM;
#ifdef CYGSEM_REDBOOT_NETWORKING_USE_GATEWAY
p = b.bp_vend;
AddOption(p,dhcpCookie);
AddOption(p,dhcpRequestOption);
AddOption(p,dhcpEndOption);
 
// Some servers insist on a minimum amount of "vendor" data
if (p < &b.bp_vend[BP_MIN_VEND_SIZE]) p = &b.bp_vend[BP_MIN_VEND_SIZE];
txSize = p - (unsigned char*)&b;
#else
txSize = sizeof(b);
#endif
 
memcpy( saved_ip_addr, __local_ip_addr, sizeof(__local_ip_addr) );
memset( __local_ip_addr, 0, sizeof(__local_ip_addr) );
 
memcpy(b.bp_chaddr, __local_enet_addr, 6);
 
/* 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;
while (retry-- > 0) {
start = MS_TICKS();
 
__udp_send((char *)&b, txSize, &r, IPPORT_BOOTPS, IPPORT_BOOTPC);
 
do {
__enet_poll();
if (__local_ip_addr[0] || __local_ip_addr[1] ||
__local_ip_addr[2] || __local_ip_addr[3]) {
/* success */
__udp_remove_listener(IPPORT_BOOTPC);
return 0;
}
} while ((MS_TICKS_DELAY() - start) < RETRY_TIME);
}
 
/* timed out */
__udp_remove_listener(IPPORT_BOOTPC);
net_debug = 0;
memcpy( __local_ip_addr, saved_ip_addr, sizeof(__local_ip_addr));
return -1;
}
 
 
/dns.c
0,0 → 1,275
//=============================================================================
//
// 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.
//
// 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
 
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);
 
#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>
/tcp.c
0,0 → 1,914
//==========================================================================
//
// 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.
//
// 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>
 
#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);
 
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);
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();
MS_TICKS_DELAY();
__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;
}
 
 
/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);
}
}
/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 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 <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)
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;
while ((MS_TICKS_DELAY() - start) < total_ms) {
__enet_poll(); // Handle the hardware
if (!recvfrom_buf) {
// Data have arrived
res = recvfrom_len;
break;
}
}
__udp_remove_listener(my_port);
return res;
}
/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;
}
/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;
}
 
 
/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 long
ntohs(unsigned short x)
{
return (((x & 0x00FF) << 8) |
((x & 0xFF00) >> 8));
}
 
#endif
/ping.c
0,0 → 1,238
//==========================================================================
//
// 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.
//
// 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);
for (tries = 0; tries < count; tries++) {
// The network stack uses the global variable '__local_ip_addr'
memcpy(hold_addr, __local_ip_addr, sizeof(hold_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)) {
__enet_poll();
}
end_time = MS_TICKS();
 
timer = MS_TICKS() + rate;
while (MS_TICKS_DELAY() < timer) {
__enet_poll();
}
 
// Clean up
memcpy(__local_ip_addr, &hold_addr, sizeof(__local_ip_addr));
 
if (icmp_received) {
received++;
if (verbose) {
diag_printf(" seq: %ld, time: %ld (ticks)\n",
ntohs(hold_hdr.seqnum), end_time-start_time);
}
}
}
__icmp_remove_listener();
// Report
diag_printf("PING - received %ld of %ld expected\n", received, count);
}
 
#endif //CYGPKG_REDBOOT_NETWORKING

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.