summaryrefslogtreecommitdiff
path: root/components/net
diff options
context:
space:
mode:
Diffstat (limited to 'components/net')
-rw-r--r--components/net/lwip-2.0.0/src/arch/sys_arch.c2
-rw-r--r--components/net/lwip-2.0.2/SConscript3
-rw-r--r--components/net/lwip-2.0.2/src/apps/README.md6
-rw-r--r--components/net/lwip-2.0.2/src/apps/SConscript13
-rw-r--r--components/net/lwip-2.0.2/src/apps/ping/ping.c201
-rw-r--r--components/net/lwip-2.0.2/src/apps/tftp/tftp_port.c87
-rw-r--r--components/net/lwip-2.0.2/src/apps/tftp/tftp_server.c4
-rw-r--r--components/net/lwip-2.0.2/src/arch/sys_arch.c6
-rw-r--r--components/net/lwip-2.0.2/src/lwipopts.h51
-rw-r--r--components/net/lwip-2.0.2/src/netif/ethernetif.c4
-rw-r--r--components/net/netutils/README.md1
-rw-r--r--components/net/netutils/SConscript10
-rw-r--r--components/net/netutils/telnet.c391
13 files changed, 766 insertions, 13 deletions
diff --git a/components/net/lwip-2.0.0/src/arch/sys_arch.c b/components/net/lwip-2.0.0/src/arch/sys_arch.c
index 7db873f130..c5b4dbbf47 100644
--- a/components/net/lwip-2.0.0/src/arch/sys_arch.c
+++ b/components/net/lwip-2.0.0/src/arch/sys_arch.c
@@ -600,7 +600,7 @@ u32_t sys_now(void)
return rt_tick_get() * (1000 / RT_TICK_PER_SECOND);
}
-WEAK
+RT_WEAK
void mem_init(void)
{
}
diff --git a/components/net/lwip-2.0.2/SConscript b/components/net/lwip-2.0.2/SConscript
index 631e4c1e6b..fa8a087c8d 100644
--- a/components/net/lwip-2.0.2/SConscript
+++ b/components/net/lwip-2.0.2/SConscript
@@ -29,7 +29,6 @@ src/core/udp.c
src/netif/ethernet.c
src/netif/ethernetif.c
src/netif/lowpan6.c
-src/netif/slipif.c
""")
ipv4_src = Split("""
@@ -75,7 +74,7 @@ if GetDepend(['RT_LWIP_SNMP']):
if GetDepend(['RT_LWIP_PPP']):
src += ppp_src
path += [GetCurrentDir() + '/src/netif/ppp']
-
+
group = DefineGroup('lwIP', src, depend = ['RT_USING_LWIP', 'RT_USING_LWIP202'], CPPPATH = path)
Return('group')
diff --git a/components/net/lwip-2.0.2/src/apps/README.md b/components/net/lwip-2.0.2/src/apps/README.md
new file mode 100644
index 0000000000..26670858c5
--- /dev/null
+++ b/components/net/lwip-2.0.2/src/apps/README.md
@@ -0,0 +1,6 @@
+Some net apps for current version LwIP.
+
+The RT-Thread develop team ported apps. It's easy to use it on finsh/msh.
+
+- ping
+- tftp
diff --git a/components/net/lwip-2.0.2/src/apps/SConscript b/components/net/lwip-2.0.2/src/apps/SConscript
new file mode 100644
index 0000000000..2bc01cc16e
--- /dev/null
+++ b/components/net/lwip-2.0.2/src/apps/SConscript
@@ -0,0 +1,13 @@
+from building import *
+
+cwd = GetCurrentDir()
+src = Glob('tftp/*.c')
+
+if GetDepend(['RT_LWIP_ICMP', 'RT_LWIP_RAW']):
+ src += Glob('ping/*.c')
+
+CPPPATH = [cwd]
+
+group = DefineGroup('LwIP', src, depend = ['RT_USING_NETUTILS', 'RT_USING_LWIP202'], CPPPATH = CPPPATH)
+
+Return('group') \ No newline at end of file
diff --git a/components/net/lwip-2.0.2/src/apps/ping/ping.c b/components/net/lwip-2.0.2/src/apps/ping/ping.c
new file mode 100644
index 0000000000..4b934f0cac
--- /dev/null
+++ b/components/net/lwip-2.0.2/src/apps/ping/ping.c
@@ -0,0 +1,201 @@
+/*
+ * netutils: ping implementation
+ */
+
+#include "lwip/opt.h"
+
+#include "lwip/mem.h"
+#include "lwip/icmp.h"
+#include "lwip/netif.h"
+#include "lwip/sys.h"
+#include "lwip/sockets.h"
+#include "lwip/inet.h"
+#include "lwip/inet_chksum.h"
+#include "lwip/ip.h"
+
+/**
+ * PING_DEBUG: Enable debugging for PING.
+ */
+#ifndef PING_DEBUG
+#define PING_DEBUG LWIP_DBG_ON
+#endif
+
+/** ping receive timeout - in milliseconds */
+#define PING_RCV_TIMEO rt_tick_from_millisecond(2000)
+/** ping delay - in milliseconds */
+#define PING_DELAY rt_tick_from_millisecond(1000)
+
+/** ping identifier - must fit on a u16_t */
+#ifndef PING_ID
+#define PING_ID 0xAFAF
+#endif
+
+/** ping additional data size to include in the packet */
+#ifndef PING_DATA_SIZE
+#define PING_DATA_SIZE 32
+#endif
+
+/* ping variables */
+static u16_t ping_seq_num;
+struct _ip_addr
+{
+ rt_uint8_t addr0, addr1, addr2, addr3;
+};
+
+/** Prepare a echo ICMP request */
+static void ping_prepare_echo( struct icmp_echo_hdr *iecho, u16_t len)
+{
+ size_t i;
+ size_t data_len = len - sizeof(struct icmp_echo_hdr);
+
+ ICMPH_TYPE_SET(iecho, ICMP_ECHO);
+ ICMPH_CODE_SET(iecho, 0);
+ iecho->chksum = 0;
+ iecho->id = PING_ID;
+ iecho->seqno = htons(++ping_seq_num);
+
+ /* fill the additional data buffer with some data */
+ for(i = 0; i < data_len; i++)
+ {
+ ((char*)iecho)[sizeof(struct icmp_echo_hdr) + i] = (char)i;
+ }
+
+ iecho->chksum = inet_chksum(iecho, len);
+}
+
+/* Ping using the socket ip */
+static err_t ping_send(int s, ip_addr_t *addr, int size)
+{
+ int err;
+ struct icmp_echo_hdr *iecho;
+ struct sockaddr_in to;
+ size_t ping_size = sizeof(struct icmp_echo_hdr) + size;
+ LWIP_ASSERT("ping_size is too big", ping_size <= 0xffff);
+
+ iecho = rt_malloc(ping_size);
+ if (iecho == RT_NULL)
+ {
+ return ERR_MEM;
+ }
+
+ ping_prepare_echo(iecho, (u16_t)ping_size);
+
+ to.sin_len = sizeof(to);
+ to.sin_family = AF_INET;
+ to.sin_addr.s_addr = addr->addr;
+
+ err = lwip_sendto(s, iecho, ping_size, 0, (struct sockaddr*)&to, sizeof(to));
+ rt_free(iecho);
+
+ return (err == ping_size ? ERR_OK : ERR_VAL);
+}
+
+static int ping_recv(int s, int *ttl)
+{
+ char buf[64];
+ int fromlen = sizeof(struct sockaddr_in), len;
+ struct sockaddr_in from;
+ struct ip_hdr *iphdr;
+ struct icmp_echo_hdr *iecho;
+
+ while((len = lwip_recvfrom(s, buf, sizeof(buf), 0, (struct sockaddr*)&from, (socklen_t*)&fromlen)) > 0)
+ {
+ if (len >= (sizeof(struct ip_hdr)+sizeof(struct icmp_echo_hdr)))
+ {
+ iphdr = (struct ip_hdr *)buf;
+ iecho = (struct icmp_echo_hdr *)(buf+(IPH_HL(iphdr) * 4));
+ if ((iecho->id == PING_ID) && (iecho->seqno == htons(ping_seq_num)))
+ {
+ *ttl = iphdr->_ttl;
+ return len;
+ }
+ }
+ }
+
+ return len;
+}
+
+rt_err_t ping(char* target, rt_uint32_t times, rt_size_t size)
+{
+ int s, ttl, recv_len;
+ struct timeval timeout = { PING_RCV_TIMEO / RT_TICK_PER_SECOND, PING_RCV_TIMEO % RT_TICK_PER_SECOND };
+ ip_addr_t ping_target;
+ rt_uint32_t send_times;
+ rt_tick_t recv_start_tick;
+ struct _ip_addr
+ {
+ rt_uint8_t addr0, addr1, addr2, addr3;
+ } *addr;
+
+ send_times = 0;
+ ping_seq_num = 0;
+
+ if(size == 0)
+ size = PING_DATA_SIZE;
+
+ if (inet_aton(target, &ping_target) == 0)
+ {
+ rt_kprintf("ping: unknown host %s\n", target);
+ return -RT_ERROR;
+ }
+ addr = (struct _ip_addr*)&ping_target;
+
+ if ((s = lwip_socket(AF_INET, SOCK_RAW, IP_PROTO_ICMP)) < 0)
+ {
+ rt_kprintf("ping: create socket failled\n");
+ return -RT_ERROR;
+ }
+
+ lwip_setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval));
+
+ while (1)
+ {
+ if (ping_send(s, &ping_target, size) == ERR_OK)
+ {
+ recv_start_tick = rt_tick_get();
+ if ((recv_len = ping_recv(s, &ttl)) >= 0)
+ {
+ rt_kprintf("%d bytes from %d.%d.%d.%d icmp_seq=%d ttl=%d time=%d ticks\n", recv_len, addr->addr0,
+ addr->addr1, addr->addr2, addr->addr3, send_times, ttl, rt_tick_get() - recv_start_tick);
+ }
+ else
+ {
+ rt_kprintf("From %d.%d.%d.%d icmp_seq=%d timeout\n", addr->addr0, addr->addr1, addr->addr2,
+ addr->addr3, send_times);
+ }
+ }
+ else
+ {
+ rt_kprintf("Send %d.%d.%d.%d - error\n", addr->addr0, addr->addr1, addr->addr2, addr->addr3);
+ }
+
+ send_times ++;
+ if (send_times >= times) break; /* send ping times reached, stop */
+
+ rt_thread_delay(PING_DELAY); /* take a delay */
+ }
+
+ lwip_close(s);
+
+ return RT_EOK;
+}
+#ifdef RT_USING_FINSH
+#include <finsh.h>
+
+FINSH_FUNCTION_EXPORT(ping, ping network host);
+
+int cmd_ping(int argc, char **argv)
+{
+ if (argc == 1)
+ {
+ rt_kprintf("Please input: ping <host address>\n");
+ }
+ else
+ {
+ ping(argv[1], 4, 0);
+ }
+
+ return 0;
+}
+FINSH_FUNCTION_EXPORT_ALIAS(cmd_ping, __cmd_ping, ping network host);
+#endif
diff --git a/components/net/lwip-2.0.2/src/apps/tftp/tftp_port.c b/components/net/lwip-2.0.2/src/apps/tftp/tftp_port.c
new file mode 100644
index 0000000000..129cc7da17
--- /dev/null
+++ b/components/net/lwip-2.0.2/src/apps/tftp/tftp_port.c
@@ -0,0 +1,87 @@
+/*
+ * File : tftp_port.c
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2006 - 2017, RT-Thread Development Team
+ *
+ * This program 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 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2017-08-17 armink first version.
+ */
+
+
+#include <rtthread.h>
+#include <dfs_posix.h>
+#include <lwip/apps/tftp_server.h>
+
+static struct tftp_context ctx;
+
+static void* tftp_open(const char* fname, const char* mode, u8_t write)
+{
+ int fd = -1;
+
+ if (!rt_strcmp(mode, "octet"))
+ {
+ if (write)
+ {
+ fd = open(fname, O_WRONLY | O_CREAT, 0);
+ }
+ else
+ {
+ fd = open(fname, O_RDONLY, 0);
+ }
+ }
+ else
+ {
+ rt_kprintf("tftp: No support this mode(%s).", mode);
+ }
+
+ return (void *) fd;
+}
+
+static int tftp_write(void* handle, struct pbuf* p)
+{
+ int fd = (int) handle;
+
+ return write(fd, p->payload, p->len);
+}
+
+#if defined(RT_USING_FINSH)
+#include <finsh.h>
+
+static void tftp_server(uint8_t argc, char **argv)
+{
+ ctx.open = tftp_open;
+ ctx.close = (void (*)(void *)) close;
+ ctx.read = (int (*)(void *, void *, int)) read;
+ ctx.write = tftp_write;
+
+ if (tftp_init(&ctx) == ERR_OK)
+ {
+ rt_kprintf("TFTP server start successfully.\n");
+ }
+ else
+ {
+ rt_kprintf("TFTP server start failed.\n");
+ }
+}
+FINSH_FUNCTION_EXPORT(tftp_server, start tftp server.);
+
+#if defined(FINSH_USING_MSH)
+MSH_CMD_EXPORT(tftp_server, start tftp server.);
+#endif /* defined(FINSH_USING_MSH) */
+
+#endif /* defined(RT_USING_FINSH) */
diff --git a/components/net/lwip-2.0.2/src/apps/tftp/tftp_server.c b/components/net/lwip-2.0.2/src/apps/tftp/tftp_server.c
index 243b0924bd..afaa3bb08d 100644
--- a/components/net/lwip-2.0.2/src/apps/tftp/tftp_server.c
+++ b/components/net/lwip-2.0.2/src/apps/tftp/tftp_server.c
@@ -226,8 +226,8 @@ recv(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16
case PP_HTONS(TFTP_WRQ):
{
const char tftp_null = 0;
- char filename[TFTP_MAX_FILENAME_LEN];
- char mode[TFTP_MAX_MODE_LEN];
+ char filename[TFTP_MAX_FILENAME_LEN + 1] = { 0 };
+ char mode[TFTP_MAX_MODE_LEN] = { 0 };
u16_t filename_end_offset;
u16_t mode_end_offset;
diff --git a/components/net/lwip-2.0.2/src/arch/sys_arch.c b/components/net/lwip-2.0.2/src/arch/sys_arch.c
index 4cddf86eb6..bb809ac6ad 100644
--- a/components/net/lwip-2.0.2/src/arch/sys_arch.c
+++ b/components/net/lwip-2.0.2/src/arch/sys_arch.c
@@ -114,7 +114,7 @@ static void tcpip_init_done_callback(void *arg)
netif_set_up(ethif->netif);
#endif
- if (!(ethif->flags & ETHIF_LINK_PHYUP))
+ if (ethif->flags & ETHIF_LINK_PHYUP)
{
netif_set_link_up(ethif->netif);
}
@@ -177,7 +177,7 @@ int lwip_system_init(void)
return 0;
}
-//INIT_COMPONENT_EXPORT(lwip_system_init);
+INIT_COMPONENT_EXPORT(lwip_system_init);
void sys_init(void)
{
@@ -602,7 +602,7 @@ u32_t sys_now(void)
}
-WEAK
+RT_WEAK
void mem_init(void)
{
}
diff --git a/components/net/lwip-2.0.2/src/lwipopts.h b/components/net/lwip-2.0.2/src/lwipopts.h
index 8afc0b97c4..d846cf2fb0 100644
--- a/components/net/lwip-2.0.2/src/lwipopts.h
+++ b/components/net/lwip-2.0.2/src/lwipopts.h
@@ -287,6 +287,12 @@
#define DEFAULT_UDP_RECVMBOX_SIZE 1
/* ---------- RAW options ---------- */
+#ifdef RT_LWIP_RAW
+#define LWIP_RAW 1
+#else
+#define LWIP_RAW 0
+#endif
+
#define DEFAULT_RAW_RECVMBOX_SIZE 1
#define DEFAULT_ACCEPTMBOX_SIZE 10
@@ -348,9 +354,30 @@
#endif /* PPP_SUPPORT */
-/* no read/write/close for socket */
-#define LWIP_POSIX_SOCKETS_IO_NAMES 0
-#define LWIP_NETIF_API 1
+/**
+ * LWIP_POSIX_SOCKETS_IO_NAMES==1: Enable POSIX-style sockets functions names.
+ * Disable this option if you use a POSIX operating system that uses the same
+ * names (read, write & close). (only used if you use sockets.c)
+ */
+#ifndef LWIP_POSIX_SOCKETS_IO_NAMES
+#define LWIP_POSIX_SOCKETS_IO_NAMES 0
+#endif
+
+/**
+ * LWIP_TCP_KEEPALIVE==1: Enable TCP_KEEPIDLE, TCP_KEEPINTVL and TCP_KEEPCNT
+ * options processing. Note that TCP_KEEPIDLE and TCP_KEEPINTVL have to be set
+ * in seconds. (does not require sockets.c, and will affect tcp.c)
+ */
+#ifndef LWIP_TCP_KEEPALIVE
+#define LWIP_TCP_KEEPALIVE 1
+#endif
+
+/**
+ * LWIP_NETIF_API==1: Support netif api (in netifapi.c)
+ */
+#ifndef LWIP_NETIF_API
+#define LWIP_NETIF_API 1
+#endif
/* MEMP_NUM_SYS_TIMEOUT: the number of simulateously active timeouts. */
#define MEMP_NUM_SYS_TIMEOUT (LWIP_TCP + IP_REASSEMBLY + LWIP_ARP + (2*LWIP_DHCP) + LWIP_AUTOIP + LWIP_IGMP + LWIP_DNS + PPP_SUPPORT)
@@ -419,4 +446,22 @@
#define SO_REUSE 0
#endif
+/*
+ ------------------------------------
+ ------- Applications options -------
+ ------------------------------------
+*/
+
+/**
+ * Max. length of TFTP filename
+ */
+#ifdef RT_LWIP_TFTP_MAX_FILENAME_LEN
+#define TFTP_MAX_FILENAME_LEN RT_LWIP_TFTP_MAX_FILENAME_LEN
+#elif defined(RT_DFS_ELM_MAX_LFN)
+#define TFTP_MAX_FILENAME_LEN RT_DFS_ELM_MAX_LFN
+#else
+#define TFTP_MAX_FILENAME_LEN 64
+#endif
+
+
#endif /* __LWIPOPTS_H__ */
diff --git a/components/net/lwip-2.0.2/src/netif/ethernetif.c b/components/net/lwip-2.0.2/src/netif/ethernetif.c
index 4dca17b3e1..5b82649662 100644
--- a/components/net/lwip-2.0.2/src/netif/ethernetif.c
+++ b/components/net/lwip-2.0.2/src/netif/ethernetif.c
@@ -180,7 +180,7 @@ static err_t eth_netif_device_init(struct netif *netif)
netif_set_up(ethif->netif);
#endif
- if (!(ethif->flags & ETHIF_LINK_PHYUP))
+ if (ethif->flags & ETHIF_LINK_PHYUP)
{
/* set link_up for this netif */
netif_set_link_up(ethif->netif);
@@ -451,7 +451,7 @@ int eth_system_device_init(void)
return (int)result;
}
-//INIT_DEVICE_EXPORT(eth_system_device_init);
+INIT_DEVICE_EXPORT(eth_system_device_init);
#ifdef RT_USING_FINSH
#include <finsh.h>
diff --git a/components/net/netutils/README.md b/components/net/netutils/README.md
new file mode 100644
index 0000000000..49545bab32
--- /dev/null
+++ b/components/net/netutils/README.md
@@ -0,0 +1 @@
+Some net utils which using standard interface such as BSD Sockets. \ No newline at end of file
diff --git a/components/net/netutils/SConscript b/components/net/netutils/SConscript
new file mode 100644
index 0000000000..853b94a857
--- /dev/null
+++ b/components/net/netutils/SConscript
@@ -0,0 +1,10 @@
+from building import *
+
+cwd = GetCurrentDir()
+src = Glob('*.c')
+
+CPPPATH = [cwd]
+
+group = DefineGroup('LwIP', src, depend = ['RT_USING_NETUTILS'], CPPPATH = CPPPATH)
+
+Return('group') \ No newline at end of file
diff --git a/components/net/netutils/telnet.c b/components/net/netutils/telnet.c
new file mode 100644
index 0000000000..d5c127b713
--- /dev/null
+++ b/components/net/netutils/telnet.c
@@ -0,0 +1,391 @@
+#include <rtthread.h>
+#include <lwip/api.h>
+#include <lwip/sockets.h>
+#include <rtdevice.h>
+
+#include <finsh.h>
+#include <shell.h>
+
+#define TELNET_PORT 23
+#define TELNET_BACKLOG 5
+#define RX_BUFFER_SIZE 256
+#define TX_BUFFER_SIZE 4096
+
+#define ISO_nl 0x0a
+#define ISO_cr 0x0d
+
+#define STATE_NORMAL 0
+#define STATE_IAC 1
+#define STATE_WILL 2
+#define STATE_WONT 3
+#define STATE_DO 4
+#define STATE_DONT 5
+#define STATE_CLOSE 6
+
+#define TELNET_IAC 255
+#define TELNET_WILL 251
+#define TELNET_WONT 252
+#define TELNET_DO 253
+#define TELNET_DONT 254
+
+struct telnet_session
+{
+ struct rt_ringbuffer rx_ringbuffer;
+ struct rt_ringbuffer tx_ringbuffer;
+
+ rt_mutex_t rx_ringbuffer_lock;
+ rt_mutex_t tx_ringbuffer_lock;
+
+ struct rt_device device;
+ rt_int32_t server_fd;
+ rt_int32_t client_fd;
+
+ /* telnet protocol */
+ rt_uint8_t state;
+ rt_uint8_t echo_mode;
+
+};
+
+static struct telnet_session* telnet;
+
+/* process tx data */
+static void send_to_client(struct telnet_session* telnet)
+{
+ rt_size_t length;
+ rt_uint8_t tx_buffer[32];
+
+ while (1)
+ {
+ rt_memset(tx_buffer, 0, sizeof(tx_buffer));
+ rt_mutex_take(telnet->tx_ringbuffer_lock, RT_WAITING_FOREVER);
+ /* get buffer from ringbuffer */
+ length = rt_ringbuffer_get(&(telnet->tx_ringbuffer), tx_buffer, sizeof(tx_buffer));
+ rt_mutex_release(telnet->tx_ringbuffer_lock);
+
+ /* do a tx procedure */
+ if (length > 0)
+ {
+ send(telnet->client_fd, tx_buffer, length, 0);
+ }
+ else break;
+ }
+}
+
+/* send telnet option to remote */
+static void send_option_to_client(struct telnet_session* telnet, rt_uint8_t option, rt_uint8_t value)
+{
+ rt_uint8_t optbuf[4];
+
+ optbuf[0] = TELNET_IAC;
+ optbuf[1] = option;
+ optbuf[2] = value;
+ optbuf[3] = 0;
+
+ rt_mutex_take(telnet->tx_ringbuffer_lock, RT_WAITING_FOREVER);
+ rt_ringbuffer_put(&telnet->tx_ringbuffer, optbuf, 3);
+ rt_mutex_release(telnet->tx_ringbuffer_lock);
+
+ send_to_client(telnet);
+}
+
+/* process rx data */
+static void process_rx(struct telnet_session* telnet, rt_uint8_t *data, rt_size_t length)
+{
+ rt_size_t rx_length, index;
+
+ for (index = 0; index < length; index ++)
+ {
+ switch(telnet->state)
+ {
+ case STATE_IAC:
+ if (*data == TELNET_IAC)
+ {
+ rt_mutex_take(telnet->rx_ringbuffer_lock, RT_WAITING_FOREVER);
+ /* put buffer to ringbuffer */
+ rt_ringbuffer_putchar(&(telnet->rx_ringbuffer), *data);
+ rt_mutex_release(telnet->rx_ringbuffer_lock);
+
+ telnet->state = STATE_NORMAL;
+ }
+ else
+ {
+ /* set telnet state according to received package */
+ switch (*data)
+ {
+ case TELNET_WILL: telnet->state = STATE_WILL; break;
+ case TELNET_WONT: telnet->state = STATE_WONT; break;
+ case TELNET_DO: telnet->state = STATE_DO; break;
+ case TELNET_DONT: telnet->state = STATE_DONT; break;
+ default: telnet->state = STATE_NORMAL; break;
+ }
+ }
+ break;
+
+ /* don't option */
+ case STATE_WILL:
+ case STATE_WONT:
+ send_option_to_client(telnet, TELNET_DONT, *data);
+ telnet->state = STATE_NORMAL;
+ break;
+
+ /* won't option */
+ case STATE_DO:
+ case STATE_DONT:
+ send_option_to_client(telnet, TELNET_WONT, *data);
+ telnet->state = STATE_NORMAL;
+ break;
+
+ case STATE_NORMAL:
+ if (*data == TELNET_IAC) telnet->state = STATE_IAC;
+ else if (*data != '\r') /* ignore '\r' */
+ {
+ rt_mutex_take(telnet->rx_ringbuffer_lock, RT_WAITING_FOREVER);
+ /* put buffer to ringbuffer */
+ rt_ringbuffer_putchar(&(telnet->rx_ringbuffer), *data);
+ rt_mutex_release(telnet->rx_ringbuffer_lock);
+ }
+ break;
+ }
+
+ data ++;
+ }
+
+ rt_mutex_take(telnet->rx_ringbuffer_lock, RT_WAITING_FOREVER);
+ /* get total size */
+ rx_length = rt_ringbuffer_data_len(&telnet->rx_ringbuffer);
+ rt_mutex_release(telnet->rx_ringbuffer_lock);
+
+ /* indicate there are reception data */
+ if ((rx_length > 0) && (telnet->device.rx_indicate != RT_NULL))
+ telnet->device.rx_indicate(&telnet->device, rx_length);
+
+ return;
+}
+
+/* client close */
+static void client_close(struct telnet_session* telnet)
+{
+ /* set console */
+ rt_console_set_device(RT_CONSOLE_DEVICE_NAME);
+ /* set finsh device */
+ finsh_set_device(RT_CONSOLE_DEVICE_NAME);
+
+ /* close connection */
+ closesocket(telnet->client_fd);
+
+ /* restore shell option */
+ finsh_set_echo(telnet->echo_mode);
+
+ rt_kprintf("resume console to %s\n", RT_CONSOLE_DEVICE_NAME);
+}
+
+/* RT-Thread Device Driver Interface */
+static rt_err_t telnet_init(rt_device_t dev)
+{
+ return RT_EOK;
+}
+
+static rt_err_t telnet_open(rt_device_t dev, rt_uint16_t oflag)
+{
+ return RT_EOK;
+}
+
+static rt_err_t telnet_close(rt_device_t dev)
+{
+ return RT_EOK;
+}
+
+static rt_size_t telnet_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size)
+{
+ rt_size_t result;
+
+ /* read from rx ring buffer */
+ rt_mutex_take(telnet->rx_ringbuffer_lock, RT_WAITING_FOREVER);
+ result = rt_ringbuffer_get(&(telnet->rx_ringbuffer), buffer, size);
+ rt_mutex_release(telnet->rx_ringbuffer_lock);
+
+ return result;
+}
+
+static rt_size_t telnet_write (rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size)
+{
+ const rt_uint8_t *ptr;
+
+ ptr = (rt_uint8_t*) buffer;
+
+ rt_mutex_take(telnet->tx_ringbuffer_lock, RT_WAITING_FOREVER);
+ while (size)
+ {
+ if (*ptr == '\n')
+ rt_ringbuffer_putchar(&telnet->tx_ringbuffer, '\r');
+
+ if (rt_ringbuffer_putchar(&telnet->tx_ringbuffer, *ptr) == 0) /* overflow */
+ break;
+ ptr++;
+ size--;
+ }
+ rt_mutex_release(telnet->tx_ringbuffer_lock);
+
+ /* send data to telnet client */
+ send_to_client(telnet);
+
+ return (rt_uint32_t) ptr - (rt_uint32_t) buffer;
+}
+
+static rt_err_t telnet_control(rt_device_t dev, rt_uint8_t cmd, void *args)
+{
+ return RT_EOK;
+}
+
+/* telnet server thread entry */
+static void telnet_thread(void* parameter)
+{
+#define RECV_BUF_LEN 64
+
+ struct sockaddr_in addr;
+ socklen_t addr_size;
+ rt_uint8_t recv_buf[RECV_BUF_LEN];
+ rt_int32_t recv_len = 0;
+
+ if ((telnet->server_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
+ {
+ rt_kprintf("telnet: create socket failed\n");
+ return;
+ }
+
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(TELNET_PORT);
+ addr.sin_addr.s_addr = INADDR_ANY;
+ rt_memset(&(addr.sin_zero), 0, sizeof(addr.sin_zero));
+ if (bind(telnet->server_fd, (struct sockaddr *)&addr, sizeof(struct sockaddr)) == -1)
+ {
+ rt_kprintf("telnet: bind socket failed\n");
+ return;
+ }
+
+ if (listen(telnet->server_fd, TELNET_BACKLOG) == -1)
+ {
+ rt_kprintf("telnet: listen socket failed\n");
+ return;
+ }
+
+ /* register telnet device */
+ telnet->device.type = RT_Device_Class_Char;
+ telnet->device.init = telnet_init;
+ telnet->device.open = telnet_open;
+ telnet->device.close = telnet_close;
+ telnet->device.read = telnet_read;
+ telnet->device.write = telnet_write;
+ telnet->device.control = telnet_control;
+
+ /* no private */
+ telnet->device.user_data = RT_NULL;
+
+ /* register telnet device */
+ rt_device_register(&telnet->device, "telnet",
+ RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STREAM);
+
+ while (1)
+ {
+ rt_kprintf("telnet server waiting for connection\n");
+
+ /* grab new connection */
+ if ((telnet->client_fd = accept(telnet->server_fd, (struct sockaddr * )&addr, &addr_size)) == -1)
+ {
+ continue;
+ }
+
+ rt_kprintf("new telnet client(%s:%d) connection, switch console to telnet...\n", inet_ntoa(addr.sin_addr), addr.sin_port);
+
+ /* process the new connection */
+ /* set console */
+ rt_console_set_device("telnet");
+ /* set finsh device */
+ finsh_set_device("telnet");
+
+ /* set init state */
+ telnet->state = STATE_NORMAL;
+
+ telnet->echo_mode = finsh_get_echo();
+ /* disable echo mode */
+ finsh_set_echo(0);
+
+ while (1)
+ {
+ /* try to send all data in tx ringbuffer */
+ send_to_client(telnet);
+
+ /* do a rx procedure */
+ if ((recv_len = recv(telnet->client_fd, recv_buf, RECV_BUF_LEN, 0)) > 0)
+ {
+ process_rx(telnet, recv_buf, recv_len);
+ }
+ else
+ {
+ /* close connection */
+ client_close(telnet);
+ break;
+ }
+ }
+ }
+}
+
+/* telnet server */
+void telnet_srv(void)
+{
+ rt_thread_t tid;
+
+ if (telnet == RT_NULL)
+ {
+ rt_uint8_t *ptr;
+
+ telnet = rt_malloc(sizeof(struct telnet_session));
+ if (telnet == RT_NULL)
+ {
+ rt_kprintf("telnet: no memory\n");
+ return;
+ }
+ /* init ringbuffer */
+ ptr = rt_malloc(RX_BUFFER_SIZE);
+ if (ptr)
+ {
+ rt_ringbuffer_init(&telnet->rx_ringbuffer, ptr, RX_BUFFER_SIZE);
+ }
+ else
+ {
+ rt_kprintf("telnet: no memory\n");
+ return;
+ }
+ ptr = rt_malloc(TX_BUFFER_SIZE);
+ if (ptr)
+ {
+ rt_ringbuffer_init(&telnet->tx_ringbuffer, ptr, TX_BUFFER_SIZE);
+ }
+ else
+ {
+ rt_kprintf("telnet: no memory\n");
+ return;
+ }
+ /* create tx ringbuffer lock */
+ telnet->tx_ringbuffer_lock = rt_mutex_create("telnet_tx", RT_IPC_FLAG_FIFO);
+ /* create rx ringbuffer lock */
+ telnet->rx_ringbuffer_lock = rt_mutex_create("telnet_rx", RT_IPC_FLAG_FIFO);
+
+ tid = rt_thread_create("telnet", telnet_thread, RT_NULL, 2048, 25, 5);
+ if (tid != RT_NULL)
+ rt_thread_startup(tid);
+ }
+ else
+ {
+ rt_kprintf("telnet: already running\n");
+ }
+
+}
+
+#ifdef RT_USING_FINSH
+#include <finsh.h>
+FINSH_FUNCTION_EXPORT(telnet_srv, startup telnet server);
+#ifdef FINSH_USING_MSH
+MSH_CMD_EXPORT(telnet_srv, startup telnet server)
+#endif /* FINSH_USING_MSH */
+#endif /* RT_USING_FINSH */