📄 net_io.c
字号:
//==========================================================================
//
// net/net_io.c
//
// Stand-alone network logical I/O support for RedBoot
//
//==========================================================================
//####COPYRIGHTBEGIN####
//
// -------------------------------------------
// The contents of this file are subject to the Red Hat eCos Public License
// Version 1.1 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://www.redhat.com/
//
// Software distributed under the License is distributed on an "AS IS"
// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
// License for the specific language governing rights and limitations under
// the License.
//
// The Original Code is eCos - Embedded Configurable Operating System,
// released September 30, 1998.
//
// The Initial Developer of the Original Code is Red Hat.
// Portions created by Red Hat are
// Copyright (C) 1998, 1999, 2000, 2001 Red Hat, Inc.
// All Rights Reserved.
// -------------------------------------------
//
//####COPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): gthomas
// Contributors: gthomas
// Date: 2000-07-14
// Purpose:
// Description:
//
// This code is part of RedBoot (tm).
//
//####DESCRIPTIONEND####
//
//==========================================================================
#include <redboot.h>
#include <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("Master's Local IP address",
bootp_master_ip,
"bootp", false,
CONFIG_IP,
0
);
RedBoot_config_option("Slave's Local IP address",
bootp_slave_ip,
"bootp", false,
CONFIG_IP,
0
);
RedBoot_config_option("Default server IP address",
bootp_server_ip,
"bootp", false,
CONFIG_IP,
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[64];
static unsigned char *out_bufp;
// 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();
printf("%s:%d\n", __FUNCTION__, __LINE__);
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;
while (out_buflen) {
if (tcp_sock.state == _CLOSE_WAIT) {
// This connection is tring to close
// This connection is breaking
if (tcp_sock.data_bytes == 0 && tcp_sock.rxcnt == 0)
__tcp_close(&tcp_sock);
}
if (tcp_sock.state == _CLOSED) {
// The connection is gone!
net_io_revert_console();
break;
}
#ifdef DEBUG_TCP
if (show_tcp) {
int old_console;
old_console = start_console();
printf("%s.%d\n", __FUNCTION__, __LINE__);
dump_buf(out_buf, out_buflen);
end_console(old_console);
}
#endif // SHOW_TCP
n = __tcp_write(&tcp_sock, bp, out_buflen);
if (n > 0) {
out_buflen -= n;
bp += n;
}
__tcp_poll();
}
out_bufp = out_buf; out_buflen = 0;
__tcp_drain(&tcp_sock);
// 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)) || (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();
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)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -