Mercurial > ecos
changeset 957:db3e0a2fda2f
2003-04-12 Andrew Lunn <andrew.lunn@ascom.ch>
* src/network_support.c (init_loopback_interface): Close the
socket when things go wrong otherwise we leak sockets.
* src/tftp_server.c (tftpd_server): Added support for IPv6 as well
as IPv4. Extended the multithreading support so that it works
correctly when there are multiple servers on multiple ports.
* doc/tcpip.sgml: Documentation for the changes made to the tftp
server.
2003-04-10 Andrew Lunn <andrew.lunn@ascom.ch>
* src/network_support.c (init_all_network_interfaces): Wait upto 4
seconds for a router solicit message to be received. Once we have
received the message we know we have a valid IPv6 address.
* src/tftp_client.c: Added support for IPv6. This requires two new
functions, tftp_client_{get|put} which are protocol version
independent.
* tests/tftp_client_test.c (tftp_test): Added tests which use IPv6
addresses.
2003-04-07 Andrew Lunn <andrew.lunn@ascom.ch>
* src/getaddrinfo.c (getaddrinfo): Correctly deal with node when
its not NULL. Its OK for the address to not parse for an address
family when AF_UNSPEC is passed in hints. Also get the socktype
correct when wildcarding for services that use UDP.
* tests/addr_test.c: Added more test cases which test IP addresses
in number format as node.
2003-04-05 Andrew Lunn <andrew.lunn@ascom.ch>
* cdl/net.cdl: Added addr_tests to the HW tests.
* tests/addr_test.c (net_test): void function not int.
* tests/ping_test.c (net_test): Added IPv6 ping test. This pings
the router which answers our router solicit message.
* src/ipv6_routing_thread.c (cyg_rs): Print out the router
advertisement message. Cleaned up the debug messages so they can
be disabled.
* src/ipv6_routing_thread.c (cyg_net_get_ipv6_advrouter): New
function to return the address of the router.
* include/network.h: Added prototype for above and
ipv6_start_routing_thread which did not have a prototype.
* src/ipv6_routing_thread.c (cyg_rs): Only wait 2 seconds before
sending the first solicit request rather than 10.
* src/dhcp_prot.c (do_dhcp_down_net): clear the if_laddrreq
before using it. If the request fails finish the IPv4 code rather
than returning,.
2003-04-02 Andrew Lunn <andrew.lunn@ascom.ch>
* tests/ping_lo_test.c: Added IPv6 ping test.
* src/getproto.c: Added the protocol ipv6-icmp.
line wrap: on
line diff
--- a/packages/net/common/current/ChangeLog +++ b/packages/net/common/current/ChangeLog @@ -1,3 +1,14 @@ +2003-04-12 Andrew Lunn <andrew.lunn@ascom.ch> + + * src/network_support.c (init_loopback_interface): Close the + socket when things go wrong otherwise we leak sockets. + + * src/tftp_server.c (tftpd_server): Added support for IPv6 as well + as IPv4. Extended the multithreading support so that it works + correctly when there are multiple servers on multiple ports. + * doc/tcpip.sgml: Documentation for the changes made to the tftp + server. + 2003-04-11 Jonathan Larmour <jifl@eCosCentric.com> * tests/linux_echo.c: Renamed to.... @@ -19,10 +30,57 @@ 2003-04-11 Michael Checky <Michael_Che * tests/nc_test_slave.c: changed 'bool' to 'int' because the compiler didn't like 'bool'. +2003-04-10 Andrew Lunn <andrew.lunn@ascom.ch> + + * src/network_support.c (init_all_network_interfaces): Wait upto 4 + seconds for a router solicit message to be received. Once we have + received the message we know we have a valid IPv6 address. + + * src/tftp_client.c: Added support for IPv6. This requires two new + functions, tftp_client_{get|put} which are protocol version + independent. + * tests/tftp_client_test.c (tftp_test): Added tests which use IPv6 + addresses. + +2003-04-07 Andrew Lunn <andrew.lunn@ascom.ch> + + * src/getaddrinfo.c (getaddrinfo): Correctly deal with node when + its not NULL. Its OK for the address to not parse for an address + family when AF_UNSPEC is passed in hints. Also get the socktype + correct when wildcarding for services that use UDP. + * tests/addr_test.c: Added more test cases which test IP addresses + in number format as node. + +2003-04-05 Andrew Lunn <andrew.lunn@ascom.ch> + + * cdl/net.cdl: Added addr_tests to the HW tests. + * tests/addr_test.c (net_test): void function not int. + * tests/ping_test.c (net_test): Added IPv6 ping test. This pings + the router which answers our router solicit message. + * src/ipv6_routing_thread.c (cyg_rs): Print out the router + advertisement message. Cleaned up the debug messages so they can + be disabled. + * src/ipv6_routing_thread.c (cyg_net_get_ipv6_advrouter): New + function to return the address of the router. + * include/network.h: Added prototype for above and + ipv6_start_routing_thread which did not have a prototype. + * src/ipv6_routing_thread.c (cyg_rs): Only wait 2 seconds before + sending the first solicit request rather than 10. + * src/dhcp_prot.c (do_dhcp_down_net): clear the if_laddrreq + before using it. If the request fails finish the IPv4 code rather + than returning,. + 2003-04-02 Andrew Lunn <andrew.lunn@ascom.ch> - * src/dhcp_prot.c (do_dhcp_down_net): SIOCGLIFADDR and SIOCDLIFADDR - take if_laddrreq not ifreq. This caused stack corruption. + * tests/ping_lo_test.c: Added IPv6 ping test. + * src/getproto.c: Added the protocol ipv6-icmp. + +2003-04-02 Andrew Lunn <andrew.lunn@ascom.ch> + + * src/dhcp_prot.c (do_dhcp_down_net): SIOCGLIFADDR and + SIOCDLIFADDR take if_laddrreq not ifreq. This caused stack + corruption. Also initialise the if_laddrreq to zero and only do + the second IOCTL call if the first once succeeds. 2003-03-21 Nick Garnett <nickg@balti.calivar.com>
--- a/packages/net/common/current/cdl/net.cdl +++ b/packages/net/common/current/cdl/net.cdl @@ -154,6 +154,31 @@ cdl_package CYGPKG_NET { threads can have precedence over TFTP server processing." } + cdl_component CYGSEM_NET_TFTPD_MULTITHREADED { + display "Multiple TFTPD server threads on the same port." + flavor bool + default_value 1 + description " + This option controls the tftp server ability to be + multi-threaded. When enabled, multiple server can be + started on the same port number. This allows multiple + concurrent transfers to be active. When this option is + not enabled, while one transfer is active, other + requests will be delayed or even ignored." + + cdl_option CYGNUM_NET_TFTPD_MULTITHREADED_PORTS { + display "Number of different ports with servers" + flavor data + default_value 1 + description " + Each set of servers running on the same port number + require a semaphore to synchronise there operation. This option + controls the number of semaphores and so the number + of port numbers multithreaded servers which can be + running on." + } + } + cdl_option CYGPKG_NET_TFTP_FILE_ACCESS { display "File I/O functions for TFTP server" flavor bool @@ -370,7 +395,8 @@ cdl_package CYGPKG_NET { tests/tcp_lo_test \ tests/udp_lo_test \ tests/multi_lo_select \ - tests/tcp_lo_select" + tests/tcp_lo_select \ + tests/addr_test.c " : "tests/ping_lo_test \ tests/tcp_lo_test \
--- a/packages/net/common/current/doc/tcpip.sgml +++ b/packages/net/common/current/doc/tcpip.sgml @@ -112,6 +112,12 @@ CYGHWR_NET_DRIVER_ETH0_IPV6_PREFIX for & This is a CDL booldata type, allowing this address to be suppressed if not desired. </PARA> + +<PARA>Alternatively, the system can configure its IPv6 address using +router solicitation. When the CDL option +CYGOPT_NET_IPV6_ROUTING_THREAD is enabled, +<function>init_all_network_interface</function> will start a thread which sends out router solicit messages, process router advertisements and thus configure an IPv6 address to the interface.</PARA> + <PARA> Refer to the test cases, <FILENAME>…/packages/net/common/<REPLACEABLE>VERSION</REPLACEABLE>/tests/ftp_test.c</FILENAME> @@ -228,6 +234,11 @@ the receive timeout. If there is such a 2nd set of pings succeeds, confirming that we can talk to a machine not previously mentioned by configuration or by bootp. It then does the same thing on the other interface, eth1.</PARA> + +<PARA>If IPv6 is enabled, the program will also ping to the address it +last received a router advertisement from. Also a ping will be made to +that address plus 32, in a similar way the the IPv4 case.</PARA> + <PROGRAMLISTING><EMPHASIS>dhcp_test</EMPHASIS> - ping test, but also manipulates DHCP leases</PROGRAMLISTING> <PARA>This test is very similar to the ping test, but in addition, provided the network package is not configured to do this automatically, @@ -362,6 +373,11 @@ be a copy of -rw-rw-rw- 1 root 1076 May 1 15:52 tftp_put </PROGRAMLISTING> + +<PARA>If the configuration contains IPv6 support, the test program +will also use IPv6. It will attempt to put/get the files listed above +from the address it last received a routers solicit from.</PARA> + <PROGRAMLISTING><EMPHASIS>tftp_server_test</EMPHASIS> - runs a tftp server for a short while</PROGRAMLISTING> <PARA>This test is truly interactive, in that you can use a standard tftp application to get and put files from the server, during the @@ -402,8 +418,81 @@ it — or it comes pre-set from the <TITLE>TFTP</TITLE> <PARA>The TFTP client and server are described in <filename>tftp_support.h</filename>; -the client API is simple and can be easily understood by reading -<filename>tftp_client_test.c</filename>.</PARA> + +<PARA>The TFTP client has and new and an older, depreciated, API. The +new API works for both IPv4 and IPv6 where as the depreciated API is +IPv4 only. +</PARA> +<PARA> +The new API is as follows: +</PARA> +<PROGRAMLISTING>int tftp_client_get(char *filename, + char *server, + int port, + char *buf, + int len, + int mode, + int *err); + +int tftp_client_put(char *filename, + char *server, + int port, + char *buf, + int len, + int mode, + int *err); +</PROGRAMLISTING> +<PARA>Currently <varname>server</varname> can only be a numeric IPv4 or +IPv6 address. The resolver is currently not used, but it is planned to +add this feature (patches welcome). If <varname>port</varname> is zero +the client connects to the default TFTP port on the server. Otherwise +the specified port is used. +</PARA> +<PARA> +The depreciated API is: +<PROGRAMLISTING>int tftp_client_get(char *filename, + struct sockaddr_in *server, + char *buf, + int len, + int mode, + int *err); + +int tftp_client_put(char *filename, + struct sockaddr_in *server, + char *buf, + int len, + int mode, + int *err); +</PROGRAMLISTING> +<PARA> +The <varname>server</varname> should contain the address of the +server to contact. If the <varname>sin_port</varname> member of the +structure is zero the default TFTP port is used. Otherwise the +specified port is used. +</PARA> +<PARA> +Both API's report errors in the same way. The functions return a value +of -1 and <varname>*err</varname> will be set to one of the +following values: +</PARA> +<PROGRAMLISTING> +#define TFTP_ENOTFOUND 1 /* file not found */ +#define TFTP_EACCESS 2 /* access violation */ +#define TFTP_ENOSPACE 3 /* disk full or allocation exceeded */ +#define TFTP_EBADOP 4 /* illegal TFTP operation */ +#define TFTP_EBADID 5 /* unknown transfer ID */ +#define TFTP_EEXISTS 6 /* file already exists */ +#define TFTP_ENOUSER 7 /* no such user */ +#define TFTP_TIMEOUT 8 /* operation timed out */ +#define TFTP_NETERR 9 /* some sort of network error */ +#define TFTP_INVALID 10 /* invalid parameter */ +#define TFTP_PROTOCOL 11 /* protocol violation */ +#define TFTP_TOOLARGE 12 /* file is larger than buffer */ +</PROGRAMLISTING> +<PARA>If there are no errors the return value is the number of bytes +transfered. +</PARA> + <PARA>The server is more complex. It requires a filesystem implementation to be supplied by the user, and attached to the tftp server by means of a vector of function pointers:</PARA> @@ -414,9 +503,52 @@ of a vector of function pointers:</PARA> int (*read)(int, void *, int); };</PROGRAMLISTING> <PARA>These functions have the obvious semantics. The structure -describing the filesystem is an argument to the <function>tftpd_start(int, -struct tftpd_fileops *);</function> call. - The first argument is the port to use for the server.</PARA> +describing the filesystem is an argument to the <function>tftpd_start</function>: +<PROGRAMLISTING> +int tftp_start(int port, + struct tftpd_fileops *ops); +</PROGRAMLISTING> +<PARA>The first argument is the port to use for the server. If this +port number is zero, the default TFTP port number will be used. The +return value from <function>tftpd_start</function> is a handle which +can be passed to <function>tftpd_stop</function>. This will kill the +tftpd thread. Note that this is not a clean shutdown. The thread will +simply be killed. <function>tftpd_stop</function> will attempt to +close the sockets the thread was listening on and free some of its +allocated memory. But if the thread was actively transferreing data at +the time <function>tftpd_stop</function> is called, it is quite likely +some memory and a socket will be leaked. Use this function with +caution (or implement a clean shutdown and please contribute the code +back :-). +</PARA> + +<PARA>There are two CDL configuration options that control how many +servers on how many different ports tftp can be +started. CYGSEM_NET_TFTPD_MULTITHREADED, when enabled, allows multiple +tftpd threads to operate on the same port number. With only one +thread, while the thread is active transferring data, new requests for +transfers will not be served until the active transfer is +complete. When multiple threads are started on the same port, multiple +transfers can take place simultaneous, up to the number of threads +started. However a semaphore is required to synchronise the +threads. This semaphore is required per port. The CDL option +CYGNUM_NET_TFTPD_MULTITHREADED_PORTS controls how many different port +numbers multithreaded servers can service. +</PARA> +<PARA>If CYGSEM_NET_TFTPD_MULTITHREADED is not enabled, only one +thread may be run per port number. But this removes the need for a +semaphore and so CYGNUM_NET_TFTPD_MULTITHREADED_PORTS is not required +and unlimited number of ports can be used. </PARA> + +<PARA>It should be noted that the TFTPD does not perform any form of +file locking. When multiple servers are active, it is assumed the +underlying filesystem will refuse to open the same file multiple +times, operate correctly with simultaneous read/writes to the same +file, or if you are unlucky, corrupt itself beyond all repair.</PARA> + +<PARA>When IPv6 is enabled the tftpd thread will listen for requests +from both IPv4 and IPv6 addresses.</PARA> + <PARA>As discussed in the description of the tftp_server_test above, an example filesystem is provided in <filename>net/common/<REPLACEABLE>VERSION</REPLACEABLE>/src/tftp_dummy_file.c</filename>
--- a/packages/net/common/current/include/network.h +++ b/packages/net/common/current/include/network.h @@ -19,7 +19,7 @@ //#####DESCRIPTIONBEGIN#### // // Author(s): gthomas -// Contributors: gthomas +// Contributors: gthomas, andrew.lunn@ascom.ch // Date: 2000-01-10 // Purpose: // Description: @@ -82,4 +82,11 @@ extern const char *eth1_name; #define CYG_NET_GET_MEM_STATS_CLUST 2 // Clust pool int cyg_net_get_mem_stats( int which, cyg_mempool_info *p ); +#ifdef CYGPKG_NET_INET6 +#ifdef CYGOPT_NET_IPV6_ROUTING_THREAD +__externC void ipv6_start_routing_thread(void); +__externC int cyg_net_get_ipv6_advrouter(struct sockaddr_in6 * addr); +#endif +#endif + #endif // _NETWORK_H_
--- a/packages/net/common/current/include/tftp_support.h +++ b/packages/net/common/current/include/tftp_support.h @@ -19,7 +19,7 @@ //#####DESCRIPTIONBEGIN#### // // Author(s): gthomas -// Contributors: gthomas +// Contributors: gthomas, andrew.lunn@ascom.ch // Date: 2000-04-06 // Purpose: // Description: @@ -81,6 +81,11 @@ struct tftpd_fileops { * Client support */ +/* IPv4 and IPv6 */ +__externC int tftp_client_get(char *, char *, int, char *, int, int, int *); +__externC int tftp_client_put(char *, char *, int, char *, int, int, int *); + +/* IPv4 only */ __externC int tftp_get(char *, struct sockaddr_in *, char *, int, int, int *); __externC int tftp_put(char *, struct sockaddr_in *, char *, int, int, int *);
--- a/packages/net/common/current/src/dhcp_prot.c +++ b/packages/net/common/current/src/dhcp_prot.c @@ -9,6 +9,7 @@ // ------------------------------------------- // This file is part of eCos, the Embedded Configurable Operating System. // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. +// Copyright (C) 2003 Andrew Lunn // // 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 @@ -41,7 +42,7 @@ //#####DESCRIPTIONBEGIN#### // // Author(s): hmt -// Contributors: gthomas +// Contributors: gthomas, andrew.lunn@ascom.ch // Date: 2000-07-01 // Purpose: DHCP support // Description: @@ -1311,17 +1312,16 @@ do_dhcp_down_net(const char *intf, struc return false; } // Now delete the ipv6 addr + memset(&iflr,0,sizeof(iflr)); strcpy(iflr.iflr_name, intf); - if (ioctl(s6, SIOCGLIFADDR, &iflr)) { - perror("SIOCGIFADDR_IN6 1"); - return false; - } + if (!ioctl(s6, SIOCGLIFADDR, &iflr)) { - strcpy(iflr.iflr_name, intf); - if (ioctl(s6, SIOCDLIFADDR, &iflr)) { /* delete IF addr */ - perror("SIOCDIFADDR_IN61"); + strcpy(iflr.iflr_name, intf); + if (ioctl(s6, SIOCDLIFADDR, &ifr)) { /* delete IF addr */ + perror("SIOCDIFADDR_IN61"); + } + close(s6); } - close(s6); } #endif /* IP6 */
--- a/packages/net/common/current/src/getaddrinfo.c +++ b/packages/net/common/current/src/getaddrinfo.c @@ -9,6 +9,7 @@ // // Copyright (C) 2000, 2001, 2002 Red Hat, Inc. // Copyright (C) 2003 Gary Thomas +// Copyright (C) 2003 andrew.lunn@ascom.ch // All Rights Reserved. // // Permission is granted to use, copy, modify and redistribute this @@ -19,7 +20,7 @@ //#####DESCRIPTIONBEGIN#### // // Author(s): gthomas -// Contributors: gthomas +// Contributors: gthomas, andrew.lunn@ascom.ch // Date: 2002-03-05 // Purpose: // Description: @@ -68,7 +69,11 @@ static int if (hints->ai_flags & AI_PASSIVE) { sa->sin_addr.s_addr = htonl(INADDR_ANY); } else { +#ifdef CYGPKG_NET_OPENBSD_STACK + sa->sin_addr.s_addr = INADDR_LOOPBACK; +#else sa->sin_addr.s_addr = htonl(INADDR_LOOPBACK); +#endif } } else { _hent = gethostbyname(node); @@ -123,11 +128,15 @@ getaddrinfo(const char *nodename, const struct addrinfo dflt_hints; struct protoent *proto = (struct protoent *)NULL; struct addrinfo *ai; +#ifdef CYGPKG_NET_INET6 + struct addrinfo *nai; +#endif char *protoname; + char *endptr; int port = 0; - int family; int err; - + int used = 0; + if (hints == (struct addrinfo *)NULL) { dflt_hints.ai_flags = 0; // No special flags dflt_hints.ai_family = PF_UNSPEC; @@ -142,12 +151,10 @@ getaddrinfo(const char *nodename, const switch (hints->ai_family) { case PF_UNSPEC: case PF_INET: - family = AF_INET; - break; + break; #ifdef CYGPKG_NET_INET6 case PF_INET6: - family = AF_INET6; - break; + break; #endif default: return EAI_FAMILY; @@ -161,7 +168,6 @@ getaddrinfo(const char *nodename, const if (hints->ai_protocol != 0) { proto = getprotobynumber(hints->ai_protocol); } - ai->ai_family = family; if (servname != (char *)NULL) { switch (hints->ai_socktype) { case 0: @@ -178,7 +184,8 @@ getaddrinfo(const char *nodename, const return EAI_SOCKTYPE; } // See if this is just a port # - if ((port = strtol(servname, 0, 0)) >= 0) { + if (((port = strtol(servname, &endptr, 0)) >= 0) && + (endptr > servname)) { ai->ai_socktype = hints->ai_socktype; if (hints->ai_socktype == 0) { // Need to have complete binding type/port @@ -199,7 +206,8 @@ getaddrinfo(const char *nodename, const freeaddrinfo(ai); return EAI_SERVICE; } - port = ntohs(serv->s_port); + port = ntohs(serv->s_port); + ai->ai_socktype = SOCK_DGRAM; } proto = getprotobyname(protoname); if (hints->ai_protocol && (hints->ai_protocol != proto->p_proto)) { @@ -211,30 +219,51 @@ getaddrinfo(const char *nodename, const // Iterate through address types and create addresses // Note: this does not handle the case where a given service can be // handled via multiple protocols, e.g. http/tcp & http/udp - err = _getaddr(ai, nodename, hints, family, port); - if (err != EAI_NONE) { + if ((hints->ai_family == AF_INET) || (hints->ai_family == PF_UNSPEC)) { + err = _getaddr(ai, nodename, hints, AF_INET, port); + if ((err != EAI_NONE) && (hints->ai_family == AF_INET)) { freeaddrinfo(ai); return err; + } + if (err == EAI_NONE) { + ai->ai_family = AF_INET; + used = 1; + } } #ifdef CYGPKG_NET_INET6 - if (hints->ai_family == PF_UNSPEC) { - // Add IPv6 address as well - struct addrinfo *nai = (struct addrinfo *)calloc(1, sizeof(struct addrinfo)); + if ((hints->ai_family == AF_INET6) || (hints->ai_family == PF_UNSPEC)) { + if (1 == used) { + nai = (struct addrinfo *)calloc(1,sizeof(struct addrinfo)); if (nai == (struct addrinfo *)NULL) { - freeaddrinfo(ai); - return EAI_MEMORY; + freeaddrinfo(ai); + return EAI_MEMORY; } ai->ai_next = nai; - nai->ai_family = PF_INET6; nai->ai_socktype = ai->ai_socktype; nai->ai_protocol = ai->ai_protocol; - err = _getaddr(nai, nodename, hints, AF_INET6, port); - if (err != EAI_NONE) { - freeaddrinfo(*res); - return err; - } + } else { + nai = ai; + } + err = _getaddr(nai, nodename, hints, AF_INET6, port); + if ((err != EAI_NONE) && (hints->ai_family == AF_INET6)) { + freeaddrinfo(ai); + return err; + } + // Free the second entry which has not been used + if ((err != EAI_NONE) && (1 == used)) { + ai->ai_next = NULL; + free(nai); + } + if (err == EAI_NONE) { + nai->ai_family = AF_INET6; + used = 1; + } } #endif + // Do we have at least one address? + if (0 == used) { + return EAI_NONAME; + } // Note: null nodename is the same as 'localhost' if (nodename == (char *)NULL) { nodename = (const char *)"localhost";
--- a/packages/net/common/current/src/getproto.c +++ b/packages/net/common/current/src/getproto.c @@ -19,7 +19,7 @@ //#####DESCRIPTIONBEGIN#### // // Author(s): gthomas -// Contributors: gthomas +// Contributors: gthomas, andrew.lunn@ascom.ch // Date: 2000-01-10 // Purpose: // Description: @@ -51,7 +51,8 @@ static struct protoent protocols[] = { { "xtp", 36}, // Xpress Tranfer Protocol { "ddp", 37}, // Datagram Delivery Protocol { "idpr-cmtp", 39}, // IDPR Control Message Transport - { "rspf", 73}, //Radio Shortest Path First. + { "ipv6-icmp", 58}, // ICMP for IPv6 + { "rspf", 73}, // Radio Shortest Path First. { "vmtp", 81}, // Versatile Message Transport { "ospf", 89}, // Open Shortest Path First IGP { "ipip", 94}, // Yet Another IP encapsulation
--- a/packages/net/common/current/src/ifaddrs.c +++ b/packages/net/common/current/src/ifaddrs.c @@ -52,6 +52,8 @@ * BSDI getifaddrs.c,v 2.12 2000/02/23 14:51:59 dab Exp */ +#include <cyg/infra/diag.h> + #include <unistd.h> #include <stdlib.h> #include <string.h>
--- a/packages/net/common/current/src/ipv6_routing_thread.c +++ b/packages/net/common/current/src/ipv6_routing_thread.c @@ -19,7 +19,7 @@ //#####DESCRIPTIONBEGIN#### // // Author(s): gthomas -// Contributors: gthomas, lhamilton +// Contributors: gthomas, lhamilton, andrew.lunn@ascom.ch // Date: 2002-04-16 // Purpose: // Description: @@ -58,7 +58,7 @@ void _show_all_interfaces(void); -#define DBG_PRINT 1 +//#define DBG_PRINT 1 #define ALLROUTER "ff02::2" #define STACK_SIZE CYGNUM_HAL_STACK_SIZE_TYPICAL+2048 @@ -87,6 +87,19 @@ static struct timeval last_ra_time; static struct timeval idle_expire; static struct icmp6stat *istat; extern struct icmp6stat cyg_icmp6stat; +static struct sockaddr_in6 router; +static int router_valid = 0; + +// Return the address of the last router to send us a router advertisement +// Copy the address into addr and return true. If we have not received an +// advertisement yet, return false +int cyg_net_get_ipv6_advrouter(struct sockaddr_in6 * addr) { + + if (addr) { + memcpy(addr,&router,sizeof(*addr)); + } + return router_valid; +} static void cyg_rs_exit(void) @@ -154,17 +167,87 @@ receive_ra_packet(void) { int len; char msg[1024]; + struct nd_router_advert *advert; + cyg_uint8 *opts; + int optlen; + int addrlen = sizeof(router); + char buf[64]; dprnt("%s", __FUNCTION__); - len = read(s, msg, sizeof(msg)); + len = recvfrom(s, msg, sizeof(msg),0,(struct sockaddr *)&router,&addrlen); if (len < 0) { dprnt(" Can't read RA data: %s", strerror(errno)); return; } + router_valid = 1; + + inet_ntop(AF_INET6,(void *)&router.sin6_addr,buf,64); + dprnt("Router Advertisement from %s",buf); dprnt("packet data (buf len=%d) :", len); +#ifdef DBG_PRINT diag_dump_buf(msg, len); +#endif + advert = (struct nd_router_advert *)msg; + + dprnt("AdvCurHopLimit: %d", (int) advert->nd_ra_curhoplimit); + dprnt("AdvManagedFlag: %s", + (advert->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) ? "yes" : "no"); + dprnt("AdvOtherConfigFlag: %s", + (advert->nd_ra_flags_reserved & ND_RA_FLAG_OTHER) ? "yes":"no"); + dprnt("AdvHomeAgentFlag: %s", + (advert->nd_ra_flags_reserved & ND_RA_FLAG_HOME_AGENT) ? + "yes" : "no"); + dprnt("AdvReachableTime: %lu", + (unsigned long)ntohl(advert->nd_ra_reachable)); + dprnt("AdvRetransTimer: %lu", + (unsigned long)ntohl(advert->nd_ra_retransmit)); + + // Now process the optinal fields + len -= sizeof(*advert); + opts = (cyg_uint8 *)(msg + sizeof(struct nd_router_advert)); + + while (len > 0) { + optlen = (opts[1] << 3); + switch (*opts) { + case ND_OPT_MTU: { + struct nd_opt_mtu *mtu = (struct nd_opt_mtu *) opts; + + dprnt("AdvLinkMTU: %lu", + (unsigned long)ntohl(mtu->nd_opt_mtu_mtu)); + break; + } + case ND_OPT_PREFIX_INFORMATION: { + struct nd_opt_prefix_info *pinfo = (struct nd_opt_prefix_info *) opts; + + inet_ntop(AF_INET6,(void *)&pinfo->nd_opt_pi_prefix,buf,64); + dprnt("Prefix: %s/%d",buf,pinfo->nd_opt_pi_prefix_len); + break; + } + case ND_OPT_SOURCE_LINKADDR: { + char *cp = buf; + int i; + + for (i = 2 ; i < optlen ; i++) { + cp += diag_sprintf(cp,"%02x ", (unsigned int) opts[i]); + } + + dprnt("AdvSourceLinkAddress: %s",buf); + break; + } + case ND_OPT_ADVINTERVAL: + case ND_OPT_HOMEAGENT_INFO: + dprnt("Mobile IPv6 entension options (not decoded)"); + break; + default: + dprnt("Unknown option %d\n", (int)*opts); + break; + } + len -= optlen; + opts += optlen; + } + racount++; get_realtime(&last_ra_time); dprnt("racount=%d, timestamp=%d sec", @@ -251,7 +334,9 @@ cyg_rs(cyg_addrword_t param) u_int hlim = 255; fd_set fdset; +#ifdef DBG_PRINT _show_all_interfaces(); +#endif memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET6; @@ -289,7 +374,7 @@ cyg_rs(cyg_addrword_t param) idle_expire.tv_usec = 0; select_timeout.tv_usec = 0; last_ra_time.tv_usec = 0; - last_ra_time.tv_sec = 10; + last_ra_time.tv_sec = 2; select(0, 0, 0, 0, &last_ra_time); racount = 0;
--- a/packages/net/common/current/src/network_support.c +++ b/packages/net/common/current/src/network_support.c @@ -128,6 +128,7 @@ cyg_bool_t init_loopback_interface(int l } if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &one, sizeof(one))) { perror("setsockopt"); + close(s); return false; } @@ -149,6 +150,7 @@ cyg_bool_t init_loopback_interface(int l if (ioctl(s, SIOCSIFADDR, &ifr)) { perror("SIOCIFADDR"); + close(s); return false; } @@ -166,6 +168,7 @@ cyg_bool_t init_loopback_interface(int l ifr.ifr_flags = IFF_UP | IFF_BROADCAST | IFF_RUNNING; if (ioctl(s, SIOCSIFFLAGS, &ifr)) { perror("SIOCSIFFLAGS"); + close(s); return false; } @@ -191,6 +194,7 @@ cyg_bool_t init_loopback_interface(int l diag_printf(", gateway: %s\n", inet_ntoa(((struct sockaddr_in *)&route.rt_gateway)->sin_addr)); if (errno != EEXIST) { perror("SIOCADDRT 3"); + close(s); return false; } } @@ -283,6 +287,9 @@ init_all_network_interfaces(void) #ifdef CYGPKG_IO_PCMCIA cyg_netdevtab_entry_t *t; #endif // CYGPKG_IO_PCMCIA +#ifdef CYGOPT_NET_IPV6_ROUTING_THREAD + int rs_wait = 40; +#endif cyg_scheduler_lock(); while ( in_init_all_network_interfaces ) { @@ -455,6 +462,14 @@ init_all_network_interfaces(void) #ifdef CYGOPT_NET_IPV6_ROUTING_THREAD ipv6_start_routing_thread(); + + // Wait for router solicit process to happen. + while (rs_wait-- && !cyg_net_get_ipv6_advrouter(NULL)) { + cyg_thread_delay(10); + } + if (rs_wait == 0 ) { + diag_printf("No router solicit received\n"); + } #endif #ifdef CYGDAT_NS_DNS_DEFAULT_SERVER
--- a/packages/net/common/current/src/tftp_client.c +++ b/packages/net/common/current/src/tftp_client.c @@ -9,6 +9,7 @@ // ------------------------------------------- // This file is part of eCos, the Embedded Configurable Operating System. // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. +// Copyright (C) 2003 Andrew.Lunn@ascom.ch // // 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 @@ -41,7 +42,7 @@ //#####DESCRIPTIONBEGIN#### // // Author(s): gthomas -// Contributors: gthomas +// Contributors: gthomas, andrew.lunn@ascom.ch // Date: 2000-04-06 // Purpose: // Description: @@ -63,25 +64,31 @@ // Read a file from a host into a local buffer. Returns the // number of bytes actually read, or (-1) if an error occurs. // On error, *err will hold the reason. -// -int -tftp_get(char *filename, - struct sockaddr_in *server, - char *buf, - int len, - int mode, - int *err) -{ - int res = 0; - int s, actual_len, data_len, recv_len, from_len; +// This version uses the server name. This can be a name for DNS lookup +// or a dotty or colony number format for IPv4 or IPv6. +int tftp_client_get(char *filename, + char *server, + int port, + char *buf, + int len, + int mode, + int *err) { + + int result = 0; + int s=-1; + int actual_len, data_len, recv_len, from_len; static int get_port = 7700; - struct sockaddr_in local_addr, server_addr, from_addr; + struct addrinfo * addrinfo; + struct addrinfo * res; + struct addrinfo hints; + int error; + + struct sockaddr local_addr, from_addr; char data[SEGSIZE+sizeof(struct tftphdr)]; struct tftphdr *hdr = (struct tftphdr *)data; char *cp, *fp; struct timeval timeout; unsigned short last_good_block = 0; - struct servent *server_info; fd_set fds; int total_timeouts = 0; @@ -103,130 +110,188 @@ tftp_get(char *filename, } while (*fp) *cp++ = *fp++; *cp++ = '\0'; - server_info = getservbyname("tftp", "udp"); - if (server_info == (struct servent *)0) { - *err = TFTP_NETERR; - return -1; - } - s = socket(AF_INET, SOCK_DGRAM, 0); - if (s < 0) { - // Couldn't open a communications channel - *err = TFTP_NETERR; - return -1; + memset(&hints,0,sizeof(hints)); + hints.ai_family = PF_UNSPEC; + error = getaddrinfo(server, "tftp", &hints, &res); + if (error) { + *err = TFTP_NETERR; + return -1; } - memset((char *)&local_addr, 0, sizeof(local_addr)); - local_addr.sin_family = AF_INET; - local_addr.sin_len = sizeof(local_addr); - local_addr.sin_addr.s_addr = htonl(INADDR_ANY); - local_addr.sin_port = htons(get_port++); - if (bind(s, (struct sockaddr *)&local_addr, sizeof(local_addr)) < 0) { - // Problem setting up my end - *err = TFTP_NETERR; - close(s); - return -1; - } - memset((char *)&server_addr, 0, sizeof(server_addr)); - server_addr.sin_family = AF_INET; - server_addr.sin_len = sizeof(server_addr); - server_addr.sin_addr = server->sin_addr; - if (server->sin_port == 0) { - server_addr.sin_port = server_info->s_port; // Network order already - } else { - server_addr.sin_port = server->sin_port; - } + + addrinfo = res; + while (addrinfo) { + s = socket(addrinfo->ai_family, addrinfo->ai_socktype, + addrinfo->ai_protocol); + if (s >= 0) { + memcpy(&local_addr,addrinfo->ai_addr,addrinfo->ai_addrlen); + switch(addrinfo->ai_addr->sa_family) { + case AF_INET: { + struct sockaddr_in * saddr = + (struct sockaddr_in *) addrinfo->ai_addr; + struct sockaddr_in * laddr = + (struct sockaddr_in *) &local_addr; + if (port) { + saddr->sin_port = htons(port); + } + laddr->sin_port = htons(get_port++); + laddr->sin_addr.s_addr = INADDR_ANY; + break; + } +#ifdef CYGPKG_NET_INET6 + case AF_INET6: { + struct sockaddr_in6 * saddr = + (struct sockaddr_in6 *) addrinfo->ai_addr; + struct sockaddr_in6 * laddr = + (struct sockaddr_in6 *) &local_addr; + if (port) { + saddr->sin6_port = htons(port); + } + laddr->sin6_port = htons(get_port++); + laddr->sin6_addr = in6addr_any; + break; + } +#endif + default: + *err = TFTP_NETERR; + goto out; + } - // Send request - if (sendto(s, data, (int)(cp - data), 0, - (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { - // Problem sending request - *err = TFTP_NETERR; - close(s); - return -1; - } + if (bind(s,&local_addr,addrinfo->ai_addrlen) < 0) { + *err = TFTP_NETERR; + goto out; + } + + // Send request + if (sendto(s, data, (int)(cp-data), 0, + addrinfo->ai_addr, + addrinfo->ai_addrlen) < 0) { + // Problem sending request + *err = TFTP_NETERR; + goto nextaddr; + } - // Read data - fp = buf; - while (true) { - timeout.tv_sec = TFTP_TIMEOUT_PERIOD; - timeout.tv_usec = 0; - FD_ZERO(&fds); - FD_SET(s, &fds); - if (select(s+1, &fds, 0, 0, &timeout) <= 0) { - if ((++total_timeouts > TFTP_TIMEOUT_MAX) || (last_good_block == 0)) { - // Timeout - no data received - *err = TFTP_TIMEOUT; - close(s); - return -1; - } - // Try resending last ACK - hdr->th_opcode = htons(ACK); - hdr->th_block = htons(last_good_block); - if (sendto(s, data, 4 /* FIXME */, 0, - (struct sockaddr *)&from_addr, from_len) < 0) { - // Problem sending request - *err = TFTP_NETERR; - close(s); - return -1; - } - } else { - recv_len = sizeof(data); - from_len = sizeof(from_addr); - if ((data_len = recvfrom(s, &data, recv_len, 0, - (struct sockaddr *)&from_addr, &from_len)) < 0) { - // What happened? - *err = TFTP_NETERR; - close(s); - return -1; - } - if (ntohs(hdr->th_opcode) == DATA) { - actual_len = 0; - if (ntohs(hdr->th_block) == (last_good_block+1)) { - // Consume this data - cp = hdr->th_data; - data_len -= 4; /* Sizeof TFTP header */ - actual_len = data_len; - res += actual_len; - while (data_len-- > 0) { - if (len-- > 0) { - *fp++ = *cp++; - } else { - // Buffer overflow - *err = TFTP_TOOLARGE; - close(s); - return -1; - } - } - last_good_block++; - } - // Send out the ACK - hdr->th_opcode = htons(ACK); - hdr->th_block = htons(last_good_block); - if (sendto(s, data, 4 /* FIXME */, 0, - (struct sockaddr *)&from_addr, from_len) < 0) { - // Problem sending request - *err = TFTP_NETERR; - close(s); - return -1; - } - if ((actual_len >= 0) && (actual_len < SEGSIZE)) { - // End of data - close(s); - return res; - } - } else - if (ntohs(hdr->th_opcode) == ERROR) { - *err = ntohs(hdr->th_code); - close(s); - return -1; - } else { - // What kind of packet is this? + // Read data + fp = buf; + while (true) { + timeout.tv_sec = TFTP_TIMEOUT_PERIOD; + timeout.tv_usec = 0; + FD_ZERO(&fds); + FD_SET(s, &fds); + if (select(s+1, &fds, 0, 0, &timeout) <= 0) { + if ((++total_timeouts > TFTP_TIMEOUT_MAX) + || (last_good_block == 0)) { + // Timeout - no data received + *err = TFTP_TIMEOUT; + goto out; + } + // Try resending last ACK + hdr->th_opcode = htons(ACK); + hdr->th_block = htons(last_good_block); + if (sendto(s, data, 4 /* FIXME */, 0, + &from_addr, from_len) < 0) { + // Problem sending request + *err = TFTP_NETERR; + goto out; + } + } else { + recv_len = sizeof(data); + from_len = sizeof(from_addr); + if ((data_len = recvfrom(s, &data, recv_len, 0, + &from_addr, &from_len)) < 0) { + // What happened? + *err = TFTP_NETERR; + goto out; + } + if (ntohs(hdr->th_opcode) == DATA) { + actual_len = 0; + if (ntohs(hdr->th_block) == (last_good_block+1)) { + // Consume this data + cp = hdr->th_data; + data_len -= 4; /* Sizeof TFTP header */ + actual_len = data_len; + result += actual_len; + while (data_len-- > 0) { + if (len-- > 0) { + *fp++ = *cp++; + } else { + // Buffer overflow + *err = TFTP_TOOLARGE; + goto out; + } + } + last_good_block++; + } + // Send out the ACK + hdr->th_opcode = htons(ACK); + hdr->th_block = htons(last_good_block); + if (sendto(s, data, 4 /* FIXME */, 0, + &from_addr, from_len) < 0) { + // Problem sending request + *err = TFTP_NETERR; + goto out; + } + if ((actual_len >= 0) && (actual_len < SEGSIZE)) { + // End of data + close(s); + freeaddrinfo(res); + return result; + } + } else + if (ntohs(hdr->th_opcode) == ERROR) { + *err = ntohs(hdr->th_code); + goto out; + } else { + // What kind of packet is this? *err = TFTP_PROTOCOL; - close(s); - return -1; - } - } + goto out; + } + } + } + } + // If we got here, it means there was a problem connecting to the + // server. Try the next address returned by getaddrinfo + nextaddr: + if (-1 != s) { + close(s); + } + addrinfo=addrinfo->ai_next; + } + // We ran into problems. Cleanup + out: + if (-1 != s) { + close (s); } + freeaddrinfo(res); + return -1; +} +// +// Read a file from a host into a local buffer. Returns the +// number of bytes actually read, or (-1) if an error occurs. +// On error, *err will hold the reason. +// +// Depreciated. Use tftp_client_get instead. +int +tftp_get(char *filename, + struct sockaddr_in *server, + char *buf, + int len, + int mode, + int *err) +{ + char server_name[20]; + char *ret; + int port; + + ret = inet_ntop(AF_INET, (void *)&server->sin_addr, + server_name, sizeof(server_name)); + if (NULL == ret) { + *err = TFTP_NETERR; + return -1; + } + port = server->sin_port; + + return tftp_client_get(filename, server_name, port, buf, len, mode, err); } // @@ -240,186 +305,247 @@ tftp_put(char *filename, int mode, int *err) { - int res = 0; + char server_name[20]; + char *ret; + int port; + + ret = inet_ntop(AF_INET, (void *)&server->sin_addr, + server_name, sizeof(server_name)); + if (NULL == ret) { + *err = TFTP_NETERR; + return -1; + } + port = server->sin_port; + + return tftp_client_put(filename, server_name, port, buf, len, mode, err); +} + +// +// Put a file to a host from a local buffer. Returns the +// number of bytes actually writen, or (-1) if an error occurs. +// On error, *err will hold the reason. +// This version uses the server name. This can be a name for DNS lookup +// or a dotty or colony number format for IPv4 or IPv6. +int tftp_client_put(char *filename, + char *server, + int port, + char *buf, + int len, + int mode, + int *err) { + + int result = 0; int s, actual_len, data_len, recv_len, from_len; static int put_port = 7800; - struct sockaddr_in local_addr, server_addr, from_addr; + struct sockaddr local_addr, from_addr; char data[SEGSIZE+sizeof(struct tftphdr)]; struct tftphdr *hdr = (struct tftphdr *)data; char *cp, *fp, *sfp; struct timeval timeout; unsigned short last_good_block = 0; - struct servent *server_info; fd_set fds; int total_timeouts = 0; + struct addrinfo hints; + struct addrinfo * addrinfo; + struct addrinfo * res; + int error; *err = 0; // Just in case - server_info = getservbyname("tftp", "udp"); - if (server_info == (struct servent *)0) { - *err = TFTP_NETERR; - return -1; - } - - s = socket(AF_INET, SOCK_DGRAM, 0); - if (s < 0) { - // Couldn't open a communications channel - *err = TFTP_NETERR; - return -1; - } - memset((char *)&local_addr, 0, sizeof(local_addr)); - local_addr.sin_family = AF_INET; - local_addr.sin_len = sizeof(local_addr); - local_addr.sin_addr.s_addr = htonl(INADDR_ANY); - local_addr.sin_port = htons(put_port++); - if (bind(s, (struct sockaddr *)&local_addr, sizeof(local_addr)) < 0) { - // Problem setting up my end - *err = TFTP_NETERR; - close(s); - return -1; + memset(&hints,0,sizeof(hints)); + hints.ai_family = PF_UNSPEC; + error = getaddrinfo(server, "tftp", &hints, &res); + if (error) { + *err = TFTP_NETERR; + return -1; } - memset((char *)&server_addr, 0, sizeof(server_addr)); - server_addr.sin_family = AF_INET; - server_addr.sin_len = sizeof(server_addr); - server_addr.sin_addr = server->sin_addr; - if (server->sin_port == 0) { - server_addr.sin_port = server_info->s_port; // Network order already - } else { - server_addr.sin_port = server->sin_port; - } + + addrinfo = res; + while (addrinfo) { + s = socket(addrinfo->ai_family, addrinfo->ai_socktype, + addrinfo->ai_protocol); + if (s >= 0) { + memcpy(&local_addr,addrinfo->ai_addr,addrinfo->ai_addrlen); + switch(addrinfo->ai_addr->sa_family) { + case AF_INET: { + struct sockaddr_in * saddr = + (struct sockaddr_in *) addrinfo->ai_addr; + struct sockaddr_in * laddr = + (struct sockaddr_in *) &local_addr; + if (port) { + saddr->sin_port = htons(port); + } + laddr->sin_port = htons(put_port++); + laddr->sin_addr.s_addr = INADDR_ANY; + break; + } +#ifdef CYGPKG_NET_INET6 + case AF_INET6: { + struct sockaddr_in6 * saddr = + (struct sockaddr_in6 *) addrinfo->ai_addr; + struct sockaddr_in6 * laddr = + (struct sockaddr_in6 *) &local_addr; + if (port) { + saddr->sin6_port = htons(port); + } + laddr->sin6_port = htons(put_port++); + laddr->sin6_addr = in6addr_any; + break; + } +#endif + default: + *err = TFTP_NETERR; + goto out; + } + if (bind(s, + (struct sockaddr *)&local_addr, + addrinfo->ai_addrlen) < 0) { + // Problem setting up my end + *err = TFTP_NETERR; + goto out; + } - while (1) { - // Create initial request - hdr->th_opcode = htons(WRQ); // Create/write file - cp = (char *)&hdr->th_stuff; - fp = filename; - while (*fp) *cp++ = *fp++; - *cp++ = '\0'; - if (mode == TFTP_NETASCII) { + while (1) { + // Create initial request + hdr->th_opcode = htons(WRQ); // Create/write file + cp = (char *)&hdr->th_stuff; + fp = filename; + while (*fp) *cp++ = *fp++; + *cp++ = '\0'; + if (mode == TFTP_NETASCII) { fp = "NETASCII"; - } else if (mode == TFTP_OCTET) { + } else if (mode == TFTP_OCTET) { fp = "OCTET"; - } else { + } else { *err = TFTP_INVALID; - return -1; - } - while (*fp) *cp++ = *fp++; - *cp++ = '\0'; - // Send request - if (sendto(s, data, (int)(cp-data), 0, - (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { + goto out; + } + while (*fp) *cp++ = *fp++; + *cp++ = '\0'; + // Send request + if (sendto(s, data, (int)(cp-data), 0, + addrinfo->ai_addr, + addrinfo->ai_addrlen) < 0) { // Problem sending request *err = TFTP_NETERR; - close(s); - return -1; - } - // Wait for ACK - timeout.tv_sec = TFTP_TIMEOUT_PERIOD; - timeout.tv_usec = 0; - FD_ZERO(&fds); - FD_SET(s, &fds); - if (select(s+1, &fds, 0, 0, &timeout) <= 0) { + goto nextaddr; + } + // Wait for ACK + timeout.tv_sec = TFTP_TIMEOUT_PERIOD; + timeout.tv_usec = 0; + FD_ZERO(&fds); + FD_SET(s, &fds); + if (select(s+1, &fds, 0, 0, &timeout) <= 0) { if (++total_timeouts > TFTP_TIMEOUT_MAX) { - // Timeout - no ACK received - *err = TFTP_TIMEOUT; - close(s); - return -1; + // Timeout - no ACK received + *err = TFTP_TIMEOUT; + goto nextaddr; } - } else { + } else { recv_len = sizeof(data); from_len = sizeof(from_addr); if ((data_len = recvfrom(s, &data, recv_len, 0, - (struct sockaddr *)&from_addr, &from_len)) < 0) { - // What happened? - *err = TFTP_NETERR; - close(s); - return -1; + &from_addr, &from_len)) < 0) { + // What happened? + *err = TFTP_NETERR; + goto out; } if (ntohs(hdr->th_opcode) == ACK) { - // Write request accepted - start sending data - break; + // Write request accepted - start sending data + break; } else - if (ntohs(hdr->th_opcode) == ERROR) { + if (ntohs(hdr->th_opcode) == ERROR) { *err = ntohs(hdr->th_code); - close(s); - return -1; - } else { + goto out; + } else { // What kind of packet is this? - *err = TFTP_PROTOCOL; - close(s); - return -1; - } - } - } - - // Send data - sfp = buf; - last_good_block = 1; - while (res < len) { - // Build packet of data to send - data_len = min(SEGSIZE, len-res); - hdr->th_opcode = htons(DATA); - hdr->th_block = htons(last_good_block); - cp = hdr->th_data; - fp = sfp; - actual_len = data_len + 4; - // FIXME - what about "netascii" data? - while (data_len-- > 0) *cp++ = *fp++; - // Send data packet - if (sendto(s, data, actual_len, 0, - (struct sockaddr *)&from_addr, from_len) < 0) { + goto out; + } + } + } + + // Send data + sfp = buf; + last_good_block = 1; + while (result < len) { + // Build packet of data to send + data_len = min(SEGSIZE, len-result); + hdr->th_opcode = htons(DATA); + hdr->th_block = htons(last_good_block); + cp = hdr->th_data; + fp = sfp; + actual_len = data_len + 4; + // FIXME - what about "netascii" data? + while (data_len-- > 0) *cp++ = *fp++; + // Send data packet + if (sendto(s, data, actual_len, 0, + &from_addr, from_len) < 0) { // Problem sending request *err = TFTP_NETERR; - close(s); - return -1; - } - // Wait for ACK - timeout.tv_sec = TFTP_TIMEOUT_PERIOD; - timeout.tv_usec = 0; - FD_ZERO(&fds); - FD_SET(s, &fds); - if (select(s+1, &fds, 0, 0, &timeout) <= 0) { + goto out; + } + // Wait for ACK + timeout.tv_sec = TFTP_TIMEOUT_PERIOD; + timeout.tv_usec = 0; + FD_ZERO(&fds); + FD_SET(s, &fds); + if (select(s+1, &fds, 0, 0, &timeout) <= 0) { if (++total_timeouts > TFTP_TIMEOUT_MAX) { - // Timeout - no data received - *err = TFTP_TIMEOUT; - close(s); - return -1; + // Timeout - no data received + *err = TFTP_TIMEOUT; + goto out; } - } else { + } else { recv_len = sizeof(data); from_len = sizeof(from_addr); if ((data_len = recvfrom(s, &data, recv_len, 0, - (struct sockaddr *)&from_addr, &from_len)) < 0) { - // What happened? - *err = TFTP_NETERR; - close(s); - return -1; + &from_addr, &from_len)) < 0) { + // What happened? + *err = TFTP_NETERR; + goto out; } if (ntohs(hdr->th_opcode) == ACK) { - if (ntohs(hdr->th_block) == last_good_block) { - // Advance pointers, etc - sfp = fp; - res += (actual_len - 4); - last_good_block++; - } else { - diag_printf("Send block #%d, got ACK for #%d\n", - last_good_block, ntohs(hdr->th_block)); - } + if (ntohs(hdr->th_block) == last_good_block) { + // Advance pointers, etc + sfp = fp; + result += (actual_len - 4); + last_good_block++; + } else { + diag_printf("Send block #%d, got ACK for #%d\n", + last_good_block, ntohs(hdr->th_block)); + } } else - if (ntohs(hdr->th_opcode) == ERROR) { + if (ntohs(hdr->th_opcode) == ERROR) { *err = ntohs(hdr->th_code); - close(s); - return -1; - } else { + goto out; + } else { // What kind of packet is this? *err = TFTP_PROTOCOL; - close(s); - return -1; - } - } + goto out; + } + } + } + close (s); + return result; + } + + // If we got here, it means there was a problem connecting to the + // server. Try the next address returned by getaddrinfo + nextaddr: + if (-1 != s) { + close(s); + } + addrinfo=addrinfo->ai_next; } - close(s); - return res; + // We ran into problems. Cleanup + out: + if (-1 != s) { + close (s); + } + freeaddrinfo(res); + return -1; } // EOF tftp_client.c + +
--- a/packages/net/common/current/src/tftp_server.c +++ b/packages/net/common/current/src/tftp_server.c @@ -9,6 +9,7 @@ // ------------------------------------------- // This file is part of eCos, the Embedded Configurable Operating System. // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. +// Copyright (C) 2003 Andrew Lunn // // 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 @@ -85,8 +86,18 @@ static struct info tftp_server_instrumen #endif // CYGOPT_NET_TFTP_SERVER_INSTRUMENT +#ifdef CYGSEM_NET_TFTPD_MULTITHREADED +struct tftpd_sem { + int port; + cyg_sem_t sem; +}; + +static struct tftpd_sem tftpd_sems[CYGNUM_NET_TFTPD_MULTITHREADED_PORTS]; +#endif //CYGSEM_NET_TFTPD_MULTITHREADED + #define STACK_SIZE (((CYGNUM_HAL_STACK_SIZE_TYPICAL+(3*(SEGSIZE+sizeof(struct tftphdr)))) + CYGARC_ALIGNMENT-1) & ~(CYGARC_ALIGNMENT-1)) static char *TFTP_tag = "TFTPD"; +#define CYGNUM_NET_MAX_INET_PROTOS 2 struct tftp_server { char *tag; char stack[STACK_SIZE]; @@ -94,6 +105,8 @@ struct tftp_server { cyg_handle_t thread_handle; int port; struct tftpd_fileops *ops; + int s[CYGNUM_NET_MAX_INET_PROTOS], num_s; + struct addrinfo *res; }; static char * errmsg[] = { @@ -107,10 +120,87 @@ static char * errmsg[] = { "No such user", // 7 TFTP_ENOUSER }; +// Little helper function to set the port number in an address +static void set_port(struct sockaddr * address, int port) { + + switch (address->sa_family) { + case AF_INET:{ + struct sockaddr_in *addr = (struct sockaddr_in *)address; + addr->sin_port = ntohs(port); + break; + } +#ifdef CYGPKG_NET_INET6 + case AF_INET6: + { + struct sockaddr_in6 *addr = (struct sockaddr_in6 *)address; + addr->sin6_port = ntohs(port); + break; + } +#endif + default: + break; + } +} + +#ifdef CYGSEM_NET_TFTPD_MULTITHREADED + +// Allocate a semaphore for a given port number if one is not already +// allocated. +static void sem_alloc(int port) { + int i; + + CYG_ASSERT(port != 0, "Invalid port number"); + + cyg_scheduler_lock(); // Avoid race with other tftpd's + for (i=0; i < CYGNUM_NET_TFTPD_MULTITHREADED_PORTS; i++) { + if (tftpd_sems[i].port == port) { + cyg_scheduler_unlock(); + return; + } + if (tftpd_sems[i].port == 0) { + tftpd_sems[i].port = port; + cyg_semaphore_init(&tftpd_sems[i].sem,1); + cyg_scheduler_unlock(); + return ; + } + } + cyg_scheduler_unlock(); + diag_printf("TFTPD: Unable to allocate a semaphore for port %d\n",port); +} + +// Wait on the semaphore for a given port number. +static void sem_wait(int port) { + int i; + CYG_ASSERT(port != 0, "Invalid port number"); + + for (i=0; i < CYGNUM_NET_TFTPD_MULTITHREADED_PORTS; i++) { + if (tftpd_sems[i].port == port) { + cyg_semaphore_wait(&tftpd_sems[i].sem); + return; + } + } + diag_printf("TFTPD: No semaphore for port %d\n",port); +} + +// Release the semaphore for a given port number. +static void sem_post(int port) { + int i; + CYG_ASSERT(port != 0, "Invalid port number"); + + for (i=0; i < CYGNUM_NET_TFTPD_MULTITHREADED_PORTS; i++) { + if (tftpd_sems[i].port == port) { + cyg_semaphore_post(&tftpd_sems[i].sem); + return; + } + } + diag_printf("TFTPD: No semaphore for port %d\n",port); +} +#endif + /* Send an error packet to the client */ static void tftpd_send_error(int s, struct tftphdr * reply, int err, - struct sockaddr_in *from_addr, int from_len) + struct sockaddr *from_addr, int from_len) { CYG_ASSERT( 0 <= err, "err underflow" ); CYG_ASSERT( sizeof(errmsg)/sizeof(errmsg[0]) > err, "err overflow" ); @@ -121,7 +211,7 @@ tftpd_send_error(int s, struct tftphdr * err = 0; // Do not copy a random string from hyperspace strcpy(reply->th_msg, errmsg[err]); sendto(s, reply, 4+strlen(reply->th_msg)+1, 0, - (struct sockaddr *)from_addr, from_len); + from_addr, from_len); } // @@ -130,7 +220,7 @@ tftpd_send_error(int s, struct tftphdr * static void tftpd_write_file(struct tftp_server *server, struct tftphdr *hdr, - struct sockaddr_in *from_addr, int from_len) + struct sockaddr *from_addr, int from_len) { char data_out[SEGSIZE+sizeof(struct tftphdr)]; char data_in[SEGSIZE+sizeof(struct tftphdr)]; @@ -141,28 +231,43 @@ tftpd_write_file(struct tftp_server *ser struct timeval timeout; fd_set fds; int total_timeouts = 0; - struct sockaddr_in client_addr, local_addr; + struct sockaddr client_addr; + struct addrinfo hints; + struct addrinfo *res; int client_len; + int error; + + memset(&hints,0,sizeof(hints)); + hints.ai_family = from_addr->sa_family; + hints.ai_flags = AI_PASSIVE; - s = socket(AF_INET, SOCK_DGRAM, 0); + error = getaddrinfo(NULL,"tftp",&hints, &res); + if (0 != error) { + diag_printf("TFTPD: can't get a suitable local address: %s\n", + gai_strerror(error)); + return; + } + s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (s < 0) { diag_printf("TFTPD: can't open socket for 'write_file'\n"); + freeaddrinfo(res); return; } - memset((char *)&local_addr, 0, sizeof(local_addr)); - local_addr.sin_family = AF_INET; - local_addr.sin_len = sizeof(local_addr); - local_addr.sin_addr.s_addr = htonl(INADDR_ANY); - local_addr.sin_port = htons(INADDR_ANY); - if (bind(s, (struct sockaddr *)&local_addr, sizeof(local_addr)) < 0) { + + // We want the stack to pick a free local port number + set_port(res->ai_addr,0); + + if (bind(s, res->ai_addr, res->ai_addrlen) < 0) { // Problem setting up my end diag_printf("TFTPD: can't bind to reply port for 'write_file'\n"); close(s); + freeaddrinfo(res); return; } if ((fd = (server->ops->open)(hdr->th_stuff, O_WRONLY)) < 0) { tftpd_send_error(s,reply,TFTP_ENOTFOUND,from_addr, from_len); close(s); + freeaddrinfo(res); return; } ok = true; @@ -176,7 +281,7 @@ tftpd_write_file(struct tftp_server *ser #ifdef CYGOPT_NET_TFTP_SERVER_INSTRUMENT tftp_server_instrument.ack.send++; #endif - sendto(s, reply, 4, 0, (struct sockaddr *)from_addr, from_len); + sendto(s, reply, 4, 0, from_addr, from_len); repeat_select: timeout.tv_sec = TFTP_TIMEOUT_PERIOD; timeout.tv_usec = 0; @@ -200,7 +305,7 @@ tftpd_write_file(struct tftp_server *ser data_len = sizeof(data_in); client_len = sizeof(client_addr); if ((data_len = recvfrom(s, data_in, data_len, 0, - (struct sockaddr *)&client_addr, &client_len)) < 0) { + &client_addr, &client_len)) < 0) { // What happened? No data here! #ifdef CYGOPT_NET_TFTP_SERVER_INSTRUMENT tftp_server_instrument.ack.resend++; @@ -248,7 +353,7 @@ tftpd_write_file(struct tftp_server *ser #endif reply->th_opcode = htons(ACK); reply->th_block = htons(block++); // postincrement - sendto(s, reply, 4, 0, (struct sockaddr *)from_addr, from_len); + sendto(s, reply, 4, 0, from_addr, from_len); break; // out of the retries loop } // Happy! Break out of the retries loop. @@ -271,6 +376,7 @@ tftpd_write_file(struct tftp_server *ser } } close(s); + freeaddrinfo(res); if (!closed) { (server->ops->close)(fd); } @@ -282,7 +388,7 @@ tftpd_write_file(struct tftp_server *ser static void tftpd_read_file(struct tftp_server *server, struct tftphdr *hdr, - struct sockaddr_in *from_addr, int from_len) + struct sockaddr *from_addr, int from_len) { char data_out[SEGSIZE+sizeof(struct tftphdr)]; char data_in[SEGSIZE+sizeof(struct tftphdr)]; @@ -293,28 +399,44 @@ tftpd_read_file(struct tftp_server *serv struct timeval timeout; fd_set fds; int total_timeouts = 0; - struct sockaddr_in client_addr, local_addr; + struct sockaddr client_addr; + struct addrinfo hints; + struct addrinfo *res; int client_len; + int error; + + memset(&hints,0,sizeof(hints)); + hints.ai_family = from_addr->sa_family; + hints.ai_flags = AI_PASSIVE; - s = socket(AF_INET, SOCK_DGRAM, 0); + error = getaddrinfo(NULL,"tftp",&hints, &res); + if (0 != error) { + diag_printf("TFTPD: can't get a suitable local address: %s\n", + gai_strerror(error)); + return; + } + s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (s < 0) { - diag_printf("TFTPD: can't open socket for 'read_file'\n"); + diag_printf("TFTPD: can't open socket for 'write_file'\n"); + freeaddrinfo(res); return; } - memset((char *)&local_addr, 0, sizeof(local_addr)); - local_addr.sin_family = AF_INET; - local_addr.sin_len = sizeof(local_addr); - local_addr.sin_addr.s_addr = htonl(INADDR_ANY); - local_addr.sin_port = htons(INADDR_ANY); - if (bind(s, (struct sockaddr *)&local_addr, sizeof(local_addr)) < 0) { + + // We want the stack to pick a free local port number + set_port(res->ai_addr,0); + + if (bind(s, res->ai_addr, res->ai_addrlen) < 0) { // Problem setting up my end - diag_printf("TFTPD: can't bind to reply port for 'read_file'\n"); + diag_printf("TFTPD: can't bind to reply port for 'write_file'\n"); close(s); + freeaddrinfo(res); return; } - if ((fd = (server->ops->open)(hdr->th_stuff, O_RDONLY)) < 0) { + + if ((fd = (server->ops->open)(hdr->th_stuff, O_WRONLY)) < 0) { tftpd_send_error(s,reply,TFTP_ENOTFOUND,from_addr, from_len); close(s); + freeaddrinfo(res); return; } block = 0; @@ -329,7 +451,7 @@ tftpd_read_file(struct tftp_server *serv tftp_server_instrument.data.send++; #endif if (sendto(s, reply, 4+len, 0, - (struct sockaddr *)from_addr, from_len) < 0) { + from_addr, from_len) < 0) { // Something went wrong with the network! ok = false; break; @@ -356,7 +478,7 @@ tftpd_read_file(struct tftp_server *serv data_len = sizeof(data_in); client_len = sizeof(client_addr); if ((data_len = recvfrom(s, data_in, data_len, 0, - (struct sockaddr *)&client_addr, + &client_addr, &client_len)) < 0) { // What happened? Maybe someone lied to us... #ifdef CYGOPT_NET_TFTP_SERVER_INSTRUMENT @@ -403,149 +525,222 @@ tftpd_read_file(struct tftp_server *serv } } close(s); + freeaddrinfo(res); (server->ops->close)(fd); } // // Actual TFTP server // -#define CYGSEM_TFTP_SERVER_MULTITHREADED -#ifdef CYGSEM_TFTP_SERVER_MULTITHREADED -static cyg_sem_t tftp_server_sem; -#endif static void tftpd_server(cyg_addrword_t p) { struct tftp_server *server = (struct tftp_server *)p; - int s; + int max_s = 0; int data_len, recv_len, from_len; - struct sockaddr_in local_addr, from_addr; - struct servent *server_info; + struct sockaddr from_addr; char data[SEGSIZE+sizeof(struct tftphdr)]; struct tftphdr *hdr = (struct tftphdr *)data; - + struct addrinfo hints; + struct addrinfo *ai; + fd_set readfds; + char name[64]; + int error; + int i; +#ifdef CYGOPT_NET_TFTP_SERVER_INSTRUMENT + struct info o = tftp_server_instrument; +#endif + #ifndef CYGPKG_NET_TESTS_USE_RT_TEST_HARNESS // Otherwise routine printfs fail the test - interrupts disabled too long. diag_printf("TFTPD [%x]: port %d\n", p, server->port); #endif - // Set up port + memset(&hints,0,sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_flags = AI_PASSIVE; + + error = getaddrinfo(NULL,"tftp",&hints, &server->res); + if (0 != error) { + diag_printf("TFTPD [%p] : can't get a local server address to bind to: %s\n", + p, gai_strerror(error)); + return; + } + + // If the port is 0, we need to use the default TFTP port. Extrace + // the port number from one of the addresses returned by + // getaddrinfo. if (server->port == 0) { - server_info = getservbyname("tftp", "udp"); - if (server_info == (struct servent *)0) { - diag_printf("TFTPD: can't get TFTP service information\n"); - return; - } - // Network order in info; host order in server: - server->port = ntohs( server_info->s_port ); + switch (server->res->ai_family) { + case AF_INET: + { + struct sockaddr_in *addr = (struct sockaddr_in *)server->res->ai_addr; + server->port = ntohs(addr->sin_port); + break; + } +#ifdef CYGPKG_NET_INET6 + case AF_INET6: + { + struct sockaddr_in6 *addr = (struct sockaddr_in6 *)server->res->ai_addr; + server->port = ntohs(addr->sin6_port); + break; + } +#endif + default: + break; + } } +#ifdef CYGSEM_NET_TFTPD_MULTITHREADED + sem_alloc(server->port); while (true) { -#ifdef CYGOPT_NET_TFTP_SERVER_INSTRUMENT - struct info o = tftp_server_instrument; -#endif - // Create socket - s = socket(AF_INET, SOCK_DGRAM, 0); - if (s < 0) { - diag_printf("TFTPD [%x]: can't open socket\n", p); - return; - } - memset((char *)&local_addr, 0, sizeof(local_addr)); - local_addr.sin_family = AF_INET; - local_addr.sin_len = sizeof(local_addr); - local_addr.sin_addr.s_addr = htonl(INADDR_ANY); - local_addr.sin_port = htons(server->port); - if (bind(s, (struct sockaddr *)&local_addr, sizeof(local_addr)) < 0) { - // Problem setting up my end - close(s); -#ifdef CYGSEM_TFTP_SERVER_MULTITHREADED -#ifndef CYGPKG_NET_TESTS_USE_RT_TEST_HARNESS - diag_printf("TFTPD [%x]: waiting to bind to service port\n", p); #endif - // Wait until the socket is free... - cyg_semaphore_wait( &tftp_server_sem ); - continue; // try re-opening and rebinding the socket. -#else - diag_printf("TFTPD [%x]: can't bind to service port\n", p); - return; + // Iterate over the addresses and create a local port to listen for requests + ai = server->res; + memset(server->s,0,sizeof(server->s)); + server->num_s = 0; + while (ai && (server->num_s < CYGNUM_NET_MAX_INET_PROTOS)) { + server->s[server->num_s] = socket(ai->ai_family, + ai->ai_socktype, + ai->ai_protocol); + if (server->s[server->num_s] < 0 ) { + diag_printf("TFTPD [%x]: can't open socket\n", p); + freeaddrinfo(server->res); + server->res = NULL; + return; + } + + set_port(ai->ai_addr, server->port); + +#ifdef CYGSEM_NET_TFTPD_MULTITHREADED + sem_wait(server->port); #endif - } - - recv_len = sizeof(data); - from_len = sizeof(from_addr); - data_len = recvfrom(s, hdr, recv_len, 0, - (struct sockaddr *)&from_addr, &from_len); - close(s); // so that other servers can bind to the TFTP socket -#ifdef CYGSEM_TFTP_SERVER_MULTITHREADED - // The socket is free... - cyg_semaphore_post( &tftp_server_sem ); -#endif - - if ( data_len < 0) { - diag_printf("TFTPD [%x]: can't read request\n", p); - } else { -#ifndef CYGPKG_NET_TESTS_USE_RT_TEST_HARNESS - diag_printf("TFTPD [%x]: received %x from %s:%d\n", p, - ntohs(hdr->th_opcode), inet_ntoa(from_addr.sin_addr), - from_addr.sin_port); + if (bind(server->s[server->num_s],ai->ai_addr, ai->ai_addrlen) < 0) { + // Problem setting up my end + diag_printf("TFTPD [%x]: can't bind to server port\n",p); + close(server->s[server->num_s]); + server->s[server->num_s] = 0; + ai = ai->ai_next; + continue; + } + // We need to know the highest socket number for select. + if (server->s[server->num_s] > max_s) + max_s = server->s[server->num_s]; + server->num_s++; + ai = ai->ai_next; + } + +#ifndef CYGSEM_NET_TFTPD_MULTITHREADED + while (true) { #endif - switch (ntohs(hdr->th_opcode)) { - case WRQ: - tftpd_write_file(server, hdr, &from_addr, from_len); - break; - case RRQ: - tftpd_read_file(server, hdr, &from_addr, from_len); - break; - case ACK: - case DATA: - case ERROR: - // Ignore - break; - default: - diag_printf("TFTPD [%x]: bogus request %x from %s:%d\n", p, - ntohs(hdr->th_opcode), - inet_ntoa(from_addr.sin_addr), - from_addr.sin_port ); - tftpd_send_error(s,hdr,TFTP_EBADOP,&from_addr,from_len); - } - } + FD_ZERO(&readfds); + for (i=0; i < CYGNUM_NET_MAX_INET_PROTOS; i++) { + if (server->s[i]) { + FD_SET(server->s[i],&readfds); + } + } + error = select(max_s+1,&readfds,NULL,NULL,NULL); + if ( -1 == error) { + diag_printf("TFTPD [%x]: error in select\n",p); + } + for (i=0; i < CYGNUM_NET_MAX_INET_PROTOS; i++) { + if (server->s[i] && FD_ISSET(server->s[i],&readfds)) { + recv_len = sizeof(data); + from_len = sizeof(from_addr); + data_len = recvfrom(server->s[i], hdr, recv_len, 0, + &from_addr, &from_len); + if ( data_len < 0) { + diag_printf("TFTPD [%x]: can't read request\n", p); + } else { +#ifdef CYGSEM_NET_TFTPD_MULTITHREADED + // Close the socket and post on the semaphore some + // another thread can start listening for requests. This + // is not quite right. select could of returned with more than + // one socket with data to read. Here we only deal with one of them + for (i=0; i < CYGNUM_NET_MAX_INET_PROTOS; i++) { + if (server->s[i]) { + close (server->s[i]); + server->s[i] = 0; + } + } + sem_post(server->port); +#endif +#ifndef CYGPKG_NET_TESTS_USE_RT_TEST_HARNESS + getnameinfo(&from_addr,sizeof(from_addr), name, sizeof(name),0,0,0); + diag_printf("TFTPD [%x]: received %x from %s\n", p, + ntohs(hdr->th_opcode), name); +#endif + switch (ntohs(hdr->th_opcode)) { + case WRQ: + tftpd_write_file(server, hdr, &from_addr, from_len); + break; + case RRQ: + tftpd_read_file(server, hdr, &from_addr, from_len); + break; + case ACK: + case DATA: + case ERROR: + // Ignore + break; + default: + getnameinfo(&from_addr,sizeof(from_addr), name, sizeof(name),0,0,0); + diag_printf("TFTPD [%x]: bogus request %x from %s\n", p, + ntohs(hdr->th_opcode), + name); + tftpd_send_error(server->s[i],hdr,TFTP_EBADOP,&from_addr,from_len); + } + #ifdef CYGOPT_NET_TFTP_SERVER_INSTRUMENT - tftp_server_instrument.total_transactions++; - - o.data.rx -= tftp_server_instrument.data.rx ; - o.data.rx_repeat -= tftp_server_instrument.data.rx_repeat; - o.data.rx_skip -= tftp_server_instrument.data.rx_skip ; - o.data.send -= tftp_server_instrument.data.send ; - o.data.resend -= tftp_server_instrument.data.resend ; - - o.ack.rx -= tftp_server_instrument.ack.rx ; - o.ack.rx_repeat -= tftp_server_instrument.ack.rx_repeat ; - o.ack.rx_skip -= tftp_server_instrument.ack.rx_skip ; - o.ack.send -= tftp_server_instrument.ack.send ; - o.ack.resend -= tftp_server_instrument.ack.resend ; - - o.err_send -= tftp_server_instrument.err_send ; - + tftp_server_instrument.total_transactions++; + + o.data.rx -= tftp_server_instrument.data.rx ; + o.data.rx_repeat -= tftp_server_instrument.data.rx_repeat; + o.data.rx_skip -= tftp_server_instrument.data.rx_skip ; + o.data.send -= tftp_server_instrument.data.send ; + o.data.resend -= tftp_server_instrument.data.resend ; + + o.ack.rx -= tftp_server_instrument.ack.rx ; + o.ack.rx_repeat -= tftp_server_instrument.ack.rx_repeat ; + o.ack.rx_skip -= tftp_server_instrument.ack.rx_skip ; + o.ack.send -= tftp_server_instrument.ack.send ; + o.ack.resend -= tftp_server_instrument.ack.resend ; + + o.err_send -= tftp_server_instrument.err_send ; + #ifndef CYGPKG_NET_TESTS_USE_RT_TEST_HARNESS - if ( o.data.rx ) diag_printf( "data rx %4d\n", -o.data.rx ); - if ( o.data.rx_repeat ) diag_printf( "data rx_repeat%4d\n", -o.data.rx_repeat ); - if ( o.data.rx_skip ) diag_printf( "data rx_skip %4d\n", -o.data.rx_skip ); - if ( o.data.send ) diag_printf( "data send %4d\n", -o.data.send ); - if ( o.data.resend ) diag_printf( "data resend %4d\n", -o.data.resend ); - - if ( o.ack.rx ) diag_printf( " ack rx %4d\n", -o.ack.rx ); - if ( o.ack.rx_repeat ) diag_printf( " ack rx_repeat%4d\n", -o.ack.rx_repeat ); - if ( o.ack.rx_skip ) diag_printf( " ack rx_skip %4d\n", -o.ack.rx_skip ); - if ( o.ack.send ) diag_printf( " ack send %4d\n", -o.ack.send ); - if ( o.ack.resend ) diag_printf( " ack resend %4d\n", -o.ack.resend ); - - if ( o.err_send ) diag_printf( "*error sends %4d\n", -o.err_send ); + if ( o.data.rx ) diag_printf( "data rx %4d\n", -o.data.rx ); + if ( o.data.rx_repeat ) diag_printf( "data rx_repeat%4d\n", -o.data.rx_repeat ); + if ( o.data.rx_skip ) diag_printf( "data rx_skip %4d\n", -o.data.rx_skip ); + if ( o.data.send ) diag_printf( "data send %4d\n", -o.data.send ); + if ( o.data.resend ) diag_printf( "data resend %4d\n", -o.data.resend ); + + if ( o.ack.rx ) diag_printf( " ack rx %4d\n", -o.ack.rx ); + if ( o.ack.rx_repeat ) diag_printf( " ack rx_repeat%4d\n", -o.ack.rx_repeat ); + if ( o.ack.rx_skip ) diag_printf( " ack rx_skip %4d\n", -o.ack.rx_skip ); + if ( o.ack.send ) diag_printf( " ack send %4d\n", -o.ack.send ); + if ( o.ack.resend ) diag_printf( " ack resend %4d\n", -o.ack.resend ); + + if ( o.err_send ) diag_printf( "*error sends %4d\n", -o.err_send ); #endif // CYGPKG_NET_TESTS_USE_RT_TEST_HARNESS #endif // CYGOPT_NET_TFTP_SERVER_INSTRUMENT +#ifdef CYGSEM_NET_TFTPD_MULTITHREADED + break; +#endif + } + } + } + // The following looks a little strange, but it keeps emacs's + // auto indention happy. +#ifndef CYGSEM_NET_TFTPD_MULTITHREADED + } +#endif +#ifdef CYGSEM_NET_TFTPD_MULTITHREADED } +#endif } + // // This function is used to create a new server [thread] which supports // the TFTP protocol on the given port. A server 'id' will be returned @@ -599,7 +794,14 @@ tftpd_stop(int p) cyg_thread_set_priority(server->thread_handle, 0); cyg_thread_delay(1); // Make sure it gets to die... if (cyg_thread_delete(server->thread_handle)) { - // Success shutting down the thread + // Success shutting down the thread. Close all its sockets. + int i; + for (i = 0 ; i < CYGNUM_NET_MAX_INET_PROTOS; i++) { + if (server->s[i]) { + close (server->s[i]); + } + } + freeaddrinfo(server->res); free(server); // Give up memory return 1; }
--- a/packages/net/common/current/tests/addr_test.c +++ b/packages/net/common/current/tests/addr_test.c @@ -19,7 +19,7 @@ //#####DESCRIPTIONBEGIN#### // // Author(s): gthomas -// Contributors: gthomas +// Contributors: gthomas, andrew.lunn@ascom.ch // Date: 2002-03-19 // Purpose: // Description: @@ -56,13 +56,13 @@ walk_addrs(struct addrinfo *ai, char *ti diag_printf("INFO: %s\n", title); while (ai) { _inet_ntop(ai->ai_addr, addr_buf, sizeof(addr_buf)); - diag_printf("INFO: Family: %d, Socket: %d, Addr: %s, Port: %d\n", + diag_printf("INFO: Family: %2d, Socket: %d, Addr: %s, Port: %d\n", ai->ai_family, ai->ai_socktype, addr_buf, _inet_port(ai->ai_addr)); ai = ai->ai_next; } } -int +void net_test(CYG_ADDRWORD data) { int err; @@ -77,6 +77,7 @@ net_test(CYG_ADDRWORD data) pexit("getaddrinfo"); } walk_addrs(addrs, "all passive"); + bzero(&hints, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; @@ -86,6 +87,7 @@ net_test(CYG_ADDRWORD data) pexit("getaddrinfo"); } walk_addrs(addrs, "all active"); + bzero(&hints, sizeof(hints)); hints.ai_family = PF_INET; hints.ai_socktype = SOCK_STREAM; @@ -95,6 +97,27 @@ net_test(CYG_ADDRWORD data) pexit("getaddrinfo"); } walk_addrs(addrs, "IPv4 passive"); + + bzero(&hints, sizeof(hints)); + hints.ai_family = PF_INET; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE; + if ((err = getaddrinfo("192.168.1.2", "7734", &hints, &addrs)) != EAI_NONE) { + diag_printf("<ERROR> can't getaddrinfo(): %s\n", gai_strerror(err)); + pexit("getaddrinfo"); + } + walk_addrs(addrs, "IPv4 passive 192.168.1.2"); + + bzero(&hints, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE; + if ((err = getaddrinfo("192.168.1.2", "7734", &hints, &addrs)) != EAI_NONE) { + diag_printf("<ERROR> can't getaddrinfo(): %s\n", gai_strerror(err)); + pexit("getaddrinfo"); + } + walk_addrs(addrs, "all passive 192.168.1.2"); + #ifdef CYGPKG_NET_INET6 bzero(&hints, sizeof(hints)); hints.ai_family = PF_INET6; @@ -105,7 +128,27 @@ net_test(CYG_ADDRWORD data) pexit("getaddrinfo"); } walk_addrs(addrs, "IPv6 passive"); + + bzero(&hints, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + if ((err = getaddrinfo(NULL, "7734", &hints, &addrs)) != EAI_NONE) { + diag_printf("<ERROR> can't getaddrinfo(): %s\n", gai_strerror(err)); + pexit("getaddrinfo"); + } + walk_addrs(addrs, "all passive"); + + bzero(&hints, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + if ((err = getaddrinfo("fe80::260:97ff:feb0:866e", "7734", &hints, &addrs)) + != EAI_NONE) { + diag_printf("<ERROR> can't getaddrinfo(): %s\n", gai_strerror(err)); + pexit("getaddrinfo"); + } + walk_addrs(addrs, "all passive fe80::260:97ff:feb0:866e"); #endif + bzero(&hints, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_DGRAM; @@ -115,7 +158,18 @@ net_test(CYG_ADDRWORD data) pexit("getaddrinfo"); } walk_addrs(addrs, "all snmp/udp"); + + bzero(&hints, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = 0; + hints.ai_flags = AI_PASSIVE; + if ((err = getaddrinfo(NULL, "snmp", &hints, &addrs)) != EAI_NONE) { + diag_printf("<ERROR> can't getaddrinfo(): %s\n", gai_strerror(err)); + pexit("getaddrinfo"); + } + walk_addrs(addrs, "all snmp/*"); CYG_TEST_PASS_FINISH("Address [library] test OK"); + } void cyg_start(void)
--- a/packages/net/common/current/tests/ping_lo_test.c +++ b/packages/net/common/current/tests/ping_lo_test.c @@ -19,7 +19,7 @@ //#####DESCRIPTIONBEGIN#### // // Author(s): gthomas, sorin@netappi.com -// Contributors: gthomas, sorin@netappi.com +// Contributors: gthomas, sorin@netappi.com, andrew.lunn@ascom.ch // Date: 2000-01-10 // Purpose: // Description: @@ -32,6 +32,10 @@ // PING test code #include <network.h> +#ifdef CYGPKG_NET_INET6 +#include <netinet/ip6.h> +#include <netinet/icmp6.h> +#endif #include <cyg/infra/testcase.h> @@ -144,7 +148,7 @@ ping_host(int s, struct sockaddr_in *hos icmp->icmp_code = 0; icmp->icmp_cksum = 0; icmp->icmp_seq = seq; - icmp->icmp_id = 0x1234; + icmp->icmp_id = UNIQUEID; // Set up ping data tp = (cyg_tick_count_t *)&icmp->icmp_data; *tp++ = cyg_current_time(); @@ -206,17 +210,166 @@ ping_test_loopback( int lo ) ping_host(s, &host); } +#ifdef CYGPKG_NET_INET6 +static int +show6_icmp(unsigned char *pkt, int len, + const struct sockaddr_in6 *from, const struct sockaddr_in6 *to) +{ + cyg_tick_count_t *tp, tv; + struct icmp6_hdr *icmp; + char fromnamebuf[128]; + char tonamebuf[128]; + int error; + + error = getnameinfo((struct sockaddr *)from,sizeof(*from), + fromnamebuf, sizeof(fromnamebuf), + NULL, 0, + NI_NUMERICHOST); + if (error) { + perror ("getnameinfo(from)"); + return 0; + } + + error = getnameinfo((struct sockaddr *)to,sizeof(*to), + tonamebuf, sizeof(tonamebuf), + NULL, 0, + NI_NUMERICHOST); + if (error) { + perror ("getnameinfo(to)"); + return 0; + } + + tv = cyg_current_time(); + icmp = (struct icmp6_hdr *)pkt; + tp = (cyg_tick_count_t *)&icmp->icmp6_data8[4]; + + if (icmp->icmp6_type != ICMP6_ECHO_REPLY) { + return 0; + } + if (icmp->icmp6_id != UNIQUEID) { + diag_printf("%s: ICMP received for wrong id - sent: %x, recvd: %x\n", + fromnamebuf, UNIQUEID, icmp->icmp6_id); + } + diag_printf("%d bytes from %s: ", len, fromnamebuf); + diag_printf("icmp_seq=%d", icmp->icmp6_seq); + diag_printf(", time=%dms\n", (int)(tv - *tp)*10); + return (!memcmp(&from->sin6_addr, &to->sin6_addr,sizeof(from->sin6_addr))); +} + +static void +ping6_host(int s, const struct sockaddr_in6 *host) +{ + struct icmp6_hdr *icmp = (struct icmp6_hdr *)pkt1; + int icmp_len = 64; + int seq, ok_recv, bogus_recv; + cyg_tick_count_t *tp; + long *dp; + struct sockaddr_in6 from; + int i, len, fromlen; + char namebuf[128]; + int error; + int echo_responce; + + ok_recv = 0; + bogus_recv = 0; + error = getnameinfo((struct sockaddr *)host,sizeof(*host), + namebuf, sizeof(namebuf), + NULL, 0, + NI_NUMERICHOST); + if (error) { + perror ("getnameinfo"); + } else { + diag_printf("PING6 server %s\n", namebuf); + } + for (seq = 0; seq < NUM_PINGS; seq++) { + // Build ICMP packet + icmp->icmp6_type = ICMP6_ECHO_REQUEST; + icmp->icmp6_code = 0; + icmp->icmp6_cksum = 0; + icmp->icmp6_seq = seq; + icmp->icmp6_id = UNIQUEID; + + // Set up ping data + tp = (cyg_tick_count_t *)&icmp->icmp6_data8[4]; + *tp++ = cyg_current_time(); + dp = (long *)tp; + for (i = sizeof(*tp); i < icmp_len; i += sizeof(*dp)) { + *dp++ = i; + } + // Add checksum + icmp->icmp6_cksum = inet_cksum( (u_short *)icmp, icmp_len+8); + // Send it off + if (sendto(s, icmp, icmp_len+8, 0, (struct sockaddr *)host, sizeof(*host)) < 0) { + perror("sendto"); + continue; + } + // Wait for a response. We get our own ECHO_REQUEST and the responce + echo_responce = 0; + while (!echo_responce) { + fromlen = sizeof(from); + len = recvfrom(s, pkt2, sizeof(pkt2), 0, (struct sockaddr *)&from, &fromlen); + if (len < 0) { + perror("recvfrom"); + echo_responce=1; + } else { + if (show6_icmp(pkt2, len, &from, host)) { + ok_recv++; + echo_responce=1; + } + } + } + } + diag_printf("Sent %d packets, received %d OK, %d bad\n", NUM_PINGS, ok_recv, bogus_recv); +} + +static void +ping6_test_loopback( int lo ) +{ + struct protoent *p; + struct timeval tv; + struct sockaddr_in6 host; + int s; + + if ((p = getprotobyname("ipv6-icmp")) == (struct protoent *)0) { + perror("getprotobyname"); + return; + } + s = socket(AF_INET6, SOCK_RAW, p->p_proto); + if (s < 0) { + perror("socket"); + return; + } + tv.tv_sec = 1; + tv.tv_usec = 0; + setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); + // Set up host address + host.sin6_family = AF_INET6; + host.sin6_len = sizeof(host); + host.sin6_addr = in6addr_loopback; + host.sin6_port = 0; + ping6_host(s, &host); + // Now try a bogus host + host.sin6_addr.s6_addr[15] = host.sin6_addr.s6_addr[15] + 32; + ping6_host(s, &host); +} +#endif + void net_test(cyg_addrword_t p) { int i; diag_printf("Start PING test\n"); + init_all_network_interfaces(); #if NLOOP > 0 for ( i = 0; i < NLOOP; i++ ) ping_test_loopback( i ); for ( i = 0; i < NLOOP; i++ ) ping_test_loopback( i ); +#ifdef CYGPKG_NET_INET6 + for ( i = 0; i < NLOOP; i++ ) + ping6_test_loopback( i ); +#endif CYG_TEST_PASS_FINISH( "Done pinging loopback" ); #endif CYG_TEST_NA( "No loopback devs" );
--- a/packages/net/common/current/tests/ping_test.c +++ b/packages/net/common/current/tests/ping_test.c @@ -19,7 +19,7 @@ //#####DESCRIPTIONBEGIN#### // // Author(s): gthomas -// Contributors: gthomas +// Contributors: gthomas, andrew.lunn@ascom.ch // Date: 2000-01-10 // Purpose: // Description: @@ -32,6 +32,10 @@ // PING test code #include <network.h> +#ifdef CYGPKG_NET_INET6 +#include <netinet/ip6.h> +#include <netinet/icmp6.h> +#endif #include <pkgconf/system.h> #include <pkgconf/net.h> @@ -215,6 +219,151 @@ ping_host(int s, struct sockaddr_in *hos diag_printf("Sent %d packets, received %d OK, %d bad\n", NUM_PINGS, ok_recv, bogus_recv); } +#ifdef CYGPKG_NET_INET6 +static int +show6_icmp(unsigned char *pkt, int len, + const struct sockaddr_in6 *from, const struct sockaddr_in6 *to) +{ + cyg_tick_count_t *tp, tv; + struct icmp6_hdr *icmp; + char fromnamebuf[128]; + char tonamebuf[128]; + int error; + + error = getnameinfo((struct sockaddr *)from,sizeof(*from), + fromnamebuf, sizeof(fromnamebuf), + NULL, 0, + NI_NUMERICHOST); + if (error) { + perror ("getnameinfo(from)"); + return 0; + } + + error = getnameinfo((struct sockaddr *)to,sizeof(*to), + tonamebuf, sizeof(tonamebuf), + NULL, 0, + NI_NUMERICHOST); + if (error) { + perror ("getnameinfo(to)"); + return 0; + } + + tv = cyg_current_time(); + icmp = (struct icmp6_hdr *)pkt; + tp = (cyg_tick_count_t *)&icmp->icmp6_data8[4]; + + if (icmp->icmp6_type != ICMP6_ECHO_REPLY) { + return 0; + } + if (icmp->icmp6_id != UNIQUEID) { + diag_printf("%s: ICMP received for wrong id - sent: %x, recvd: %x\n", + fromnamebuf, UNIQUEID, icmp->icmp6_id); + } + diag_printf("%d bytes from %s: ", len, fromnamebuf); + diag_printf("icmp_seq=%d", icmp->icmp6_seq); + diag_printf(", time=%dms\n", (int)(tv - *tp)*10); + return (!memcmp(&from->sin6_addr, &to->sin6_addr,sizeof(from->sin6_addr))); +} + +static void +ping6_host(int s, const struct sockaddr_in6 *host) +{ + struct icmp6_hdr *icmp = (struct icmp6_hdr *)pkt1; + int icmp_len = 64; + int seq, ok_recv, bogus_recv; + cyg_tick_count_t *tp; + long *dp; + struct sockaddr_in6 from; + int i, len, fromlen; + char namebuf[128]; + int error; + int echo_responce; + + ok_recv = 0; + bogus_recv = 0; + error = getnameinfo((struct sockaddr *)host,sizeof(*host), + namebuf, sizeof(namebuf), + NULL, 0, + NI_NUMERICHOST); + if (error) { + perror ("getnameinfo"); + } else { + diag_printf("PING6 server %s\n", namebuf); + } + for (seq = 0; seq < NUM_PINGS; seq++) { + // Build ICMP packet + icmp->icmp6_type = ICMP6_ECHO_REQUEST; + icmp->icmp6_code = 0; + icmp->icmp6_cksum = 0; + icmp->icmp6_seq = seq; + icmp->icmp6_id = UNIQUEID; + + // Set up ping data + tp = (cyg_tick_count_t *)&icmp->icmp6_data8[4]; + *tp++ = cyg_current_time(); + dp = (long *)tp; + for (i = sizeof(*tp); i < icmp_len; i += sizeof(*dp)) { + *dp++ = i; + } + // Add checksum + icmp->icmp6_cksum = inet_cksum( (u_short *)icmp, icmp_len+8); + // Send it off + if (sendto(s, icmp, icmp_len+8, 0, (struct sockaddr *)host, + sizeof(*host)) < 0) { + perror("sendto"); + continue; + } + // Wait for a response. We get our own ECHO_REQUEST and the responce + echo_responce = 0; + while (!echo_responce) { + fromlen = sizeof(from); + len = recvfrom(s, pkt2, sizeof(pkt2), 0, (struct sockaddr *)&from, + &fromlen); + if (len < 0) { + perror("recvfrom"); + echo_responce=1; + } else { + if (show6_icmp(pkt2, len, &from, host)) { + ok_recv++; + echo_responce=1; + } + } + } + } + diag_printf("Sent %d packets, received %d OK, %d bad\n", NUM_PINGS, + ok_recv, bogus_recv); +} + +static void +ping6_test( struct sockaddr_in6 *host) +{ + struct protoent *p; + struct timeval tv; + struct sockaddr_in6 addr; + int s; + + if ((p = getprotobyname("ipv6-icmp")) == (struct protoent *)0) { + perror("getprotobyname"); + return; + } + s = socket(AF_INET6, SOCK_RAW, p->p_proto); + if (s < 0) { + perror("socket"); + return; + } + tv.tv_sec = 1; + tv.tv_usec = 0; + setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); + + ping6_host(s, host); + + // Now try a bogus host + memcpy(&addr,host,sizeof(addr)); + addr.sin6_addr.s6_addr[15] = addr.sin6_addr.s6_addr[15] + 32; + ping6_host(s, &addr); +} +#endif + static void ping_test(struct bootp *bp) { @@ -249,6 +398,10 @@ ping_test(struct bootp *bp) void net_test(cyg_addrword_t p) { +#ifdef CYGPKG_NET_INET6 + struct sockaddr_in6 ipv6router; +#endif + diag_printf("Start PING test\n"); TNR_INIT(); init_all_network_interfaces(); @@ -262,6 +415,13 @@ net_test(cyg_addrword_t p) ping_test(ð1_bootp_data); } #endif +#ifdef CYGPKG_NET_INET6 + if (cyg_net_get_ipv6_advrouter(&ipv6router)) { + ping6_test(&ipv6router); + } else { + CYG_TEST_FAIL("No router advertisement recieved"); + } +#endif TNR_PRINT_ACTIVITY(); CYG_TEST_PASS_FINISH("Ping test OK"); }
--- a/packages/net/common/current/tests/tftp_client_test.c +++ b/packages/net/common/current/tests/tftp_client_test.c @@ -62,6 +62,10 @@ tftp_test(struct bootp *bp) { int res, err, len; struct sockaddr_in host; +#ifdef CYGPKG_NET_INET6 + struct sockaddr_in6 ipv6router; + char server[64]; +#endif memset((char *)&host, 0, sizeof(host)); host.sin_len = sizeof(host); @@ -75,10 +79,35 @@ tftp_test(struct bootp *bp) diag_dump_buf(buf, min(res,1024)); } len = res; - diag_printf("Trying tftp_put %d %16s, length %d\n", + diag_printf("Trying tftp_put %s %16s, length %d\n", PUTFILE, inet_ntoa(host.sin_addr), len); res = tftp_put( PUTFILE, &host, buf, len, TFTP_OCTET, &err); diag_printf("put - res: %d\n", res); + +#ifdef CYGPKG_NET_INET6 + // Wait for router solicit process to happen. + if (!cyg_net_get_ipv6_advrouter(&ipv6router)) { + diag_printf("No router advertisement recieved\n"); + cyg_test_exit(); + } + + getnameinfo((struct sockaddr *)&ipv6router,sizeof(ipv6router), + server, sizeof(server), 0 ,0 ,NI_NUMERICHOST); + + diag_printf("Trying tftp_get %s using IPv6 from %16s...\n", GETFILE, server); + + res = tftp_client_get( GETFILE, server, 0, buf, sizeof(buf), + TFTP_OCTET, &err); + diag_printf("IPv6 res = %d, err = %d\n", res, err); + if (res > 0) { + diag_dump_buf(buf, min(res,1024)); + } + len = res; + diag_printf("Trying tftp_put %s using IPv6 to %16s, length %d\n", + PUTFILE, server, len); + res = tftp_client_put( PUTFILE, server, 0, buf, len, TFTP_OCTET, &err); + diag_printf("put - res: %d\n", res); +#endif } void @@ -115,3 +144,5 @@ cyg_start(void) cyg_thread_resume(thread_handle); // Start it cyg_scheduler_start(); } + +
--- a/packages/net/common/current/tests/tftp_server_test.c +++ b/packages/net/common/current/tests/tftp_server_test.c @@ -81,22 +81,63 @@ pexit(char *s) static void tftp_test(struct bootp *bp) { - int server_id, res; + int res; + int server1_id = 0; + int server2_id = 0; + int server3_id = 0; + extern struct tftpd_fileops dummy_fileops; - server_id = tftpd_start(0, &dummy_fileops); - if (server_id > 0) { - diag_printf("TFTP server created - id: %x\n", server_id); - // Only let the server run for 5 minutes - cyg_thread_delay(2*100); // let the tftpd start up first - TNR_ON(); - cyg_thread_delay(5*60*100); - TNR_OFF(); - res = tftpd_stop(server_id); - diag_printf("TFTP server stopped - res: %d\n", res); + + server1_id = tftpd_start(0, &dummy_fileops); + if (server1_id > 0) { + diag_printf("TFTP server created - id: %x\n", server1_id); + } else { + diag_printf("Couldn't create first server!\n"); + } + +#ifdef CYGSEM_NET_TFTPD_MULTITHREADED + server2_id = tftpd_start(0, &dummy_fileops); + if (server2_id > 0) { + diag_printf("Second TFTP server created - id: %x\n", server2_id); + } else { + diag_printf("Couldn't create a second server!\n"); + } +#if CYGNUM_NET_TFTPD_MULTITHREADED_PORTS > 1 + server3_id = tftpd_start(1025, &dummy_fileops); + if (server3_id > 0) { + diag_printf("Third TFTP server created - id: %x\n", server3_id); } else { - diag_printf("Couldn't create a server!\n"); + diag_printf("Couldn't create a third server!\n"); + } +#endif //CYGNUM_NET_TFTPD_MULTITHREADED_PORTS > 1 +#else //CYGSEM_NET_TFTPD_MULTITHREADED + server2_id = tftpd_start(1025, &dummy_fileops); + if (server2_id > 0) { + diag_printf("Second TFTP server created - id: %x\n", server2_id); + } else { + diag_printf("Couldn't create a second server!\n"); } -} +#endif //!CYGSEM_NET_TFTPD_MULTITHREADED + + // Only let the server run for 5 minutes + cyg_thread_delay(2*100); // let the tftpd start up first + TNR_ON(); + cyg_thread_delay(5*60*100); + TNR_OFF(); + + if (server1_id > 0) { + res = tftpd_stop(server1_id); + diag_printf("TFTP server - id: %x stopped - res: %d\n", server1_id, res); + } + if (server2_id > 0) { + res = tftpd_stop(server2_id); + diag_printf("TFTP server - id: %x stopped - res: %d\n", server2_id, res); + } + if (server3_id > 0) { + res = tftpd_stop(server2_id); + diag_printf("TFTP server - id: %x stopped - res: %d\n", server2_id, res); + } +} void net_test(cyg_addrword_t param)
