T168_111\system\Ethernet\net:第34~47

sock_var.h  。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

#ifndef SOCK_VAR_H

/******************************************************************************
 *                                                                            *
 *                         M O D U L E   D E F I N E                          *
 *                                                                            *
 ******************************************************************************/

#define SOCK_VAR_H

/******************************************************************************
 *                                                                            *
 *        C O M P I L E R   D E F I N E D   I N C L U D E   F I L E S         *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *            U S E R   D E F I N E D   I N C L U D E   F I L E S             *
 *                                                                            *
 ******************************************************************************/

#include "XNutOS.h"

#include "netbuf.h"

#ifdef __cplusplus
extern "C" {            /* Assume C declarations for C++ */
#endif    /* __cplusplus */

/******************************************************************************
 *                                                                            *
 *                        G L O B A L   D E F I N E S                         *
 *                                                                            *
 ******************************************************************************/

/*
 * TCP send flags.
 */
#define SO_FIN      0x01    /*!< \brief Socket transmit flag. Send FIN after all data has been transmitted. */
#define SO_SYN      0x02    /*!< \brief Socket transmit flag. Send SYN first. */
#define SO_FORCE    0x08    /*!< \brief Socket transmit flag. Force sending ACK. */
#define SO_ACK      0x10    /*!< \brief Socket transmit flag. Send ACK. */

/******************************************************************************
 *                                                                            *
 *                 S T R U C T U R E   D E F I N I T I O N S                  *
 *                                                                            *
 ******************************************************************************/

/*!
 * \brief UDP socket type.
 */
typedef struct udp_socket UDPSOCKET;

/*!
 * \brief UDP socket information structure.
 *
 * Applications should not rely on the content of this structure.
 * It may change without notice.
 */
struct udp_socket {
    UDPSOCKET *so_next;     /*!< \brief Link to next tcp socket structure. */
    u_short so_local_port;  /*!< \brief Local port number in net byte order. */
    NETBUF  *so_rx_nb;      /*!< \brief Received, but not read by application. */
    NUTHANDLE so_rx_rdy;    /*!< \brief Receiver event queue. */
    int     so_rx_cnt;      /*!< \brief Number of data bytes in the receive buffer. */
    int     so_rx_bsz;      /*!< \brief Receive buffer size. */

    u_short so_last_error;  /*!< \brief Last error of socket */
    u_long  so_remote_addr; /*!< \brief Remote IP address in net byte order. Important just in case of an error */
    u_short so_remote_port; /*!< \brief Remote port number in net byte order. Important just in case of an error */
};


/*!
 * \brief TCP socket type.
 */
typedef struct tcp_socket TCPSOCKET;

/*!
 * \brief TCP socket information structure.
 *
 * Applications should not rely on the content of this structure.
 * It may change without notice.
 */
struct tcp_socket {
    TCPSOCKET *so_next;     /*!< \brief Link to next tcp socket structure. */
    void *so_device;        /*!< \brief Always zero. */
    u_char so_devtype;        /*!< \brief Device type, always IFTYP_TCPSOCK. */
    int (*so_devread) (TCPSOCKET *, void *, int); /*!< \brief Read from device. */
    int (*so_devwrite) (TCPSOCKET *, CONST void *, int); /*!< \brief Write to device. */
    int (*so_devioctl) (TCPSOCKET *, int, void *); /*!< \brief Driver control function. */
    
    u_short so_devocnt;     /*!< \brief Number of data bytes in output buffer. */
    u_char *so_devobuf;     /*!< \brief Pointer to output buffer. */
    u_short so_devobsz;     /*!< \brief Output buffer size. */

    volatile u_char  so_state;       /*!< \brief Connection state, see tcp_fsm.h */
    u_long  so_local_addr;  /*!< \brief Local IP address in net byte order. */
    u_short so_local_port;  /*!< \brief Local port number in net byte order. */
    u_long  so_remote_addr; /*!< \brief Remote IP address in net byte order. */
    u_short so_remote_port; /*!< \brief Remote port number in net byte order. */

    u_char  so_tx_flags;    /*!< \brief Flags used during transmissions - see below */
    u_long  so_tx_isn;      /*!< \brief Initial sequence number. */
    u_long  so_tx_una;      /*!< \brief Unacknowledged sequence number. */
    u_long  so_tx_nxt;      /*!< \brief Next sequence number to send. */
    u_long  so_tx_wl1;      /*!< \brief Sequence number of last window update. */
    u_long  so_tx_wl2;      /*!< \brief Acknowledged sequence of last window update. */
    u_short so_tx_win;      /*!< \brief Peer's receive window. */
    u_char  so_tx_dup;      /*!< \brief Duplicate ACK counter. */
    NETBUF  *so_tx_nbq;     /*!< \brief Network buffers waiting to be acknowledged. */
    NUTHANDLE  so_tx_tq;    /*!< \brief Threads waiting for transmit buffer space. */

    u_long  so_rx_isn;      /*!< \brief Initial sequence number of remote. */
    u_long  so_rx_nxt;      /*!< \brief Next sequence number to receive. */
    u_short so_rx_win;      /*!< \brief Local receive window. */
    int     so_rx_cnt;      /*!< \brief Number of data bytes in the receive buffer. */
    int     so_rx_bsz;      /*!< \brief Receive buffer size. */
    int     so_rd_cnt;      /*!< \brief Number of bytes read from buffer top. */
    char    so_rx_apc;      /*!< \brief Number of packets received in advance. */
    NETBUF  *so_rx_buf;     /*!< \brief Data waiting to be read by application. */
    NUTHANDLE  so_rx_tq;    /*!< \brief Threads waiting for received data. */
    NETBUF  *so_rx_nbq;     /*!< \brief Network buffers received in advance. */

    u_short so_mss;         /*!< \brief MSS, limited by remote option or MTU. */

    u_long  so_rtt_seq;     /*!< \brief Sequence number for RTT calculation. */
    u_short so_rtto;        /*!< \brief Current retransmission timeout. */
    u_short so_retransmits; /*!< \brief Number of retransmits. */
    u_short so_time_wait;   /*!< \brief Time wait counter. */
    u_short so_retran_time; /*!< \brief Retransmit time counter. */
    u_short so_last_error;  /*!< \brief Last error code. */
    NUTHANDLE  so_pc_tq;    /*!< \brief Listening thread. */
    NUTHANDLE  so_ac_tq;    /*!< \brief Connecting thread. */

    u_long  so_read_to;     /*!< \brief Read timeout. */
    u_long  so_write_to;    /*!< \brief Write timeout. */
    u_long  so_oos_drop;    /*!< \brief Out of sequence dropped. */
};

/******************************************************************************
 *                                                                            *
 *    G L O B A L   V A R I A B L E S   -   N O   I N I T I A L I Z E R S     *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *       G L O B A L   V A R I A B L E S   -   I N I T I A L I Z E R S        *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *                   F U N C T I O N   P R O T O T Y P E S                    *
 *                                                                            *
 ******************************************************************************/

int NutUdpInput(NUTDEVICE * dev, NETBUF *nb);
int NutUdpOutput(UDPSOCKET *sock, u_long dest, u_short port, NETBUF *nb);

int NutTcpOutput(TCPSOCKET *sock, CONST u_char *data, u_short size);
int NutTcpReject(NETBUF *nb);

#ifdef __cplusplus
}                       /* End of extern "C" { */
#endif    /* __cplusplus */

#endif

socket.h  。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

#ifndef SOCKET_H

/******************************************************************************
 *                                                                            *
 *                         M O D U L E   D E F I N E                          *
 *                                                                            *
 ******************************************************************************/

#define SOCKET_H

/******************************************************************************
 *                                                                            *
 *        C O M P I L E R   D E F I N E D   I N C L U D E   F I L E S         *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *            U S E R   D E F I N E D   I N C L U D E   F I L E S             *
 *                                                                            *
 ******************************************************************************/

#include "sock_var.h"
#include "tcp_fsm.h"

#ifdef __cplusplus
extern "C" {            /* Assume C declarations for C++ */
#endif    /* __cplusplus */

/******************************************************************************
 *                                                                            *
 *                        G L O B A L   D E F I N E S                         *
 *                                                                            *
 ******************************************************************************/

/*
 * Types
 */
#define SOCK_STREAM 1       /*!< \brief Stream socket */
#define SOCK_DGRAM  2       /*!< \brief Datagram socket */
#define SOCK_RAW    3       /*!< \brief Raw-protocol interface */

/*
 * Option flags per-socket.
 */
#define SO_DEBUG        0x0001      /*!< \brief Turn on debugging info recording */
#define SO_ACCEPTCONN   0x0002      /*!< \brief Socket has had listen() */
#define SO_REUSEADDR    0x0004      /*!< \brief Allow local address reuse */
#define SO_KEEPALIVE    0x0008      /*!< \brief Keep connections alive */
#define SO_DONTROUTE    0x0010      /*!< \brief Just use interface addresses */
#define SO_BROADCAST    0x0020      /*!< \brief Permit sending of broadcast msgs */
#define SO_USELOOPBACK  0x0040      /*!< \brief Bypass hardware when possible */
#define SO_LINGER       0x0080      /*!< \brief Linger on close if data present */
#define SO_OOBINLINE    0x0100      /*!< \brief Leave received OOB data in line */
#define SO_REUSEPORT    0x0200      /*!< \brief Allow local address & port reuse */

/*
 * Additional options, not kept in so_options.
 */
#define SO_SNDBUF       0x1001      /*!< \brief Send buffer size */
#define SO_RCVBUF       0x1002      /*!< \brief Receive buffer size */
#define SO_SNDLOWAT     0x1003      /*!< \brief Send low-water mark */
#define SO_RCVLOWAT     0x1004      /*!< \brief Receive low-water mark */
#define SO_SNDTIMEO     0x1005      /*!< \brief Send timeout */
#define SO_RCVTIMEO     0x1006      /*!< \brief Receive timeout */
#define SO_ERROR        0x1007      /*!< \brief Get error status and clear */
#define SO_TYPE         0x1008      /*!< \brief Get socket type */

/*
 * Address families.
 */
#define AF_INET     2       /*!< \brief internetwork: UDP, TCP, etc. */


/******************************************************************************
 *                                                                            *
 *                 S T R U C T U R E   D E F I N I T I O N S                  *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *    G L O B A L   V A R I A B L E S   -   N O   I N I T I A L I Z E R S     *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *       G L O B A L   V A R I A B L E S   -   I N I T I A L I Z E R S        *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *                   F U N C T I O N   P R O T O T Y P E S                    *
 *                                                                            *
 ******************************************************************************/

TCPSOCKET *NutTcpCreateSocket(void);
int NutTcpSetSockOpt(TCPSOCKET *sock, int optname, CONST void *optval, int optlen);
int NutTcpGetSockOpt(TCPSOCKET *sock, int optname, void *optval, int optlen);
int NutTcpConnect(TCPSOCKET *sock, u_long addr, u_short port);
int NutTcpAccept(TCPSOCKET *sock, u_short port);
int NutTcpInput(NUTDEVICE * dev, NETBUF *nb);
int NutTcpSend(TCPSOCKET *sock, CONST void *data, int len);
int NutTcpCloseSocket(TCPSOCKET *sock);
void NutTcpDestroySocket(TCPSOCKET *sock);
int NutTcpReceive(TCPSOCKET *sock, void *data, int size);
TCPSOCKET *NutTcpFindSocket(u_short lport, u_short rport, u_long raddr);
int NutTcpError(TCPSOCKET *sock);
int NutTcpAbortSocket(TCPSOCKET *sock, u_short last_error);
void NutTcpDiscardBuffers(TCPSOCKET * sock);

int NutTcpDeviceRead(TCPSOCKET *sock, void *buffer, int size);
int NutTcpDeviceWrite(TCPSOCKET *sock, CONST void *buffer, int size);
int NutTcpDeviceIOCtl(TCPSOCKET *sock, int cmd, void *param);
int NutTcpDeviceClose(TCPSOCKET *sock);

UDPSOCKET *NutUdpCreateSocket(u_short port);
int NutUdpSendTo(UDPSOCKET *sock, u_long addr, u_short port, void *data, int len);
int NutUdpReceiveFrom(UDPSOCKET *sock, u_long *addr, u_short *port, void *data, int size, u_long timeout);
int NutUdpDestroySocket(UDPSOCKET *sock);
UDPSOCKET *NutUdpFindSocket(u_short port);
int NutUdpSetSockOpt(UDPSOCKET *sock, int optname, CONST void *optval, int optlen);
int NutUdpGetSockOpt(UDPSOCKET *sock, int optname, void *optval, int optlen);

#ifdef NUT_UDP_ICMP_SUPPORT
extern int NutUdpSetSocketError(UDPSOCKET * sock, u_long remote_addr, u_short remote_port, u_short error);
extern int NutUdpError(UDPSOCKET * sock, u_long * addr, u_short * port);
#endif

#ifdef __cplusplus
}                       /* End of extern "C" { */
#endif    /* __cplusplus */

#endif

tcp.h   、、、。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

#ifndef TCP_H

/******************************************************************************
 *                                                                            *
 *                         M O D U L E   D E F I N E                          *
 *                                                                            *
 ******************************************************************************/

#define TCP_H

/******************************************************************************
 *                                                                            *
 *        C O M P I L E R   D E F I N E D   I N C L U D E   F I L E S         *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *            U S E R   D E F I N E D   I N C L U D E   F I L E S             *
 *                                                                            *
 ******************************************************************************/

#ifdef __cplusplus
extern "C" {            /* Assume C declarations for C++ */
#endif    /* __cplusplus */

/******************************************************************************
 *                                                                            *
 *                        G L O B A L   D E F I N E S                         *
 *                                                                            *
 ******************************************************************************/

#define TH_FIN  0x01    /*!< \brief Finishing transmission. */
#define TH_SYN  0x02    /*!< \brief Synchronizing sequence numbers. */
#define TH_RST  0x04    /*!< \brief Reset connection. */
#define TH_PUSH 0x08    /*!< \brief Push data to application level. */
#define TH_ACK  0x10    /*!< \brief Acknowledge field is valid. */
#define TH_URG  0x20    /*!< \brief Urgent data present. */

/*! \brief TCP flag mask. */
#define TH_FLAGS (TH_FIN | TH_SYN | TH_RST | TH_ACK | TH_URG)


#define TCPOPT_EOL                  0   /*!< \brief End of options. */
#define TCPOPT_NOP                  1   /*!< \brief Nothing. */
#define TCPOPT_MAXSEG               2   /*!< \brief Maximum segment size. */
#define TCPOLEN_MAXSEG              4   /*!< \brief Maximum segment size length. */
#define TCPOPT_WINDOW               3   /*!< \brief Receive window. */
#define TCPOLEN_WINDOW              3   /*!< \brief Receive window length. */


#define TCP_MSS             536     /*!< \brief Default maximum segment size.
                                         The maximum size of an IP datagram, that will
                                         not become fragmented, is 576. The maximum
                                         IP datagram for Ethernet is 1500. Reduce this
                                         number by 40, 20 bytes TCP header and 20 bytes
                                         IP header.
                                         \showinitializer 
                                     */
#define TCP_WINSIZE         3216    /*!< \brief Default window size.
                                         It's recommended to set this 6 times the maximum
                                         segment size.
                                         \showinitializer 
                                     */

#define TCP_MAXWIN          65535   /*!< \brief Largest value for (unscaled) window. \showinitializer */
#define TTCP_CLIENT_SND_WND 4096    /*!< \brief Default send window for T/TCP client. \showinitializer */

#define TCP_MAX_WINSHIFT    14      /*!< \brief Maximum window shift. \showinitializer */

#define TCP_MAXHLEN         (0xf<<2)    /*!< \brief Maximum length of header in bytes. */
#define TCP_MAXOLEN         (TCP_MAXHLEN - sizeof(struct tcphdr))   /*!< \brief Maximum space left for options. */

/*
 * User-settable options.
 */
#define TCP_NODELAY 0x01    /*!< \brief Don't delay send to coalesce segments. */
#define TCP_MAXSEG  0x02    /*!< \brief Set maximum segment size. */
#define TCP_NOPUSH  0x04    /*!< \brief Don't push last block of write. */
#define TCP_NOOPT   0x08    /*!< \brief Don't use TCP options. */

/******************************************************************************
 *                                                                            *
 *                 S T R U C T U R E   D E F I N I T I O N S                  *
 *                                                                            *
 ******************************************************************************/

/*!
 * \typedef TCPHDR
 * \brief TCP protocol header type.
 */
#if defined(__ICCARM__)
#pragma diag_suppress = Pa039    // Use of address of unaligned structure member
#pragma pack ( 1 )
#endif

typedef struct tcphdr {
    u_short th_sport;       /*!< \brief Source port. */
    u_short th_dport;       /*!< \brief Destination port. */
    u_long  th_seq;         /*!< \brief Sequence number of first octet in this segment. */
    u_long  th_ack;         /*!< \brief Expected sequence number of next octet. */
#ifndef BIG_ENDIAN
    u_char  th_x2:4,        /*!< \brief Unused. */
            th_off:4;       /*!< \brief Data offset. */
#else /* #ifndef BIG_ENDIAN */
    u_char  th_off:4,       /*!< \brief Data offset. */
            th_x2:4;        /*!< \brief Unused. */
#endif
    u_char  th_flags;       /*!< \brief Control flags. */
    u_short th_win;         /*!< \brief Number of acceptable octects. */
    u_short th_sum;         /*!< \brief 96 byte pseudo header checksum. */
    u_short th_urp;         /*!< \brief Urgent data pointer. */
} TCPHDR;

#if defined(__ICCARM__)
#pragma pack ( )
#endif


/*!
 * \typedef TCPPSEUDOHDR
 * \brief TCP pseudo header type.
 */
typedef struct _TCPPSEUDOHDR {
    u_long  tph_src;    /*!< \brief IP address of sender. */
    u_long  tph_dst;    /*!< \brief IP address of target. */
    u_char  tph_mbz;    /*!< \brief mbz */
    u_char  tph_p;      /*!< \brief p */
    u_short tph_len;    /*!< \brief len */
    u_short tph_sum;    /*!< \brief Checksum */
} TCPPSEUDOHDR;

/******************************************************************************
 *                                                                            *
 *    G L O B A L   V A R I A B L E S   -   N O   I N I T I A L I Z E R S     *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *       G L O B A L   V A R I A B L E S   -   I N I T I A L I Z E R S        *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *                   F U N C T I O N   P R O T O T Y P E S                    *
 *                                                                            *
 ******************************************************************************/


#ifdef __cplusplus
}                       /* End of extern "C" { */
#endif    /* __cplusplus */

