/platform/FNET/fnet_stack/stack/fnet_tcp.c
C | 4121 lines | 2565 code | 678 blank | 878 comment | 471 complexity | bc5ed71aa75ec5379df171b086c22f30 MD5 | raw file
Possible License(s): GPL-3.0, LGPL-3.0
Large files files are truncated, but you can click here to view the full file
- /**************************************************************************
- *
- * Copyright 2011-2015 by Andrey Butok. FNET Community.
- * Copyright 2008-2010 by Andrey Butok. Freescale Semiconductor, Inc.
- * Copyright 2003 by Alexey Shervashidze, Andrey Butok. Motorola SPS.
- *
- ***************************************************************************
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License Version 3
- * or later (the "LGPL").
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * You should have received a copy of the GNU General Public License
- * and the GNU Lesser General Public License along with this program.
- * If not, see <http://www.gnu.org/licenses/>.
- *
- **********************************************************************/ /*!
- *
- * @file fnet_tcp.c
- *
- * @author Olexandr Servasidze, Andrey Butok.
- *
- * @brief TCP protocol implementation.
- *
- ***************************************************************************/
-
- #include "fnet.h"
-
- #if FNET_CFG_TCP
-
- #include "fnet_socket_prv.h"
- #include "fnet_timer_prv.h"
- #include "fnet_tcp.h"
- #include "fnet_checksum.h"
- #include "fnet_prot.h"
-
- /************************************************************************
- * Definitions
- *************************************************************************/
- struct fnet_tcp_segment
- {
- fnet_socket_option_t *sockoption;
- struct sockaddr src_addr;
- struct sockaddr dest_addr;
- unsigned long seq;
- unsigned long ack;
- unsigned char flags;
- unsigned short wnd;
- unsigned short urgpointer;
- void *options;
- char optlen;
- fnet_netbuf_t *data;
- };
-
- /************************************************************************
- * Function Prototypes
- *************************************************************************/
- static void fnet_tcp_slowtimo( void *cookie );
- static void fnet_tcp_fasttimo( void *cookie );
- static void fnet_tcp_slowtimosk( fnet_socket_t *sk );
- static void fnet_tcp_fasttimosk( fnet_socket_t *sk );
- static int fnet_tcp_inputsk( fnet_socket_t *sk, fnet_netbuf_t *insegment, struct sockaddr *src_addr, struct sockaddr *dest_addr);
- static void fnet_tcp_initconnection( fnet_socket_t *sk );
- static int fnet_tcp_dataprocess( fnet_socket_t *sk, fnet_netbuf_t *insegment, int *ackparam );
- static int fnet_tcp_sendheadseg( fnet_socket_t *sk, unsigned char flags, void *options, char optlen );
- static int fnet_tcp_senddataseg( fnet_socket_t *sk, void *options, char optlen, unsigned long datasize );
- static unsigned long fnet_tcp_getrcvwnd( fnet_socket_t *sk );
- static int fnet_tcp_sendseg( struct fnet_tcp_segment *segment);
- static void fnet_tcp_sendrst( fnet_socket_option_t *sockoption, fnet_netbuf_t *insegment, struct sockaddr *src_addr, struct sockaddr *dest_addr);
- static void fnet_tcp_sendrstsk( fnet_socket_t *sk );
- static void fnet_tcp_sendack( fnet_socket_t *sk );
- static void fnet_tcp_abortsk( fnet_socket_t *sk );
- static void fnet_tcp_setsynopt( fnet_socket_t *sk, char *options, char *optionlen );
- static void fnet_tcp_getsynopt( fnet_socket_t *sk );
- static int fnet_tcp_addopt( fnet_netbuf_t *segment, unsigned char len, void *data );
- static void fnet_tcp_getopt( fnet_socket_t *sk, fnet_netbuf_t *segment );
- static unsigned long fnet_tcp_getsize( unsigned long pos1, unsigned long pos2 );
- static void fnet_tcp_rtimeo( fnet_socket_t *sk );
- static void fnet_tcp_ktimeo( fnet_socket_t *sk );
- static void fnet_tcp_ptimeo( fnet_socket_t *sk );
- static int fnet_tcp_hit( unsigned long startpos, unsigned long endpos, unsigned long pos );
- static int fnet_tcp_addinpbuf( fnet_socket_t *sk, fnet_netbuf_t *insegment, int *ackparam );
- static fnet_socket_t *fnet_tcp_findsk( struct sockaddr *src_addr, struct sockaddr *dest_addr );
- static void fnet_tcp_addpartialsk( fnet_socket_t *mainsk, fnet_socket_t *partialsk );
- static void fnet_tcp_movesk2incominglist( fnet_socket_t *sk );
- static void fnet_tcp_closesk( fnet_socket_t *sk );
- static void fnet_tcp_delpartialsk( fnet_socket_t *sk );
- static void fnet_tcp_delincomingsk( fnet_socket_t *sk );
- static void fnet_tcp_delcb( fnet_tcp_control_t *cb );
- #if !FNET_CFG_TCP_DISCARD_OUT_OF_ORDER
- static void fnet_tcp_deletetmpbuf( fnet_tcp_control_t *cb );
- #endif
- static void fnet_tcp_delsk( fnet_socket_t ** head, fnet_socket_t *sk );
- static int fnet_tcp_sendanydata( fnet_socket_t *sk, int oneexec );
- #if FNET_CFG_TCP_URGENT
- static void fnet_tcp_urgprocessing( fnet_socket_t *sk, fnet_netbuf_t ** segment, unsigned long repdatasize, int *ackparam );
- #endif
- static void fnet_tcp_finprocessing( fnet_socket_t *sk, unsigned long ack );
- static int fnet_tcp_init( void );
- static void fnet_tcp_release( void );
- static void fnet_tcp_input(fnet_netif_t *netif, struct sockaddr *src_addr, struct sockaddr *dest_addr, fnet_netbuf_t *nb, fnet_netbuf_t *ip_nb);
- static void fnet_tcp_control_input(fnet_prot_notify_t command, struct sockaddr *src_addr, struct sockaddr *dest_addr, fnet_netbuf_t *nb);
- static int fnet_tcp_attach( fnet_socket_t *sk );
- static int fnet_tcp_close( fnet_socket_t *sk );
- static int fnet_tcp_connect( fnet_socket_t *sk, struct sockaddr *foreign_addr);
- static fnet_socket_t *fnet_tcp_accept( fnet_socket_t *listensk );
- static int fnet_tcp_rcv( fnet_socket_t *sk, char *buf, int len, int flags, struct sockaddr *foreign_addr);
- static int fnet_tcp_snd( fnet_socket_t *sk, char *buf, int len, int flags, const struct sockaddr *foreign_addr);
- static int fnet_tcp_shutdown( fnet_socket_t *sk, int how );
- static int fnet_tcp_setsockopt( fnet_socket_t *sk, int level, int optname, char *optval, unsigned int optlen );
- static int fnet_tcp_getsockopt( fnet_socket_t *sk, int level, int optname, char *optval, unsigned int *optlen );
- static int fnet_tcp_listen( fnet_socket_t *sk, int backlog );
- static void fnet_tcp_drain( void );
-
- #if FNET_CFG_DEBUG_TRACE_TCP
- void fnet_tcp_trace(char *str, fnet_tcp_header_t *tcp_hdr);
- #else
- #define fnet_tcp_trace(str, tcp_hdr)
- #endif
-
-
- #if 0 /* For Debug needs.*/
- int FNET_DEBUG_check_send_buffer(fnet_socket_t *sk);
- #endif
-
- /************************************************************************
- * Global Variables
- *************************************************************************/
- /* Initial Sequence Number
- * tcpcb_isntime is changed by STEPISN every 0.5 sec.
- * Additionaly, each time a connection is established,
- * tcpcb_isntime is also incremented by FNET_TCP_STEPISN */
- static unsigned long fnet_tcp_isntime = 1;
-
- /* Timers.*/
- static fnet_timer_desc_t fnet_tcp_fasttimer;
- static fnet_timer_desc_t fnet_tcp_slowtimer;
-
-
- /*****************************************************************************
- * Protocol API structure.
- ******************************************************************************/
- static const fnet_socket_prot_if_t fnet_tcp_socket_api =
- {
- 1, /* TRUE = connection required by protocol.*/
- fnet_tcp_attach, /* A new socket has been created.*/
- fnet_tcp_close,
- fnet_tcp_connect,
- fnet_tcp_accept,
- fnet_tcp_rcv,
- fnet_tcp_snd,
- fnet_tcp_shutdown,
- fnet_tcp_setsockopt,
- fnet_tcp_getsockopt,
- fnet_tcp_listen
- };
-
- /* Protocol structure.*/
- fnet_prot_if_t fnet_tcp_prot_if =
- {
- 0,
- AF_SUPPORTED, /* Protocol domain.*/
- SOCK_STREAM, /* Socket type.*/
- FNET_IP_PROTOCOL_TCP, /* Protocol number.*/
- fnet_tcp_init,
- fnet_tcp_release,
- fnet_tcp_input,
- fnet_tcp_control_input, /* Control input (from below).*/
- fnet_tcp_drain,
- &fnet_tcp_socket_api /* Socket API */
- };
-
- /************************************************************************
- * NAME: fnet_tcp_init
- *
- * DESCRIPTION: This function performs a protocol initialization.
- *
- * RETURNS: If no error occurs, this function returns ERR_OK. Otherwise
- * it returns FNET_ERR.
- *************************************************************************/
- static int fnet_tcp_init( void )
- {
-
- /* Create the slow timer.*/
- fnet_tcp_fasttimer = fnet_timer_new(FNET_TCP_FASTTIMO / FNET_TIMER_PERIOD_MS, fnet_tcp_fasttimo, 0);
-
- if(!fnet_tcp_fasttimer)
- return FNET_ERR;
-
- /* Create the fast timer.*/
- fnet_tcp_slowtimer = fnet_timer_new(FNET_TCP_SLOWTIMO / FNET_TIMER_PERIOD_MS, fnet_tcp_slowtimo, 0);
-
- if(!fnet_tcp_slowtimer)
- {
- fnet_timer_free(fnet_tcp_fasttimer);
- fnet_tcp_fasttimer = 0;
- return FNET_ERR;
- }
-
- return FNET_OK;
- }
-
- /************************************************************************
- * NAME: fnet_tcp_release
- *
- * DESCRIPTION: This function resets and deletes sockets and releases timers.
- *
- * RETURNS: None.
- *************************************************************************/
- static void fnet_tcp_release( void )
- {
- fnet_tcp_control_t *cb;
-
- fnet_isr_lock();
-
- /* Release sockets.*/
- while(fnet_tcp_prot_if.head)
- {
- cb = (fnet_tcp_control_t *)fnet_tcp_prot_if.head->protocol_control;
- cb->tcpcb_flags |= FNET_TCP_CBF_CLOSE;
- fnet_tcp_abortsk(fnet_tcp_prot_if.head);
- }
-
- /* Free timers.*/
- fnet_timer_free(fnet_tcp_fasttimer);
- fnet_timer_free(fnet_tcp_slowtimer);
-
- fnet_tcp_fasttimer = 0;
- fnet_tcp_slowtimer = 0;
-
- fnet_isr_unlock();
- }
-
- /************************************************************************
- * NAME: fnet_tcp_input
- *
- * DESCRIPTION: This function receives, checks and routes input segments.
- *
- * RETURNS: FNET_OK.
- *************************************************************************/
- static void fnet_tcp_input(fnet_netif_t *netif, struct sockaddr *src_addr, struct sockaddr *dest_addr, fnet_netbuf_t *nb, fnet_netbuf_t *ip_nb)
- {
-
- fnet_socket_t *sk;
- fnet_netbuf_t *buf;
- unsigned short checksum;
- unsigned long tcp_length;
-
- tcp_length = (unsigned long)FNET_TCP_LENGTH(nb);
-
- fnet_netbuf_free_chain(ip_nb);
-
- /* The header must reside in contiguous area of the memory.*/
- buf = fnet_netbuf_pullup(nb, (int)tcp_length);
-
- if(!buf)
- {
- goto DROP;
- }
-
- nb = buf;
-
- /*Checksum.*/
- #if FNET_CFG_CPU_ETH_HW_RX_PROTOCOL_CHECKSUM || FNET_CFG_CPU_ETH_HW_TX_PROTOCOL_CHECKSUM
- if(nb->flags & FNET_NETBUF_FLAG_HW_PROTOCOL_CHECKSUM)
- {
- checksum = 0;
- }
- else
- #endif
- {
- checksum = fnet_checksum_pseudo_start( nb, FNET_HTONS((unsigned short)FNET_IP_PROTOCOL_TCP), (unsigned short)nb->total_length );
- checksum = fnet_checksum_pseudo_end( checksum, (char *)src_addr->sa_data, (char *)dest_addr->sa_data,
- (dest_addr->sa_family == AF_INET) ? sizeof(fnet_ip4_addr_t) : sizeof(fnet_ip6_addr_t) );
- }
-
- if(checksum
- || (fnet_socket_addr_is_broadcast(src_addr, netif)
- || fnet_socket_addr_is_multicast(src_addr))
- || (nb->total_length < tcp_length) /* Check the length.*/)
- {
- goto DROP;
- }
-
- /* Set port numbers.*/
- src_addr->sa_port = FNET_TCP_SPORT(nb);
- dest_addr->sa_port = FNET_TCP_DPORT(nb);
-
- if(fnet_socket_addr_is_broadcast(dest_addr, netif) || fnet_socket_addr_is_multicast(dest_addr))
- {
- /* Send RST.*/
- fnet_tcp_sendrst(0, nb, dest_addr, src_addr);
- goto DROP;
- }
-
- fnet_tcp_trace("RX", buf->data_ptr); /* TCP trace.*/
-
- sk = fnet_tcp_findsk(src_addr, dest_addr);
-
- if(sk)
- {
- if(sk->state == SS_LISTENING)
- {
- sk->foreign_addr = *src_addr;
- }
-
- nb->next_chain = 0;
-
- /* Process the segment.*/
- if(fnet_tcp_inputsk(sk, nb, src_addr, dest_addr) == FNET_TRUE)
- goto DROP;
- }
- else
- {
- if(!(FNET_TCP_FLAGS(nb) & FNET_TCP_SGT_RST))
- fnet_tcp_sendrst(0, nb, dest_addr, src_addr);
-
- goto DROP;
- }
-
-
- /* Wake-up user application.*/
- fnet_os_event_raise();
-
- return;
-
- DROP:
- /* Wake-up user application.*/
- fnet_os_event_raise();
-
- /* Delete the segment.*/
- fnet_netbuf_free_chain(nb);
- }
-
-
- /************************************************************************
- * NAME: fnet_tcp_control_input
- *
- * DESCRIPTION: This function process ICMP errors.
- *
- * RETURNS: None.
- *************************************************************************/
- static void fnet_tcp_control_input(fnet_prot_notify_t command, struct sockaddr *src_addr, struct sockaddr *dest_addr, fnet_netbuf_t *nb)
- {
- fnet_tcp_header_t *tcp_header; /* Pointer to the TCP header.*/
- fnet_socket_t *sk; /* Pointer to the socket.*/
- fnet_tcp_control_t *cb;
-
- if(src_addr && dest_addr && nb)
- {
- tcp_header = nb->data_ptr;
-
- /* Find the corresponding socket.*/
- dest_addr->sa_port = tcp_header->destination_port;
- src_addr->sa_port = tcp_header->source_port;
-
- sk = fnet_tcp_findsk(dest_addr, src_addr);
-
- if(sk)
- {
- /* Initialize the pointer of the control block.*/
- cb = sk->protocol_control;
-
- switch(command)
- {
- case FNET_PROT_NOTIFY_QUENCH: /* Someone said to slow down.*/
- /* Begin the Slow Start algorithm.*/
- cb->tcpcb_cwnd = cb->tcpcb_sndmss;
- break;
- case FNET_PROT_NOTIFY_MSGSIZE: /* Message size forced drop.*/
- sk->options.local_error = FNET_ERR_MSGSIZE;
- break;
- case FNET_PROT_NOTIFY_UNREACH_HOST: /* No route to host.*/
- case FNET_PROT_NOTIFY_UNREACH_NET: /* No route to network.*/
- case FNET_PROT_NOTIFY_UNREACH_SRCFAIL: /* Source route failed.*/
- sk->options.local_error = FNET_ERR_HOSTUNREACH;
- break;
- case FNET_PROT_NOTIFY_PARAMPROB: /* Header incorrect.*/
- sk->options.local_error = FNET_ERR_NOPROTOOPT; /* Bad protocol option.*/
- break;
- case FNET_PROT_NOTIFY_UNREACH_PORT: /* bad port #.*/
- case FNET_PROT_NOTIFY_UNREACH_PROTOCOL:
- if(sk->state != SS_LISTENING) /* Avoid listening sockets.*/
- {
- sk->options.local_error = FNET_ERR_CONNRESET;
- fnet_tcp_closesk(sk);
- }
- break;
- default:
- break;
- }
- }
- }
- }
-
- /************************************************************************
- * NAME: fnet_tcp_attach
- *
- * DESCRIPTION: This function performs the initialization of the
- * socket's options and creates the structure of the control blok.
- *
- * RETURNS: If no error occurs, this function returns FNET_OK. Otherwise
- * it returns FNET_ERR.
- *************************************************************************/
- static int fnet_tcp_attach( fnet_socket_t *sk )
- {
- struct tcpcb *cb;
-
- /* Create the control block.*/
- cb = (struct tcpcb *)fnet_malloc_zero(sizeof(fnet_tcp_control_t));
-
- /* Check the memory allocation.*/
- if(!cb)
- {
- fnet_socket_set_error(sk, FNET_ERR_NOMEM);
- return FNET_ERR;
- }
-
- sk->protocol_control = (void *)cb;
-
- /* Set the maximal segment size option.*/
- sk->options.tcp_opt.mss = FNET_CFG_SOCKET_TCP_MSS;
-
- /* Default setting of the flags.*/
- sk->options.tcp_opt.flags =
- #if FNET_CFG_TCP_URGENT
- TCP_BSD |
- #endif
- TCP_NODELAY;
- sk->options.tcp_opt.keep_idle = FNET_TCP_KEEPIDLE_DEFAULT; /* TCP_KEEPIDLE option. */
- sk->options.tcp_opt.keep_intvl = FNET_TCP_KEEPINTVL_DEFAULT; /* TCP_KEEPINTVL option. */
- sk->options.tcp_opt.keep_cnt = FNET_TCP_KEEPCNT_DEFAULT; /* TCP_KEEPCNT option. */
-
- sk->options.flags = SO_KEEPALIVE;
-
- /* Set the IP options.*/
- #if FNET_CFG_IP4
- sk->options.ip_opt.ttl = FNET_TCP_TTL_DEFAULT;
- sk->options.ip_opt.tos = 0;
- #endif
-
- #if FNET_CFG_IP6
- sk->options.ip6_opt.hops_unicast = 0; /* Defined by ND.*/
- #endif
-
-
- /* Set the buffer sizes.*/
- sk->send_buffer.count_max = FNET_TCP_TX_BUF_MAX;
- sk->receive_buffer.count_max = FNET_TCP_RX_BUF_MAX;
-
- return FNET_OK;
- }
-
- /************************************************************************
- * NAME: fnet_tcp_close
- *
- * DESCRIPTION: This function performs the connection termination.
- *
- * RETURNS: If no error occurs, this function returns FNET_OK. Otherwise
- * it returns FNET_ERR.
- *************************************************************************/
- static int fnet_tcp_close( fnet_socket_t *sk )
- {
- fnet_tcp_control_t *cb = (fnet_tcp_control_t *)sk->protocol_control;
-
- /* If the connection is closed, free the memory.*/
- if(sk->state == SS_UNCONNECTED)
- {
- cb->tcpcb_flags |= FNET_TCP_CBF_CLOSE;
- fnet_tcp_closesk(sk);
- return FNET_OK;
- }
-
- /* If SO_LINGER option is present.*/
- if(sk->options.flags & SO_LINGER)
- {
-
- if(sk->options.linger_ticks == 0)
- /* Linger is 0 so close the socket immediately. */
- {
- /* Hard reset.*/
- fnet_isr_lock();
- cb->tcpcb_flags |= FNET_TCP_CBF_CLOSE;
- fnet_tcp_abortsk(sk);
- fnet_isr_unlock();
- return FNET_OK;
- }
- }
-
- fnet_isr_lock();
-
- if(sk->state != SS_CONNECTED)
- {
- cb->tcpcb_flags |= FNET_TCP_CBF_CLOSE;
- fnet_tcp_abortsk(sk);
-
- /* Unlock interrupts.*/
- fnet_isr_unlock();
- return FNET_OK;
- }
-
- /* If the socket is not unlocked, try to send the data.*/
- if(!sk->send_buffer.is_shutdown)
- {
- sk->send_buffer.is_shutdown = 1;
- fnet_tcp_sendanydata(sk, 1);
- }
-
- fnet_isr_unlock();
-
-
-
- fnet_isr_lock();
-
- /* After this moment the unconnecetd socket must be deleted.*/
- cb->tcpcb_flags |= FNET_TCP_CBF_CLOSE;
-
- /* If the socket is already unconnected, close the socket.*/
- if(sk->state == SS_UNCONNECTED)
- {
- fnet_tcp_closesk(sk);
- }
- else
- {
- if(cb->tcpcb_connection_state != FNET_TCP_CS_TIME_WAIT)
- {
- if((sk->options.flags & SO_LINGER) && sk->options.linger_ticks)
- cb->tcpcb_timers.connection = ((sk->options.linger_ticks * FNET_TIMER_PERIOD_MS)
- / FNET_TCP_SLOWTIMO);
- else
- cb->tcpcb_timers.connection = FNET_TCP_ABORT_INTERVAL;
-
- sk->receive_buffer.is_shutdown = 1;
- }
-
- if(sk->receive_buffer.count)
- fnet_socket_buffer_release(&sk->receive_buffer);
- }
-
- fnet_isr_unlock();
-
- return FNET_OK;
- }
-
- /************************************************************************
- * NAME: fnet_tcp_connect
- *
- * DESCRIPTION: This function performs the connection establishment.
- *
- * RETURNS: If no error occurs, this function returns FNET_OK. Otherwise
- * it returns FNET_ERR.
- *************************************************************************/
- static int fnet_tcp_connect( fnet_socket_t *sk, struct sockaddr *foreign_addr)
- {
- fnet_tcp_control_t *cb;
- char options[FNET_TCP_MAX_OPT_SIZE];
- char optionlen;
- int error;
- fnet_netif_t *netif;
-
- if((netif = fnet_socket_addr_route(foreign_addr)) == FNET_NULL)
- {
- error = FNET_ERR_NETUNREACH;
- goto ERROR;
- }
-
- /* TCP doesn't support broadcasting and multicasting.*/
- if(fnet_socket_addr_is_broadcast(foreign_addr, netif) || fnet_socket_addr_is_multicast(foreign_addr))
- {
- error = FNET_ERR_ADDRNOTAVAIL;
- goto ERROR;
- }
-
- /* Initialize the pointer to the control block.*/
- cb = (fnet_tcp_control_t *)sk->protocol_control;
-
- /* Initialize the control block.*/
- fnet_tcp_initconnection(sk);
-
- /* Set synchronized options.*/
- fnet_tcp_setsynopt(sk, options, &optionlen);
-
- /* Initialize sequnece number parameters.*/
- cb->tcpcb_sndseq = fnet_tcp_isntime;
- cb->tcpcb_maxrcvack = fnet_tcp_isntime + 1;
- #if FNET_CFG_TCP_URGENT
- cb->tcpcb_sndurgseq = cb->tcpcb_sndseq - 1;
- #endif /* FNET_CFG_TCP_URGENT */
-
- /* Set the foreign address.*/
- sk->foreign_addr = *foreign_addr;
-
- fnet_isr_lock();
-
- /* Send SYN segment.*/
- error = fnet_tcp_sendheadseg(sk, FNET_TCP_SGT_SYN, options, optionlen);
-
- /* Check the result.*/
- if(error)
- {
- fnet_isr_unlock();
- goto ERROR;
- }
-
- /* Change the states.*/
- cb->tcpcb_connection_state = FNET_TCP_CS_SYN_SENT;
- sk->state = SS_CONNECTING;
-
- /* Increase Initial Sequence Number.*/
- fnet_tcp_isntime += FNET_TCP_STEPISN;
-
- /* Initialize Abort Timer.*/
- cb->tcpcb_timers.retransmission = cb->tcpcb_rto;
- cb->tcpcb_timers.connection = FNET_TCP_ABORT_INTERVAL_CON;
-
- fnet_isr_unlock();
-
- return FNET_OK;
-
- ERROR:
- fnet_socket_set_error(sk, error);
- return FNET_ERR;
- }
-
- /************************************************************************
- * NAME: fnet_tcp_accept
- *
- * DESCRIPTION: This function removes the created socket
- * from the incoming queue of the listening socket,
- * and adds this socket to the main list.
- *
- * RETURNS: If the incoming socket is present, this function returns
- * the first created incoming socket. Otherwise, it returns 0.
- *************************************************************************/
- static fnet_socket_t *fnet_tcp_accept( fnet_socket_t *listensk )
- {
- fnet_socket_t *sk= FNET_NULL;
-
- /* If the incoming socket is not present, return.*/
- if(listensk->incoming_con)
- {
- fnet_isr_lock();
- /* Find the first incoming socket.*/
- sk = listensk->incoming_con;
-
- while(sk->next)
- sk = sk->next;
-
- /* Delete the incoming socket from the list.*/
- sk->head_con->incoming_con_len--;
- fnet_socket_list_del(&sk->head_con->incoming_con, sk);
-
- fnet_isr_unlock();
- sk->head_con = 0;
- }
-
- return sk;
- }
-
- /************************************************************************
- * NAME: fnet_tcp_rcv
- *
- * DESCRIPTION: This function receives the data and sends the acknowledgment
- * (This acknowledgment segment informs about the new free size
- * in the input buffer).
- *
- * RETURNS: If no error occurs, this function returns the length
- * of the received data. Otherwise, it returns FNET_ERR.
- *************************************************************************/
- static int fnet_tcp_rcv( fnet_socket_t *sk, char *buf, int len, int flags, struct sockaddr *foreign_addr)
- {
- fnet_tcp_control_t *cb = (fnet_tcp_control_t *)sk->protocol_control;
- int remove; /* Remove flag. 1 means that the data must be deleted
- * from the input buffer after the reading.*/
- int error_code;
-
- /* Receive the flags.*/
- remove = !(flags & MSG_PEEK);
-
- #if FNET_CFG_TCP_URGENT
- /* Reading of the OOB data.*/
- if(flags & MSG_OOB)
- {
- /* If the OOB data can't be read, return.*/
- if(sk->options.flags & SO_OOBINLINE)
- {
- error_code = FNET_ERR_INVAL;
- goto ERROR;
- }
-
- /* If the OOB data is present, read */
- if(cb->tcpcb_flags & FNET_TCP_CBF_RCVURGENT)
- {
- fnet_isr_lock();
-
- if(remove)
- {
- cb->tcpcb_rcvurgmark = FNET_TCP_NOT_USED;
- cb->tcpcb_flags &= ~FNET_TCP_CBF_RCVURGENT;
- }
-
- *buf = cb->tcpcb_iobc;
- fnet_isr_unlock();
-
- return FNET_TCP_URGENT_DATA_SIZE;
- }
- else
- {
- /* If the socket is not connected , return with the error. */
- if(sk->state != SS_CONNECTED)
- {
- error_code = FNET_ERR_NOTCONN;
- goto ERROR;
- }
-
- return 0;
- }
- }
- #endif /* FNET_CFG_TCP_URGENT */
-
- fnet_isr_lock();
-
- #if FNET_CFG_TCP_URGENT
- /* Calculate the length of the data that can be received.*/
- if(cb->tcpcb_rcvurgmark > 0 && len >= cb->tcpcb_rcvurgmark)
- {
- len = cb->tcpcb_rcvurgmark;
-
- if(remove)
- cb->tcpcb_rcvurgmark = FNET_TCP_NOT_USED;
- }
- else
- #endif /* FNET_CFG_TCP_URGENT */
- if(sk->receive_buffer.count < len)
- {
- len = (int)sk->receive_buffer.count;
- }
-
- /* Copy the data to the buffer.*/
- len = fnet_socket_buffer_read_record(&sk->receive_buffer, buf, len, remove);
-
- /* Remove the data from input buffer.*/
- if(remove)
- {
- /* Recalculate the new free size in the input buffer.*/
- cb->tcpcb_newfreercvsize += len;
-
- /* If the window is opened, send acknowledgment.*/
- if((cb->tcpcb_newfreercvsize >= (cb->tcpcb_rcvmss << 1)
- || cb->tcpcb_newfreercvsize >= (cb->tcpcb_rcvcountmax >> 1) /* More than half of RX buffer.*/
- || (!cb->tcpcb_rcvwnd && cb->tcpcb_newfreercvsize)) && (sk->state == SS_CONNECTED))
- fnet_tcp_sendack(sk);
- }
-
- /* If the socket is not connected and the data are not received, return with error.*/
- if(len == 0 && sk->state != SS_CONNECTED)
- {
- error_code = FNET_ERR_NOTCONN;
- goto ERROR_UNLOCK;
- }
- else
- {
- /* Set the foreign address and port.*/
- if(foreign_addr)
- *foreign_addr = sk->foreign_addr;
-
- /* If the socket is closed by peer and no data.*/
- if((len == 0) && (cb->tcpcb_flags & FNET_TCP_CBF_FIN_RCVD))
- {
- error_code = FNET_ERR_CONNCLOSED;
- goto ERROR_UNLOCK;
- }
- }
-
- fnet_isr_unlock();
- return len;
-
- ERROR_UNLOCK:
- fnet_isr_unlock();
- #if FNET_CFG_TCP_URGENT
- ERROR:
- #endif
- fnet_socket_set_error(sk, error_code);
- return FNET_ERR;
- }
-
- /************************************************************************
- * NAME: fnet_tcp_snd
- *
- * DESCRIPTION: This function adds the data to the output buffer and
- * sends the data that can be sent.
- *
- * RETURNS: If no error occurs, this function returns the length
- * of the data that is added to the output buffer.
- * Otherwise, it returns FNET_ERR.
- *************************************************************************/
- static int fnet_tcp_snd( fnet_socket_t *sk, char *buf, int len, int flags, const struct sockaddr *foreign_addr)
- {
- fnet_tcp_control_t *cb = (fnet_tcp_control_t *)sk->protocol_control;
- fnet_netbuf_t *netbuf;
- long sendlength = len; /* Size of the data that must be sent.*/
- long sentlength = 0; /* Length of the sent data.*/
- long freespace; /* Free space in the output buffer.*/
- long currentlen; /* Current length.*/
- int dontroute = 0; /* Routing flag.*/
- unsigned long malloc_max;
- int error_code;
-
- FNET_COMP_UNUSED_ARG(foreign_addr);
-
- /* If the size of the data greater than the maximal size of the output buffer, return*/
- if(sendlength > FNET_TCP_MAX_BUFFER)
- {
- error_code = FNET_ERR_INVAL;
- goto ERROR;
- }
-
- /* If the socket is not connected, return*/
- if(sk->state != SS_CONNECTED)
- {
- error_code = FNET_ERR_NOTCONN;
- goto ERROR;
- }
-
-
- if(sendlength)
- {
- fnet_isr_lock();
-
- /* Caclulate a free space in the output buffer.*/
- freespace = (long)(sk->send_buffer.count_max - sk->send_buffer.count);
-
- /* Check maximum allocated memory chunck */
- malloc_max = fnet_malloc_max_netbuf();
-
- if(malloc_max < (long)(FNET_CFG_CPU_ETH0_MTU*1.5)) /* TBD I do not like it ????*/
- {
- freespace = 0;
- }
- else if(freespace > malloc_max)
- {
- freespace = (long)malloc_max;
- }
-
-
- /* If the function is nonblocking and the data length greater than the freespace, recalculate the size of the data*/
- if(freespace < sendlength)
- {
- /* If the data can't be added to the output buffer, return*/
- if(freespace <= 0)
- {
- fnet_isr_unlock();
- return 0;
- }
- else
- {
- /* Recalculate the data size.*/
- sendlength = freespace;
- #if FNET_CFG_TCP_URGENT
- flags &= ~MSG_OOB;
- #endif /* FNET_CFG_TCP_URGENT */
- }
- }
-
- #if FNET_CFG_TCP_URGENT
- /* Process the OOB data.*/
- if(flags & MSG_OOB)
- {
- /* If the urgent data are already present, the urgent byte will not be added.*/
- if(FNET_TCP_COMP_GE(cb->tcpcb_sndurgseq, cb->tcpcb_rcvack))
- {
- sendlength -= 1;
-
- /* If the data size is 0, return.*/
- if(!sendlength)
- {
- fnet_isr_unlock();
- return 0;
- }
- }
- else
- {
- /* Calculate the new sequence number of the urgent data.*/
- cb->tcpcb_sndurgseq = cb->tcpcb_rcvack + sk->send_buffer.count + sendlength - 1;
- }
-
- }
- #endif /* FNET_CFG_TCP_URGENT */
-
- /* If the routing tables should be bypassed for this message only, set dontroute flag.*/
- if((flags & MSG_DONTROUTE) && !(sk->options.flags & SO_DONTROUTE))
- {
- dontroute = 1;
- sk->options.flags |= SO_DONTROUTE;
- }
-
-
- /* Receive the freespace value.*/
- /* TBD*/
- #if 0
- freespace = (long)(sk->send_buffer.count_max - sk->send_buffer.count);
- #endif
-
- /* Try to add the data.*/
- if(freespace > 0)
- {
- cb->tcpcb_flags |= FNET_TCP_CBF_INSND;
-
- /* Calculate the data size that can be added.*/
- if(sendlength > freespace)
- currentlen = freespace;
- else
- currentlen = sendlength;
-
- netbuf = fnet_netbuf_from_buf(&buf[sentlength], currentlen, FNET_TRUE);
-
- /* Check the memory allocation.*/
- if(netbuf)
- {
- sentlength += currentlen;
-
- if(fnet_socket_buffer_append_record(&sk->send_buffer, netbuf) == FNET_OK)
- {
-
- /* If the window of another side is closed, set the persist timer.*/
- if(!cb->tcpcb_sndwnd)
- {
- if(cb->tcpcb_timers.persist == FNET_TCP_TIMER_OFF)
- {
- cb->tcpcb_cprto = cb->tcpcb_rto;
- cb->tcpcb_timers.persist = cb->tcpcb_cprto;
- }
- }
- else
- {
- /* Try to send the data.*/
- while(1)
- {
- /* If the connection is not established, delete the data. Otherwise try to send the data*/
- if(sk->state == SS_CONNECTED)
- {
- if(!fnet_tcp_sendanydata(sk, 1))
- {
- cb->tcpcb_flags &= ~FNET_TCP_CBF_INSND;
- break;
- }
- }
- else
- {
- /* If socket is not connected, delete the output buffer.*/
- fnet_socket_buffer_release(&sk->send_buffer);
- cb->tcpcb_flags &= ~FNET_TCP_CBF_INSND;
- break;
- }
- }
- }
- }
- else /* Not able to add to the socket send buffer.*/
- {
- fnet_netbuf_free( netbuf );
- fnet_isr_unlock();
- return 0;
- }
- }
- }
-
- /* Receive the freespace value.*/
- freespace = (long)(sk->send_buffer.count_max - sk->send_buffer.count);
-
- #if FNET_CFG_TCP_URGENT
- if(FNET_TCP_COMP_GE(cb->tcpcb_sndurgseq, cb->tcpcb_rcvack + sk->send_buffer.count))
- cb->tcpcb_sndurgseq = cb->tcpcb_rcvack - 1;
- #endif /* FNET_CFG_TCP_URGENT */
-
-
- /* Remove the dontroute flag.*/
- if(dontroute)
- sk->options.flags &= ~SO_DONTROUTE;
-
-
- fnet_isr_unlock();
- }
- return sentlength;
-
- ERROR:
- fnet_socket_set_error(sk, error_code);
- return FNET_ERR;
- }
-
- /************************************************************************
- * NAME: fnet_tcp_shutdown
- *
- * DESCRIPTION: This function closes a write-half, read-half, or
- * both halves of the connection.
- *
- * RETURNS: If no error occurs, this function returns FNET_OK. Otherwise
- * it returns FNET_ERR.
- *************************************************************************/
- static int fnet_tcp_shutdown( fnet_socket_t *sk, int how )
- {
- /* If the socket is not connected, return.*/
- if(sk->state != SS_CONNECTED)
- {
- fnet_socket_set_error(sk, FNET_ERR_NOTCONN);
- return FNET_ERR;
- }
- else
- {
- fnet_isr_lock();
-
- /* Shutdown the writing.*/
- if(how & SD_WRITE && !sk->send_buffer.is_shutdown)
- {
- /* Set the flag of the buffer.*/
- sk->send_buffer.is_shutdown = 1;
-
- /* Send the data that is in the output buffer.*/
- fnet_tcp_sendanydata(sk, 1);
- }
-
- /* Shutdown the reading.*/
- if(how & SD_READ && !sk->receive_buffer.is_shutdown)
- {
- fnet_socket_buffer_release(&sk->receive_buffer);
-
- /* Set the flag of the buffer (Data can't be read).*/
- sk->receive_buffer.is_shutdown = 1;
- }
-
- fnet_isr_unlock();
-
- return FNET_OK;
- }
- }
-
- /************************************************************************
- * NAME: fnet_tcp_setsockopt
- *
- * DESCRIPTION: This function sets a TCP option.
- *
- * RETURNS: If no error occurs, this function returns FNET_OK. Otherwise
- * it returns FNET_ERR.
- *************************************************************************/
- static int fnet_tcp_setsockopt( fnet_socket_t *sk, int level, int optname, char *optval, unsigned int optlen )
- {
- int error_code;
-
- /* If the level is not IPPROTO_TCP, go to IP processing.*/
- if(level == IPPROTO_TCP)
- {
- /* Check the option size.*/
- switch(optname)
- {
- case TCP_MSS:
- if(optlen != sizeof(unsigned short))
- {
- error_code = FNET_ERR_INVAL;
- goto ERROR;
- }
- break;
- case TCP_KEEPCNT:
- case TCP_KEEPINTVL:
- case TCP_KEEPIDLE:
- case TCP_NODELAY:
- #if FNET_CFG_TCP_URGENT
- case TCP_BSD:
- #endif
- if(optlen != sizeof(int))
- {
- error_code = FNET_ERR_INVAL;
- goto ERROR;
- }
- break;
- default:
- /* The option is not supported.*/
- error_code = FNET_ERR_NOPROTOOPT;
- goto ERROR;
- }
-
- /* Process the option.*/
- switch(optname)
- {
- /* Maximal segment size option.*/
- case TCP_MSS:
- if(!(*((unsigned short *)(optval))))
- {
- error_code = FNET_ERR_INVAL;
- goto ERROR;
- }
-
- sk->options.tcp_opt.mss = *((unsigned short *)(optval));
- break;
- /* Keepalive probe retransmit limit.*/
- case TCP_KEEPCNT:
- if(!(*((unsigned int *)(optval))))
- {
- error_code = FNET_ERR_INVAL;
- goto ERROR;
- }
-
- sk->options.tcp_opt.keep_cnt = *((int *)(optval));
- break;
- /* Keepalive retransmit interval.*/
- case TCP_KEEPINTVL:
- if(!(*((unsigned int *)(optval))))
- {
- error_code = FNET_ERR_INVAL;
- goto ERROR;
- }
-
- sk->options.tcp_opt.keep_intvl = *((int *)(optval))*(1000/FNET_TCP_SLOWTIMO);
- break;
- /* Time between keepalive probes.*/
- case TCP_KEEPIDLE:
- if(!(*((unsigned int *)(optval))))
- {
- error_code = FNET_ERR_INVAL;
- goto ERROR;
- }
-
- sk->options.tcp_opt.keep_idle = *((int *)(optval))*(1000/FNET_TCP_SLOWTIMO);
- break;
- #if FNET_CFG_TCP_URGENT
- /* BSD interpretation of the urgent pointer.*/
- case TCP_BSD:
- #endif
- /* TCP_NO_DELAY option.*/
- case TCP_NODELAY:
- if(*((int *)(optval)))
- sk->options.tcp_opt.flags |= optname;
- else
- sk->options.tcp_opt.flags &= ~optname;
-
- break;
- }
-
- return FNET_OK;
- }
- else
- {
- /* IP level option processing.*/
- return fnet_ip_setsockopt(sk, level, optname, optval, optlen);
- }
-
- ERROR:
- fnet_socket_set_error(sk, error_code);
- return FNET_ERR;
- }
-
- /************************************************************************
- * NAME: fnet_tcp_getsockopt
- *
- * DESCRIPTION: This function receives a TCP option.
- *
- * RETURNS: If no error occurs, this function returns FNET_OK. Otherwise
- * it returns FNET_ERR.
- *************************************************************************/
- static int fnet_tcp_getsockopt( fnet_socket_t *sk, int level, int optname, char *optval, unsigned int *optlen )
- {
-
- fnet_tcp_control_t *cb = (fnet_tcp_control_t *)sk->protocol_control;
-
-
- if(level == IPPROTO_TCP)
- {
- switch(optname)
- {
- case TCP_KEEPCNT:
- *((int *)(optval)) = sk->options.tcp_opt.keep_cnt;
- break;
- case TCP_KEEPINTVL:
- *((int *)(optval)) = sk->options.tcp_opt.keep_intvl/(1000/FNET_TCP_SLOWTIMO);
- break;
- case TCP_KEEPIDLE:
- *((int *)(optval)) = sk->options.tcp_opt.keep_idle/(1000/FNET_TCP_SLOWTIMO);
- break;
- #if FNET_CFG_TCP_URGENT
- case TCP_BSD:
- #endif
- case TCP_NODELAY:
- if(sk->options.tcp_opt.flags & optname)
- *((int *)(optval)) = 1;
- else
- *((int *)(optval)) = 0;
- break;
- case TCP_FINRCVD:
- if(cb->tcpcb_flags & FNET_TCP_CBF_FIN_RCVD)
- *((int *)(optval)) = 1;
- else
- *((int *)(optval)) = 0;
- break;
- #if FNET_CFG_TCP_URGENT
- case TCP_URGRCVD:
- if(cb->tcpcb_flags & FNET_TCP_CBF_RCVURGENT)
- *((int *)(optval)) = 1;
- else
- *((int *)(optval)) = 0;
- break;
- #endif
- case TCP_MSS:
- *((unsigned short *)(optval)) = sk->options.tcp_opt.mss;
- *optlen = sizeof(unsigned short);
- return FNET_OK;
- default:
- fnet_socket_set_error(sk, FNET_ERR_NOPROTOOPT);
- return FNET_ERR;
- }
-
- *optlen = sizeof(int);
-
- return FNET_OK;
- }
- else
- {
- /* IP level option processing.*/
- return fnet_ip_getsockopt(sk, level, optname, optval, optlen);
- }
- }
-
- /************************************************************************
- * NAME: fnet_tcp_listen
- *
- * DESCRIPTION: This function changes
- * the state of the socket to the listening state.
- *
- * RETURNS: FNET_OK.
- *************************************************************************/
- static int fnet_tcp_listen( fnet_socket_t *sk, int backlog )
- {
- /* Initializen the pointer to the control block.*/
- fnet_tcp_control_t *cb = (fnet_tcp_control_t *)sk->protocol_control;
-
-
- if(sk->state == SS_LISTENING)
- {
- /* If the socket number of the listening socket is greater than the new backlog,
- * delete the sockets.*/
- fnet_isr_lock();
-
- while(backlog < sk->partial_con_len + sk->incoming_con_len && sk->partial_con_len)
- fnet_tcp_abortsk(sk->partial_con);
-
- while(backlog < sk->incoming_con_len)
- fnet_tcp_abortsk(sk->incoming_con);
-
- sk->con_limit = backlog;
- fnet_isr_unlock();
- }
- else
- {
- fnet_tcp_initconnection(sk);
-
- /* Foreign address must be any.*/
- ((struct sockaddr_in *)(&sk->foreign_addr))->sin_addr.s_addr = INADDR_ANY;
- sk->foreign_addr.sa_port = 0;
- sk->foreign_addr.sa_family = AF_INET;
- sk->con_limit = backlog;
-
- /* Change the state.*/
- cb->tcpcb_connection_state = FNET_TCP_CS_LISTENING;
- sk->state = SS_LISTENING;
- }
-
- return FNET_OK;
- }
-
- /************************************************************************
- * NAME: fnet_tcp_drain
- *
- * DESCRIPTION: fnet_tcp_drain removes the temporary data.
- *
- * RETURNS: None.
- *************************************************************************/
- static void fnet_tcp_drain( void )
- {
- fnet_socket_t *sk;
- fnet_socket_t *delsk;
- fnet_tcp_control_t *cb;
-
-
- fnet_isr_lock();
-
- /* Receive the pointer to the first socket.*/
- sk = fnet_tcp_prot_if.head;
-
- while(sk)
- {
- cb = (fnet_tcp_control_t *)sk->protocol_control;
- delsk = sk;
- sk = sk->next;
-
- /* if((cb->tcpcb_connection_state == FNET_TCP_CS_TIME_WAIT) && (cb->tcpcb_flags & FNET_TCP_CBF_CLOSE))*/
- if((cb->tcpcb_flags & FNET_TCP_CBF_CLOSE))
- {
- /* Remove the socket that to be closed. */
- fnet_tcp_closesk(delsk);
- }
- /* Delete all partial and incoming connections */
- else if(delsk->state == SS_LISTENING)
- {
- while(delsk->partial_con)
- fnet_tcp_abortsk(delsk->partial_con);
- #if 0
- while (delsk->incoming_con)
- fnet_tcp_abortsk(delsk->incoming_con);
- #endif
- }
- #if !FNET_CFG_TCP_DISCARD_OUT_OF_ORDER
- else
- /* Remove the temporary data.*/
- fnet_tcp_deletetmpbuf(cb);
- #endif
- }
-
-
- fnet_isr_unlock();
- }
-
- /************************************************************************
- * NAME: fnet_tcp_initconnection
- *
- * DESCRIPTION: This function creates and initializes the control block,
- * and initializes the socket.
- *
- * RETURNS: None.
- *************************************************************************/
- static void fnet_tcp_initconnection( fnet_socket_t *sk )
- {
- fnet_tcp_control_t *cb;
-
- cb = sk->protocol_control;
-
- fnet_memset_zero(cb, sizeof(fnet_tcp_control_t));
-
- /* Set the default maximal segment size value.*/
- cb->tcpcb_sndmss = FNET_TCP_DEFAULT_MSS;
- cb->tcpcb_rcvmss = sk->options.tcp_opt.mss;
-
- /* Set the length of the socket buffers.*/
- cb->tcpcb_rcvcountmax = sk->receive_buffer.count_max;
-
- /* The input buffer can't be greater than the FNET_TCP_MAX_BUFFER value.*/
- if(cb->tcpcb_rcvcountmax > FNET_TCP_MAX_BUFFER)
- cb->tcpcb_rcvcountmax = FNET_TCP_MAX_BUFFER;
-
- /* If a segment size greater than the buffer length, recalculate the segment size.*/
- if(cb->tcpcb_rcvcountmax < cb->tcpcb_rcvmss)
- cb->tcpcb_rcvmss = (unsigned short)cb->tcpcb_rcvcountmax;
-
- /* Receive a scale of the input window.*/
- while(FNET_TCP_MAXWIN << cb->tcpcb_recvscale < cb->tcpcb_rcvcountmax)
- cb->tcpcb_recvscale++;
-
- /* Stop all timers.*/
- cb->tcpcb_timers.retransmission = FNET_TCP_TIMER_OFF;
- cb->tcpcb_timers.connection = FNET_TCP_TIMER_OFF;
- cb->tcpcb_timers.abort = FNET_TCP_TIMER_OFF;
- cb->tcpcb_timers.round_trip = FNET_TCP_TIMER_OFF;
- cb->tcpcb_timers.persist = FNET_TCP_TIMER_OFF;
- cb->tcpcb_timers.keepalive = FNET_TCP_TIMER_OFF;
- cb->tcpcb_timers.delayed_ack = FNET_TCP_TIMER_OFF;
-
- /* Initialize the retransmission timeout.*/
- cb->tcpcb_rto = cb->tcpcb_crto = FNET_TCP_TIMERS_INIT;
-
- #if FNET_CFG_TCP_URGENT
- /* Initialize the receive urgent mark.*/
- cb->tcpcb_rcvurgmark = FNET_TCP_NOT_USED;
- #endif /* FNET_CFG_TCP_URGENT */
-
- /* Initialize Slow Start Threshold.*/
- cb->tcpcb_ssthresh = FNET_TCP_MAX_BUFFER;
-
- /* Clear the input buffer.*/
- if(sk->receive_buffer.count)
- fnet_socket_buffer_release(&sk->receive_buffer);
-
- }
-
- /************************************************************************
- * NAME: fnet_tcp_inputsk
- *
- * DESCRIPTION: This function processes the input segments of
- * the corresponding socket.
- *
- * RETURNS: TRUE if the input segment must be deleted. Otherwise
- * this function returns FALSE.
- *************************************************************************/
- static int fnet_tcp_inputsk( fnet_socket_t *sk, fnet_netbuf_t *insegment, struct sockaddr *src_addr, struct sockaddr *dest_addr)
- {
- fnet_tcp_control_t *cb = (fnet_tcp_control_t *)sk->protocol_control;
- fnet_tcp_control_t *pcb; /* Pointer to the partial control block.*/
- unsigned char sgmtype; /* Flags of the segment.*/
- fnet_socket_t *psk; /* Pointer to the partial socket.*/
- int result = FNET_TRUE;
- char options[FNET_TCP_MAX_OPT_SIZE];
- char optionlen;
- unsigned long repsize; /* Size of repeated data.*/
- int ackparam = 0; /* Acknowledgment parameter.*/
- unsigned long tcp_seq = fnet_ntohl(FNET_TCP_SEQ(insegment));
- unsigned long tcp_length = (unsigned long)FNET_TCP_LENGTH(insegment);
- unsigned long tcp_ack = fnet_ntohl(FNET_TCP_ACK(insegment));
-
- /* Get the flags.*/
- sgmtype = (unsigned char)(FNET_TCP_FLAGS(insegment));
-
- /* Check the sequence number.*/
- switch(cb->tcpcb_connection_state)
- {
- case FNET_TCP_CS_SYN_SENT:
- case FNET_TCP_CS_LISTENING:
- break;
-
- case FNET_TCP_CS_SYN_RCVD:
- if(cb->tcpcb_prev_connection_state == FNET_TCP_CS_SYN_SENT && (sgmtype & FNET_TCP_SGT_SYN))
- {
- /* Check the sequence number for simultaneouos open.*/
- if(tcp_seq == cb->tcpcb_sndack - 1)
- break;
- }
- default:
- if(FNET_TCP_COMP_G(cb->tcpcb_sndack, tcp_seq))
- {
- if(FNET_TCP_COMP_G(tcp_seq + insegment->total_length - tcp_length, cb->tcpcb_sndack))
- {
- /* Delete the left repeated part.*/
- repsize = fnet_tcp_getsize(tcp_seq, cb->tcpcb_sndack);
- fnet_netbuf_cut_center(&insegment, (int)tcp_length, (int)repsize);
-
- /* If urgent flag is present, recalculate of the urgent pointer.*/
- if(sgmtype & FNET_TCP_SGT_URG)
- {
- if((int)fnet_ntohs(FNET_TCP_URG(insegment)) - (int)repsize >= 0)
- {
- FNET_TCP_URG(insegment) = fnet_htons((…
Large files files are truncated, but you can click here to view the full file