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 *)ð_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, ð_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, ð_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(ð_hdr.destination, dest, sizeof(enet_addr_t)); |
memcpy(ð_hdr.source, __local_enet_addr, sizeof(enet_addr_t)); |
eth_hdr.type = htons(eth_type); |
|
eth_drv_write((char *)ð_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 |