#endif

tcp_fsm.h  。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

#ifndef TCP_FSM_H

/******************************************************************************
 *                                                                            *
 *                         M O D U L E   D E F I N E                          *
 *                                                                            *
 ******************************************************************************/

#define TCP_FSM_H

/******************************************************************************
 *                                                                            *
 *        C O M P I L E R   D E F I N E D   I N C L U D E   F I L E S         *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *            U S E R   D E F I N E D   I N C L U D E   F I L E S             *
 *                                                                            *
 ******************************************************************************/

#ifdef __cplusplus
extern "C" {            /* Assume C declarations for C++ */
#endif    /* __cplusplus */

/******************************************************************************
 *                                                                            *
 *                        G L O B A L   D E F I N E S                         *
 *                                                                            *
 ******************************************************************************/

#define TCP_NSTATES         11  /*!< \brief Total number of possible states. */

/*
 * Warning: Do NOT change the values or the order of the TCP states.
 * Some functions in tcpsm.c rely on the the order below.
 */
#define TCPS_CLOSED         0   /*!< \brief closed */
#define TCPS_LISTEN         1   /*!< \brief listening for connection */
#define TCPS_SYN_SENT       2   /*!< \brief active, have sent syn */
#define TCPS_SYN_RECEIVED   3   /*!< \brief have sent and received syn */
#define TCPS_ESTABLISHED    4   /*!< \brief established */
#define TCPS_CLOSE_WAIT     5   /*!< \brief rcvd fin, waiting for close */
#define TCPS_FIN_WAIT_1     6   /*!< \brief have closed, sent fin */
#define TCPS_CLOSING        7   /*!< \brief closed xchd FIN; await FIN ACK */
#define TCPS_LAST_ACK       8   /*!< \brief had fin and close; await FIN ACK */
#define TCPS_FIN_WAIT_2     9   /*!< \brief have closed, fin is acked */
#define TCPS_TIME_WAIT      10  /*!< \brief in 2*msl quiet wait after close */

/******************************************************************************
 *                                                                            *
 *                 S T R U C T U R E   D E F I N I T I O N S                  *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *    G L O B A L   V A R I A B L E S   -   N O   I N I T I A L I Z E R S     *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *       G L O B A L   V A R I A B L E S   -   I N I T I A L I Z E R S        *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *                   F U N C T I O N   P R O T O T Y P E S                    *
 *                                                                            *
 ******************************************************************************/

void NutTcpStateMachine(NETBUF *nb);
int NutTcpInitStateMachine(void);

int NutTcpStatePassiveOpenEvent(TCPSOCKET *sock);
int NutTcpStateActiveOpenEvent(TCPSOCKET *sock);
int NutTcpStateCloseEvent(TCPSOCKET *sock);
int NutTcpStateWindowEvent(TCPSOCKET *sock);

int NutTcpStateRetranTimeout(TCPSOCKET *sock);

#ifdef __cplusplus
}                       /* End of extern "C" { */
#endif    /* __cplusplus */

#endif

tcpin.c   。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

/******************************************************************************
 *                                                                            *
 *                         M O D U L E   D E F I N E                          *
 *                                                                            *
 ******************************************************************************/

#define TCPIN_C

/******************************************************************************
 *                                                                            *
 *        C O M P I L E R   D E F I N E D   I N C L U D E   F I L E S         *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *            U S E R   D E F I N E D   I N C L U D E   F I L E S             *
 *                                                                            *
 ******************************************************************************/

#include "Common.h"
#include "XCore.h"
#include "XNutOS.h"

#include "ip.h"
#include "socket.h"
#include "tcp.h"

#ifdef NUTDEBUG
#include "netdebug.h"
#endif

#if defined(NUTNET)

/******************************************************************************
 *                                                                            *
 *                         L O C A L   D E F I N E S                          *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *                        L O C A L   T Y P E D E F S                         *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *             L O C A L   F U N C T I O N   P R O T O T Y P E S              *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *    L O C A L   I N I T I A L I Z E D   D A T A   D E F I N I T I O N S     *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *    L O C A L   U N I T I A L I Z E D   D A T A   D E F I N I T I O N S     *
 *                                                                            *
 ******************************************************************************/


/*!
 * \brief Process incoming TCP segments from IP layer.
 *
 * \warning The caller must take care not to pass broadcast
 *          or multicast segments.
 *
 * \note This routine is called by the IP layer on incoming 
 *       TCP  segments. Applications typically do not call 
 *       this function.
 *
 */
int NutTcpInput(NUTDEVICE * dev, NETBUF * nb)
{
    TCPHDR *th = (TCPHDR *) nb->nb_tp.vp;

    /* Process unicasts only. */
    if (th && (nb->nb_flags & NBAF_UNICAST) != 0) {
        int hdrlen = th->th_off * 4;

        /* Check the header length. */
        if (hdrlen >= sizeof(TCPHDR) && hdrlen <= nb->nb_tp.sz) {
            nb->nb_ap.sz = nb->nb_tp.sz - hdrlen;
            if (nb->nb_ap.sz) {
                nb->nb_ap.vp = ((u_long *) th) + th->th_off;
            }
            nb->nb_tp.sz = hdrlen;

            /*
            ** According to RFC1122 we MUST check the checksum
            ** on incoming segments. Anyway, we rely on lower
            ** level checksums to save processing resources.
            **
            ** However, we may combine checksum calculation
            ** with moving data to the receiver buffer.
            **/

            NutTcpStateMachine(nb);

            return 0;
        }
    }
    /* Silently discard this segment. */
    NutNetBufFree(nb);

    return 0;
}

#endif

tcpout.c   。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

/******************************************************************************
 *                                                                            *
 *                         M O D U L E   D E F I N E                          *
 *                                                                            *
 ******************************************************************************/

#define TCPOUT_C

/******************************************************************************
 *                                                                            *
 *        C O M P I L E R   D E F I N E D   I N C L U D E   F I L E S         *
 *                                                                            *
 ******************************************************************************/

#include <string.h>

/******************************************************************************
 *                                                                            *
 *            U S E R   D E F I N E D   I N C L U D E   F I L E S             *
 *                                                                            *
 ******************************************************************************/

#include "Common.h"
#include "XCore.h"
#include "XNutOS.h"

#include "errno.h"
#include "in.h"
#include "ip.h"
#include "icmp.h"
#include "ip_icmp.h"
#include "ipcsum.h"
#include "socket.h"
#include "tcp.h"

#ifdef NUTDEBUG
#include "netdebug.h"
#endif

#if defined(NUTNET)

/******************************************************************************
 *                                                                            *
 *                         L O C A L   D E F I N E S                          *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *                        L O C A L   T Y P E D E F S                         *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *             L O C A L   F U N C T I O N   P R O T O T Y P E S              *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *    L O C A L   I N I T I A L I Z E D   D A T A   D E F I N I T I O N S     *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *    L O C A L   U N I T I A L I Z E D   D A T A   D E F I N I T I O N S     *
 *                                                                            *
 ******************************************************************************/


/*!
 * \brief Initiate TCP segment transmission.
 *
 * Check the TCP socket status and send any segment waiting
 * for transmission.
 *
 * The function will not return until the data has been stored in the 
 * network device hardware for transmission. If the device is not ready 
 * for transmitting a new packet, the calling thread will be suspended 
 * until the device becomes ready again. 
 *
 * If the target host is connected through an Ethernet network and if 
 * the hardware address of that host is currently unknown, an ARP 
 * request is sent out and the function will block until a response 
 * is received or an ARP timeout occurs.
 *
 * Segments containing data or SYN and FIN flags are added to a special 
 * queue for unacknowledged segments and will be retransmitted by the 
 * TCP timer thread, if not acknowledged by the remote within a specific 
 * time. The state machine will remove these segments from the queue
 * as soon as they are acknowledged.
 *
 * \note This function is mainly used by the TCP state machine.
 *       Applications typically do not call this function but 
 *       use NutTcpSend(), which is part of the TCP socket interface.
 *
 * \param sock  Socket descriptor. This pointer must have been retrieved 
 *              by calling NutTcpCreateSocket().
 * \param data  Pointer to TCP segment contents.
 * \param size  TCP segment length.
 *
 * \return 0 on success, -1 otherwise. Returning 0 does not imply that 
 *         the data has been successfully delivered, because flow control 
 *         and retransmission is still handled in the background.
 */
int NutTcpOutput(TCPSOCKET * sock, CONST u_char * data, u_short size)
{
    NETBUF *nb;
    NETBUF *nb_clone = 0;
    TCPHDR *th;
    u_short csum;
    u_char hlen;

    /*
     * Check if anything to send at all.
     */
    if (size == 0
        && (sock->so_tx_flags & (SO_SYN | SO_FIN | SO_FORCE)) == 0)
        return 0;

    /*
     * Build TCP header. Add room for MAXSEG option if this is a
     * SYN segment.
     */
    hlen = sizeof(TCPHDR);
    if (sock->so_tx_flags & SO_SYN)
        hlen += 4;
    if ((nb = NutNetBufAlloc(0, NBAF_TRANSPORT, hlen)) == 0) {
        sock->so_last_error = ENOBUFS;
        return -1;
    }
    th = (TCPHDR *) nb->nb_tp.vp;
    th->th_sport = sock->so_local_port;
    th->th_dport = sock->so_remote_port;
    th->th_x2 = 0;
    th->th_off = hlen >> 2;

    sock->so_tx_flags &= ~SO_FORCE;

    /*
     * Process ACK flag.
     */
    th->th_seq = htonl(sock->so_tx_nxt);
    if (sock->so_tx_flags & SO_ACK) {
        th->th_flags = TH_ACK;
        sock->so_tx_flags &= ~SO_ACK;
        th->th_ack = htonl(sock->so_rx_nxt);
    } else {
        th->th_flags = 0;
        th->th_ack = 0;
    }

    /*
     * Any SYN is sent first. Add options too. We rely on the caller 
     * not to send a SYN segment with data, because this may break
     * some old stacks.
     */
    if (sock->so_tx_flags & SO_SYN) {
        u_char *cp;
        u_short n_mss = htons(sock->so_mss);

        th->th_flags |= TH_SYN;
        sock->so_tx_flags &= ~SO_SYN;
        sock->so_tx_nxt++;

        cp = (u_char *) (th + 1);
        *cp++ = TCPOPT_MAXSEG;
        *cp++ = TCPOLEN_MAXSEG;
        *cp++ = *(u_char *)&n_mss;
        *cp = *((u_char *)(&n_mss) + 1);
    }

    /*
     * Next preference is sending data. Set PUSH flag.
     */
    else if (size) {
        if ((nb = NutNetBufAlloc(nb, NBAF_APPLICATION, size)) == 0) {
            sock->so_last_error = ENOBUFS;
            return -1;
        }
        memcpy(nb->nb_ap.vp, (void *)data, size);
        sock->so_tx_nxt += size;
        th->th_flags |= TH_PUSH;
    }

    /*
     * If all data sent, transmit any waiting FIN.
     */
    else if (sock->so_tx_flags & SO_FIN) {
        th->th_flags |= TH_FIN;
        sock->so_tx_flags &= ~SO_FIN;
        sock->so_tx_nxt++;
        //@@@printf ("[%04X]TcpOutput: sending FIN\n", (u_short) sock);
    }

    /*
     * We close our receiver window, if it is
     * below the maximum segment size.
     */
    if (sock->so_rx_win < sock->so_mss)
        th->th_win = 0;
    else
        th->th_win = htons(sock->so_rx_win);
    th->th_sum = 0;
    th->th_urp = 0;

    /*
     * Calculate TCP checksum.
     */
    csum =
        NutIpPseudoChkSumPartial(sock->so_local_addr, sock->so_remote_addr,
                                 IPPROTO_TCP,
                                 htons(nb->nb_tp.sz + nb->nb_ap.sz));
    csum = NutIpChkSumPartial(csum, th, nb->nb_tp.sz);
    th->th_sum = NutIpChkSum(csum, nb->nb_ap.vp, nb->nb_ap.sz);

#ifdef NUTDEBUG
    if (__tcp_trf)
        NutDumpTcpHeader(__tcp_trs, "OUT", sock, nb);
#endif

    /*
     * To avoid a race condition in tcp state machine, the segment is first
     * appended to the transmission que, and then sent to the network.
     */

    /*
     * Append the segment to our transmission queue.
     */
    //@@@printf ("[%04X]TcpOutput: size: %u, flags: %u\n", (u_short) sock, size, th->th_flags);
    if (size || ((th->th_flags & (TH_FIN | TH_SYN)))) {
        //@@@printf ("[%04X]TcpOutput: appending nb to queue\n", (u_short) sock);
        NETBUF *nbp;

        nb->nb_next = 0;
        if ((nbp = sock->so_tx_nbq) == 0) {
            sock->so_tx_nbq = nb;
            /*
             * First entry, so initialize our retransmission timer.
             * It is also set at various places in the state machine,
             * but here is the best central point to do it. We may
             * carefully check later, if we can remove some in the
             * state machine.
             */
            sock->so_retran_time = (u_short) NutGetMillis() | 1;
        }
        else {
            while (nbp->nb_next)
                nbp = nbp->nb_next;
            nbp->nb_next = nb;
        }
        if (sock->so_rtt_seq == 0)
            sock->so_rtt_seq = ntohl (th->th_seq);
        nb_clone = NutNetBufClone (nb);
        if (nb_clone == NULL) {
            sock->so_last_error = ENOBUFS;
            return -1;
        }
    }
    else
        nb_clone = nb;

    /*
     * IP output might fail because of routing, ARP or network device 
     * problems or because the system ran out of memory.
     */
    if (NutIpOutput(IPPROTO_TCP, sock->so_remote_addr, nb_clone)) 
        return -1;

    NutNetBufFree (nb_clone);
    return 0;
}

/*!
 * \brief Reject an incoming segment.
 *
 * Send RST in response to an incoming segment, which should
 * be rejected.
 *
 * The function avoids to send out a RST segment in response to 
 * an incoming RST segment.
 *
 * \note This function is mainly used by the TCP state machine.
 *       Applications typically do not call this function.
 *
 * \param nb Network buffer structure of the incoming segment. 
 *           Will be released within this function.
 *
 * \return 0 on success, -1 otherwise.
 */
int NutTcpReject(NETBUF * nb)
{
    u_short csum;
    IPHDR *ih = (IPHDR *) nb->nb_nw.vp;
    TCPHDR *th = (TCPHDR *) nb->nb_tp.vp;

    /*
     * Never send RST in response to RST.
     */
    if (th->th_flags & TH_RST) {
        NutNetBufFree(nb);
        return 0;
    }

    /*
     * Remove any application data and TCP header options.
     */
    nb->nb_ap.sz = 0;
    nb->nb_tp.sz = sizeof(TCPHDR);

    /*
     * Swap ports.
     */
    csum = th->th_sport;
    th->th_sport = th->th_dport;
    th->th_dport = csum;

    /*
     * If the incoming segment has an ACK field, the reset
     * takes its sequence number from the ACK field of the
     * segment, otherwise the reset has sequence number zero
     * and the ACK field is set to the sum of the sequence
     * number and segment length of the incoming segment.
     */
    if (th->th_flags & TH_ACK) {
        th->th_flags = TH_RST;
        th->th_seq = th->th_ack;
        th->th_ack = 0;
    } else {
        if (th->th_flags & TH_SYN)
            th->th_ack = htonl(ntohl(th->th_seq) + 1);
        else
            th->th_ack = th->th_seq;
        th->th_seq = 0;
        th->th_flags = TH_RST | TH_ACK;
    }
    th->th_x2 = 0;
    th->th_off = sizeof(TCPHDR) / 4;
    th->th_win = 0;
    th->th_urp = 0;

    /*
     * Calculate TCP checksum without application data.
     */
    th->th_sum = 0;
    csum =
        NutIpPseudoChkSumPartial(ih->ip_dst, ih->ip_src, IPPROTO_TCP, 
                                 htons(nb->nb_tp.sz));
    th->th_sum = NutIpChkSum(csum, th, nb->nb_tp.sz);

    /*
     * Sent segment back to the source.
     */
#ifdef NUTDEBUG
    if (__tcp_trf)
        NutDumpTcpHeader(__tcp_trs, "REJ", 0, nb);
#endif
    if(NutIpOutput(IPPROTO_TCP, ih->ip_src, nb) == 0)
        NutNetBufFree(nb);
    return 0;
}

