/*************************************************************************************** File: tcp.c Date: 10.7.2002 Version: 0.1 Author: Jari Lahti (jari@violasystems.com) Description: This file contains TCP processing functionality Version Info: 10.7.2002 - First version (JaL) ***************************************************************************************/ #include "opentcp.h" //#include "../../../Examples/Quadros_ss+OpenTCP/Mcf523x/tcpTest/C_Source/mcu_port.h" struct TCPFrame ReceivedTCPPacket; struct tcb TCPSocket[NO_OF_TCPSOCKETS + 1]; UINT8 tcp_tempbuf[MIN_TCP_HLEN + 1]; /* structure we use to keep track on tx & rx stuff */ /* this is needed for easy integration of opentcp principles */ /* and Motorola eth drivers without lot of re-code */ extern struct { INT16 unprocessed; /* Number of unprocessed rx packets */ INT16 next_receive; /* The entry in RxNBUF we receive */ NBUF* cur_rxframe; /* current nbuf entry we are using */ NBUF* cur_txframe; /* current nbuf entry we are using */ UINT8* rxp; /* Read pointer */ UINT8* txp; /* Write pointer */ } eth_wrapper; /*******************************************************************************/ /******* TCP API functions ********/ /*******************************************************************************/ /******************************************************************************** Function: tcp_getsocket Parameters: UINT8 soctype - type of socket wanted (client, server or clientserver) UINT8 tos - type of service for socket UINT16 tout - timeout of socket in seconds INT32 (*listener)(INT8, UINT8, UINT32, UINT32) - listening function Return val: INT8 - (-1) = Error - >0 = handle to reserved socket Date: 21.7.2002 Desc: Try to get free socket from socket pool and return handle to it *********************************************************************************/ INT8 tcp_getsocket (UINT8 soctype, UINT8 tos, UINT16 tout, INT32 (*listener)(INT8, UINT8, UINT32, UINT32) ) { INT8 i; struct tcb* soc; if( NO_OF_TCPSOCKETS < 0 ) return(-1); if( NO_OF_TCPSOCKETS == 0 ) return(-1); if( (soctype != TCP_TYPE_SERVER) && (soctype != TCP_TYPE_CLIENT) && (soctype != TCP_TYPE_CLIENT_SERVER) && (soctype != TCP_TYPE_NONE) ) { DEBUGOUT("Invalid socket type requested\r\n"); return(-1); } if(listener == 0) { DEBUGOUT("ERROR:Event listener function not specified\r\n"); return(-1); } DEBUGOUT("Searching for free TCP socket...\r\n"); for(i=0; i < NO_OF_TCPSOCKETS; i++) { soc = &TCPSocket[i]; /* Get Socket */ if(soc->state == TCP_STATE_FREE) { /* We found it */ DEBUGOUT("Free socket found\r\n"); soc->state = TCP_STATE_RESERVED; soc->type = soctype; soc->tos = tos; soc->event_listener = listener; soc->rem_ip = 0; soc->remport = 0; soc->locport = 0; soc->flags = 0; soc->mss = (UINT16)TCP_MIN_MSS; soc->tout = (UINT32)tout * TIMERTIC; return(i); } } /* We are there so no socket found */ DEBUGOUT("No socket found\r\n"); return(-1); } /******************************************************************************** Function: tcp_releasesocket Parameters: INT8 sochandle - handle to socket to be released Return val: INT8 - (-1) = Error - >0 = handle to released socket Date: 21.7.2002 Desc: Try to release given socket *********************************************************************************/ INT8 tcp_releasesocket (INT8 sochandle) { struct tcb* soc; if( NO_OF_TCPSOCKETS < 0 ) return(-1); if( NO_OF_TCPSOCKETS == 0 ) return(-1); if( sochandle > NO_OF_TCPSOCKETS ) { DEBUGOUT("Socket handle non-valid\r\n"); return(-1); } if( sochandle < 0 ) { DEBUGOUT("Socket handle non-valid\r\n"); return(-1); } soc = &TCPSocket[sochandle]; /* Get referense */ if( (soc->state != TCP_STATE_FREE) && (soc->state != TCP_STATE_RESERVED) && (soc->state != TCP_STATE_CLOSED) ) { DEBUGOUT("Socket is not on valid state to be released\r\n"); return(-1); } /* We are there so all OK */ soc->state = TCP_STATE_FREE; soc->type = TCP_TYPE_NONE; soc->tos = 0; soc->event_listener = 0; soc->rem_ip = 0; soc->remport = 0; soc->locport = 0; soc->flags = 0; return(sochandle); } /******************************************************************************** Function: tcp_listen Parameters: INT8 sochandle - handle to socket to be placed on listen UINT16 port - port to listen for Return val: INT8 - (-1) = Error - >0 = Handle to listening socket (OK) Date: 12.7.2002 Desc: Try to set TCP socket to listen on given port *********************************************************************************/ INT8 tcp_listen (INT8 sochandle, UINT16 port) { struct tcb* soc; if( NO_OF_TCPSOCKETS < 0 ) return(-1); if( NO_OF_TCPSOCKETS == 0 ) return(-1); if( sochandle > NO_OF_TCPSOCKETS ) { DEBUGOUT("Socket handle non-valid\r\n"); return(-1); } if( sochandle < 0 ) { DEBUGOUT("Socket handle non-valid\r\n"); return(-1); } soc = &TCPSocket[sochandle]; /* Get referense */ if( (soc->type & TCP_TYPE_SERVER) == 0 ) { DEBUGOUT("Socket has no server properties\r\n"); return(-1); } if( soc->event_listener == 0) { DEBUGOUT("ERROR:No event listener function specified\r\n"); return(-1); } if( (soc->state != TCP_STATE_RESERVED) && (soc->state != TCP_STATE_LISTENING) && (soc->state != TCP_STATE_CLOSED) && (soc->state != TCP_STATE_TIMED_WAIT) ) { DEBUGOUT("Not possible to listen, socket on connected state\r\n"); return(-1); } /* Init socket */ soc->state = TCP_STATE_LISTENING; //soc->type = TCP_TYPE_SERVER; soc->flags = 0; soc->rem_ip = 0; soc->remport = 0; soc->locport = port; soc->send_unacked = 0; soc->myflags = 0; soc->send_next = 0xFFFFFFFF; soc->send_mtu = TCP_DEF_MTU; //soc->rtt = 0; soc->receive_next = 0; soc->retries_left = 0; DEBUGOUT("TCP listening socket created\r\n"); return(sochandle); } /******************************************************************************** Function: tcp_connect Parameters: UINT8 sochandle - handle to socket to be used UINT32 ip - ip address to connect to UINT16 rport - port to connect to UINT16 myport - local port Return val: INT8 - (-1) = Error - >0 = Connection procedure started (OK) Date: 21.7.2002 Desc: Try to connect to remote IP & port *********************************************************************************/ INT8 tcp_connect (INT8 sochandle, UINT32 ip, UINT16 rport, UINT16 myport ) { struct tcb* soc; DEBUGOUT("FUNCTION: tcp_connect\r\n"); if( NO_OF_TCPSOCKETS < 0 ) return(-1); if( NO_OF_TCPSOCKETS == 0 ) return(-1); if( sochandle > NO_OF_TCPSOCKETS ) { DEBUGOUT("Socket handle non-valid\r\n"); return(-1); } if( sochandle < 0 ) { DEBUGOUT("Socket handle non-valid\r\n"); return(-1); } /* Is the local port defined */ if( myport == 0 ) myport = tcp_getfreeport(); if( myport == 0 ) return(-1); soc = &TCPSocket[sochandle]; /* Get referense */ /* Do we have client properties? */ if( (soc->type & TCP_TYPE_CLIENT) == 0 ) { DEBUGOUT("Socket has no client properties\r\n"); return(-1); } if( soc->event_listener == 0) { DEBUGOUT("ERROR:No event listener function specified\r\n"); return(-1); } /* Are we on LISTENING, RESERVED or CLOSED state */ if( (soc->state != TCP_STATE_RESERVED) && (soc->state != TCP_STATE_LISTENING) && (soc->state != TCP_STATE_CLOSED) ) { DEBUGOUT("Socket on unvalid state to initialize CONNECT\r\n"); return(-1); } /* Then just set parameters and send SYN */ soc->rem_ip = ip; soc->remport = rport; soc->locport = myport; soc->flags = 0; soc->send_mtu = TCP_DEF_MTU; /* get initial sequence number */ soc->send_unacked = tcp_initseq(); soc->send_next = soc->send_unacked + 1; soc->myflags = TCP_FLAG_SYN; tcp_sendcontrol(sochandle); tcp_newstate(soc, TCP_STATE_SYN_SENT); return(sochandle); } /******************************************************************************** Function: tcp_send Parameters: INT8 sockethandle - handle to processed socket UINT8* buf - data buffer (start of user data) UINT16 blen - buffer length in bytes (user space) UINT16 dlen - legth of data in bytes (user data) Return val: INT16 - (-1) Not OK >0 Number of bytes sent Date: 25.7.2002 Desc: Send user data by using TCP *********************************************************************************/ INT16 tcp_send (INT8 sockethandle, UINT8* buf, UINT16 blen, UINT16 dlen) { struct tcb* soc; DEBUGOUT("Entering to send TCP data packet\r\n"); if( sockethandle < 0 ) { DEBUGOUT("ERROR:Socket Handle not valid (<0)\r\n"); return(-1); } if( sockethandle > NO_OF_TCPSOCKETS ) { DEBUGOUT("ERROR:Socket Handle not valid (>NO_OF_TCPSOCKETS)\r\n"); return(-1); } soc = &TCPSocket[sockethandle]; /* Get socket */ if(soc->state != TCP_STATE_CONNECTED) { DEBUGOUT("TCP is not connected!!\r\n"); return(-1); } if(soc->send_unacked != soc->send_next) { DEBUGOUT("TCP contains unacked data, cannot send more\r\n"); return(-1); } //IAS if( dlen > soc->mss) dlen=soc->mss; ///IAS if( dlen > blen ) dlen = blen; if(dlen + MIN_TCP_HLEN > soc->send_mtu) { if(soc->send_mtu > MIN_TCP_HLEN) dlen = soc->send_mtu - MIN_TCP_HLEN; else return(-1); } soc->send_next += dlen; soc->myflags = TCP_FLAG_ACK | TCP_FLAG_PUSH; //ProcessTCPOut(sockethandle, buf - MIN_TCP_HLEN, blen + MIN_TCP_HLEN + 1, dlen); ProcessTCPOut(sockethandle, buf - (UINT8)(TCP_APP_OFFSET - 1) , blen + TCP_APP_OFFSET +1 , dlen); return(dlen); } /******************************************************************************** Function: tcp_close Parameters: INT8 sochandle - handle to socket to be closed Return val: INT8 - (-2) = Unacked data, try again - (-1) = Error (General) - >0 = Handle to closed socket (OK) Date: 21.7.2002 Desc: Try to close socket to closed state *********************************************************************************/ INT8 tcp_close (INT8 sochandle) { struct tcb* soc; DEBUGOUT("FUNCTION: tcp_close\r\n"); if( NO_OF_TCPSOCKETS < 0 ) return(-1); if( NO_OF_TCPSOCKETS == 0 ) return(-1); if( sochandle > NO_OF_TCPSOCKETS ) { DEBUGOUT("Socket handle non-valid\r\n"); return(-1); } if( sochandle < 0 ) { DEBUGOUT("Socket handle non-valid\r\n"); return(-1); } soc = &TCPSocket[sochandle]; /* Get referense */ switch(soc->state) { case TCP_STATE_LISTENING: tcp_newstate(soc, TCP_STATE_CLOSED); break; case TCP_STATE_SYN_RECEIVED: soc->myflags = TCP_FLAG_ACK | TCP_FLAG_FIN; soc->send_unacked++; soc->send_next++; tcp_sendcontrol(sochandle); tcp_newstate(soc, TCP_STATE_FINW1); break; case TCP_STATE_SYN_SENT: tcp_newstate(soc, TCP_STATE_CLOSED); break; case TCP_STATE_FINW1: case TCP_STATE_FINW2: case TCP_STATE_CLOSING: case TCP_STATE_TIMED_WAIT: case TCP_STATE_LAST_ACK: /* We are closing already */ break; case TCP_STATE_CONNECTED: /* Is there unacked data? */ if(soc->send_unacked == soc->send_next ) { /* There is no unacked data */ soc->myflags = TCP_FLAG_ACK | TCP_FLAG_FIN; soc->send_next++; tcp_sendcontrol(sochandle); tcp_newstate(soc, TCP_STATE_FINW1); } else { /* Can't do much but raise pollable flag to soc->flags */ /* and process it on tcp_poll */ soc->flags |= TCP_INTFLAGS_CLOSEPENDING; return(sochandle); } break; default: return(-1); } return(sochandle); } /******************************************************************************** Function: tcp_getstate Parameters: INT8 sochandle - handle to socket to be queried Return val: INT8 - (-1) = Error - >0 = State of socket Date: 21.7.2002 Desc: Return the state of wanted socket *********************************************************************************/ INT8 tcp_getstate (INT8 sochandle) { struct tcb* soc; if( NO_OF_TCPSOCKETS < 0 ) return(-1); if( NO_OF_TCPSOCKETS == 0 ) return(-1); if( sochandle > NO_OF_TCPSOCKETS ) { DEBUGOUT("Socket handle non-valid\r\n"); return(-1); } if( sochandle < 0 ) { DEBUGOUT("Socket handle non-valid\r\n"); return(-1); } soc = &TCPSocket[sochandle]; /* Get referense */ return(soc->state); } /******************************************************************************** Function: tcp_checksend Parameters: UINT8 sochandle - handle to socket to be inspected Return val: INT16 - (-1) = Not possible to send - >0 = Free buffer space Date: 23.7.2002 Desc: Check is it possible to send data by using given socket *********************************************************************************/ INT16 tcp_checksend (UINT8 sochandle) { struct tcb* soc; if( NO_OF_TCPSOCKETS < 0 ) return(-1); if( NO_OF_TCPSOCKETS == 0 ) return(-1); if( sochandle > NO_OF_TCPSOCKETS ) { DEBUGOUT("Socket handle non-valid\r\n"); return(-1); } soc = &TCPSocket[sochandle]; /* Get referense */ if(soc->state != TCP_STATE_CONNECTED) return(-1); if(soc->send_unacked == soc->send_next) return(soc->send_mtu); return(-1); } /******************************************************************************** Function: tcp_abort Parameters: INT8 sochandle - handle to socket to be aborted Return val: INT8 - (-1) = Error - >0 = Handle to aborted socket Date: 21.7.2002 Desc: Reset connection and place socket to closed state *********************************************************************************/ INT8 tcp_abort (INT8 sochandle) { struct tcb* soc; DEBUGOUT("FUNCTION: tcp_abort\r\n"); if( NO_OF_TCPSOCKETS < 0 ) return(-1); if( NO_OF_TCPSOCKETS == 0 ) return(-1); if( sochandle > NO_OF_TCPSOCKETS ) { DEBUGOUT("Socket handle non-valid\r\n"); return(-1); } if( sochandle < 0 ) { DEBUGOUT("Socket handle non-valid\r\n"); return(-1); } soc = &TCPSocket[sochandle]; /* Get referense */ switch (soc->state) { case TCP_STATE_FREE: return(-1); case TCP_STATE_RESERVED: case TCP_STATE_CLOSED: return(sochandle); case TCP_STATE_TIMED_WAIT: case TCP_STATE_LISTENING: tcp_newstate(soc, TCP_STATE_CLOSED); return(sochandle); case TCP_STATE_SYN_SENT: case TCP_STATE_SYN_RECEIVED: case TCP_STATE_CONNECTED: case TCP_STATE_FINW1: case TCP_STATE_FINW2: case TCP_STATE_CLOSING: case TCP_STATE_LAST_ACK: soc->myflags = TCP_FLAG_RESET; tcp_sendcontrol(sochandle); tcp_newstate(soc, TCP_STATE_CLOSED); return(sochandle); default: return(-1); } } /******************************************************************************** Function: tcp_poll Parameters: void Return val: void Date: 19.7.2002 Desc: Poll TCP sockets for timeout *********************************************************************************/ void tcp_poll (void) { struct tcb* soc; static UINT8 handle = 0; UINT8 i; INT32 temp; UINT8 old_retries; if(handle >= NO_OF_TCPSOCKETS) handle = 0; for(i=0; i < NO_OF_TCPSOCKETS; i++ ) { if(handle >= NO_OF_TCPSOCKETS) handle = 0; soc = &TCPSocket[handle]; switch(soc->state) { case TCP_STATE_FREE: case TCP_STATE_RESERVED: case TCP_STATE_CLOSED: case TCP_STATE_LISTENING: break; case TCP_STATE_CONNECTED: /* In CONNECTED State we have */ /* something to do only if we have unacked data */ /* or if connection has been IDLE too long or */ /* unserved close is isuued by user */ /* or we want to keep lower layer alive */ /* if(soc->send_next > soc->send_unacked) temp = soc->send_next - soc->send_unacked; else temp = soc->send_unacked - soc->send_next; */ temp = soc->send_next - soc->send_unacked; /* Unserved Close? */ if(soc->flags & TCP_INTFLAGS_CLOSEPENDING) { /* Can we send the close now */ if(temp == 0) { soc->myflags = TCP_FLAG_ACK | TCP_FLAG_FIN; soc->send_next++; tcp_sendcontrol(handle); tcp_newstate(soc, TCP_STATE_FINW1); soc->flags ^= TCP_INTFLAGS_CLOSEPENDING; handle++; return; } } /* Socket timeout? */ if(check_timer(soc->persist_timerh) == 0) { soc->myflags = TCP_FLAG_ACK | TCP_FLAG_FIN; soc->send_next++; tcp_sendcontrol(handle); tcp_newstate(soc, TCP_STATE_FINW1); /* Inform application */ soc->event_listener(handle, TCP_EVENT_CLOSE, soc->rem_ip, soc->remport); handle++; return; } /* Is there unacked data? */ if(temp == 0) { /* Make sure we do not enter to retransmit imidiately when data */ /* But if ARP is not ready ensure fast retransmit */ if( arp_keepcache(soc->rem_ip) < 0 ) init_timer(soc->retransmit_timerh, TCP_INIT_RETRY_TOUT); else init_timer(soc->retransmit_timerh, TCP_DEF_RETRY_TOUT); break; } /* Is there timeout? */ if( check_timer(soc->retransmit_timerh) != 0 ) break; DEBUGOUT("Timeout on CONNECTED State\r\n"); /* De we have retries left */ if(soc->retries_left == 0) { /* No retries, must reset */ DEBUGOUT("Retries used up, resetting\r\n"); soc->myflags = TCP_FLAG_RESET; tcp_sendcontrol(handle); /* Inform application */ soc->event_listener(handle, TCP_EVENT_ABORT, soc->rem_ip, soc->remport); if(soc->type & TCP_TYPE_SERVER ) tcp_newstate(soc, TCP_STATE_LISTENING); else tcp_newstate(soc, TCP_STATE_CLOSED); handle++; return; } soc->retries_left--; init_timer(soc->retransmit_timerh, TCP_DEF_RETRY_TOUT); /* Yep, there is unacked data */ /* Application should send the old data */ if(temp>soc->send_mtu) temp = soc->send_mtu; /* Rewind Send Next because the send process will adjust it */ /* So cheat the tcp_send to think there is no unacked data */ soc->send_next = soc->send_unacked; /* tcp_send will set the retries_left to maximum but this is */ /* retransmitting already so we need to retain it in order to */ /* avoid dead-lock */ old_retries = soc->retries_left; temp = soc->event_listener(handle, TCP_EVENT_REGENERATE, (UINT32)temp, 0); soc->retries_left = old_retries; if(temp <= 0) { /* No data by application, must be something wrong */ soc->myflags = TCP_FLAG_RESET; tcp_sendcontrol(handle); /* Inform application */ soc->event_listener(handle, TCP_EVENT_ABORT, soc->rem_ip, soc->remport); if(soc->type & TCP_TYPE_SERVER ) tcp_newstate(soc, TCP_STATE_LISTENING); else tcp_newstate(soc, TCP_STATE_CLOSED); handle++; return; } /* Application has send data */ handle++; return; case TCP_STATE_SYN_SENT: case TCP_STATE_SYN_RECEIVED: /* Is there timeout? */ if( check_timer(soc->retransmit_timerh) != 0 ) break; DEBUGOUT("Timeout\r\n"); /* Yep, timeout. Is there reties left? */ if( soc->retries_left ) { soc->retries_left--; if(soc->state == TCP_STATE_SYN_SENT) init_timer(soc->retransmit_timerh, TCP_SYN_RETRY_TOUT); else init_timer(soc->retransmit_timerh, TCP_DEF_RETRY_TOUT); tcp_sendcontrol(handle); handle++; return; } else { /* Retries used up */ DEBUGOUT("Retries used up, resetting\r\n"); if(soc->type & TCP_TYPE_SERVER ) tcp_newstate(soc, TCP_STATE_LISTENING); else tcp_newstate(soc, TCP_STATE_CLOSED); soc->myflags = TCP_FLAG_RESET; tcp_sendcontrol(handle); /* Inform application */ soc->event_listener(handle, TCP_EVENT_ABORT, soc->rem_ip, soc->remport); handle++; return; } break; case TCP_STATE_TIMED_WAIT: /* Is there timeout? */ if( check_timer(soc->retransmit_timerh) != 0 ) break; DEBUGOUT("Timeout\r\n"); if(soc->retries_left) { soc->retries_left--; init_timer(soc->retransmit_timerh, TCP_DEF_RETRY_TOUT); break; } if(soc->type & TCP_TYPE_SERVER ) tcp_newstate(soc, TCP_STATE_LISTENING); else tcp_newstate(soc, TCP_STATE_CLOSED); break; case TCP_STATE_LAST_ACK: case TCP_STATE_FINW1: case TCP_STATE_CLOSING: /* Is there timeout? */ if( check_timer(soc->retransmit_timerh) != 0 ) break; DEBUGOUT("Timeout\r\n"); /* Yep, timeout. Is there reties left? */ if( soc->retries_left ) { soc->retries_left--; init_timer(soc->retransmit_timerh, TCP_DEF_RETRY_TOUT); soc->myflags = TCP_FLAG_FIN | TCP_FLAG_ACK; tcp_sendcontrol(handle); handle++; return; } else { /* Retries used up */ DEBUGOUT("Retries used up, resetting\r\n"); if(soc->type & TCP_TYPE_SERVER ) tcp_newstate(soc, TCP_STATE_LISTENING); else tcp_newstate(soc, TCP_STATE_CLOSED); soc->myflags = TCP_FLAG_RESET; tcp_sendcontrol(handle); /* Inform application */ soc->event_listener(handle, TCP_EVENT_ABORT, soc->rem_ip, soc->remport); handle++; return; } break; case TCP_STATE_FINW2: /* Is there timeout? */ if( check_timer(soc->retransmit_timerh) != 0 ) break; DEBUGOUT("Timeout\r\n"); /* Yep, timeout. Is there reties left? */ if( soc->retries_left ) { /* Still keep waiting for FIN */ soc->retries_left--; init_timer(soc->retransmit_timerh, TCP_DEF_RETRY_TOUT); break; } else { /* Retries used up */ DEBUGOUT("Retries used up, resetting\r\n"); if(soc->type & TCP_TYPE_SERVER ) tcp_newstate(soc, TCP_STATE_LISTENING); else tcp_newstate(soc, TCP_STATE_CLOSED); soc->myflags = TCP_FLAG_RESET; tcp_sendcontrol(handle); /* Inform application */ soc->event_listener(handle, TCP_EVENT_ABORT, soc->rem_ip, soc->remport); handle++; return; } break; default: break; } /* Go to next socket if there was no event */ handle++; } } /******************************************************************************** Function: tcp_init Parameters: - Return val: INT8 - (-1) = Error - >0 = Number of sockets initialized Date: 14.6.2002 Desc: Set TCP sockets to known values. Called once when processor starts! *********************************************************************************/ INT8 tcp_init (void) { UINT16 i; INT16 h; struct tcb* soc; if( NO_OF_TCPSOCKETS < 0 ) return(-1); if( NO_OF_TCPSOCKETS == 0 ) return(0); DEBUGOUT("Initializing TCP"); for(i=0; i < NO_OF_TCPSOCKETS; i++) { soc = &TCPSocket[i]; /* Get Socket */ h = -1; soc->state = TCP_STATE_FREE; soc->type = TCP_TYPE_NONE; soc->flags = 0; soc->rem_ip = 0; soc->remport = 0; soc->locport = 0; soc->myflags = 0; soc->send_mtu = TCP_DEF_MTU; soc->tos = 0; soc->tout = 0; soc->event_listener = 0; /* Reserve Timers */ h = get_timer(); if( h < 0 ) { DEBUGOUT("\n\rERROR:Error getting timer for TCP Socket!\n\r"); return(-1); } init_timer(h,0); /* No timeout */ soc->persist_timerh = h; h = get_timer(); if( h < 0 ) { DEBUGOUT("\n\rERROR:Error getting timer for TCP Socket!\n\r"); return(-1); } init_timer(h,0); /* No timeout */ soc->retransmit_timerh = h; soc->retries_left = 0; DEBUGOUT("."); } DEBUGOUT("\n\rTCP Initialized\n\r"); /* Return number of sockets initialized */ return(i+1); } /*******************************************************************************/ /******* TCP Internal functions ********/ /*******************************************************************************/ /******************************************************************************** Function: ProcessTCPIn Parameters: struct IPFrame* frame - pointer to received IP frame structure UINT16 len - legth of data in bytes Return val: INT16 - (-1) Not OK >0 Packet OK Date: 12.7.2002 Desc: Check and process received TCP frame *********************************************************************************/ INT16 ProcessTCPIn (struct IPFrame* frame, UINT16 len) { struct tcb* soc; UINT16 hlen; UINT8 olen; UINT8 oKind; //IAS UINT8 oPLen; //IAS UINT16 dlen; UINT16 i; INT8 sochandle; INT16 temp; /* Is this TCP? */ DEBUGOUT("Processing TCP...\n\r"); if( frame->protocol != IP_TCP ) { DEBUGOUT("ERROR: The protocol is not TCP\n\r"); return(-1); } /* Calculate checksum for received packet */ NETWORK_RECEIVE_INITIALIZE(frame->BufIndex); if( TCP_CheckCS(frame, len) == 1) { DEBUGOUT("TCP Checksum OK\n\r"); } else { DEBUGOUT("ERROR:TCP Checksum failed\r\n"); return(-1); } /* Get the header */ NETWORK_RECEIVE_INITIALIZE(frame->BufIndex); ReceivedTCPPacket.sport = RECEIVE_NETWORK_B(); ReceivedTCPPacket.sport <<= 8; ReceivedTCPPacket.sport |= RECEIVE_NETWORK_B(); ReceivedTCPPacket.dport = RECEIVE_NETWORK_B(); ReceivedTCPPacket.dport <<= 8; ReceivedTCPPacket.dport |= RECEIVE_NETWORK_B(); ReceivedTCPPacket.seqno = RECEIVE_NETWORK_B(); ReceivedTCPPacket.seqno <<= 8; ReceivedTCPPacket.seqno |= RECEIVE_NETWORK_B(); ReceivedTCPPacket.seqno <<= 8; ReceivedTCPPacket.seqno |= RECEIVE_NETWORK_B(); ReceivedTCPPacket.seqno <<= 8; ReceivedTCPPacket.seqno |= RECEIVE_NETWORK_B(); ReceivedTCPPacket.ackno = RECEIVE_NETWORK_B(); ReceivedTCPPacket.ackno <<= 8; ReceivedTCPPacket.ackno |= RECEIVE_NETWORK_B(); ReceivedTCPPacket.ackno <<= 8; ReceivedTCPPacket.ackno |= RECEIVE_NETWORK_B(); ReceivedTCPPacket.ackno <<= 8; ReceivedTCPPacket.ackno |= RECEIVE_NETWORK_B(); ReceivedTCPPacket.hlen_flags = RECEIVE_NETWORK_B(); ReceivedTCPPacket.hlen_flags <<= 8; ReceivedTCPPacket.hlen_flags |= RECEIVE_NETWORK_B(); ReceivedTCPPacket.window = RECEIVE_NETWORK_B(); ReceivedTCPPacket.window <<= 8; ReceivedTCPPacket.window |= RECEIVE_NETWORK_B(); ReceivedTCPPacket.checksum = RECEIVE_NETWORK_B(); ReceivedTCPPacket.checksum <<= 8; ReceivedTCPPacket.checksum |= RECEIVE_NETWORK_B(); ReceivedTCPPacket.urgent = RECEIVE_NETWORK_B(); ReceivedTCPPacket.urgent <<= 8; ReceivedTCPPacket.urgent |= RECEIVE_NETWORK_B(); /* Little check for options */ hlen = ReceivedTCPPacket.hlen_flags & 0xF000; hlen >>= 10; if( hlen < MIN_TCP_HLEN ) { DEBUGOUT("ERROR: Received TCP Header too short\r\n"); return(-1); } if(hlen == MIN_TCP_HLEN) DEBUGOUT("TCP does not contain options\r\n"); olen = hlen - MIN_TCP_HLEN; if( olen > MAX_TCP_OPTLEN ) { DEBUGOUT("ERROR: Received TCP header contains too long option field\r\n"); return(-1); } /* Calculate data length */ if( hlen > len ) { DEBUGOUT("ERROR: TCP header longer than packet\r\n"); return(-1); } dlen = len - hlen - olen; /* Get options (if any) */ for(i=0; isip); return(-1); } //DEBUGOUT("here\r\n"); ReceivedTCPPacket.BufIndex = frame->BufIndex + hlen; NETWORK_RECEIVE_INITIALIZE(ReceivedTCPPacket.BufIndex); /* Get socket reference */ soc = &TCPSocket[sochandle]; /* Process the packet on TCP State Machine */ switch(soc->state) { case TCP_STATE_CONNECTED: DEBUGOUT("CONNECTED State\r\n"); /* Check for RESET */ if(ReceivedTCPPacket.hlen_flags & TCP_FLAG_RESET) { DEBUGOUT("ERROR:Reset received\r\n"); /* Inform application */ soc->event_listener(sochandle, TCP_EVENT_ABORT, soc->rem_ip, soc->remport); if(soc->type & TCP_TYPE_SERVER) tcp_newstate(soc, TCP_STATE_LISTENING); else tcp_newstate(soc, TCP_STATE_CLOSED); return(-1); } /* Check for SYN (If the peer didn't get our SYN+ACK or ACK) */ if( ReceivedTCPPacket.hlen_flags & TCP_FLAG_SYN ) { /* Is it the SYN+ACK we have already ACKed but maybe ACK lost? */ if( ReceivedTCPPacket.hlen_flags & TCP_FLAG_ACK ) { /* It's SYN+ACK but how about sequence */ if( (ReceivedTCPPacket.seqno + 1) == soc->receive_next ) { if( ReceivedTCPPacket.ackno == soc->send_next ) { DEBUGOUT("Received SYN+ACK again\r\n"); /* ACK the SYN */ soc->myflags = TCP_FLAG_ACK; tcp_sendcontrol(sochandle); return(0); } } /* It is maybe SYN again so it haven't get our SYN + ACK */ /* Let our retransmission handle it */ return(0); } } /* Do we have unacked data? */ if( soc->send_unacked != soc->send_next ) { /* Yep, is the ACK valid? */ if( (ReceivedTCPPacket.hlen_flags & TCP_FLAG_ACK) == 0) { DEBUGOUT("Packet without ACK and unacked data. Packet not processed\r\n"); return(0); } if( ReceivedTCPPacket.ackno == soc->send_next ) { /* We don't have unacked data now */ soc->send_unacked = soc->send_next; /* Inform application */ soc->event_listener(sochandle, TCP_EVENT_ACK, soc->rem_ip, soc->remport); } } /* Is the sequence OK */ if(soc->receive_next != ReceivedTCPPacket.seqno) { /* Out of range, inform what we except */ DEBUGOUT("Too big sequence number received\r\n"); soc->myflags = TCP_FLAG_ACK; tcp_sendcontrol(sochandle); return(0); } /* Generate data event to application */ //IAS //soc->event_listener(sochandle, TCP_EVENT_DATA, dlen, (UINT32)ReceivedTCPPacket.ackno); //IAS if(dlen>0){ DEBUGOUT("Giving data to listener\r\n"); soc->event_listener(sochandle, TCP_EVENT_DATA, dlen, (UINT32)ReceivedTCPPacket.ackno); }else{ DEBUGOUT("No data, not giving to listener\r\n"); } //original //soc->event_listener(sochandle, TCP_EVENT_DATA, dlen, 0); //IAS ///IAS soc->receive_next += dlen; #if 0 diff = soc->receive_next - ReceivedTCPPacket.seqno; if( diff > TCP_HALF_SEQ_SPACE ) { /* Out of range, inform what we except */ DEBUGOUT("Too big sequence number received\r\n"); soc->myflags = TCP_FLAG_ACK; tcp_sendcontrol(sochandle); return(0); } /* Does the packet contain data that we don't have already */ if( dlen > diff ) { /* Consume old data */ for(i=0; ievent_listener(sochandle, TCP_EVENT_DATA, dlen - diff, 0); soc->receive_next += dlen - diff; } #endif /* Is the FIN flag set? */ if( ReceivedTCPPacket.hlen_flags & TCP_FLAG_FIN ) { DEBUGOUT("Other end want's to close\r\n"); /* Inform application if we don't have unacked data */ if( soc->send_unacked == soc->send_next) { soc->event_listener(sochandle, TCP_EVENT_CLOSE, soc->rem_ip, soc->remport); /* ACK FIN and set our own FIN */ soc->receive_next++; soc->send_next++; soc->myflags = TCP_FLAG_ACK | TCP_FLAG_FIN; tcp_newstate(soc, TCP_STATE_LAST_ACK); tcp_sendcontrol(sochandle); return(0); } } /* ACK the data if there was it */ if(dlen) { soc->myflags = TCP_FLAG_ACK; tcp_sendcontrol(sochandle); } /* Keep our socket from timeout */ tcp_newstate(soc, TCP_STATE_CONNECTED); //init_timer(soc->persist_timerh, soc->tout); return(0); break; case TCP_STATE_FREE: /* Reset connection */ tcp_sendreset(&ReceivedTCPPacket, frame->sip); return(-1); break; case TCP_STATE_CLOSED: /* Reset connection */ tcp_sendreset(&ReceivedTCPPacket, frame->sip); return(-1); break; case TCP_STATE_LISTENING: DEBUGOUT("LISTENING State...\r\n"); /* Check Flags */ if(ReceivedTCPPacket.hlen_flags & TCP_FLAG_RESET) { DEBUGOUT("ERROR:Reset received\r\n"); tcp_newstate(soc, TCP_STATE_LISTENING); return(-1); } if(ReceivedTCPPacket.hlen_flags & TCP_FLAG_ACK) { DEBUGOUT("ERROR:Ack received\r\n"); tcp_newstate(soc, TCP_STATE_LISTENING); /* Reset connection */ tcp_sendreset(&ReceivedTCPPacket, frame->sip); return(-1); } if((ReceivedTCPPacket.hlen_flags & TCP_FLAG_SYN) == 0) { DEBUGOUT("ERROR:No SYN set on packet\r\n"); tcp_newstate(soc, TCP_STATE_LISTENING); /* Reset connection */ tcp_sendreset(&ReceivedTCPPacket, frame->sip); return(-1); } /* OK, SYN received */ /* Inform application and see if accepted */ temp = (INT16)soc->event_listener(sochandle, TCP_EVENT_CONREQ, soc->rem_ip, soc->remport); if( temp == -1) { DEBUGOUT("Application disregarded connection request\r\n"); tcp_sendreset(&ReceivedTCPPacket, frame->sip); return(-1); } if( temp == -2 ) { DEBUGOUT("Application wants to think about accepting conreq\r\n"); return(1); } /* The connection request was accepted */ DEBUGOUT("Next state SYN_RECEIVED\r\n"); if(soc->flags & TCP_INTFLAGS_CLOSEPENDING) soc->flags ^= TCP_INTFLAGS_CLOSEPENDING; //IAS //get packet options we need MSS for optimization i=0; //olen offset while(imss = (UINT8)ReceivedTCPPacket.opt[i++]; soc->mss <<= 8; soc->mss |= (UINT8)ReceivedTCPPacket.opt[i++]; if(soc->mss > TCP_MAX_MSS) soc->mss = TCP_MAX_MSS; if(soc->mss < TCP_MIN_MSS) soc->mss = TCP_MIN_MSS; break; default: i+=oPLen; break; } continue; } break; } ///IAS tcp_newstate(soc, TCP_STATE_SYN_RECEIVED); soc->receive_next = ReceivedTCPPacket.seqno + 1; /* Ack SYN */ soc->send_unacked = tcp_initseq(); soc->myflags = TCP_FLAG_SYN | TCP_FLAG_ACK; tcp_sendcontrol(sochandle); soc->send_next = soc->send_unacked + 1; return(1); break; case TCP_STATE_SYN_RECEIVED: DEBUGOUT("SYN_RECEIVED State...\r\n"); /* Check Flags */ if(ReceivedTCPPacket.hlen_flags & TCP_FLAG_RESET) { DEBUGOUT("ERROR:Reset received\r\n"); /* Inform application */ soc->event_listener(sochandle, TCP_EVENT_ABORT, soc->rem_ip, soc->remport); if(soc->type & TCP_TYPE_SERVER) tcp_newstate(soc, TCP_STATE_LISTENING); else tcp_newstate(soc, TCP_STATE_CLOSED); return(-1); } /* Is it SYN+ACK (if we are the because of simultaneous open) */ if( (ReceivedTCPPacket.hlen_flags & TCP_FLAG_SYN) && (ReceivedTCPPacket.hlen_flags & TCP_FLAG_ACK) ) { if( ReceivedTCPPacket.ackno != soc->send_next ) { DEBUGOUT("SYN+ACK received but wrong Ack\n\r"); return(-1); } DEBUGOUT("SYN+ACK received, this side established\n\r"); /* Get peer's seq number */ soc->receive_next = ReceivedTCPPacket.seqno; soc->receive_next++; /* ACK SYN */ /* We have no unacked data */ soc->send_unacked = soc->send_next; tcp_newstate(soc, TCP_STATE_CONNECTED); soc->myflags = TCP_FLAG_ACK; tcp_sendcontrol(sochandle); /* Inform application */ soc->event_listener(sochandle, TCP_EVENT_CONNECTED, soc->rem_ip, soc->remport); return(0); } /* Is it ACK? */ if( ReceivedTCPPacket.hlen_flags & TCP_FLAG_ACK ) { if( ReceivedTCPPacket.ackno != soc->send_next ) { DEBUGOUT("ACK received but wrong Ack\n\r"); return(-1); } if( ReceivedTCPPacket.seqno != soc->receive_next ) { DEBUGOUT("ACK received but Wrong SEQ number\n\r"); return(-1); } DEBUGOUT("ACK received, this side CONNECTED\r\n"); /* We have no unacked data */ soc->send_unacked = soc->send_next; tcp_newstate(soc, TCP_STATE_CONNECTED); /* Inform application */ soc->event_listener(sochandle, TCP_EVENT_CONNECTED, soc->rem_ip, soc->remport); return(0); } /* Is it SYN? */ if( ReceivedTCPPacket.hlen_flags & TCP_FLAG_SYN ) { DEBUGOUT("Repeated SYN\r\n"); return(0); } /* We didn't understood this one, keep on trying but info with RESET */ DEBUGOUT("Unrecognized packet\n\r"); tcp_sendreset(&ReceivedTCPPacket, frame->sip); return(-1); break; case TCP_STATE_SYN_SENT: DEBUGOUT("SYN_SENT State\r\n"); /* Check for RESET */ if(ReceivedTCPPacket.hlen_flags & TCP_FLAG_RESET) { DEBUGOUT("ERROR:Reset received\r\n"); /* Inform application */ soc->event_listener(sochandle, TCP_EVENT_ABORT, soc->rem_ip, soc->remport); if(soc->type & TCP_TYPE_SERVER) tcp_newstate(soc, TCP_STATE_LISTENING); else tcp_newstate(soc, TCP_STATE_CLOSED); return(-1); } /* Is it SYN+ACK? */ if( (ReceivedTCPPacket.hlen_flags & TCP_FLAG_SYN) && (ReceivedTCPPacket.hlen_flags & TCP_FLAG_ACK) ) { /* Rigth ACK? */ if( ReceivedTCPPacket.ackno != soc->send_next ) { DEBUGOUT("SYN+ACK received but wrong Ack\n\r"); return(-1); } DEBUGOUT("SYN+ACK received, this side established\n\r"); /* Get peer's seq number */ soc->receive_next = ReceivedTCPPacket.seqno; soc->receive_next++; /* ACK SYN */ /* We have no unacked data */ soc->send_unacked = soc->send_next; tcp_newstate(soc, TCP_STATE_CONNECTED); soc->myflags = TCP_FLAG_ACK; tcp_sendcontrol(sochandle); /* Inform application */ soc->event_listener(sochandle, TCP_EVENT_CONNECTED, soc->rem_ip, soc->remport); return(0); } /* Is it SYN (simultaneous open) */ if(ReceivedTCPPacket.hlen_flags & TCP_FLAG_SYN) { DEBUGOUT("Simultaneous open, next SYN_RECEIVED\r\n"); /* Get peer's seq number */ soc->receive_next = ReceivedTCPPacket.seqno; soc->receive_next++; /* ACK SYN */ tcp_newstate(soc, TCP_STATE_SYN_RECEIVED); soc->myflags = TCP_FLAG_SYN | TCP_FLAG_ACK; tcp_sendcontrol(sochandle); return(0); } /* This is something we didn't understood, maybe the other peer has */ /* still old connection on or something */ tcp_sendreset(&ReceivedTCPPacket, frame->sip); return(-1); break; case TCP_STATE_FINW1: DEBUGOUT("FINW1 State\r\n"); /* Check for RESET */ if(ReceivedTCPPacket.hlen_flags & TCP_FLAG_RESET) { DEBUGOUT("ERROR:Reset received\r\n"); /* Inform application */ soc->event_listener(sochandle, TCP_EVENT_ABORT, soc->rem_ip, soc->remport); if(soc->type & TCP_TYPE_SERVER) tcp_newstate(soc, TCP_STATE_LISTENING); else tcp_newstate(soc, TCP_STATE_CLOSED); return(-1); } /* Is it FIN+ACK? */ if( (ReceivedTCPPacket.hlen_flags & TCP_FLAG_FIN) && (ReceivedTCPPacket.hlen_flags & TCP_FLAG_ACK) ) { /* Rigth ACK? */ if( ReceivedTCPPacket.ackno != soc->send_next ) { DEBUGOUT("FIN+ACK received but wrong Ack\n\r"); return(-1); } DEBUGOUT("FIN+ACK received, next TIMED_WAIT\n\r"); /* ACK FIN and all data */ soc->receive_next = ReceivedTCPPacket.seqno; soc->receive_next++; soc->receive_next += dlen; /* We have no unacked data */ soc->send_unacked = soc->send_next; tcp_newstate(soc, TCP_STATE_TIMED_WAIT); soc->myflags = TCP_FLAG_ACK; tcp_sendcontrol(sochandle); return(0); } /* Is it just FIN */ if( ReceivedTCPPacket.hlen_flags & TCP_FLAG_FIN ) { DEBUGOUT("Simultaneous close, next CLOSING\n\r"); /* ACK FIN and all data */ soc->receive_next = ReceivedTCPPacket.seqno; soc->receive_next++; soc->receive_next += dlen; tcp_newstate(soc, TCP_STATE_CLOSING); soc->myflags = TCP_FLAG_ACK; tcp_sendcontrol(sochandle); return(0); } /* Is it just ACK? */ if( ReceivedTCPPacket.hlen_flags & TCP_FLAG_ACK ) { /* Rigth ACK? */ if( ReceivedTCPPacket.ackno != soc->send_next ) { DEBUGOUT("ACK received but wrong Ack\n\r"); return(-1); } DEBUGOUT("Our FIN is ACKed but peer don't agree to disconnect yet\r\n"); DEBUGOUT("Next FINW2\r\n"); /* We have no unacked data */ soc->send_unacked = soc->send_next; tcp_newstate(soc, TCP_STATE_FINW2); return(0); } tcp_sendreset(&ReceivedTCPPacket, frame->sip); return(-1); break; case TCP_STATE_FINW2: DEBUGOUT("FINW2 State\r\n"); /* Check for RESET */ if(ReceivedTCPPacket.hlen_flags & TCP_FLAG_RESET) { DEBUGOUT("ERROR:Reset received\r\n"); /* Inform application */ soc->event_listener(sochandle, TCP_EVENT_ABORT, soc->rem_ip, soc->remport); if(soc->type & TCP_TYPE_SERVER) tcp_newstate(soc, TCP_STATE_LISTENING); else tcp_newstate(soc, TCP_STATE_CLOSED); return(-1); } /* Do we finally get FIN? */ if( ReceivedTCPPacket.hlen_flags & TCP_FLAG_FIN ) { DEBUGOUT("FIN received, next TIMED_WAIT\n\r"); /* ACK FIN and all data */ soc->receive_next = ReceivedTCPPacket.seqno; soc->receive_next++; soc->receive_next += dlen; tcp_newstate(soc, TCP_STATE_TIMED_WAIT); soc->myflags = TCP_FLAG_ACK; tcp_sendcontrol(sochandle); return(0); } tcp_sendreset(&ReceivedTCPPacket, frame->sip); return(-1); break; case TCP_STATE_CLOSING: DEBUGOUT("CLOSING State...\r\n"); /* Check for RESET */ if(ReceivedTCPPacket.hlen_flags & TCP_FLAG_RESET) { DEBUGOUT("ERROR:Reset received\r\n"); /* Inform application */ soc->event_listener(sochandle, TCP_EVENT_ABORT, soc->rem_ip, soc->remport); if(soc->type & TCP_TYPE_SERVER) tcp_newstate(soc, TCP_STATE_LISTENING); else tcp_newstate(soc, TCP_STATE_CLOSED); return(-1); } /* Is it ACK? */ if( ReceivedTCPPacket.hlen_flags & TCP_FLAG_ACK ) { /* Rigth ACK? */ if( ReceivedTCPPacket.ackno != soc->send_next ) { DEBUGOUT("ACK received but wrong Ack\n\r"); return(-1); } DEBUGOUT("Our FIN is ACKed and peer wants to close too\r\n"); DEBUGOUT("Next TIMED_WAIT\r\n"); /* We have no unacked data */ soc->send_unacked = soc->send_next; tcp_newstate(soc, TCP_STATE_TIMED_WAIT); return(0); } /* Is it repeated FIN? */ if( ReceivedTCPPacket.hlen_flags & TCP_FLAG_FIN ) { DEBUGOUT("Repeated FIN, repeat ACK\n\r"); /* ACK FIN and all data */ soc->receive_next = ReceivedTCPPacket.seqno; soc->receive_next++; soc->receive_next += dlen; soc->myflags = TCP_FLAG_ACK; tcp_sendcontrol(sochandle); return(0); } tcp_sendreset(&ReceivedTCPPacket, frame->sip); return(-1); break; case TCP_STATE_LAST_ACK: DEBUGOUT("LAST_ACK State...\r\n"); /* Check for RESET */ if(ReceivedTCPPacket.hlen_flags & TCP_FLAG_RESET) { DEBUGOUT("ERROR:Reset received\r\n"); /* Inform application */ soc->event_listener(sochandle, TCP_EVENT_ABORT, soc->rem_ip, soc->remport); if(soc->type & TCP_TYPE_SERVER) tcp_newstate(soc, TCP_STATE_LISTENING); else tcp_newstate(soc, TCP_STATE_CLOSED); return(-1); } /* Is it ACK? */ if( ReceivedTCPPacket.hlen_flags & TCP_FLAG_ACK ) { /* Rigth ACK? */ if( ReceivedTCPPacket.ackno != soc->send_next ) { DEBUGOUT("ACK received but wrong Ack\n\r"); return(-1); } DEBUGOUT("Last ACK received, next LISTENING or CLOSED\r\n"); /* We have no unacked data */ soc->send_unacked = soc->send_next; if(soc->type & TCP_TYPE_SERVER) tcp_newstate(soc, TCP_STATE_LISTENING); else tcp_newstate(soc, TCP_STATE_CLOSED); return(0); } /* Is it repeated FIN? */ if( ReceivedTCPPacket.hlen_flags & TCP_FLAG_FIN ) { DEBUGOUT("Repeated FIN, repeat ACK\n\r"); /* ACK FIN and all data */ soc->receive_next = ReceivedTCPPacket.seqno; soc->receive_next++; soc->receive_next += dlen; soc->myflags = TCP_FLAG_FIN | TCP_FLAG_ACK; tcp_sendcontrol(sochandle); return(0); } tcp_sendreset(&ReceivedTCPPacket, frame->sip); return(-1); break; case TCP_STATE_TIMED_WAIT: DEBUGOUT("TIMED_WAIT State...\r\n"); /* Check for RESET */ if(ReceivedTCPPacket.hlen_flags & TCP_FLAG_RESET) { DEBUGOUT("ERROR:Reset received\r\n"); /* Inform application */ soc->event_listener(sochandle, TCP_EVENT_ABORT, soc->rem_ip, soc->remport); if(soc->type & TCP_TYPE_SERVER) tcp_newstate(soc, TCP_STATE_LISTENING); else tcp_newstate(soc, TCP_STATE_CLOSED); return(-1); } /* Is it repeated FIN? */ if( ReceivedTCPPacket.hlen_flags & TCP_FLAG_FIN ) { DEBUGOUT("Repeated FIN, repeat ACK\n\r"); /* ACK FIN and all data */ soc->receive_next = ReceivedTCPPacket.seqno; soc->receive_next++; soc->receive_next += dlen; soc->myflags = TCP_FLAG_ACK; tcp_sendcontrol(sochandle); return(0); } tcp_sendreset(&ReceivedTCPPacket, frame->sip); return(-1); break; default: DEBUGOUT("ERROR:TCP State machine in unknown state!!\r\n"); tcp_sendreset(&ReceivedTCPPacket, frame->sip); RESET_SYSTEM(); } DEBUGOUT("Should not be there!\r\n"); return(-1); } /******************************************************************************** Function: ProcessTCPOut Parameters: INT8 sockethandle - handle to processed socket UINT8* buf - data buffer UINT16 blen - buffer length in bytes UINT16 dlen - legth of data in bytes Return val: INT16 - (-1) Not OK >0 Packet OK Date: 16.7.2002 Desc: Calculate checksum for TCP packet and send it to IP. Buffer must contain 21 bytes free on start of it for TCP //NOTE CHANGED TO 21 BYTES from 20 by IAS header assembly. *********************************************************************************/ INT16 ProcessTCPOut (INT8 sockethandle, UINT8* buf, UINT16 blen, UINT16 dlen) { struct tcb* soc; UINT16 cs; UINT8 cs_cnt; UINT8* buf_start; UINT16 hlen_incr; hlen_incr=0; DEBUGOUT("Entering to send TCP packet\r\n"); if( sockethandle < 0 ) { DEBUGOUT("ERROR:Socket Handle not valid (<0)\r\n"); return(-1); } if( sockethandle > NO_OF_TCPSOCKETS ) { DEBUGOUT("ERROR:Socket Handle not valid (>NO_OF_TCPSOCKETS)\r\n"); return(-1); } if( (dlen + MIN_TCP_HLEN) > blen ) //TODO I think this is flawed /IAS { DEBUGOUT("ERROR:Transmit buffer too small for TCP header\r\n"); return(-1); } soc = &TCPSocket[sockethandle]; /* Get socket */ //IAS if(soc->myflags == (TCP_FLAG_SYN | TCP_FLAG_ACK)) { hlen_incr=4; } buf+=(TCP_APP_OFFSET-MIN_TCP_HLEN-1-hlen_incr); blen-=(TCP_APP_OFFSET-MIN_TCP_HLEN-1-hlen_incr); ///IAS buf_start = buf; if( (dlen + MIN_TCP_HLEN + hlen_incr) > soc->send_mtu ) { DEBUGOUT("ERROR:Send MTU exceeded\r\n"); return(-1); } /* Assemble TCP header to buffer */ *buf++ = (UINT8)(soc->locport >> 8); *buf++ = (UINT8)soc->locport; *buf++ = (UINT8)(soc->remport >> 8); *buf++ = (UINT8)soc->remport; *buf++ = (UINT8)(soc->send_unacked >>24); *buf++ = (UINT8)(soc->send_unacked >>16); *buf++ = (UINT8)(soc->send_unacked >>8); *buf++ = (UINT8)(soc->send_unacked); *buf++ = (UINT8)(soc->receive_next >>24); *buf++ = (UINT8)(soc->receive_next >>16); *buf++ = (UINT8)(soc->receive_next >>8); *buf++ = (UINT8)(soc->receive_next); *buf = (MIN_TCP_HLEN + hlen_incr) >> 2; *buf <<= 4; buf++; *buf++ = soc->myflags; //*buf++ = (UINT8)((TCP_DEF_MTU) >> 8); //*buf++ = (UINT8)TCP_DEF_MTU; *buf++ = (UINT8)((TCP_WIN_SIZE) >> 8); *buf++ = (UINT8)TCP_WIN_SIZE; *buf++ = 0; /* Checksum */ *buf++ = 0; *buf++ = 0; /* Urgent */ *buf++ = 0; //IAS if(soc->myflags == (TCP_FLAG_SYN | TCP_FLAG_ACK)) { *buf++ = (UINT8)(2); *buf++ = (UINT8)(4); *buf++ = (UINT8)((soc->mss) >> 8); *buf++ = (UINT8)(soc->mss); } ///IAS /* Calculate checksum */ cs = 0; cs_cnt = 0; /* Do it firstly to IP pseudo header */ cs = IpCheckSum(cs, (UINT8)(localmachine.localip >> 24), cs_cnt++); cs = IpCheckSum(cs, (UINT8)(localmachine.localip >> 16), cs_cnt++); cs = IpCheckSum(cs, (UINT8)(localmachine.localip >> 8), cs_cnt++); cs = IpCheckSum(cs, (UINT8)localmachine.localip, cs_cnt++); cs = IpCheckSum(cs, (UINT8)(soc->rem_ip >> 24), cs_cnt++); cs = IpCheckSum(cs, (UINT8)(soc->rem_ip >> 16), cs_cnt++); cs = IpCheckSum(cs, (UINT8)(soc->rem_ip >> 8), cs_cnt++); cs = IpCheckSum(cs, (UINT8)soc->rem_ip, cs_cnt++); cs = IpCheckSum(cs, 0, cs_cnt++); cs = IpCheckSum(cs, (UINT8)IP_TCP, cs_cnt++); cs = IpCheckSum(cs, (UINT8)((dlen + MIN_TCP_HLEN + hlen_incr) >> 8), cs_cnt++); cs = IpCheckSum(cs, (UINT8)(dlen + MIN_TCP_HLEN + hlen_incr), cs_cnt++); /* Go to TCP header + data */ buf = buf_start; cs = IpCheckSumBuf(cs, buf, dlen + MIN_TCP_HLEN + hlen_incr); cs = ~ cs; #if 0 /* Is the padding required? */ if(dlen & 0x01) { DEBUGOUT("Padding required\r\n"); *buf = 0; dlen++; } #endif /* Save checksum in correct place */ buf = buf_start + 16; *buf++ = (UINT8)(cs >> 8); *buf = (UINT8)cs; /* Send it to IP */ DEBUGOUT("Sending TCP...\r\n"); ProcessIPOut(soc->rem_ip, IP_TCP, soc->tos, 100, buf_start, dlen + MIN_TCP_HLEN + hlen_incr); DEBUGOUT("TCP packet sent\r\n"); return(0); } /******************************************************************************** Function: tcp_sendcontrol Parameters: INT8 sochandle - handle to socket Return val: void Date: 17.7.2002 Desc: Send a control packet with predefined flags *********************************************************************************/ void tcp_sendcontrol (INT8 sockethandle) { //struct tcb* soc; DEBUGOUT("Entering to send TCP control packet\r\n"); if( sockethandle < 0 ) { DEBUGOUT("ERROR:Socket Handle not valid (<0)\r\n"); return; } if( sockethandle > NO_OF_TCPSOCKETS ) { DEBUGOUT("ERROR:Socket Handle not valid (>NO_OF_TCPSOCKETS)\r\n"); return; } //soc = &TCPSocket[sockethandle]; /* Get socket */ ProcessTCPOut(sockethandle, &tcp_tempbuf[0], MIN_TCP_HLEN + 1, 0); return; } /******************************************************************************** Function: tcp_sendreset Parameters: struct TCPFrame* frame - received TCP packet UINT32 remip - remote IP address of packet Return val: void Date: 20.8.2002 Desc: Uses socket NO_OF_TCPSOCKETS to send a RESET packet to peer. This function is used when we are establishing connection but we receive something else than SYN or SYN+ACK when it's possible that the peer has still old connection on which needs to be resetted without canceling the connection establishment on process. *********************************************************************************/ void tcp_sendreset (struct TCPFrame *frame, UINT32 remip) { struct tcb* soc; soc = &TCPSocket[NO_OF_TCPSOCKETS]; /* Get socket */ /* Is this itself a reset packet? */ if( frame->hlen_flags & TCP_FLAG_RESET ) return; /* Set temporary tcb variables */ soc->rem_ip = remip; soc->remport = frame->sport; soc->locport = frame->dport; soc->tos = 0; soc->send_unacked = frame->ackno; soc->myflags = TCP_FLAG_RESET | TCP_FLAG_ACK; soc->receive_next = frame->seqno; /* Is there SYN or FIN? */ if( (frame->hlen_flags & TCP_FLAG_SYN) || ( frame->hlen_flags & TCP_FLAG_FIN) ) soc->receive_next++; soc->send_mtu = TCP_DEF_MTU; tcp_sendcontrol(NO_OF_TCPSOCKETS); } /******************************************************************************** Function: tcp_initseq Parameters: - Return val: UINT32 initial sequence number Date: 17.7.2002 Desc: Get and return initial sequence number *********************************************************************************/ UINT32 tcp_initseq (void) { DEBUGOUT("Calculating initial sequence number\r\n"); return( ( (UINT32)BaseTimer << 24) | 0x00FFFFFF ); } /******************************************************************************** Function: tcp_mapsocket Parameters: struct IPFrame* ipframe - pointer to received IP frame struct TCPFrame* tcpframe - pointer to frame to be mapped Return val: INT8 - (-1) = Error (No resources) - >0 = Handle to mapped socket Date: 12.7.2002 Desc: Try to find a socket for received TCP packet or allocate listening one *********************************************************************************/ INT8 tcp_mapsocket (struct IPFrame* ipframe, struct TCPFrame* tcpframe) { struct tcb* soc; UINT8 i; /* Check if there is already connection on */ for( i=0; i < NO_OF_TCPSOCKETS; i++) { soc = &TCPSocket[i]; /* Get socket */ if(soc->state == TCP_STATE_LISTENING) continue; /* No match */ if(soc->remport != tcpframe->sport) continue; if(soc->locport != tcpframe->dport) continue; if(soc->rem_ip != ipframe->sip) continue; /* There is connection on already */ DEBUGOUT("Active connection socket found\r\n"); return(i); } /* Allocate listening one if SYN packet (Connection Request) */ DEBUGOUT("No active connection, checking if SYN packet\r\n"); /* Is it SYN? */ if( (tcpframe->hlen_flags & TCP_FLAG_SYN) == 0 ) return(-1); if( tcpframe->hlen_flags & TCP_FLAG_ACK ) return(-1); if( tcpframe->hlen_flags & TCP_FLAG_RESET ) return(-1); if( tcpframe->hlen_flags & TCP_FLAG_FIN ) return(-1); DEBUGOUT("Trying to allocate listening one for SYN packet\r\n"); /* Search listening sockets */ for( i=0; i < NO_OF_TCPSOCKETS; i++) { soc = &TCPSocket[i]; /* Get socket */ if(soc->state != TCP_STATE_LISTENING) continue; if(soc->locport != tcpframe->dport) continue; /* Bind it */ soc->rem_ip = ipframe->sip; soc->remport = tcpframe->sport; DEBUGOUT("Allocated new socket\r\n"); return(i); } /* No success */ DEBUGOUT("ERROR:No socket found or allocated for TCP packet\r\n"); return(-1); } /******************************************************************************** Function: tcp_newstate Parameters: struct tcb* soc - socket structure operated UINT8 nstate - new state Return val: void Date: 18.7.2002 Desc: Change state of socket and reload timers. Call this function periodically on connected state to keep connection on. *********************************************************************************/ void tcp_newstate (struct tcb* soc, UINT8 nstate) { soc->state = nstate; soc->retries_left = TCP_DEF_RETRIES; /* Retransmit timer */ init_timer(soc->retransmit_timerh, TCP_DEF_RETRY_TOUT); /* In some states we don't want to wait for many retries (e.g. TIMED_WAIT) */ switch(soc->state) { case TCP_STATE_TIMED_WAIT: soc->retries_left = 0; break; case TCP_STATE_SYN_SENT: /* When we are sending SYN it's propably that ARP is not valid */ /* Do retransmit faster on first time */ init_timer(soc->retransmit_timerh, TCP_INIT_RETRY_TOUT); soc->retries_left = TCP_CON_ATTEMPTS; break; case TCP_STATE_LAST_ACK: case TCP_STATE_FINW1: case TCP_STATE_FINW2: case TCP_STATE_CLOSING: soc->retries_left = 1; break; default: break; } /* KeepAlive timer */ if(soc->state == TCP_STATE_CONNECTED) init_timer(soc->persist_timerh, soc->tout); return; } /******************************************************************************** Function: tcp_getfreeport Parameters: void Return val: UINT16 - 0 = no free ports >0 = Free local TCP port Date: 19.8.2002 Desc: Gets next free (not used) local port *********************************************************************************/ UINT16 tcp_getfreeport (void) { struct tcb* soc; static UINT16 lastport = 1; UINT16 start; UINT16 i; /* Try with every port to every socket untill free found */ for( start = lastport++; start != lastport; lastport++) { if(lastport == TCP_PORTS_END) lastport = 1; for(i = 0; i < NO_OF_TCPSOCKETS; i++) { soc = &TCPSocket[i]; /* Get socket */ if( (soc->state > TCP_STATE_CLOSED) && (soc->locport == lastport) ) { /* Blaah, this socket has reserved the port, go to next one */ break; } } /* Did we found it? */ if( i == NO_OF_TCPSOCKETS) break; } if(lastport == start) { DEBUGOUT("Out of TCP ports!!\n\r"); return(0); } return(lastport); } /******************************************************************************** Function: TCP_CheckCS Parameters: struct IPFrame* ipframe - pointer to IP frame that carried TCP UINT16 len - length of TCP portion Return val: UINT8 0 - Checksum corrupted UINT8 1 - Checksum OK Date: 16.7.2002 Desc: Calculate is the TCP frame uncorrupted. May be made more intelligent/faster by using carry method. *********************************************************************************/ UINT8 TCP_CheckCS (struct IPFrame* ipframe, UINT16 len) { UINT16 cs; UINT8 cs_cnt; cs = 0; cs_cnt = 0; //mcu_cs4_on(); /* Do it firstly to IP pseudo header */ cs = IpCheckSum(cs, (UINT8)(ipframe->sip >> 24), cs_cnt++); cs = IpCheckSum(cs, (UINT8)(ipframe->sip >> 16), cs_cnt++); cs = IpCheckSum(cs, (UINT8)(ipframe->sip >> 8), cs_cnt++); cs = IpCheckSum(cs, (UINT8)ipframe->sip, cs_cnt++); cs = IpCheckSum(cs, (UINT8)(ipframe->dip >> 24), cs_cnt++); cs = IpCheckSum(cs, (UINT8)(ipframe->dip >> 16), cs_cnt++); cs = IpCheckSum(cs, (UINT8)(ipframe->dip >> 8), cs_cnt++); cs = IpCheckSum(cs, (UINT8)ipframe->dip, cs_cnt++); cs = IpCheckSum(cs, 0, cs_cnt++); cs = IpCheckSum(cs, (UINT8)ipframe->protocol, cs_cnt++); cs = IpCheckSum(cs, (UINT8)(len >> 8), cs_cnt++); cs = IpCheckSum(cs, (UINT8)len, cs_cnt++); /* Go to TCP data */ /** while(len>15) { //RECEIVE_NETWORK_BUF(tcp_tempbuf,16); //cs = IpCheckSumBuf(cs, tcp_tempbuf,16); cs = IpCheckSumBuf(cs, eth_wrapper.rxp,16); eth_wrapper.rxp+=16; len -= 16; cs_cnt += 16; } while(len--) { cs = IpCheckSum(cs, RECEIVE_NETWORK_B(), (UINT8)cs_cnt++); } **/ cs = IpCheckSumBuf(cs, eth_wrapper.rxp, len); eth_wrapper.rxp+=len; cs = ~ cs; //mcu_cs4_off(); if(cs != IP_GOOD_CS) { return (0); } /* It's OK */ return(1); }