diff --git a/net/apps/chargen.c b/net/apps/chargen.c new file mode 100644 index 0000000000..3e6400de28 --- /dev/null +++ b/net/apps/chargen.c @@ -0,0 +1,204 @@ +#include + +#include "lwip/sockets.h" +#define MAX_SERV 5 /* Maximum number of chargen services. Don't need too many */ +#define CHARGEN_THREAD_NAME "chargen" +#define CHARGEN_PRIORITY 200 /* Really low priority */ +#define CHARGEN_THREAD_STACKSIZE 1024 +struct charcb +{ + struct charcb *next; + int socket; + struct sockaddr_in cliaddr; + socklen_t clilen; + char nextchar; +}; + +static struct charcb *charcb_list = 0; +static int do_read(struct charcb *p_charcb); +static void close_chargen(struct charcb *p_charcb); + +/************************************************************** + * void chargen_thread(void *arg) + * + * chargen task. This server will wait for connections on well + * known TCP port number: 19. For every connection, the server will + * write as much data as possible to the tcp port. + **************************************************************/ +static void chargen_thread(void *arg) +{ + int listenfd; + struct sockaddr_in chargen_saddr; + fd_set readset; + fd_set writeset; + int i, maxfdp1; + struct charcb *p_charcb; + + /* First acquire our socket for listening for connections */ + listenfd = lwip_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + + LWIP_ASSERT("chargen_thread(): Socket create failed.", listenfd >= 0); + memset(&chargen_saddr, 0, sizeof(chargen_saddr)); + chargen_saddr.sin_family = AF_INET; + chargen_saddr.sin_addr.s_addr = htonl(INADDR_ANY); + chargen_saddr.sin_port = htons(19); // Chargen server port + + if (lwip_bind(listenfd, (struct sockaddr *) &chargen_saddr, sizeof(chargen_saddr)) == -1) + LWIP_ASSERT("chargen_thread(): Socket bind failed.", 0); + + /* Put socket into listening mode */ + if (lwip_listen(listenfd, MAX_SERV) == -1) + LWIP_ASSERT("chargen_thread(): Listen failed.", 0); + + /* Wait forever for network input: This could be connections or data */ + for (;;) + { + maxfdp1 = listenfd+1; + + /* Determine what sockets need to be in readset */ + FD_ZERO(&readset); + FD_ZERO(&writeset); + FD_SET(listenfd, &readset); + for (p_charcb = charcb_list; p_charcb; p_charcb = p_charcb->next) + { + if (maxfdp1 < p_charcb->socket + 1) + maxfdp1 = p_charcb->socket + 1; + FD_SET(p_charcb->socket, &readset); + FD_SET(p_charcb->socket, &writeset); + } + + /* Wait for data or a new connection */ + i = lwip_select(maxfdp1, &readset, &writeset, 0, 0); + + if (i == 0) continue; + + /* At least one descriptor is ready */ + if (FD_ISSET(listenfd, &readset)) + { + /* We have a new connection request!!! */ + /* Lets create a new control block */ + p_charcb = (struct charcb *)rt_calloc(1, sizeof(struct charcb)); + if (p_charcb) + { + p_charcb->socket = lwip_accept(listenfd, + (struct sockaddr *) &p_charcb->cliaddr, + &p_charcb->clilen); + if (p_charcb->socket < 0) + rt_free(p_charcb); + else + { + /* Keep this tecb in our list */ + p_charcb->next = charcb_list; + charcb_list = p_charcb; + p_charcb->nextchar = 0x21; + } + } + else + { + /* No memory to accept connection. Just accept and then close */ + int sock; + struct sockaddr cliaddr; + socklen_t clilen; + + sock = lwip_accept(listenfd, &cliaddr, &clilen); + if (sock >= 0) + lwip_close(sock); + } + } + /* Go through list of connected clients and process data */ + for (p_charcb = charcb_list; p_charcb; p_charcb = p_charcb->next) + { + if (FD_ISSET(p_charcb->socket, &readset)) + { + /* This socket is ready for reading. This could be because someone typed + * some characters or it could be because the socket is now closed. Try reading + * some data to see. */ + if (do_read(p_charcb) < 0) + break; + } + if (FD_ISSET(p_charcb->socket, &writeset)) + { + char line[80]; + char setchar = p_charcb->nextchar; + + for( i = 0; i < 59; i++) + { + line[i] = setchar; + if (++setchar == 0x7f) + setchar = 0x21; + } + line[i] = 0; + strcat(line, "\n\r"); + if (lwip_write(p_charcb->socket, line, strlen(line)) < 0) + { + close_chargen(p_charcb); + break; + } + if (++p_charcb->nextchar == 0x7f) + p_charcb->nextchar = 0x21; + } + } + } +} + +/************************************************************** + * void close_chargen(struct charcb *p_charcb) + * + * Close the socket and remove this charcb from the list. + **************************************************************/ +static void close_chargen(struct charcb *p_charcb) +{ + struct charcb *p_search_charcb; + + /* Either an error or tcp connection closed on other + * end. Close here */ + lwip_close(p_charcb->socket); + + /* Free charcb */ + if (charcb_list == p_charcb) + charcb_list = p_charcb->next; + else + for (p_search_charcb = charcb_list; p_search_charcb; p_search_charcb = p_search_charcb->next) + { + if (p_search_charcb->next == p_charcb) + { + p_search_charcb->next = p_charcb->next; + break; + } + } + + rt_free(p_charcb); +} + +/************************************************************** + * void do_read(struct charcb *p_charcb) + * + * Socket definitely is ready for reading. Read a buffer from the socket and + * discard the data. If no data is read, then the socket is closed and the + * charcb is removed from the list and freed. + **************************************************************/ +static int do_read(struct charcb *p_charcb) +{ + char buffer[80]; + int readcount; + + /* Read some data */ + readcount = lwip_read(p_charcb->socket, &buffer, 80); + if (readcount <= 0) + { + close_chargen(p_charcb); + return -1; + } + return 0; +} + +void chargen_init(void) +{ + rt_thread_t chargen; + + chargen = rt_thread_create(CHARGEN_THREAD_NAME, + chargen_thread, RT_NULL, + CHARGEN_THREAD_STACKSIZE, + CHARGEN_PRIORITY, 5); + if (chargen != RT_NULL) rt_thread_startup(chargen); +} diff --git a/net/apps/ping.c b/net/apps/ping.c new file mode 100644 index 0000000000..045b7d026d --- /dev/null +++ b/net/apps/ping.c @@ -0,0 +1,195 @@ +/* + * 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 target - should be a "struct ip_addr" */ +#ifndef PING_TARGET +#define PING_TARGET (netif_default?netif_default->gw:ip_addr_any) +#endif + +/** ping receive timeout - in milliseconds */ +#ifndef PING_RCV_TIMEO +#define PING_RCV_TIMEO 1000 +#endif + +/** ping delay - in milliseconds */ +#ifndef PING_DELAY +#define PING_DELAY 100 +#endif + +/** 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 result action - no default action */ +#ifndef PING_RESULT +#define PING_RESULT(ping_ok) +#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, struct ip_addr *addr) +{ + int err; + struct icmp_echo_hdr *iecho; + struct sockaddr_in to; + size_t ping_size = sizeof(struct icmp_echo_hdr) + PING_DATA_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 ? ERR_OK : ERR_VAL); +} + +static void ping_recv(int s) +{ + char buf[64]; + int fromlen, len; + struct sockaddr_in from; + struct ip_hdr *iphdr; + struct icmp_echo_hdr *iecho; + struct _ip_addr *addr; + + 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))) + { + addr = (struct _ip_addr *)&(from.sin_addr); + rt_kprintf("ping: recv %d.%d.%d.%d\n", addr->addr0, addr->addr1, addr->addr2, addr->addr3); + + 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))) + { + /* do some ping result processing */ + PING_RESULT((ICMPH_TYPE(iecho) == ICMP_ER)); + return; + } + else + { + rt_kprintf("ping: drop\n"); + } + } + } + + if (len == 0) + { + LWIP_DEBUGF( PING_DEBUG, ("ping: recv - %lu ms - timeout\n", (sys_now()-ping_time))); + } + + /* do some ping result processing */ + PING_RESULT(0); +} + +rt_err_t ping(char* target, rt_uint32_t time, rt_size_t size) +{ + int s; + int timeout = PING_RCV_TIMEO; + struct ip_addr ping_target; + rt_uint32_t send_time; + struct _ip_addr + { + rt_uint8_t addr0, addr1, addr2, addr3; + } *addr; + + send_time = 0; + + if (inet_aton(target, (struct in_addr*)&ping_target) == 0) return -RT_ERROR; + addr = (struct _ip_addr*)&ping_target; + + if ((s = lwip_socket(AF_INET, SOCK_RAW, IP_PROTO_ICMP)) < 0) + { + rt_kprintf("create socket failled\n"); + return -RT_ERROR; + } + + lwip_setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); + + while (1) + { + if (ping_send(s, &ping_target) == ERR_OK) + { + rt_kprintf("ping: send %d.%d.%d.%d\n", addr->addr0, addr->addr1, addr->addr2, addr->addr3); + ping_recv(s); + } + else + { + rt_kprintf("ping: send %d.%d.%d.%d - error\n", addr->addr0, addr->addr1, addr->addr2, addr->addr3); + } + + send_time ++; + if (send_time > time) break; /* send ping times reached, stop */ + + rt_thread_delay(PING_DELAY); /* take a delay */ + } + + return RT_EOK; +} +#ifdef RT_USING_FINSH +#include +FINSH_FUNCTION_EXPORT(ping, ping network host); +#endif diff --git a/net/apps/sntp.c b/net/apps/sntp.c new file mode 100644 index 0000000000..a9a3f7ddc8 --- /dev/null +++ b/net/apps/sntp.c @@ -0,0 +1,213 @@ +/** + * @file + * SNTP client module + * + */ + +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + */ + +#include "lwip/sys.h" +#include "lwip/sockets.h" + +#include +#include + +/** This is an example of a "SNTP" client (with socket API). + * + * For a list of some public NTP servers, see this link : + * http://support.ntp.org/bin/view/Servers/NTPPoolServers + * + */ + +/** + * SNTP_DEBUG: Enable debugging for SNTP. + */ +#ifndef SNTP_DEBUG +#define SNTP_DEBUG LWIP_DBG_ON +#endif + +/** SNTP server port */ +#ifndef SNTP_PORT +#define SNTP_PORT 123 +#endif + +/** SNTP server address as IPv4 address in "u32_t" format */ +#ifndef SNTP_SERVER_ADDRESS +#define SNTP_SERVER_ADDRESS inet_addr("213.161.194.93") /* pool.ntp.org */ +#endif + +/** SNTP receive timeout - in milliseconds */ +#ifndef SNTP_RECV_TIMEOUT +#define SNTP_RECV_TIMEOUT 3000 +#endif + +/** SNTP update delay - in milliseconds */ +#ifndef SNTP_UPDATE_DELAY +#define SNTP_UPDATE_DELAY 60000 +#endif + +/** SNTP macro to change system time and/or the update the RTC clock */ +#ifndef SNTP_SYSTEM_TIME +#define SNTP_SYSTEM_TIME(t) +#endif + +/* SNTP protocol defines */ +#define SNTP_MAX_DATA_LEN 48 +#define SNTP_RCV_TIME_OFS 32 +#define SNTP_LI_NO_WARNING 0x00 +#define SNTP_VERSION (4/* NTP Version 4*/<<3) +#define SNTP_MODE_CLIENT 0x03 +#define SNTP_MODE_SERVER 0x04 +#define SNTP_MODE_BROADCAST 0x05 +#define SNTP_MODE_MASK 0x07 + +/* number of seconds between 1900 and 1970 */ +#define DIFF_SEC_1900_1970 (2208988800) + +/** + * SNTP processing + */ +static void sntp_process( time_t t) +{ + /* change system time and/or the update the RTC clock */ + SNTP_SYSTEM_TIME(t); + + /* display local time from GMT time */ + LWIP_DEBUGF( SNTP_DEBUG, ("sntp_process: %s", ctime(&t))); +} + +/** + * SNTP request + */ +static void sntp_request() +{ + int sock; + struct sockaddr_in local; + struct sockaddr_in to; + int tolen; + int size; + int timeout; + u8_t sntp_request [SNTP_MAX_DATA_LEN]; + u8_t sntp_response[SNTP_MAX_DATA_LEN]; + u32_t sntp_server_address; + u32_t timestamp; + time_t t; + + /* initialize SNTP server address */ + sntp_server_address = SNTP_SERVER_ADDRESS; + + /* if we got a valid SNTP server address... */ + if (sntp_server_address!=0) + { + /* create new socket */ + sock = socket( AF_INET, SOCK_DGRAM, 0); + if (sock>=0) + { + /* prepare local address */ + memset(&local, 0, sizeof(local)); + local.sin_family = AF_INET; + local.sin_port = htons(INADDR_ANY); + local.sin_addr.s_addr = htonl(INADDR_ANY); + + /* bind to local address */ + if (bind( sock, (struct sockaddr *)&local, sizeof(local))==0) + { + /* set recv timeout */ + timeout = SNTP_RECV_TIMEOUT; + setsockopt( sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout)); + + /* prepare SNTP request */ + memset( sntp_request, 0, sizeof(sntp_request)); + sntp_request[0] = SNTP_LI_NO_WARNING | SNTP_VERSION | SNTP_MODE_CLIENT; + + /* prepare SNTP server address */ + memset(&to, 0, sizeof(to)); + to.sin_family = AF_INET; + to.sin_port = htons(SNTP_PORT); + to.sin_addr.s_addr = sntp_server_address; + + /* send SNTP request to server */ + if (sendto( sock, sntp_request, sizeof(sntp_request), 0, (struct sockaddr *)&to, sizeof(to))>=0) + { + /* receive SNTP server response */ + tolen = sizeof(to); + size = recvfrom( sock, sntp_response, sizeof(sntp_response), 0, (struct sockaddr *)&to, (socklen_t *)&tolen); + + /* if the response size is good */ + if (size == SNTP_MAX_DATA_LEN) + { + /* if this is a SNTP response... */ + if (((sntp_response[0] & SNTP_MODE_MASK) == SNTP_MODE_SERVER) || ((sntp_response[0] & SNTP_MODE_MASK) == SNTP_MODE_BROADCAST)) + { + /* extract GMT time from response */ + SMEMCPY( ×tamp, (sntp_response+SNTP_RCV_TIME_OFS), sizeof(timestamp)); + t = (ntohl(timestamp) - DIFF_SEC_1900_1970); + + /* do time processing */ + sntp_process(t); + + } + else + { + LWIP_DEBUGF( SNTP_DEBUG, ("sntp_request: not response frame code\n")); + } + } + else + { + LWIP_DEBUGF( SNTP_DEBUG, ("sntp_request: not recvfrom==%i\n", errno)); + } + } + else + { + LWIP_DEBUGF( SNTP_DEBUG, ("sntp_request: not sendto==%i\n", errno)); + } + } + /* close the socket */ + closesocket(sock); + } + } +} + +/** + * SNTP thread + */ +static void +sntp_thread(void *arg) +{ + LWIP_UNUSED_ARG(arg); + while(1) + { + sntp_request(); + sys_msleep(SNTP_UPDATE_DELAY); + } +} + +void sntp_init(void) +{ + sys_thread_new("sntp_thread", sntp_thread, NULL, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO); +} diff --git a/net/apps/tftp.c b/net/apps/tftp.c new file mode 100644 index 0000000000..2a0e385533 --- /dev/null +++ b/net/apps/tftp.c @@ -0,0 +1,171 @@ +#include +#include + +#include + +#define TFTP_PORT 69 +/* opcode */ +#define TFTP_RRQ 1 /* read request */ +#define TFTP_WRQ 2 /* write request */ +#define TFTP_DATA 3 /* data */ +#define TFTP_ACK 4 /* ACK */ +#define TFTP_ERROR 5 /* error */ + +rt_uint8_t tftp_buffer[512 + 4]; +/* tftp client */ +void tftp_get(const char* host, const char* filename) +{ + int fd, sock_fd; + struct sockaddr_in tftp_addr, from_addr; + rt_uint32_t length; + socklen_t fromlen; + + /* make local file name */ + getcwd((char*)tftp_buffer, sizeof(tftp_buffer)); + strcat((char*)tftp_buffer, "/"); + strcat((char*)tftp_buffer, filename); + + /* open local file for write */ + fd = open((char*)tftp_buffer, O_RDWR, 0); + if (fd < 0) + { + rt_kprintf("can't open local filename\n"); + return; + } + + /* connect to tftp server */ + inet_aton(host, (struct in_addr*)&(tftp_addr.sin_addr)); + tftp_addr.sin_family = AF_INET; + tftp_addr.sin_port = htons(TFTP_PORT); + + sock_fd = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP); + if (sock_fd < 0) + { + close(fd); + rt_kprintf("can't create a socket\n"); + return ; + } + + /* make tftp request */ + tftp_buffer[0] = 0; /* opcode */ + tftp_buffer[1] = TFTP_RRQ; /* RRQ */ + length = rt_sprintf((char *)&tftp_buffer[2], "%s", filename) + 2; + tftp_buffer[length] = 0; length ++; + length += rt_sprintf((char*)&tftp_buffer[length], "%s", "octet"); + tftp_buffer[length] = 0; length ++; + + fromlen = sizeof(struct sockaddr_in); + + /* send request */ + lwip_sendto(sock_fd, tftp_buffer, length, 0, + (struct sockaddr *)&tftp_addr, fromlen); + + do + { + length = lwip_recvfrom(sock_fd, tftp_buffer, sizeof(tftp_buffer), 0, + (struct sockaddr *)&from_addr, &fromlen); + + if (length > 0) + { + write(fd, &tftp_buffer[4], length - 4); + rt_kprintf("#"); + + /* make ACK */ + tftp_buffer[0] = 0; tftp_buffer[1] = TFTP_ACK; /* opcode */ + /* send ACK */ + lwip_sendto(sock_fd, tftp_buffer, 4, 0, + (struct sockaddr *)&from_addr, fromlen); + } + } while (length != 516); + + close(fd); + lwip_close(sock_fd); +} +FINSH_FUNCTION_EXPORT(tftp_get, get file from tftp server); + +void tftp_put(const char* host, const char* filename) +{ + int fd, sock_fd; + struct sockaddr_in tftp_addr, from_addr; + rt_uint32_t length, block_number = 0; + socklen_t fromlen; + + /* make local file name */ + getcwd((char*)tftp_buffer, sizeof(tftp_buffer)); + strcat((char*)tftp_buffer, "/"); + strcat((char*)tftp_buffer, filename); + + /* open local file for write */ + fd = open((char*)tftp_buffer, O_RDONLY, 0); + if (fd < 0) + { + rt_kprintf("can't open local filename\n"); + return; + } + + /* connect to tftp server */ + inet_aton(host, (struct in_addr*)&(tftp_addr.sin_addr)); + tftp_addr.sin_family = AF_INET; + tftp_addr.sin_port = htons(TFTP_PORT); + tftp_addr.sin_addr.s_addr = htonl(tftp_addr.sin_addr.s_addr); + + sock_fd = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP); + if (sock_fd < 0) + { + close(fd); + rt_kprintf("can't create a socket\n"); + return ; + } + + /* make tftp request */ + tftp_buffer[0] = 0; /* opcode */ + tftp_buffer[1] = TFTP_WRQ; /* WRQ */ + length = rt_sprintf((char *)&tftp_buffer[2], "%s", filename) + 2; + tftp_buffer[length] = 0; length ++; + length += rt_sprintf((char*)&tftp_buffer[length], "%s", "octet"); + tftp_buffer[length] = 0; length ++; + + fromlen = sizeof(struct sockaddr_in); + + /* send request */ + lwip_sendto(sock_fd, tftp_buffer, length, 0, + (struct sockaddr *)&tftp_addr, fromlen); + + /* wait ACK 0 */ + length = lwip_recvfrom(sock_fd, tftp_buffer, sizeof(tftp_buffer), 0, + (struct sockaddr *)&from_addr, &fromlen); + if (!(tftp_buffer[0] == 0 && + tftp_buffer[1] == TFTP_ACK && + tftp_buffer[2] == 0 && + tftp_buffer[3] == 0)) + { + rt_kprintf("tftp server error\n"); + close(fd); + return; + } + + do + { + length = read(fd, &tftp_buffer[4], 512); + if (length > 0) + { + /* make opcode and block number */ + tftp_buffer[0] = 0; tftp_buffer[1] = TFTP_DATA; + tftp_buffer[2] = block_number ; tftp_buffer[3] = block_number; + + lwip_sendto(sock_fd, tftp_buffer, length + 4, 0, + (struct sockaddr *)&from_addr, fromlen); + } + + /* receive ack */ + length = lwip_recvfrom(sock_fd, tftp_buffer, sizeof(tftp_buffer), 0, + (struct sockaddr *)&from_addr, &fromlen); + if (length > 0) + { + } + } while (length != 516); + + close(fd); + lwip_close(sock_fd); +} +FINSH_FUNCTION_EXPORT(tftp_put, put file to tftp server);