#endif

tcpsm.c   。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

/******************************************************************************
 *                                                                            *
 *                         M O D U L E   D E F I N E                          *
 *                                                                            *
 ******************************************************************************/

#define TCPSM_C

/******************************************************************************
 *                                                                            *
 *        C O M P I L E R   D E F I N E D   I N C L U D E   F I L E S         *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *            U S E R   D E F I N E D   I N C L U D E   F I L E S             *
 *                                                                            *
 ******************************************************************************/

#include "Common.h"
#include "XCore.h"
#include "XNutOS.h"

#include "errno.h"
#include "in.h"
#include "ip.h"
#include "route.h"
#include "socket.h"
#include "tcputil.h"
#include "tcp.h"

#ifdef NUTDEBUG
#include "netdebug.h"
#endif

#if defined(NUTNET)

/******************************************************************************
 *                                                                            *
 *                         L O C A L   D E F I N E S                          *
 *                                                                            *
 ******************************************************************************/

#ifndef TCP_RETRIES_MAX
#define TCP_RETRIES_MAX         7
#endif

/******************************************************************************
 *                                                                            *
 *                        L O C A L   T Y P E D E F S                         *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *             L O C A L   F U N C T I O N   P R O T O T Y P E S              *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *    L O C A L   I N I T I A L I Z E D   D A T A   D E F I N I T I O N S     *
 *                                                                            *
 ******************************************************************************/

static NUTHANDLE tcpThread = 0;

/******************************************************************************
 *                                                                            *
 *    L O C A L   U N I T I A L I Z E D   D A T A   D E F I N I T I O N S     *
 *                                                                            *
 ******************************************************************************/

extern TCPSOCKET *tcpSocketList;

NUTHANDLE tcp_in_rdy;
NETBUF *volatile tcp_in_nbq;
static u_short tcp_in_cnt;

static size_t tcp_adv_cnt;
static size_t tcp_adv_max = TCP_WINSIZE;

/* ================================================================
 * Helper functions
 * ================================================================
 */


/*!
 * \brief Reads TCP option fields if any, and writes the data to
 *        the socket descriptor if important for us.
 *
 * \param sock Socket descriptor. This pointer must have been 
 *             retrieved by calling NutTcpCreateSocket().
 * \param nb   Network buffer structure containing a TCP segment.
 */
static void NutTcpInputOptions(TCPSOCKET * sock, NETBUF * nb)
{
    u_char *cp;
    u_short s;
    
    /* any options there? */
    if (nb->nb_tp.sz <= sizeof (TCPHDR))
        return;
    
    /* loop through available options */
    for (cp = ((u_char*) nb->nb_tp.vp) + sizeof(TCPHDR); (*cp != TCPOPT_EOL) 
       && (cp - (u_char *)nb->nb_tp.vp < (int)nb->nb_tp.sz); )
    {
        switch (*cp)
        {
            /* On NOP just proceed to next option */
            case TCPOPT_NOP:
                cp++;
                continue;
                
            /* Read MAXSEG option */
            case TCPOPT_MAXSEG:
                s = ntohs(((u_short)cp[2] << 8) | cp[3]);
                if (s < sock->so_mss)
                    sock->so_mss = s;
                cp += TCPOLEN_MAXSEG;
                break;
            /* Ignore any other options */
            default:
                cp += *(u_char*) (cp + 1);
                break;
        }
    }
}

/*!
 * \brief Move application data in sync from the network buffer 
 *        structure to the socket's receive buffer.
 *
 * \param sock Socket descriptor. This pointer must have been 
 *             retrieved by calling NutTcpCreateSocket().
 * \param nb   Network buffer structure containing a TCP segment.
 */
static void NutTcpProcessAppData(TCPSOCKET * sock, NETBUF * nb)
{
    /* TODO: Zero windows issue */
    if ((((TCPHDR *) (nb->nb_tp.vp))->th_flags & TH_FIN) == 0) {
        if (nb->nb_ap.sz > sock->so_rx_win)
            nb->nb_ap.sz = sock->so_rx_win;

        if (nb->nb_ap.sz == 0 || sock->so_rx_win < sock->so_mss) {
            sock->so_tx_flags |= SO_ACK | SO_FORCE;
            NutNetBufFree(nb);
            NutTcpOutput(sock, 0, 0);
            return;
        }
    }

    /*
     * Add the NETBUF to the socket's input buffer.
     */
    if (sock->so_rx_buf) {
        NETBUF *nbp = sock->so_rx_buf;

        while (nbp->nb_next)
            nbp = nbp->nb_next;
        nbp->nb_next = nb;
    } else
        sock->so_rx_buf = nb;

    /*
     * Update the number of bytes available in the socket's input buffer
     * and the sequence number we expect next.
     */
    sock->so_rx_cnt += nb->nb_ap.sz;
    sock->so_rx_nxt += nb->nb_ap.sz;

    /*
     * Reduce our TCP window size.
     */
    if (nb->nb_ap.sz >= sock->so_rx_win)
        sock->so_rx_win = 0;
    else
        sock->so_rx_win -= nb->nb_ap.sz;

    /*
     * Set the socket's ACK flag. This will enable ACK transmission in
     * the next outgoing segment. If no more NETBUFs are queued, we
     * force immediate transmission of the ACK.
     */
    sock->so_tx_flags |= SO_ACK;
    if (nb->nb_next)
        nb->nb_next = 0;
    else
        sock->so_tx_flags |= SO_FORCE;

    if (++sock->so_rx_apc > 8) {
        NETBUF *nbq;
        char apc = sock->so_rx_apc;
        int cnt = sock->so_rx_cnt;

        for (nbq = sock->so_rx_buf; nbq; nbq = nbq->nb_next) {
            if (nbq->nb_ap.sz < 256) {
                sock->so_rx_apc -= NutNetBufCollect(nbq, cnt);
                break;
            }
            if (--apc < 8) {
                break;
            }
            cnt -= nbq->nb_ap.sz;
        }
    }
    NutTcpOutput(sock, 0, 0);
}

/*
 * \param sock Socket descriptor.
 */
static void NutTcpProcessSyn(TCPSOCKET * sock, IPHDR * ih, TCPHDR * th)
{
    u_short mss;
    NUTDEVICE *dev;
    IFNET *nif;

    sock->so_local_addr = ih->ip_dst;
    sock->so_remote_port = th->th_sport;
    sock->so_remote_addr = ih->ip_src;

    sock->so_rx_nxt = sock->so_tx_wl1 = sock->so_rx_isn = ntohl(th->th_seq);
    sock->so_rx_nxt++;
    sock->so_tx_win = ntohs(th->th_win);

    /*
     * To avoid unnecessary fragmentation, limit the
     * maximum segment size to the maximum transfer
     * unit of our interface.
     */
    if ((dev = NutIpRouteQuery(ih->ip_src, 0)) != 0) {
        nif = dev->dev_icb;
        mss = nif->if_mtu - sizeof(IPHDR) - sizeof(TCPHDR);
        if (sock->so_mss == 0 || sock->so_mss > mss)
            sock->so_mss = mss;

        /* Limit output buffer size to mms */
        if (sock->so_devobsz > sock->so_mss)
            sock->so_devobsz = sock->so_mss;
    }
}

/*!
 * \brief ACK processing.
 *
 * \param sock Socket descriptor. This pointer must have been 
 *             retrieved by calling NutTcpCreateSocket().
 *
 */
static int NutTcpProcessAck(TCPSOCKET * sock, TCPHDR * th, u_short length)
{
    NETBUF *nb;
    u_long h_seq;
    u_long h_ack;

    /*
     * If remote acked something not yet send, reply immediately.
     */
    h_ack = ntohl(th->th_ack);
    if (SeqIsAfter(h_ack, sock->so_tx_nxt)) {
        sock->so_tx_flags |= SO_ACK | SO_FORCE;
        return 0;
    }

    /*
     * If the new sequence number or acknowledged sequence number
     * is above our last update, we adjust our transmit window.
     * Avoid dupe ACK processing on window updates.
     */
    if (h_ack == sock->so_tx_una) {
        h_seq = ntohl(th->th_seq);
        if (SeqIsAfter(h_seq, sock->so_tx_wl1) || (h_seq == sock->so_tx_wl1 && !SeqIsAfter(sock->so_tx_wl2, h_ack))) {
            sock->so_tx_win = ntohs(th->th_win);
            sock->so_tx_wl1 = h_seq;
            sock->so_tx_wl2 = h_ack;
        }
    }

    /*
     * Ignore old ACKs but wake up sleeping transmitter threads, because
     * the window size may have changed.
     */
    if (SeqIsAfter(sock->so_tx_una, h_ack)) {
        return 0;
    }

    /*
     * Process duplicate ACKs.
     */
    if (h_ack == sock->so_tx_una) {
        /*
         * Don't count, if nothing is waiting for ACK,
         * segment contains data or on SYN/FIN segments.
         */
        if (sock->so_tx_nbq && length == 0 && (th->th_flags & (TH_SYN | TH_FIN)) == 0) {
            /*
             * If dupe counter reaches it's limit, resend
             * the oldest unacknowledged netbuf.
             */
            if (++sock->so_tx_dup >= 3) {
                sock->so_tx_dup = 0;
#ifdef NUTDEBUG
                if (__tcp_trf)
                    NutDumpTcpHeader(__tcp_trs, "RET", sock, sock->so_tx_nbq);
#endif
                /*
                 * Retransmit first unacked packet from queue.
                 * Actually we got much more trouble if this fails.
                 */
                if (NutTcpStateRetranTimeout(sock))
                    return -1;
            }
        }
        return 0;
    }

    /*
     * We're here, so the ACK must have actually acked something
     */
    sock->so_tx_dup = 0;
    sock->so_tx_una = h_ack;

    /*
     * Bugfix contributed by Liu Limin: If the remote is slow and this
     * line is missing, then Ethernut will send a full data packet even
     * if the remote closed the window.
     */
    sock->so_tx_win = ntohs(th->th_win);

    /* 
     * Do round trip time calculation.
     */
    if (sock->so_rtt_seq && SeqIsAfter(h_ack, sock->so_rtt_seq))
        NutTcpCalcRtt (sock);
    sock->so_rtt_seq = 0;
    /*
     * Remove all acknowledged netbufs.
     */
    while ((nb = sock->so_tx_nbq) != 0) {
        /* Calculate the sequence beyond this netbuf. */
        h_seq = ntohl(((TCPHDR *) (nb->nb_tp.vp))->th_seq) + nb->nb_ap.sz;
        if (((TCPHDR *) (nb->nb_tp.vp))->th_flags & (TH_SYN | TH_FIN)) {
            h_seq++;
        }
        //@@@printf ("[%04X]*: processack, check seq#: %lu\n", (u_short) sock, h_seq);
        if (SeqIsAfter(h_seq, h_ack)) {
            break;
        }
        sock->so_tx_nbq = nb->nb_next;
        NutNetBufFree(nb);
    }

    /*
     * Reset retransmit timer and wake up waiting transmissions.
     */
    if (sock->so_tx_nbq) {
        sock->so_retran_time = (u_short) NutGetMillis() | 1;
    } else {
        sock->so_retran_time = 0;
    }
    sock->so_retransmits = 0;

    return 0;
}

/* ================================================================
 * State changes.
 * ================================================================
 */
/*!
 * State change, possibly inform application.
 *
 * \param sock  Socket descriptor.
 * \param state New state to switch to.
 *
 * \return 0 on success, -1 on illegal state change attempt.
 */
static int NutTcpStateChange(TCPSOCKET * sock, u_char state)
{
    int rc = 0;
    ureg_t txf = 0;

    switch (sock->so_state) {
        /* Handle the most common case first. */
    case TCPS_ESTABLISHED:
        switch (state) {
        case TCPS_FIN_WAIT_1:
            /*
             * Closed by application.
             */
            sock->so_tx_flags |= SO_FIN | SO_ACK;
            txf = 1;

#ifdef RTLCONNECTHACK
            /*
             * Hack alert!
             * On the RTL8019AS we got a problem. Because of not handling
             * the CHRDY line, the controller drops outgoing packets when
             * a browser opens multiple connections concurrently, producing
             * several short incoming packets. Empirical test showed, that
             * a slight delay during connects and disconnects helped to
             * remarkably reduce this problem.
             */
            NutDelay(5);
#endif
            break;
        case TCPS_CLOSE_WAIT:
            /*
             * FIN received.
             */
            sock->so_tx_flags |= SO_ACK | SO_FORCE;
            txf = 1;
            break;
        default:
            rc = -1;
            break;
        }
        break;

    case TCPS_LISTEN:
        /*
         * SYN received.
         */
        if (state == TCPS_SYN_RECEIVED) {
            sock->so_tx_flags |= SO_SYN | SO_ACK;
            txf = 1;
#ifdef RTLCONNECTHACK
            /*
             * Hack alert!
             * On the RTL8019AS we got a problem. Because of not handling
             * the CHRDY line, the controller drops outgoing packets when
             * a browser opens multiple connections concurrently, producing
             * several short incoming packets. Empirical test showed, that
             * a slight delay during connects and disconnects helped to
             * remarkably reduce this problem.
             */
            NutDelay(5);
#endif
        } else
            rc = -1;
        break;

    case TCPS_SYN_SENT:
        switch (state) {
        case TCPS_LISTEN:
            /*
             * RST received on passive socket.
             */
            break;
        case TCPS_SYN_RECEIVED:
            /*
             * SYN received.
             */
            sock->so_tx_flags |= SO_SYN | SO_ACK;
            txf = 1;
            break;
        case TCPS_ESTABLISHED:
            /*
             * SYNACK received.
             */
            sock->so_tx_flags |= SO_ACK | SO_FORCE;
            txf = 1;
            break;
        default:
            rc = -1;
            break;
        }
        break;

    case TCPS_SYN_RECEIVED:
        switch (state) {
        case TCPS_LISTEN:
            /*
             * RST received on passive socket.
             */
            break;
        case TCPS_ESTABLISHED:
            /*
             * ACK of SYN received.
             */
            break;
        case TCPS_FIN_WAIT_1:
            /*
             * Closed by application.
             */
            sock->so_tx_flags |= SO_FIN;
            txf = 1;
            break;
        case TCPS_CLOSE_WAIT:
            /*
             * FIN received.
             */
            sock->so_tx_flags |= SO_FIN | SO_ACK;
            txf = 1;
            break;
        default:
            rc = -1;
            break;
        }
        break;

    case TCPS_FIN_WAIT_1:
        switch (state) {
        case TCPS_FIN_WAIT_1:
        case TCPS_FIN_WAIT_2:
            /*
             * ACK of FIN received.
             */
            break;
        case TCPS_CLOSING:
            /*
             * FIN received.
             */
            sock->so_tx_flags |= SO_ACK | SO_FORCE;
            txf = 1;
            break;
        case TCPS_TIME_WAIT:
            /*
             * FIN and ACK of FIN received.
             */
            break;
        default:
            rc = -1;
            break;
        }
        break;

    case TCPS_FIN_WAIT_2:
        /*
         * FIN received.
         */
        if (state != TCPS_TIME_WAIT)
            rc = -1;
        sock->so_tx_flags |= SO_ACK | SO_FORCE;
        txf = 1;
        break;

    case TCPS_CLOSE_WAIT:
        /*
         * Closed by application.
         */
        if (state == TCPS_LAST_ACK) {
            sock->so_tx_flags |= SO_FIN | SO_ACK;
            txf = 1;
        } else
            rc = -1;
        break;

    case TCPS_CLOSING:
        /*
         * ACK of FIN received.
         */
        if (state != TCPS_TIME_WAIT)
            rc = -1;
        break;

    case TCPS_LAST_ACK:
        rc = -1;
        break;

    case TCPS_TIME_WAIT:
        rc = -1;
        break;

    case TCPS_CLOSED:
        switch (state) {
        case TCPS_LISTEN:
            /*
             * Passive open by application.
             */
            break;
        case TCPS_SYN_SENT:
            /*
             * Active open by application.
             */
            sock->so_tx_flags |= SO_SYN;
            txf = 1;
            break;
        default:
            rc = -1;
            break;
        }
        break;
    }
#ifdef NUTDEBUG
    if (__tcp_trf) {
        fprintf(__tcp_trs, " %04x-", (u_int) sock);
        if (rc)
            NutDumpSockState(__tcp_trs, sock->so_state, "**ERR ", "**>");
        NutDumpSockState(__tcp_trs, state, "[>", "]");
    }
#endif

    if (rc == 0) {
        sock->so_state = state;
        if (txf && NutTcpOutput(sock, 0, 0)) {
            if (state == TCPS_SYN_SENT) {
                rc = -1;
                sock->so_last_error = EHOSTDOWN;
                NutEventPostAsync(&sock->so_ac_tq);
            }
        }
        if (state == TCPS_CLOSE_WAIT) {
            /*
             * Inform application.
             */
            NutEventBroadcast(&sock->so_rx_tq);
            NutEventBroadcast(&sock->so_pc_tq);
            NutEventBroadcast(&sock->so_ac_tq);
        }
    }
    return rc;
}

/* ================================================================
 * Application events.
 * ================================================================
 */
/*!
 * \brief Initiated by the application.
 *
 * \param sock Socket descriptor. This pointer must have been 
 *             retrieved by calling NutTcpCreateSocket().
 *
 * \return 0 if granted, error code otherwise.
 */
int NutTcpStatePassiveOpenEvent(TCPSOCKET * sock)
{
    if (sock->so_state != TCPS_CLOSED)
        return (sock->so_last_error = EISCONN);

    NutTcpStateChange(sock, TCPS_LISTEN);

    /*
     * Block application.
     */
    NutEventWait(&sock->so_pc_tq, 0);

    return 0;
}

/*!
 * \brief Initiated by the application.
 *
 * The caller must make sure, that the socket is in closed state.
 *
 * \param sock Socket descriptor. This pointer must have been 
 *             retrieved by calling NutTcpCreateSocket().
 *
 * \return 0 if granted, -1 otherwise.
 */
int NutTcpStateActiveOpenEvent(TCPSOCKET * sock)
{
    /*
     * Switch state to SYN_SENT. This will
     * transmit a SYN packet.
     */
    NutTcpStateChange(sock, TCPS_SYN_SENT);

    /*
     * Block application.
     */
     if(sock->so_state == TCPS_SYN_SENT)
        NutEventWait(&sock->so_ac_tq, 0);

    if (sock->so_state != TCPS_ESTABLISHED)
        return -1;

    return 0;
}

/*!
 * \brief Socket close by application.
 *
 * If socket is in state SYN_RECEIVED or ESTABLISHED,
 * it is changed to FINWAIT1.
 *
 * No further data sending is accepted.
 * Receiving is still allowed.
 *
 * \param sock Socket descriptor. This pointer must have been 
 *             retrieved by calling NutTcpCreateSocket().
 */
int NutTcpStateCloseEvent(TCPSOCKET * sock)
{
    if (sock == 0)
        return -1;

    NutThreadYield();

    switch (sock->so_state) {
    case TCPS_LISTEN:
    case TCPS_SYN_SENT:
    case TCPS_CLOSED:
        /*
         * No connection yet, immediately destroy the socket.
         */
        NutTcpDestroySocket(sock);
        break;

    case TCPS_SYN_RECEIVED:
    case TCPS_ESTABLISHED:
        /*
         * Send a FIN and wait for ACK or FIN.
         */
        //@@@printf ("[%04X]ESTABLISHED: going to FIN_WAIT_1\n", (u_short) sock);
        NutTcpStateChange(sock, TCPS_FIN_WAIT_1);
        break;

    case TCPS_CLOSE_WAIT:
        /* 
         * RFC 793 is wrong. 
         */
        //@@@printf("[%04X]CLOSE_WAIT: going to LAST_ACK\n", (u_short) sock);
        NutTcpStateChange(sock, TCPS_LAST_ACK);
        break;

    case TCPS_FIN_WAIT_1:
    case TCPS_FIN_WAIT_2:
    case TCPS_CLOSING:
    case TCPS_LAST_ACK:
    case TCPS_TIME_WAIT:
        sock->so_last_error = EALREADY;
        return -1;

    default:
        sock->so_last_error = ENOTCONN;
        return -1;
    }
    return 0;
}

/*!
 * \brief Initiated by the application.
 *
 * \param sock Socket descriptor. This pointer must have been 
 *             retrieved by calling NutTcpCreateSocket().
 */
int NutTcpStateWindowEvent(TCPSOCKET * sock)
{
    if (sock == 0)
        return -1;
    sock->so_tx_flags |= SO_ACK | SO_FORCE;
    NutTcpOutput(sock, 0, 0);

    return 0;
}

/* ================================================================
 * Timeout events.
 * ================================================================
 */
/*!
 * \brief Retransmit a segment after ACK timeout.
 *
 * This function is called by the TCP timer.
 *
 * \param sock Socket descriptor. This pointer must have been 
 *             retrieved by calling NutTcpCreateSocket().
 * \returns Nonzero if socket was aborted due to reach of retransmit 
 *          limit or network error.
 *
 */
int NutTcpStateRetranTimeout(TCPSOCKET * sock)
{
    NETBUF *so_tx_next;
    if (sock->so_retransmits++ > TCP_RETRIES_MAX)
    {
        /* Abort the socket */
        NutTcpAbortSocket(sock, ETIMEDOUT);
        return -1;
    } else {
#ifdef NUTDEBUG
        if (__tcp_trf)
            NutDumpTcpHeader(__tcp_trs, "RET", sock, sock->so_tx_nbq);
#endif
        /* We must save sock->so_tx_nbq->nb_next before calling NutIpOutput,
         * because in case of error the NETBUF is release by NutIpOutput and
         * not longer available.
         */
        so_tx_next = sock->so_tx_nbq->nb_next;
        if (NutIpOutput(IPPROTO_TCP, sock->so_remote_addr, sock->so_tx_nbq)) {
            /* Adjust packet queue */
            sock->so_tx_nbq = so_tx_next;
            /* Abort the socket */
            NutTcpAbortSocket(sock, ENETDOWN);
            return -1;
        } else {
            /* Restart the retransmission timer. */
            sock->so_retran_time = (u_short) NutGetMillis() | 1;
            return 0;
        }
    }
}

/* ================================================================
 * Segment arrival events.
 * ================================================================
 */

/*!
 * \brief
 * Process incoming segments in listening state.
 *
 * Wait for a connection request from a remote socket.
 *
 * \param sock Socket descriptor.
 * \param nb   Network buffer structure containing a TCP segment.
 */
static void NutTcpStateListen(TCPSOCKET * sock, u_char flags, TCPHDR * th, NETBUF * nb)
{
    /*
     * Got a SYN segment. Store relevant data in our socket
     * structure and switch to TCPS_SYN_RECEIVED.
     */
    if ((flags & (TH_SYN | TH_ACK | TH_RST)) == TH_SYN) {
        NutTcpProcessSyn(sock, nb->nb_nw.vp, th);
        NutTcpStateChange(sock, TCPS_SYN_RECEIVED);
        NutNetBufFree(nb);
    } else
        NutTcpReject(nb);
}


/*!
 * \brief Process incoming segments in SYN-SENT state.
 *
 * Wait for a matching connection request after having sent ours.
 *
 * \param sock Socket descriptor.
 * \param nb   Network buffer structure containing a TCP segment.
 */
static void NutTcpStateSynSent(TCPSOCKET * sock, u_char flags, TCPHDR * th, NETBUF * nb)
{
    /*
     * Validate ACK, if set.
     */
    if (flags & TH_ACK) {
        if (!SeqIsBetween(ntohl(th->th_ack), sock->so_tx_isn + 1, sock->so_tx_nxt)) {
            NutTcpReject(nb);
            return;
        }
    }

    /*
     * Handle RST flag. If we were in the LISTEN state,
     * then we return to the LISTEN state, otherwise we
     * abort the connection and go to the CLOSED state.
     */
    if (flags & TH_RST) {
        if (flags & TH_ACK) {
            /*if (sock->so_pc_tq)
                NutTcpStateChange(sock, TCPS_LISTEN);
            else */
                NutTcpAbortSocket(sock, ECONNREFUSED);
        }
        NutNetBufFree(nb);
        return;
    }

    /*
     * Handle SYN flag. If we got a valid ACK too, then
     * our connection is established. Otherwise enter
     * SYNRCVD state.
     */
    if (flags & TH_SYN) {
        NutTcpProcessSyn(sock, nb->nb_nw.vp, th);
        if (flags & TH_ACK) {
            NutTcpProcessAck(sock, th, nb->nb_ap.sz);
            NutTcpStateChange(sock, TCPS_ESTABLISHED);
            /* Wake up the actively connecting thread. */
            NutEventPost(&sock->so_ac_tq);
        } else {
            NutTcpStateChange(sock, TCPS_SYN_RECEIVED);
        }
    }
    NutNetBufFree(nb);
}

/*
 * \brief
 * Process incoming segments in SYN-RECEIVED state.
 *
 * Waiting for a confirming connection request
 * acknowledgment after having both received
 * and sent a connection request.
 *
 * \param sock Socket descriptor.
 * \param nb   Network buffer structure containing a TCP segment.
 */
static void NutTcpStateSynReceived(TCPSOCKET * sock, u_char flags, TCPHDR * th, NETBUF * nb)
{
    /*
     * If our previous ack receives a reset response,
     * then we fall back to the listening state.
     */
    if (flags & TH_RST) {
        if (sock->so_pc_tq)
            NutTcpStateChange(sock, TCPS_LISTEN);
        else 
            NutTcpAbortSocket(sock, ECONNREFUSED);
        NutNetBufFree(nb);
        sock->so_retran_time = 0;
        NutTcpDiscardBuffers(sock);
        return;
    }

    /*
     * Reject SYNs.
     */
    if (flags & TH_SYN) {
        NutTcpReject(nb);
        return;
    }

    /*
     * Silently discard segments without ACK.
     */
    if ((flags & TH_ACK) == 0) {
        NutNetBufFree(nb);
        return;
    }

    /*
     * Reject out of window sequence.
     */
    if (!SeqIsBetween(ntohl(th->th_ack), sock->so_tx_una + 1, sock->so_tx_nxt)) {
        NutTcpReject(nb);
        return;
    }

    /* Acknowledge processing. */
    NutTcpProcessAck(sock, th, nb->nb_ap.sz);

    /*
     * Even SYN segments may contain application data, which will be stored
     * in the socket's input buffer. However, there is no need to post an
     * event to any thread waiting for data, because our connection is not 
     * yet established.
     */
    if (nb->nb_ap.sz)
        NutTcpProcessAppData(sock, nb);
    else
        NutNetBufFree(nb);

    /*
     * Process state change.
     */
    if (flags & TH_FIN) {
        sock->so_rx_nxt++;
        NutTcpStateChange(sock, TCPS_CLOSE_WAIT);
    } else {
        NutTcpStateChange(sock, TCPS_ESTABLISHED);
        NutEventPost(&sock->so_pc_tq);
        NutEventPost(&sock->so_ac_tq);
    }
}

/*
 * \brief Process incoming segments from established connections.
 *
 * Received application data will be delivered to the application
 * until we receive a FIN segment.
 *
 * \param sock  Socket descriptor.
 * \param flags TCP flags.
 * \param th    Pointer to the TCP header within the NETBUF.
 * \param nb    Network buffer structure containing a TCP segment.
 *
 * \todo We may remove the unused counter of dropped segments, which
 *       were out of sequence.
 */
static void NutTcpStateEstablished(TCPSOCKET * sock, u_char flags, TCPHDR * th, NETBUF * nb)
{
    if (flags & TH_RST) {
        NutNetBufFree(nb);
        NutTcpAbortSocket(sock, ECONNRESET);
        return;
    }

    /*
     * Reject SYNs. Silently discard late SYNs
     * (Thanks to Mike Cornelius).
     */
    if (flags & TH_SYN) {
        if (ntohl(th->th_seq) != sock->so_rx_isn)
            NutTcpReject(nb);
        else
            NutNetBufFree(nb);
        return;
    }

    /*
     * Silently discard segments without ACK.
     */
    if ((flags & TH_ACK) == 0) {
        NutNetBufFree(nb);
        return;
    }

    NutTcpProcessAck(sock, th, nb->nb_ap.sz);

    /*
     * If the sequence number of the incoming segment is larger than 
     * expected, we probably missed one or more previous segments. Let's 
     * add this one to a linked list of segments received in advance and 
     * hope that the missing data will arrive later.
     */
    if (SeqIsAfter(ntohl(th->th_seq),sock->so_rx_nxt)) {
        NETBUF *nbq;
        NETBUF **nbqp;
        TCPHDR *thq;
        u_long th_seq;
        u_long thq_seq;

        if (nb->nb_ap.sz) {
            /* Keep track of the number of bytes used by packets
            ** received in advance. Honor a global limit. */
            tcp_adv_cnt += nb->nb_dl.sz + sizeof(IPHDR) + sizeof (TCPHDR) + nb->nb_ap.sz;
            if (tcp_adv_cnt > tcp_adv_max) {
                /* Limit reached, discard the packet. */
                NutNetBufFree(nb);
                tcp_adv_cnt -= nb->nb_dl.sz + sizeof(IPHDR) + sizeof (TCPHDR) + nb->nb_ap.sz;
            } else {
                nbq = sock->so_rx_nbq;
                nbqp = &sock->so_rx_nbq;
                while (nbq) {
                    thq = (TCPHDR *) (nbq->nb_tp.vp);
                    th_seq = ntohl(th->th_seq);
                    thq_seq = ntohl(thq->th_seq);
                    if (SeqIsAfter(thq_seq, th_seq)) {
                        *nbqp = nb;
                        nb->nb_next = nbq;
                        break;
                    }
                    if (th_seq == thq_seq) {
                        NutNetBufFree(nb);
                        sock->so_tx_flags |= SO_ACK | SO_FORCE;
                        NutTcpOutput(sock, 0, 0);
                        return;
                    }
                    nbqp = &nbq->nb_next;
                    nbq = nbq->nb_next;
                }
                if (nbq == 0) {
                    *nbqp = nb;
                    nb->nb_next = 0;
                }
            }
        } else
            NutNetBufFree(nb);

        sock->so_tx_flags |= SO_ACK | SO_FORCE;
        NutTcpOutput(sock, 0, 0);
        return;
    }

    /*
     * Acknowledge any sequence numbers not expected, 
     * even if they do not contain any data. Keepalive
     * packets contain a sequence number one less
     * than the next data expected and they do not 
     * contain any data.
     */
    if (ntohl(th->th_seq) != sock->so_rx_nxt) {
        sock->so_tx_flags |= SO_ACK | SO_FORCE;
        /* This seems to be unused. */
        sock->so_oos_drop++;
        NutNetBufFree(nb);
        NutTcpOutput(sock, 0, 0);
    }

    /*
     * The sequence number is exactly what we expected.
     */
    else if (nb->nb_ap.sz) {
        NutTcpProcessAppData(sock, nb);
        /*
         * Process segments we may have received in advance.
         */
        while ((nb = sock->so_rx_nbq) != 0) {
            th = (TCPHDR *) (nb->nb_tp.vp);
            if (SeqIsAfter(ntohl(th->th_seq), sock->so_rx_nxt))
                break;
            sock->so_rx_nbq = nb->nb_next;
            /* Update the heap space used by packets 
            ** received in advance. */
            tcp_adv_cnt -= nb->nb_dl.sz + sizeof(IPHDR) + sizeof (TCPHDR) + nb->nb_ap.sz;
            if (ntohl(th->th_seq) == sock->so_rx_nxt) {
                NutTcpProcessAppData(sock, nb);
                flags |= th->th_flags;
            } else
                NutNetBufFree(nb);
        }
        /* Wake up a thread waiting for data. */
        NutEventPost(&sock->so_rx_tq);
    } else {
        NutNetBufFree(nb);
        //sock->so_tx_flags |= SO_ACK | SO_FORCE;
        //NutTcpOutput(sock, 0, 0);
    }
    if (flags & TH_FIN) {
        //@@@printf ("[%04X]ESTABLISHED: going to CLOSE_WAIT\n", (u_short) sock);
        sock->so_rx_nxt++;
        NutTcpStateChange(sock, TCPS_CLOSE_WAIT);
    }
}

/*
 * \brief Process incoming segments in FIN-WAIT1 state.
 *
 * Waiting for a connection termination request
 * from the remote, or an acknowledgment of the
 * connection termination request previously sent.
 *
 * The application already closed the socket.
 *
 * \param sock Socket descriptor.
 * \param nb   Network buffer structure containing a TCP segment.
 *
 * \todo The out of sync case seems to be ignored. Anyway, do we
 *       really need to process application data in this state?
 */
static void NutTcpStateFinWait1(TCPSOCKET * sock, u_char flags, TCPHDR * th, NETBUF * nb)
{
    //@@@printf ("[%04X]FIN_WAIT_1: incomming segment, IP %04X\n", (u_short) sock, ntohs(((IPHDR*)nb->nb_nw.vp)->ip_id));
    if (flags & TH_RST) {
        NutNetBufFree(nb);
        NutTcpDestroySocket(sock);
        return;
    }

    /*
     * Reject SYNs.
     */
    if (flags & TH_SYN) {
        NutTcpReject(nb);
        return;
    }

    /*
     * Silently discard segments without ACK.
     */
    if ((flags & TH_ACK) == 0) {
        NutNetBufFree(nb);
        return;
    }

    //@@@if (flags & TH_FIN) printf ("[%04X]FIN_WAIT_1: received FIN\n", (u_short) sock);
    //@@@printf ("[%04X]FIN_WAIT_1: received ACK: %lu, unack: %lu, next: %lu\n", (u_short) sock, ntohl(th->th_ack), sock->so_tx_una, sock->so_tx_nxt);
    
    //@@@printf ("[%04X]FIN_WAIT_1:  pre processack, nbq: %04X\n", (u_short) sock, (u_short) sock->so_tx_nbq);
    NutTcpProcessAck(sock, th, nb->nb_ap.sz);
    //@@@printf ("[%04X]FIN_WAIT_1: post processack, nbq: %04X\n", (u_short) sock, (u_short) sock->so_tx_nbq);

    /*
     * All segments had been acknowledged, including our FIN.
     */
    if (sock->so_tx_nxt == sock->so_tx_una) {
        //@@@printf ("[%04X]FIN_WAIT_1: going to FIN_WAIT_2\n", (u_short) sock);
        NutTcpStateChange(sock, TCPS_FIN_WAIT_2);
    }

    /*
     * Process application data and release the network buffer.
     * Is this really required?
     */
    if (nb->nb_ap.sz) {
        NutTcpProcessAppData(sock, nb);
        /* Wake up a thread waiting for data. */
        NutEventPost(&sock->so_rx_tq);
    }
    else
        NutNetBufFree(nb);

    if (flags & TH_FIN) {
        sock->so_rx_nxt++;
        /* 
         * Our FIN has been acked.
         */
        sock->so_time_wait = 0;
        //@@@printf ("[%04X]FIN_WAIT_1: going to CLOSING\n", (u_short) sock);
        if (sock->so_state == TCPS_FIN_WAIT_2)
            NutTcpStateChange(sock, TCPS_TIME_WAIT);
        else
            NutTcpStateChange(sock, TCPS_CLOSING);
    }
}

/*
 * \brief Process incoming segments in FIN-WAIT2 state.
 *
 * Waiting for a connection termination request
 * from the remote.
 *
 * The application already closed the socket.
 *
 * \param sock Socket descriptor.
 * \param nb   Network buffer structure containing a TCP segment.
 *
 * \todo There's probably no need to process application data.
 */
static void NutTcpStateFinWait2(TCPSOCKET * sock, u_char flags, TCPHDR * th, NETBUF * nb)
{
    //@@@printf ("[%04X]FIN_WAIT_2: incomming segment, IP %04X\n", (u_short) sock, ntohs(((IPHDR*)nb->nb_nw.vp)->ip_id));
    if (flags & TH_RST) {
        NutNetBufFree(nb);
        NutTcpDestroySocket(sock);
        return;
    }

    /*
     * Reject SYNs.
     */
    if (flags & TH_SYN) {
        NutTcpReject(nb);
        return;
    }

    /*
     * Silently discard segments without ACK.
     */
    if ((flags & TH_ACK) == 0) {
        NutNetBufFree(nb);
        return;
    }

    //@@@printf ("[%04X]FIN_WAIT_2: received ACK: %lu, unack: %lu, next: %lu\n", (u_short) sock, ntohl(th->th_ack), sock->so_tx_una, sock->so_tx_nxt);
    /*
     * Process acknowledge and application data and release the 
     * network buffer.
     */
    NutTcpProcessAck(sock, th, nb->nb_ap.sz);

    //@@@if (sock->so_tx_nbq) printf ("[%04X]FIN_WAIT_2: xmit buffer not empty!", (u_short) sock);
    /* Do we really need this? */
    if (nb->nb_ap.sz) {
        NutTcpProcessAppData(sock, nb);
        /* Wake up a thread waiting for data. */
        NutEventPost(&sock->so_rx_tq);
    }
    else
        NutNetBufFree(nb);

    if (flags & TH_FIN) {
        sock->so_rx_nxt++;
        sock->so_time_wait = 0;
        //@@@printf ("[%04X]FIN_WAIT_2: going to TIME_WAIT\n", (u_short) sock);
        NutTcpStateChange(sock, TCPS_TIME_WAIT);
    }
}

/*
 * \brief
 * Process incoming segments in CLOSE-WAIT state.
 *
 * Waiting for a connection termination request
 * from the local application.
 *
 * \param sock Socket descriptor.
 * \param nb   Network buffer structure containing a TCP segment.
 */
static void NutTcpStateCloseWait(TCPSOCKET * sock, u_char flags, TCPHDR * th, NETBUF * nb)
{
    //@@@printf ("[%04X]CLOSE_WAIT: incomming segment, IP %04X\n", (u_short) sock, ((IPHDR*)nb->nb_nw.vp)->ip_id);
    if (flags & TH_RST) {
        NutNetBufFree(nb);
        NutTcpAbortSocket(sock, ECONNRESET);
        return;
    }

    /*
     * Reject SYNs.
     */
    if (flags & TH_SYN) {
        NutTcpReject(nb);
        return;
    }

    /*
     * Silently discard segments without ACK.
     */
    if ((flags & TH_ACK) == 0) {
        NutNetBufFree(nb);
        return;
    }

    NutTcpProcessAck(sock, th, nb->nb_ap.sz);

    NutNetBufFree(nb);
}

/*
 * \brief
 * Process incoming segments in CLOSING state.
 *
 * Waiting for a connection termination request
 * acknowledgment from the remote.
 *
 * The application already closed the socket.
 *
 * \param sock Socket descriptor.
 * \param nb   Network buffer structure containing a TCP segment.
 */
static void NutTcpStateClosing(TCPSOCKET * sock, u_char flags, TCPHDR * th, NETBUF * nb)
{
    //@@@printf ("[%04X]CLOSING: Incomming segment\n", (u_short) sock);
    if (flags & TH_RST) {
        NutNetBufFree(nb);
        NutTcpDestroySocket(sock);
        return;
    }

    /*
     * Reject SYNs.
     */
    if (flags & TH_SYN) {
        NutTcpReject(nb);
        return;
    }

    /*
     * Silently discard segments without ACK.
     */
    if ((flags & TH_ACK) == 0) {
        NutNetBufFree(nb);
        return;
    }

    NutTcpProcessAck(sock, th, nb->nb_ap.sz);

    /*
     * All segments had been acknowledged, including our FIN.
     */
    if (sock->so_tx_nxt == sock->so_tx_una) {
        sock->so_time_wait = 0;
        NutTcpStateChange(sock, TCPS_TIME_WAIT);
        //@@@printf ("[%04X]CLOSING: Going to TIME_WAIT\n", (u_short) sock);
    }
    //@@@else printf ("[%04X]CLOSING: NOT changing state\n", (u_short) sock);

    NutNetBufFree(nb);
}

/*!
 * \brief
 * Process incoming segment in LAST_ACK state.
 *
 * Waiting for an acknowledgment of the connection termination
 * request previously sent.
 *
 * The application already closed the socket.
 *
 * \param sock  Socket descriptor.
 * \param flags TCP flags of incoming segment.
 * \param th    TCP header of incoming segment.
 * \param nb    Network buffer structure containing a TCP segment.
 */
static void NutTcpStateLastAck(TCPSOCKET * sock, u_char flags, TCPHDR * th, NETBUF * nb)
{
    //@@@printf ("[%04X]LAST_ACK: incomming segment, IP %04X\n", (u_short) sock, ((IPHDR*)nb->nb_nw.vp)->ip_id);
    if (flags & TH_RST) {
        NutNetBufFree(nb);
        NutTcpDestroySocket(sock);
        return;
    }

    /*
     * Reject SYNs.
     */
    if (flags & TH_SYN) {
        NutTcpReject(nb);
        return;
    }

    /*
     * Silently discard segments without ACK.
     */
    if ((flags & TH_ACK) == 0) {
        NutNetBufFree(nb);
        return;
    }

    NutTcpProcessAck(sock, th, nb->nb_ap.sz);
    NutNetBufFree(nb);

    if (sock->so_tx_nxt == sock->so_tx_una) 
        NutTcpDestroySocket(sock);
    //@@@else printf ("[%04X]LAST_ACK: no destroy sock\n", (u_short) sock);
}

/*!
 * \brief Process incoming TCP segments.
 *
 * Processing is based on the current state of the socket connection.
 *
 * \param sock Socket descriptor. This pointer must have been 
 *             retrieved by calling NutTcpCreateSocket().
 * \param nb   Network buffer structure containing a TCP segment.
 *             Will be released within this routine.
 */
static void NutTcpStateProcess(TCPSOCKET * sock, NETBUF * nb)
{
    u_long tx_win;
    u_long tx_una;
    TCPHDR *th = (TCPHDR *) nb->nb_tp.vp;
    u_char flags = th->th_flags;

#ifdef NUTDEBUG
    if (__tcp_trf) {
        fprintf(__tcp_trs, " %04x-", (u_int) sock);
        NutDumpSockState(__tcp_trs, sock->so_state, "[", ">]");
    }
#endif
    switch (sock->so_state) {
        /* Handle the most common case first. */
    case TCPS_ESTABLISHED:
        tx_win = sock->so_tx_win;
        tx_una = sock->so_tx_una;
        NutTcpStateEstablished(sock, flags, th, nb);
        /* Wake up all threads waiting for transmit, if something interesting happened. */
        if(sock->so_state != TCPS_ESTABLISHED || /* Status changed. */
           sock->so_tx_win > tx_win ||           /* Windows changed. */
           sock->so_tx_una != tx_una) {          /* Unacknowledged data changed. */
            NutEventBroadcast(&sock->so_tx_tq);
        }
        break;
    case TCPS_LISTEN:
        NutTcpStateListen(sock, flags, th, nb);
        break;
    case TCPS_SYN_SENT:
        NutTcpStateSynSent(sock, flags, th, nb);
        break;
    case TCPS_SYN_RECEIVED:
        NutTcpStateSynReceived(sock, flags, th, nb);
        break;
    case TCPS_FIN_WAIT_1:
        NutTcpStateFinWait1(sock, flags, th, nb);
        break;
    case TCPS_FIN_WAIT_2:
        NutTcpStateFinWait2(sock, flags, th, nb);
        break;
    case TCPS_CLOSE_WAIT:
        NutTcpStateCloseWait(sock, flags, th, nb);
        break;
    case TCPS_CLOSING:
        NutTcpStateClosing(sock, flags, th, nb);
        break;
    case TCPS_LAST_ACK:
        NutTcpStateLastAck(sock, flags, th, nb);
        break;
    case TCPS_TIME_WAIT:
        /*
         * Ignore everything while in TIME_WAIT state.
         */
        NutNetBufFree(nb);
        break;
    case TCPS_CLOSED:
        /*
         * Reject everything while in CLOSED state.
         */
        NutTcpReject(nb);
        break;
    default:
        NutNetBufFree(nb);
        break;
    }
}

/*! \fn NutTcpSm(void *arg)
 * \brief TCP state machine thread.
 *
 * The TCP state machine serves two purposes: It processes incoming TCP
 * segments and handles TCP timers.
 */
THREAD(NutTcpSm, arg)
{
    NETBUF *nb;
    NETBUF *nbx;
    TCPHDR *th;
    IPHDR *ih;
    TCPSOCKET *sock;
    u_char tac = 0;

    /*
     * It won't help giving us a higher priority than the application
     * code. We depend on the speed of the reading application.
     */
    NutThreadSetPriority(NUT_THREAD_TCPSM_PRIORITY);
    
    for (;;) {
        if (++tac > 3 || NutEventWait(&tcp_in_rdy, 200)) {
            tac = 0;
            for (sock = tcpSocketList; sock; sock = sock->so_next) {

                /*
                 * Send late acks.
                 */
                if (sock->so_tx_flags & SO_ACK) {
                    sock->so_tx_flags |= SO_FORCE;
                    NutTcpOutput(sock, 0, 0);
                }

                /*
                 * Process retransmit timer.
                 */
                if (sock->so_tx_nbq && sock->so_retran_time) {
                    if ((u_short)NutGetMillis() - (sock->so_retran_time & ~1) >= sock->so_rtto) {
                        NutTcpStateRetranTimeout(sock);
                    }
                }

                /*
                 * Destroy sockets after timeout in TIMEWAIT state.
                 */
                if (sock->so_state == TCPS_TIME_WAIT || sock->so_state == TCPS_FIN_WAIT_2) {
                    if (sock->so_time_wait++ >= 9) {
                        NutTcpDestroySocket(sock);
                        break;
                    }
                }

                /*
                 * Recover from SYN flood attacks.
                 */
                else if (sock->so_state == TCPS_SYN_RECEIVED) {
                    if (sock->so_time_wait++ >= 45) {
                        sock->so_state = TCPS_LISTEN;
                        sock->so_time_wait = 0;
                    }
                }
            }
        } else {
            nb = tcp_in_nbq;
            tcp_in_nbq = 0;
            tcp_in_cnt = 0;
            while (nb) {
                ih = (IPHDR *) nb->nb_nw.vp;
                th = (TCPHDR *) nb->nb_tp.vp;
                sock = NutTcpFindSocket(th->th_dport, th->th_sport, ih->ip_src);
#ifdef NUTDEBUG
                if (__tcp_trf)
                    NutDumpTcpHeader(__tcp_trs, " IN", sock, nb);
#endif
                nbx = nb->nb_next;
                if (sock) {
                    NutTcpInputOptions(sock, nb);
                    NutTcpStateProcess(sock, nb);
                }

                /*
                 * Reject the segment, if no matching socket was found.
                 */
                else
                    NutTcpReject(nb);
                nb = nbx;
            }
        }
    }
}

/*!
 * \brief Process incoming TCP segments.
 *
 * All incoming TCP packets are passed to this routine. They will
 * be added to a global queue and processed by the TCP state
 * machine, which is running on a separate thread.
 *
 * \note This routine is called by the IP layer on incoming 
 *       TCP segments. Applications typically do not call 
 *       this function.
 */
void NutTcpStateMachine(NETBUF * nb)
{
    NETBUF *nbp;
    u_short size;

    nb->nb_next = 0;

    /*
     * Incoming TCP segments are rejected and released if no TCP
     * sockets have been opened. Not doing so would add them
     * to the queue and never release the NETBUF. Thanks to
     * Ralph Mason for this fix.
     */
    if (tcpThread == 0) {
        NutTcpReject(nb);
        return;
    }

    if ((nbp = tcp_in_nbq) == 0) {
        tcp_in_nbq = nb;
        NutEventPost(&tcp_in_rdy);
    } else {
        size = nb->nb_nw.sz + nb->nb_tp.sz + nb->nb_ap.sz;
        if (tcp_in_cnt + size + 2048 < NutHeapAvailable()) {
            tcp_in_cnt += size;
            while (nbp->nb_next)
                nbp = nbp->nb_next;
            nbp->nb_next = nb;
            NutEventPost(&tcp_in_rdy);
        } else
            NutNetBufFree(nb);
    }
}

/*!
 * \brief Start TCP state machine.
 *
 * The socket interface will automatically call this routine as
 * soon as the first socket is created.
 *
 * \return 0 on success, -1 otherwise.
 */
int NutTcpInitStateMachine(void)
{
    if (tcpThread == 0 && (tcpThread = NutThreadCreate("tcpsm", NutTcpSm, NULL, NUT_THREAD_TCPSM_STACK)) == 0)
        return -1;
    return 0;
}

/*!
 * \brief Closes socket with error.
 *
 * Aborts any socket activity and sets last error.
 *
 * \param sock  Socket descriptor.
 * \param last_error Error number to report
 *
 * \note This routine is called internally by Nut/Net.
 *       Applications typically do not call this function.
 *
 * \return 0 on success, -1 otherwise.
 */
int NutTcpAbortSocket(TCPSOCKET * sock, u_short last_error)
{
    sock->so_last_error = last_error;
    sock->so_retran_time = 0;
    sock->so_time_wait = 0;
    /*
     * If NutTcpCloseSocket was already called, we have to change
     * to TCPS_TIME_WAIT state, otherwise the socket will not be destroyed.
     * For the other cases just go to TCPS_CLOSED.
     */
    if (sock->so_state >= TCPS_FIN_WAIT_1)      /* FIN_WAIT_1, FIN_WAIT_2, CLOSING, LAST_ACK, TIME_WAIT */
        sock->so_state = TCPS_TIME_WAIT;
    else
        sock->so_state = TCPS_CLOSED;
    NutTcpDiscardBuffers(sock);
    NutEventBroadcast(&sock->so_rx_tq);
    NutEventBroadcast(&sock->so_tx_tq);
    NutEventBroadcast(&sock->so_pc_tq);
    NutEventBroadcast(&sock->so_ac_tq);
    return 0;
}

#endif

tcpsock.c  。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

/******************************************************************************
 *                                                                            *
 *                         M O D U L E   D E F I N E                          *
 *                                                                            *
 ******************************************************************************/

#define TCPSOCK_C

/******************************************************************************
 *                                                                            *
 *        C O M P I L E R   D E F I N E D   I N C L U D E   F I L E S         *
 *                                                                            *
 ******************************************************************************/

#include <string.h>
#include <stdio.h>

/******************************************************************************
 *                                                                            *
 *            U S E R   D E F I N E D   I N C L U D E   F I L E S             *
 *                                                                            *
 ******************************************************************************/

#include "Common.h"
#include "XCore.h"
#include "XNutOS.h"
#include "XLib.h"

#include "errno.h"
#include "route.h"
#include "in.h"
#include "ip.h"
#include "icmp.h"
#include "ip_icmp.h"
#include "ipcsum.h"
#include "socket.h"
#include "tcp.h"

#ifdef NUTDEBUG
#include "netdebug.h"
#endif

#if defined(NUTNET)

/******************************************************************************
 *                                                                            *
 *                         L O C A L   D E F I N E S                          *
 *                                                                            *
 ******************************************************************************/

#define TICK_RATE   1

/******************************************************************************
 *                                                                            *
 *                        L O C A L   T Y P E D E F S                         *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *             L O C A L   F U N C T I O N   P R O T O T Y P E S              *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *    L O C A L   I N I T I A L I Z E D   D A T A   D E F I N I T I O N S     *
 *                                                                            *
 ******************************************************************************/

TCPSOCKET *tcpSocketList = 0;   /*!< Global linked list of all TCP sockets. */

//static volatile u_short last_local_port = 4096; /* Unassigned local port. */
static u_short last_local_port = 4096; /* Unassigned local port. */

static u_char tcpStateRunning = 0;

/******************************************************************************
 *                                                                            *
 *    L O C A L   U N I T I A L I Z E D   D A T A   D E F I N I T I O N S     *
 *                                                                            *
 ******************************************************************************/


void NutTcpDiscardBuffers(TCPSOCKET * sock)
{
    NETBUF *nb;
    while ((nb = sock->so_rx_buf) != 0) {
        sock->so_rx_buf = nb->nb_next;
        NutNetBufFree(nb);
    }
    while ((nb = sock->so_tx_nbq) != 0) {
        sock->so_tx_nbq = nb->nb_next;
        NutNetBufFree(nb);
    }
    while ((nb = sock->so_rx_nbq) != 0) {
        sock->so_rx_nbq = nb->nb_next;
        NutNetBufFree(nb);
    }
}


/*!
 * \brief Destroy a previously allocated socket.
 *
 * Remove socket from the socket list and release occupied memory.
 *
 * Applications must not call this function. It is automatically called 
 * by a timer after the socket has been closed by NutTcpCloseSocket().
 *
 * \param sock Socket descriptor. This pointer must have been 
 *             retrieved by calling NutTcpCreateSocket().
 */
void NutTcpDestroySocket(TCPSOCKET * sock)
{
    TCPSOCKET *sp;
    TCPSOCKET *volatile *spp;
    
    //@@@printf ("[%04X] Calling destroy.\n", (u_short) sock);

    /*
     * Remove socket from the list.
     */
    sp = tcpSocketList;
    spp = &tcpSocketList;
    while (sp) {
        if (sp == sock) {
            *spp = sp->so_next;
            break;
        }
        spp = &sp->so_next;
        sp = sp->so_next;
    }

    /*
     * Free all memory occupied by the socket.
     */
    if (sp) {
        NutTcpDiscardBuffers(sock);
        if (sock->so_devocnt)
        {
            NutHeapFree(sock->so_devobuf);
            sock->so_devocnt = 0;
        }
        memset(sock, 0, sizeof(TCPSOCKET));
        NutHeapFree(sock);
    }
}

/*!
 * \brief Find a matching socket.
 *
 * Loop through all sockets and find a matching connection (prefered) 
 * or a listening socket.
 *
 * Applications typically do not call this function.
 *
 * \param lport Local port number.
 * \param rport Remote port number.
 * \param raddr Remote IP address in network byte order.
 *
 * \return Socket descriptor.
 */
TCPSOCKET *NutTcpFindSocket(u_short lport, u_short rport, u_long raddr)
{
    TCPSOCKET *sp;
    TCPSOCKET *sock = 0;

    /*
     * Try to find an exact match for the remote
     * address and port first.
     */
    for (sp = tcpSocketList; sp; sp = sp->so_next) {
        if (sp->so_local_port == lport) {
            if (sp->so_remote_addr == raddr && sp->so_remote_port == rport && sp->so_state != TCPS_CLOSED) {
                sock = sp;
                break;
            }
        }
    }

    /*
     * If no exact match exists, try a listening socket.
     * This part had been totally wrong, because it
     * didn't check the local port number and accepted
     * incoming requests on any port. Thanks to
     * Alejandro Lopez, who pointed this out.
     */
    if (sock == 0) {
        for (sp = tcpSocketList; sp; sp = sp->so_next) {
            if (sp->so_state == TCPS_LISTEN && sp->so_local_port == lport) {
                sock = sp;
                break;
            }
        }
    }

    return sock;
}


/*!
 * \brief Create a TCP socket.
 *
 * Allocates a TCPSOCKET structure from heap memory, initializes 
 * it and returns a pointer to that structure.
 *
 * The very first call will also start the TCP state machine, 
 * which is running in a separate thread.
 *
 * \return Socket descriptor of the newly created TCP socket or
 *         0 if there is not enough memory left.
 */
TCPSOCKET *NutTcpCreateSocket(void)
{
    TCPSOCKET *sock = 0;

    if (tcpStateRunning || (tcpStateRunning = (NutTcpInitStateMachine() == 0))) {

        if ((sock = NutHeapAllocClear(sizeof(TCPSOCKET))) != 0) {
            sock->so_state = TCPS_CLOSED;

            /*
             * Initialize the virtual device interface.
             */
            sock->so_devtype = IFTYP_TCPSOCK;
            sock->so_devread = NutTcpDeviceRead;
            sock->so_devwrite = NutTcpDeviceWrite;
            sock->so_devioctl = NutTcpDeviceIOCtl;

            sock->so_tx_isn = NutGetTickCount();  /* Generate the ISN from the nut_ticks counter */
            sock->so_tx_una = sock->so_tx_isn;
            sock->so_tx_nxt = sock->so_tx_isn;
            sock->so_rx_bsz = sock->so_rx_win = TCP_WINSIZE;

            sock->so_mss = TCP_MSS;
            sock->so_rtto = 1000; /* Initial retransmission time out */

            sock->so_next = tcpSocketList;

            sock->so_devobsz = TCP_MSS; /* Default output buffer size is TCP_MSS bytes */

            tcpSocketList = sock;
        }
    }
    return sock;
}

/*!
 * \brief Set value of a TCP socket option.
 *
 * The following values can be set:
 *
 * - #TCP_MAXSEG  Maximum segment size (#u_short). Can only be set if
                  socket is not yet connected.
 * - #SO_SNDTIMEO Socket send timeout (#u_long).
 * - #SO_RCVTIMEO Socket receive timeout (#u_long).
 * - #SO_SNDBUF   Socket output buffer size (#u_short).
 *
 * \param sock    Socket descriptor. This pointer must have been 
 *                retrieved by calling NutTcpCreateSocket().
 * \param optname Option to set.
 * \param optval  Pointer to the value.
 * \param optlen  Length of the value.
 * \return 0 on success, -1 otherwise. The specific error code
 *         can be retrieved by calling NutTcpError().
 */
int NutTcpSetSockOpt(TCPSOCKET * sock, int optname, CONST void *optval, int optlen)
{
    int rc = -1;

    if (sock == 0)
        return -1;
    switch (optname) {

    case TCP_MAXSEG:
        if (optval == 0 || optlen != sizeof(u_short))
            sock->so_last_error = EINVAL;
        else if (sock->so_state != TCPS_CLOSED) 
            sock->so_last_error = EISCONN;
        else {
            sock->so_mss = *((u_short *) optval);
            rc = 0;
        }
        break;

    case SO_RCVBUF:
        if (optval == 0 || optlen != sizeof(u_short))
            sock->so_last_error = EINVAL;
        else {
            sock->so_rx_bsz = *((u_short *) optval);
            sock->so_rx_win = sock->so_rx_bsz;
            rc = 0;
        }
        break;

    case SO_SNDTIMEO:
        if (optval == 0 || optlen != sizeof(u_long))
            sock->so_last_error = EINVAL;
        else {
            sock->so_write_to = *((u_long *) optval);
            rc = 0;
        }
        break;

    case SO_RCVTIMEO:
        if (optval == 0 || optlen != sizeof(u_long))
            sock->so_last_error = EINVAL;
        else {
            sock->so_read_to = *((u_long *) optval);
            rc = 0;
        }
        break;

    case SO_SNDBUF:
        if (optval == 0 || optlen != sizeof(u_short))
            sock->so_last_error = EINVAL;
        else {
            NutTcpDeviceWrite(sock, 0, 0);
            sock->so_devobsz = *((u_short *) optval);
            rc = 0;
        }
        break;

    default:
        sock->so_last_error = ENOPROTOOPT;
        break;
    }
    return rc;
}

/*!
 * \brief Get a TCP socket option value.
 *
 * The following values can be set:
 *
 * - #TCP_MAXSEG  Maximum segment size (#u_short).
 * - #SO_SNDTIMEO Socket send timeout (#u_long).
 * - #SO_RCVTIMEO Socket receive timeout (#u_long).
 * - #SO_SNDBUF   Socket output buffer size (#u_short).
 *
 * \param sock    Socket descriptor. This pointer must have been 
 *                retrieved by calling NutTcpCreateSocket().
 * \param optname Option to get.
 * \param optval  Points to a buffer receiving the value.
 * \param optlen  Length of the value buffer.
 *
 * \return 0 on success, -1 otherwise. The specific error code
 *         can be retrieved by calling NutTcpError().
 */
int NutTcpGetSockOpt(TCPSOCKET * sock, int optname, void *optval, int optlen)
{
    int rc = -1;

    if (sock == 0)
        return -1;
    switch (optname) {

    case TCP_MAXSEG:
        if (optval == 0 || optlen != sizeof(u_short))
            sock->so_last_error = EINVAL;
        else {
            *((u_short *) optval) = sock->so_mss;
            rc = 0;
        }
        break;

    case SO_RCVBUF:
        if (optval == 0 || optlen != sizeof(u_short))
            sock->so_last_error = EINVAL;
        else {
            *((u_short *) optval) = sock->so_rx_bsz;
            rc = 0;
        }
        break;

    case SO_SNDTIMEO:
        if (optval == 0 || optlen != sizeof(u_long))
            sock->so_last_error = EINVAL;
        else {
            *((u_long *) optval) = sock->so_write_to;
            rc = 0;
        }
        break;

    case SO_RCVTIMEO:
        if (optval == 0 || optlen != sizeof(u_long))
            sock->so_last_error = EINVAL;
        else {
            *((u_long *) optval) = sock->so_read_to;
            rc = 0;
        }
        break;

    case SO_SNDBUF:
        if (optval == 0 || optlen != sizeof(u_short))
            sock->so_last_error = EINVAL;
        else {
            *((u_short *) optval) = sock->so_devobsz;
            rc = 0;
        }
        break;
    default:
        sock->so_last_error = ENOPROTOOPT;
        break;
    }
    return rc;
}

/*!
 * \brief Connect to a remote socket.
 *
 * This function tries to establish a connection to the specified
 * remote port of the specified remote server. The calling thread
 * will be suspended until a connection is successfully established 
 * or an error occurs.
 *
 * This function is typically used by TCP client applications.
 *
 * \param sock Socket descriptor. This pointer must have been 
 *             retrieved by calling NutTcpCreateSocket().
 * \param addr IP address of the host to connect (network byte order).
 * \param port Port number to connect (host byte order).
 *
 * \return 0 on success, -1 otherwise. The specific error code
 *         can be retrieved by calling NutTcpError().
 */
int NutTcpConnect(TCPSOCKET * sock, u_long addr, u_short port)
{
    TCPSOCKET *sp;
    NUTDEVICE *dev;

    if (sock == 0)
        return -1;
    /*
     * Despite RFC793 we do not allow a passive
     * open to become active.
     */
    if (sock->so_state == TCPS_LISTEN) {
        sock->so_last_error = EOPNOTSUPP;
        return -1;
    } else if (sock->so_state != TCPS_CLOSED) {
        sock->so_last_error = EISCONN;
        return -1;
    }

    /*
     * Find an unused local port.
     */
    do {
        if (++last_local_port == 0)
            last_local_port = 4096;

        sp = tcpSocketList;
        while (sp) {
            /* Thanks to Ralph Mason for fixing the byte order bug. */
            if (sp->so_local_port == htons(last_local_port))
                break;
            sp = sp->so_next;
        }
    } while (sp);

    /*
     * OK - we've got a new port. Now fill
     * remaining parts of the socket structure.
     */
    sock->so_local_port = htons(last_local_port);
    sock->so_remote_port = htons(port);
    sock->so_remote_addr = addr;

    /*
     * Get local address for this destination.
     */
    if ((dev = NutIpRouteQuery(addr, 0)) != 0) {
        IFNET *nif = dev->dev_icb;
        sock->so_local_addr = nif->if_local_ip;
    } else {
        sock->so_last_error = EHOSTUNREACH;
        return -1;
    }

    /*
     * Trigger active open event for the state machine.
     * This will suspend the thread until synchronized.
     */
    return NutTcpStateActiveOpenEvent(sock);
}

/*!
 * \brief Wait for incoming connect from a remote socket.
 *
 * The calling thread will be suspended until until an
 * incoming connection request is received.
 *
 * This function is typically used by TCP server applications.
 *
 * \param sock Socket descriptor. This pointer must have been 
 *             retrieved by calling NutTcpCreateSocket().
 * \param port Port number to listen to (host byte order).
 *
 * \return 0 on success, -1 otherwise. The specific error code
 *         can be retrieved by calling NutTcpError().
 */
int NutTcpAccept(TCPSOCKET * sock, u_short port)
{
    sock->so_local_port = htons(port);

    return NutTcpStatePassiveOpenEvent(sock);
}

/*!
 * \brief Send data on a connected TCP socket.
 *
 * \param sock Socket descriptor. This pointer must have been 
 *             retrieved by calling NutTcpCreateSocket(). In
 *             addition a connection must have been established
 *             by calling NutTcpConnect or NutTcpAccept.
 * \param data Pointer to a buffer containing the data to send.
 * \param len  Number of bytes to be sent.
 *
 * \return If successful, the number of bytes added to the socket transmit 
 *         buffer. This is limited to the maximum segment size of the 
 *         connection and thus may be less than the specified number of 
 *         bytes to send. The return value -1 indicates a fatal error.
 *         On time out, a value of 0 is returned.
 */
int NutTcpSend(TCPSOCKET * sock, CONST void *data, int len)
{
    u_short unacked;

    /*
     * Check parameters.
     */
    NutThreadYield();
    
    if (sock == 0)
        return -1;
    if (data == 0 || len == 0)
        return 0;

    /*
     * Limit the transmission size to our maximum segment size.
     */
    if (len > sock->so_mss)
        len = sock->so_mss;

    for (;;) {
        /*
         * We can only send on an established connection.
         */
        if (sock->so_state != TCPS_ESTABLISHED) {
            sock->so_last_error = ENOTCONN;
            return -1;
        }

        /*
         * Limit the size of unacknowledged data to four full segments.
         * Also wait for peer's window open wide enough to take all our 
         * data. This also avoids silly window syndrome on our side.
         */
        unacked = sock->so_tx_nxt - sock->so_tx_una;
        if ((unacked >> 2) < sock->so_mss && len <= sock->so_tx_win - unacked) {
            break;
        }
        if (NutEventWait(&sock->so_tx_tq, sock->so_write_to)) {
            return 0;
        }
    }
    /*
     * The segment will be automatically retransmitted if not 
     * acknowledged in time. If this returns an error, it's a 
     * fatal one.
     */
    sock->so_tx_flags |= SO_ACK;
    if (NutTcpOutput(sock, data, len))
        return -1;
    return len;
}

/*!
 * \brief Receive data on a connected TCP socket.
 *
 * \param sock Socket descriptor. This pointer must have been 
 *             retrieved by calling NutTcpCreateSocket(). In
 *             addition a connection must have been established
 *             by calling NutTcpConnect or NutTcpAccept.
 * \param data Pointer to the buffer that receives the data.
 * \param size Size of the buffer.
 *
 * \return If successful, the number of received data bytes
 *         is returned. This may be less than the specified
 *         size of the buffer. The return value 0 indicates
 *         a timeout, while -1 is returned in case of an error 
 *         or broken connection. Call NutTcpError() to determine
 *         the specific error code.
 */
int NutTcpReceive(TCPSOCKET * sock, void *data, int size)
{
    int i;

    NutThreadYield();
    /*
     * Check parameters.
     */
    if (sock == 0)
        return -1;
    if (sock->so_state != TCPS_ESTABLISHED && sock->so_state != TCPS_CLOSE_WAIT) {
        sock->so_last_error = ENOTCONN;
        return -1;
    }
    if (data == 0 || size == 0)
        return 0;

    /*
     * Wait until any data arrived, a timeout occurs
     * or the connection terminates.
     */
    while (sock->so_rx_cnt - sock->so_rd_cnt == 0) {
        if (sock->so_state != TCPS_ESTABLISHED) {
            sock->so_last_error = ENOTCONN;
            return -1;
        }
        if (NutEventWait(&sock->so_rx_tq, sock->so_read_to))
            return 0;
    }

    if (size > sock->so_rx_cnt - sock->so_rd_cnt)
        size = sock->so_rx_cnt - sock->so_rd_cnt;
    if (size) {
        NETBUF *nb;
        u_short rd_cnt;         /* Bytes read from NETBUF. */
        u_short nb_cnt;         /* Bytes left in NETBUF. */
        u_short ab_cnt;         /* Total bytes in app buffer. */
        u_short mv_cnt;         /* Bytes to move to app buffer. */

        rd_cnt = sock->so_rd_cnt;

        ab_cnt = 0;
        while (ab_cnt < size) {
            nb = sock->so_rx_buf;
            nb_cnt = nb->nb_ap.sz - rd_cnt;
            mv_cnt = size - ab_cnt;
            if (mv_cnt > nb_cnt)
                mv_cnt = nb_cnt;
            memcpy((char *) data + ab_cnt, (char *) (nb->nb_ap.vp) + rd_cnt, mv_cnt);
            ab_cnt += mv_cnt;
            rd_cnt += mv_cnt;
            if (mv_cnt >= nb_cnt) {
                sock->so_rx_buf = nb->nb_next;
                sock->so_rx_cnt -= rd_cnt;
                NutNetBufFree(nb);
                sock->so_rx_apc--;
                nb = sock->so_rx_buf;
                rd_cnt = 0;
            }
        }
        sock->so_rd_cnt = rd_cnt;

        /*
         * Update our receive window.
         */
        if (sock->so_state == TCPS_ESTABLISHED) {
            i = sock->so_rx_win;
            if ((i += size) > sock->so_rx_bsz)
                i = sock->so_rx_bsz;

            if (sock->so_rx_win <= sock->so_mss && i > sock->so_mss) {
                sock->so_rx_win = i;
                NutTcpStateWindowEvent(sock);
            } else {
                sock->so_rx_win = i;
            }
        }
    }
    return size;
}

/*!
 * \brief Close TCP socket.
 *
 * Note, that the socket may not be immediately destroyed
 * after calling this function. However, the application 
 * must not use the socket after this call.
 *
 * \param sock Socket descriptor. This pointer must have been 
 *             retrieved by calling NutTcpCreateSocket().
 *
 * \return 0 on success, -1 otherwise.
 */
int NutTcpCloseSocket(TCPSOCKET * sock)
{
    /* Flush buffer first */
    //@@@printf ("[%04X] Calling close\n", (u_short) sock);
    NutTcpDeviceWrite(sock, 0, 0);
    return NutTcpStateCloseEvent(sock);
}

/*!
 * \brief Return specific code of the last error.
 *
 * Possible error codes (net/errno.h) are:
 *
 * - EWOULDBLOCK: Operation would block
 * - EINPROGRESS: Operation now in progress
 * - EALREADY: Operation already in progress
 * - ENOTSOCK: Socket operation on non-socket
 * - EDESTADDRREQ: Destination address required
 * - EMSGSIZE: Message too long
 * - EPROTOTYPE: Protocol wrong type for socket
 * - ENOPROTOOPT: Protocol not available
 * - EPROTONOSUPPORT: Protocol not supported
 * - ESOCKTNOSUPPORT: Socket type not supported
 * - EOPNOTSUPP: Operation not supported on socket
 * - EPFNOSUPPORT: Protocol family not supported
 * - EAFNOSUPPORT: Address family not supported by protocol family
 * - EADDRINUSE: Address already in use
 * - EADDRNOTAVAIL: Can't assign requested address
 * - ENETDOWN: Network is down
 * - ENETUNREACH: Network is unreachable
 * - ENETRESET: Network dropped connection on reset
 * - ECONNABORTED: Software caused connection abort
 * - ECONNRESET: Connection reset by peer
 * - ENOBUFS: No buffer space available
 * - EISCONN: Socket is already connected
 * - ENOTCONN: Socket is not connected
 * - ESHUTDOWN: Can't send after socket shutdown
 * - ETOOMANYREFS: Too many references: can't splice
 * - ETIMEDOUT: Connection timed out
 * - ECONNREFUSED: Connection refused
 * - ELOOP: Too many levels of symbolic links
 * - ENAMETOOLONG: File name too long
 * - EHOSTDOWN: Host is down
 * - EHOSTUNREACH: No route to host
 * - ENOTEMPTY: Directory not empty
 *
 * \param sock Socket descriptor. This pointer must have been 
 *             retrieved by calling NutTcpCreateSocket().
 *
 * \note Applications must not call this function to retrieve the
 *       error code if NutTcpCloseSocket() or NutTcpDestroySocket()
 *       failed.
 *
 * \todo Not all error codes are properly set right now. Some socket
 *       functions return an error without setting an error code.
 */
int NutTcpError(TCPSOCKET * sock)
{
    if (sock == 0)
        return ENOTSOCK;
    return sock->so_last_error;
}

/*! 
 * \brief Read from virtual socket device.
 *
 * TCP sockets can be used like other Nut/OS devices. This routine
 * is part of the virtual socket device driver.
 *
 * This function is called by the low level input routines of the 
 * \ref xrCrtLowio "C runtime library", using the _NUTDEVICE::dev_read 
 * entry.
 *
 * \param sock   Socket descriptor. This pointer must have been 
 *               retrieved by calling NutTcpCreateSocket().
 * \param buffer Pointer to the buffer that receives the data.
 * \param size   Maximum number of bytes to read.
 *
 * \return The number of bytes read, which may be less than the number
 *         of bytes specified. A return value of -1 indicates an error,
 *         while zero is returned in case of a timeout.
 */
int NutTcpDeviceRead(TCPSOCKET * sock, void *buffer, int size)
{
    return NutTcpReceive(sock, buffer, size);
}

static int SendBuffer(TCPSOCKET * sock, CONST void *buffer, int size)
{
    int rc;
    int bite;

    for (rc = 0; rc < size; rc += bite) {
        if ((bite = NutTcpSend(sock, (u_char *) buffer + rc, size - rc)) <= 0) {
            return -1;
        }
    }
    return rc;
}

/*! 
 * \brief Write to a socket.
 *
 * TCP sockets can be used like other Nut/OS devices. This routine
 * is part of the virtual socket device driver.
 *
 * This function is called by the low level output routines of the 
 * \ref xrCrtLowio "C runtime library", using the 
 * \ref _NUTDEVICE::dev_write entry.
 *
 * In contrast to NutTcpSend() this routine provides some buffering.
 *
 * \param sock Socket descriptor. This pointer must have been 
 *             retrieved by calling NutTcpCreateSocket().
 * \param buf  Pointer to the data to be written.
 * \param size Number of bytes to write. If zero, then the output buffer 
 *             will be flushed.
 *
 * \return The number of bytes written. A return value of -1 indicates 
 *         an error.
 *
 */
int NutTcpDeviceWrite(TCPSOCKET * sock, CONST void *buf, int size)
{
    int rc;
    u_short sz;
    /* hack alert for ICCAVR */
    u_char *buffer = (u_char*) buf;

    /*
     * Check parameters.
     */
    if (sock == 0)
        return -1;
    if (sock->so_state != TCPS_ESTABLISHED) {
        sock->so_last_error = ENOTCONN;
        return -1;
    }

    /* Flush buffer? */
    if (size == 0) {
        if (sock->so_devocnt) {
            if (SendBuffer(sock, sock->so_devobuf, sock->so_devocnt) < 0) {
                NutHeapFree(sock->so_devobuf);
                sock->so_devocnt = 0;
                return -1;
            }
            NutHeapFree(sock->so_devobuf);
            sock->so_devocnt = 0;
        }
        return 0;
    }

    /* If we don't have a buffer so far... */
    if (sock->so_devocnt == 0) {
        /* If new data block is bigger or equal than buffer size
         * send first part of data to nic and store remaining
         * bytes in buffer
         */
        if ((u_short) size >= sock->so_devobsz) {
            rc = size % sock->so_devobsz;
            if (SendBuffer(sock, buffer, size - rc) < 0)
                return -1;
            buffer += size - rc;
        } else
            rc = size;

        /* If there are some remainings bytes, allocate buffer
         * and store them
         */
        if (rc) {
            if (!(sock->so_devobuf = NutHeapAlloc(sock->so_devobsz)))
                return -1;
            memcpy(sock->so_devobuf, buffer, rc);
            sock->so_devocnt = rc;
        }
        return size;
    }

    /* Check if new data fully fits in output buffer */
    if (sock->so_devocnt + size < sock->so_devobsz) {
        memcpy(sock->so_devobuf + sock->so_devocnt, buffer, size);
        sock->so_devocnt += size;
        return size;
    }

    /* Otherwise store first bytes of new data in buffer and flush
     * the buffer
     */
    sz = sock->so_devobsz - sock->so_devocnt;
    memcpy(sock->so_devobuf + sock->so_devocnt, buffer, sz);
    buffer += sz;
    if (SendBuffer(sock, sock->so_devobuf, sock->so_devobsz) < 0) {
        NutHeapFree(sock->so_devobuf);
        sock->so_devocnt = 0;
        return -1;
    }

    /* If remaining data is bigger or equal than buffer size
     * send first part of data to nic and later store remaining
     * bytes in buffer
     */
    sz = size - sz;
    if (sz >= sock->so_devobsz) {
        rc = size % sock->so_devobsz;
        if (SendBuffer(sock, buffer, sz - rc) < 0) {
            NutHeapFree(sock->so_devobuf);
            sock->so_devocnt = 0;
            return -1;
        }
        buffer += sz - rc;
    } else
        rc = sz;

    /* If there are some remainings bytes, store them in buffer
     */
    if (rc)
        memcpy(sock->so_devobuf, buffer, rc);
    else                        /* Otherwise free buffer */
        NutHeapFree(sock->so_devobuf);
    sock->so_devocnt = rc;

    return size;
}

/*! 
 * \brief Driver control function.
 *
 * Used by the virtual device driver to modify or query device specific 
 * settings.
 *
 * \param sock  Socket descriptor. This pointer must have been 
 *              retrieved by calling NutTcpCreateSocket().
 * \param cmd   Requested control function. May be set to one of the
 *              following constants:
 *              - \ref IOCTL_GETFILESIZE
 *              - \ref IOCTL_GETINBUFCOUNT
 *              - \ref IOCTL_GETOUTBUFCOUNT
 *
 * \param param Points to a buffer that contains any data required for
 *              the given control function or receives data from that
 *              function.
 * \return 0 on success, -1 otherwise.
 */
int NutTcpDeviceIOCtl(TCPSOCKET * sock, int cmd, void *param)
{
    u_long *lvp = (u_long *) param;
    int rc = 0;
    
    switch (cmd) {
    case IOCTL_GETFILESIZE:
    case IOCTL_GETINBUFCOUNT:
        *lvp = (sock->so_rx_cnt - sock->so_rd_cnt);
        break;
    case IOCTL_GETOUTBUFCOUNT:
        *lvp = (sock->so_devocnt);
        break;
    default:
        rc = -1;
    }
    
    return rc;    
}

#endif

tcputil.c  。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

/******************************************************************************
 *                                                                            *
 *                         M O D U L E   D E F I N E                          *
 *                                                                            *
 ******************************************************************************/

#define TCPUTIL_C

/******************************************************************************
 *                                                                            *
 *        C O M P I L E R   D E F I N E D   I N C L U D E   F I L E S         *
 *                                                                            *
 ******************************************************************************/

#include <stdio.h>

/******************************************************************************
 *                                                                            *
 *            U S E R   D E F I N E D   I N C L U D E   F I L E S             *
 *                                                                            *
 ******************************************************************************/

#include "Common.h"
#include "XCore.h"
#include "XNutOS.h"

#include "tcputil.h"

#if defined(NUTNET)

/******************************************************************************
 *                                                                            *
 *                         L O C A L   D E F I N E S                          *
 *                                                                            *
 ******************************************************************************/

/* Limit retransmission timeout to 200ms as lower and 20secs as upper boundary */
#ifndef TCP_RTTO_MIN
#define TCP_RTTO_MIN    200
#endif
#ifndef TCP_RTTO_MAX
#define TCP_RTTO_MAX    20000
#endif

#define min(a,b) ((a>b)?b:a)
#define max(a,b) ((a>b)?a:b)

/******************************************************************************
 *                                                                            *
 *                        L O C A L   T Y P E D E F S                         *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *             L O C A L   F U N C T I O N   P R O T O T Y P E S              *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *    L O C A L   I N I T I A L I Z E D   D A T A   D E F I N I T I O N S     *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *    L O C A L   U N I T I A L I Z E D   D A T A   D E F I N I T I O N S     *
 *                                                                            *
 ******************************************************************************/

/*
 * Calculate round trip time.
 */
void NutTcpCalcRtt(TCPSOCKET * sock)
{
    u_short delta;
    
    if (sock->so_retran_time == 0)
        return;
        
    delta = (u_short) NutGetMillis() - (sock->so_retran_time & ~1);
    
    /* According to RFC793 (or STD007), page 41, we use 0.8 for ALPHA and 2.0 for BETA. */
    sock->so_rtto = min (TCP_RTTO_MAX, max(TCP_RTTO_MIN, (delta * 4 + sock->so_rtto * 8) / 10));
    //@@@printf ("[%04X] new retran timeout: %u, delta: %u\n", (u_short) sock, sock->so_rtto, delta);
}

#endif

tcputil.h                     。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

#ifndef TCPUTIL_H

/******************************************************************************
 *                                                                            *
 *                         M O D U L E   D E F I N E                          *
 *                                                                            *
 ******************************************************************************/

#define TCPUTIL_H

/******************************************************************************
 *                                                                            *
 *        C O M P I L E R   D E F I N E D   I N C L U D E   F I L E S         *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *            U S E R   D E F I N E D   I N C L U D E   F I L E S             *
 *                                                                            *
 ******************************************************************************/

#include "XNutOS.h"

#include "sock_var.h"
#include "tcp_fsm.h"

#ifdef __cplusplus
extern "C" {            /* Assume C declarations for C++ */
#endif    /* __cplusplus */

/******************************************************************************
 *                                                                            *
 *                        G L O B A L   D E F I N E S                         *
 *                                                                            *
 ******************************************************************************/

/*! \brief Wraparound-safe TCP sequence number comparison, (low <= x <= high)
 *
 * Returns true if x is between low and high inclusive,
 * false otherwise.
 */
#define SeqIsBetween(x, low, high) \
  ((u_long)(x - low) <= (u_long)(high - low))

/*! \brief Wraparound-safe TCP sequence number comparison, (x > low)
 *
 * Returns true if number x comes after low.
 *
 * Values between low   ... low+1 - (1<<31) are in the past
 * Values between low+1 ... low   + (1<<31) are in the future
 */
#define SeqIsAfter(x, low) \
  ((long)(low - x) < 0)

/******************************************************************************
 *                                                                            *
 *                 S T R U C T U R E   D E F I N I T I O N S                  *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *    G L O B A L   V A R I A B L E S   -   N O   I N I T I A L I Z E R S     *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *       G L O B A L   V A R I A B L E S   -   I N I T I A L I Z E R S        *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *                   F U N C T I O N   P R O T O T Y P E S                    *
 *                                                                            *
 ******************************************************************************/

void NutTcpCalcRtt(TCPSOCKET * sock);

#ifdef __cplusplus
}                       /* End of extern "C" { */
#endif    /* __cplusplus */

#endif

udp.h                      。。。。。。。。。。。。。。。。。。。。。。。。。。。。

#ifndef UDP_H

/******************************************************************************
 *                                                                            *
 *                         M O D U L E   D E F I N E                          *
 *                                                                            *
 ******************************************************************************/

#define UDP_H

/******************************************************************************
 *                                                                            *
 *        C O M P I L E R   D E F I N E D   I N C L U D E   F I L E S         *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *            U S E R   D E F I N E D   I N C L U D E   F I L E S             *
 *                                                                            *
 ******************************************************************************/

#include "netbuf.h"

#ifdef __cplusplus
extern "C" {            /* Assume C declarations for C++ */
#endif    /* __cplusplus */

/******************************************************************************
 *                                                                            *
 *                        G L O B A L   D E F I N E S                         *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *                 S T R U C T U R E   D E F I N I T I O N S                  *
 *                                                                            *
 ******************************************************************************/

/*!
 * \typedef UDPHDR
 * \brief UDP protocol header type.
 */
typedef struct udphdr {
    u_short uh_sport;   /*!< \brief Source port */
    u_short uh_dport;   /*!< \brief Destination port */
    u_short uh_ulen;    /*!< \brief UDP length */
    u_short uh_sum;     /*!< \brief UDP checksum */
} UDPHDR;

/******************************************************************************
 *                                                                            *
 *    G L O B A L   V A R I A B L E S   -   N O   I N I T I A L I Z E R S     *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *       G L O B A L   V A R I A B L E S   -   I N I T I A L I Z E R S        *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *                   F U N C T I O N   P R O T O T Y P E S                    *
 *                                                                            *
 ******************************************************************************/


#ifdef __cplusplus
}                       /* End of extern "C" { */
#endif    /* __cplusplus */

#endif

udpin.c                            。。。。。。。。。。。。。。。。。。。。。。。。。。

/******************************************************************************
 *                                                                            *
 *                         M O D U L E   D E F I N E                          *
 *                                                                            *
 ******************************************************************************/

#define UDPIN_C

/******************************************************************************
 *                                                                            *
 *        C O M P I L E R   D E F I N E D   I N C L U D E   F I L E S         *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *            U S E R   D E F I N E D   I N C L U D E   F I L E S             *
 *                                                                            *
 ******************************************************************************/

#include "Common.h"
#include "XCore.h"
#include "XNutOS.h"

#include "udp.h"
#include "socket.h"
#include "ip_icmp.h"
#include "icmp.h"

#if defined(NUTNET)

/******************************************************************************
 *                                                                            *
 *                         L O C A L   D E F I N E S                          *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *                        L O C A L   T Y P E D E F S                         *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *             L O C A L   F U N C T I O N   P R O T O T Y P E S              *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *    L O C A L   I N I T I A L I Z E D   D A T A   D E F I N I T I O N S     *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *    L O C A L   U N I T I A L I Z E D   D A T A   D E F I N I T I O N S     *
 *                                                                            *
 ******************************************************************************/


/*!
 * \brief Handle incoming UDP packets.
 *
 * \note This routine is called by the IP layer on
 *       incoming UDP packets. Applications typically do
 *       not call this function.
 *
 * \param nb    Network buffer structure containing the UDP packet.
 */
int NutUdpInput(NUTDEVICE * dev, NETBUF * nb)
{
    UDPHDR *uh;
    UDPSOCKET *sock;

    uh = (UDPHDR *) nb->nb_tp.vp;
    /* Make sure that the datagram contains a full header. */
    if (uh == NULL || nb->nb_tp.sz < sizeof(UDPHDR)) {
        NutNetBufFree(nb);
        return 0;
    }

    nb->nb_ap.sz = nb->nb_tp.sz - sizeof(UDPHDR);
    nb->nb_tp.sz = sizeof(UDPHDR);
    if (nb->nb_ap.sz) {
        nb->nb_ap.vp = uh + 1;
    }

    /*
     * Find a port. If none exists and if this datagram hasn't been
     * broadcasted, return an ICMP unreachable.
     */
    if ((sock = NutUdpFindSocket(uh->uh_dport)) == 0) {
        if ((nb->nb_flags & NBAF_UNICAST) == 0 || 
            NutIcmpResponse(ICMP_UNREACH, ICMP_UNREACH_PORT, 0, nb) == 0) {
            NutNetBufFree(nb);
        }
        return 0;
    }

    /* if buffer size is defined, use packet queue */
    if (sock->so_rx_bsz) {
        /* New packet fits into the buffer? */
        if (sock->so_rx_cnt + nb->nb_ap.sz > sock->so_rx_bsz) {
            /* No, so discard it */
            NutNetBufFree(nb);
            return 0;
        } else {
            /* if a first packet is already in the queue, find the end
             * and add the new packet */
            if (sock->so_rx_nb) {
                NETBUF *snb;
                for (snb = sock->so_rx_nb; snb->nb_next != 0; snb = snb->nb_next);
                snb->nb_next = nb;
            } else
                sock->so_rx_nb = nb;

            /* increment input buffer count */
            sock->so_rx_cnt += nb->nb_ap.sz;
        };
    } else {                    /* no packet queue */
        /* if a packet is still buffered, discard it */
        if (sock->so_rx_nb) {
            NutNetBufFree(sock->so_rx_nb);
        }
        sock->so_rx_nb = nb;
        sock->so_rx_cnt = nb->nb_ap.sz; /* set input buffer count to size of new packet */
    };

    /* post the event only, if one thread is waiting */
    if (sock->so_rx_rdy)
        NutEventPost(&sock->so_rx_rdy);
    return 0;
}

#endif

udpout.c                          。。。。。。。。。。。。。。。。。。。。。。。

/******************************************************************************
 *                                                                            *
 *                         M O D U L E   D E F I N E                          *
 *                                                                            *
 ******************************************************************************/

#define UDPOUT_C

/******************************************************************************
 *                                                                            *
 *        C O M P I L E R   D E F I N E D   I N C L U D E   F I L E S         *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *            U S E R   D E F I N E D   I N C L U D E   F I L E S             *
 *                                                                            *
 ******************************************************************************/

#include "Common.h"
#include "XCore.h"

#include "in.h"
#include "ip.h"
#include "udp.h"
#include "ipcsum.h"
#include "route.h"
#include "socket.h"

#if defined(NUTNET)

/******************************************************************************
 *                                                                            *
 *                         L O C A L   D E F I N E S                          *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *                        L O C A L   T Y P E D E F S                         *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *             L O C A L   F U N C T I O N   P R O T O T Y P E S              *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *    L O C A L   I N I T I A L I Z E D   D A T A   D E F I N I T I O N S     *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *    L O C A L   U N I T I A L I Z E D   D A T A   D E F I N I T I O N S     *
 *                                                                            *
 ******************************************************************************/


/*!
 * \brief Send a UDP packet.
 *
 * \param sock  Socket descriptor. This pointer must have been 
 *              retrieved by calling NutUdpCreateSocket().
 * \param daddr IP address of the remote host in network byte order.
 * \param port  Remote port number in host byte order.
 * \param nb    Network buffer structure containing the datagram. 
 *              This buffer will be released if the function returns
 *              an error.
 *
 * \note Applications typically do not call this function but 
 *       use the UDP socket interface.
 *
 * \return 0 on success, -1 otherwise.
 */
int NutUdpOutput(UDPSOCKET * sock, u_long daddr, u_short port, NETBUF * nb)
{
    u_long saddr;
    u_long csum;
    UDPHDR *uh;
    NUTDEVICE *dev;
    IFNET *nif;

    if ((nb = NutNetBufAlloc(nb, NBAF_TRANSPORT, sizeof(UDPHDR))) == 0)
        return -1;

    uh = nb->nb_tp.vp;
    uh->uh_sport = sock->so_local_port;
    uh->uh_dport = htons(port);
    uh->uh_ulen = htons((u_short)(nb->nb_tp.sz + nb->nb_ap.sz));

    /*
     * Get local address for this destination.
     */
    if ((dev = NutIpRouteQuery(daddr, &saddr)) != 0) {
        nif = dev->dev_icb;
        saddr = nif->if_local_ip;
    } else
        saddr = 0;

    uh->uh_sum = 0;
    csum = NutIpPseudoChkSumPartial(saddr, daddr, IPPROTO_UDP, uh->uh_ulen);
    csum = NutIpChkSumPartial(csum, uh, sizeof(UDPHDR));
    uh->uh_sum = NutIpChkSum(csum, nb->nb_ap.vp, nb->nb_ap.sz);

    return NutIpOutput(IPPROTO_UDP, daddr, nb);
}

#endif

udpsock.c                   。。。。。。。。。。。。。。。。。。。。。。。。

/******************************************************************************
 *                                                                            *
 *                         M O D U L E   D E F I N E                          *
 *                                                                            *
 ******************************************************************************/

#define UDPSOCKET_C

/******************************************************************************
 *                                                                            *
 *        C O M P I L E R   D E F I N E D   I N C L U D E   F I L E S         *
 *                                                                            *
 ******************************************************************************/

#include <string.h>

/******************************************************************************
 *                                                                            *
 *            U S E R   D E F I N E D   I N C L U D E   F I L E S             *
 *                                                                            *
 ******************************************************************************/

#include "Common.h"
#include "XCore.h"
#include "XNutOS.h"

#include "ip.h"
#include "udp.h"
#include "in.h"
#include "socket.h"
#include "errno.h"

#if defined(NUTNET)

/******************************************************************************
 *                                                                            *
 *                         L O C A L   D E F I N E S                          *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *                        L O C A L   T Y P E D E F S                         *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *             L O C A L   F U N C T I O N   P R O T O T Y P E S              *
 *                                                                            *
 ******************************************************************************/

/* None */

/******************************************************************************
 *                                                                            *
 *    L O C A L   I N I T I A L I Z E D   D A T A   D E F I N I T I O N S     *
 *                                                                            *
 ******************************************************************************/

static u_short last_local_port = 4096;  /* Unassigned local port. */

/******************************************************************************
 *                                                                            *
 *    L O C A L   U N I T I A L I Z E D   D A T A   D E F I N I T I O N S     *
 *                                                                            *
 ******************************************************************************/

UDPSOCKET *udpSocketList;       /*!< Global linked list of all UDP sockets. */

/*!
 * \brief Create a UDP socket.
 *
 * \param  port Server applications provide the local port number
 *              with this parameter. Client applications should
 *              pass zero.
 *
 * \return Socket descriptor of the newly created UDP socket or
 *         0 if there is not enough memory left.
 *
 */
UDPSOCKET *NutUdpCreateSocket(u_short port)
{
    UDPSOCKET *sock;

    if (port == 0) {
        do {
            if (++last_local_port == 0)
                last_local_port = 4096;
            port = htons(last_local_port);
            sock = udpSocketList;
            while (sock) {
                if (sock->so_local_port == port)
                    break;
                sock = sock->so_next;
            }
        } while (sock);
        port = last_local_port;
    }
    if ((sock = NutHeapAllocClear(sizeof(UDPSOCKET))) != 0) {
        sock->so_local_port = htons(port);
        sock->so_next = udpSocketList;
        udpSocketList = sock;
    }
    return sock;
}

/*!
 * \brief Send a UDP datagram.
 *
 * \param sock Socket descriptor. This pointer must have been 
 *             retrieved by calling NutUdpCreateSocket().
 * \param addr IP address of the remote host in network byte order.
 * \param port Remote port number in host byte order.
 * \param data Pointer to a buffer containing the data to send.
 * \param len  Number of bytes to be sent.
 *
 * \return 0 on success, -1 otherwise. The specific error code
 *         can be retrieved by calling NutUdpError().
 */
int NutUdpSendTo(UDPSOCKET * sock, u_long addr, u_short port, void *data, int len)
{
    int rc;
    NETBUF *nb;

#ifdef NUT_UDP_ICMP_SUPPORT
    if (sock->so_last_error)
        return -1;
#endif

    if ((nb = NutNetBufAlloc(0, NBAF_APPLICATION, len)) == 0) {
        sock->so_last_error = ENOMEM;
        return -1;
    }
    memcpy(nb->nb_ap.vp, data, len);

    /* Bugfix by Ralph Mason. We should not free the NETBUF in case of an error. */
    if ((rc = NutUdpOutput(sock, addr, port, nb)) == 0)
        NutNetBufFree(nb);

    return rc;
}

/*!
 * \brief Receive a UDP datagram.
 *
 * \param sock    Socket descriptor. This pointer must have been 
 *                retrieved by calling NutUdpCreateSocket().
 * \param addr    IP address of the remote host in network byte order.
 * \param port    Remote port number in host byte order.
 * \param data    Pointer to the buffer that receives the data.
 * \param size    Size of the buffer that receives the data.
 * \param timeout Maximum number of milliseconds to wait.
 *
 * \return The number of bytes received, if successful. The return
 *         value < 0 indicates an error. The specific error code
 *         can be retrieved by calling NutUdpError().
 *
 * \note Timeout is limited to the granularity of the system timer.
 */
 /* @@@ 2003-10-24: modified by OS for udp packet queue */
int NutUdpReceiveFrom(UDPSOCKET * sock, u_long * addr, u_short * port, void *data, int size, u_long timeout)
{
    IPHDR *ip;
    UDPHDR *uh;
    NETBUF *nb;

#ifdef NUT_UDP_ICMP_SUPPORT
    /* The ICMP handler might have set an error condition. */
    if (sock->so_last_error)
        return -1;
#endif

    if (sock->so_rx_nb == 0)
        NutEventWait(&sock->so_rx_rdy, timeout);

#ifdef NUT_UDP_ICMP_SUPPORT
    /* An ICMP message might have posted the rx event. So check again */
    if (sock->so_last_error)
        return -1;
#endif

    if ((nb = sock->so_rx_nb) == 0)
        return 0;

    /* forward the queue's head to the next packet */
    sock->so_rx_nb = nb->nb_next;

    ip = nb->nb_nw.vp;
    *addr = ip->ip_src;

    uh = nb->nb_tp.vp;
    *port = htons(uh->uh_sport);

    if (size > nb->nb_ap.sz)
        size = nb->nb_ap.sz;

    sock->so_rx_cnt -= nb->nb_ap.sz;    /* decrement input buffer count */

    memcpy(data, nb->nb_ap.vp, size);
    NutNetBufFree(nb);

    return size;
}

/*!
 * \brief Close UDP socket.
 *
 * The memory occupied by the socket is immediately released
 * after calling this function. The application  must not use 
 * the socket after this call.
 *
 * \param sock Socket descriptor. This pointer must have been 
 *             retrieved by calling NutUdpCreateSocket().
 *
 * \return 0 on success, -1 otherwise.
 */
 /* @@@ 2003-10-24: modified by OS for udp packet queue */
int NutUdpDestroySocket(UDPSOCKET * sock)
{
    UDPSOCKET *sp;
    UDPSOCKET **spp;
    int rc = -1;
    NETBUF *nb;

    spp = &udpSocketList;
    sp = udpSocketList;

    while (sp) {
        if (sp == sock) {
            *spp = sock->so_next;
            /* packets may have arrived that the application 
               did not read before closing the socket. */
            while ((nb = sock->so_rx_nb) != 0) {
                sock->so_rx_nb = nb->nb_next;
                NutNetBufFree(nb);
            }
            NutHeapFree(sock);
            rc = 0;
            break;
        }
        spp = &sp->so_next;
        sp = sp->so_next;
    }
    return rc;
}

/*!
 * \brief Return specific code of the last error and the IP address / port of 
 *        the host to which the communication failed
 *
 * Possible error codes are:
 * - ENOTSOCK: Socket operation on non-socket
 * - EMSGSIZE: Message too long
 * - ENOPROTOOPT: Protocol not available
 * - EOPNOTSUPP: Operation not supported on socket
 * - ENETUNREACH: Network is unreachable
 * - ECONNREFUSED: Connection refused
 * - EHOSTDOWN: Host is down
 * - EHOSTUNREACH: No route to host
 *
 * \param sock Socket descriptor. This pointer must have been 
 *             retrieved by calling NutUdpCreateSocket().
 * \param addr IP address of the remote host in network byte order.
 * \param port Remote port number in host byte order.
 *
 * \todo Not all error codes are properly set right now. Some socket
 *       functions return an error without setting an error code.
 */
int NutUdpError(UDPSOCKET * sock, u_long * addr, u_short * port)
{
    int rc;
    
    if (sock == 0) {
        addr = 0;
        port = 0;
        return ENOTSOCK;
    }
    
    if (sock->so_last_error) {
        rc = sock->so_last_error;
        *port = ntohs(sock->so_remote_port);
        *addr = sock->so_remote_addr;

        sock->so_last_error  = 0;
        sock->so_remote_port = 0;
        sock->so_remote_addr = 0;
        return rc;
    }     
    return 0;
}

/*!
 * \brief Find a matching socket.
 *
 * Loop through all sockets and find a matching one.
 *
 * \note Applications typically do not need to call this function.
 *
 * \param port  Local port number.
 *
 * \return Socket descriptor.
 */
UDPSOCKET *NutUdpFindSocket(u_short port)
{
    UDPSOCKET *sp;
    UDPSOCKET *sock = 0;

    for (sp = udpSocketList; sp; sp = sp->so_next) {
        if (sp->so_local_port == port) {
            sock = sp;
            break;
        }
    }
    return sock;
}

/*!
 * \brief Set value of a UDP socket option.
 *
 * The following values can be set:
 *
 * - #SO_RCVBUF   Socket input buffer size (#u_short).
 *
 * \param sock    Socket descriptor. This pointer must have been 
 *                retrieved by calling NutUdpCreateSocket().
 * \param optname Option to set.
 * \param optval  Pointer to the value.
 * \param optlen  Length of the value.
 * \return 0 on success, -1 otherwise. 
 */
int NutUdpSetSockOpt(UDPSOCKET * sock, int optname, CONST void *optval, int optlen)
{
    int rc = -1;

    if (sock == 0)
        return -1;
    switch (optname) {

    case SO_RCVBUF:
        if (optval != 0 && optlen == sizeof(u_short)) {
            sock->so_rx_bsz = *((u_short *) optval);
            rc = 0;
        }
        break;

    default:
        /* sock->so_last_error = ENOPROTOOPT; */
        break;
    }
    return rc;
}

/*!
 * \brief Get a UDP socket option value.
 *
 * The following values can be set:
 *
 * - #SO_RCVBUF   Socket input buffer size (#u_short).
 *
 * \param sock    Socket descriptor. This pointer must have been 
 *                retrieved by calling NutUdpCreateSocket().
 * \param optname Option to get.
 * \param optval  Points to a buffer receiving the value.
 * \param optlen  Length of the value buffer.
 *
 * \return 0 on success, -1 otherwise. 
 */
int NutUdpGetSockOpt(UDPSOCKET * sock, int optname, void *optval, int optlen)
{
    int rc = -1;

    if (sock == 0)
        return -1;
    switch (optname) {

    case SO_RCVBUF:
        if (optval != 0 && optlen == sizeof(u_short)) {
            *((u_short *) optval) = sock->so_rx_bsz;
            rc = 0;
        }
        break;

    default:
        /* sock->so_last_error = ENOPROTOOPT; */
        break;
    }
    return rc;
}

/*!
 * \brief Set a UDP socket error.
 *
 * This function should only be used together (and from) the icmp input routine 
 *    
 * The following values can be set:
 *
 * - #EHOSTUNREACH   Host is unreachable
 *
 * \param sock    Socket descriptor. This pointer must have been 
 *                retrieved by calling NutUdpCreateSocket().
 * \param remote_addr remote ip address in network byte order
 * \param remote_port remote port in network byte order
 * \param error   Error number.
 *
 * \return 0 on success, -1 otherwise. 
 */

int NutUdpSetSocketError(UDPSOCKET * sock, u_long remote_addr, u_short remote_port, u_short error)
{
    if (sock == 0)
        return -1;
    
    sock->so_remote_addr = remote_addr;
    sock->so_remote_port = remote_port;
    sock->so_last_error  = error;

    /* post the event only, if a thread is waiting */
    if (sock->so_rx_rdy)
        NutEventPost(&sock->so_rx_rdy);

    return 0;
}

#endif

  • 13
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值