📄 tcp.c
字号:
/******************************************************************
* tcp.c: Transmission Control Protocol
*
* Copyright (c) 2001 Atmel Corporation.
* All Rights Reserved.
*
* You are autorized to use, copy and distribute this software only at
* a single site (the term "site" meaning a single company location).
* This copyright notice must be included in any copy, modification
* or portion of this software merged into another program.
*
* This software is licenced solely for use with Atmel AVR micro
* controller family. The software may not be modified to execute on
* any other microcontroller architectures
*
* This software is provided "as is"; Without warranties either express
* or implied, including any warranty regarding merchantability,
* fitness for a particular purpose or noninfringement.
*
* In no event shall Atmel or its suppliers be liable for any special,
* indirect,incidential or concequential damages resulting from the
* use or inability to use this software.
*
* Revision history:
*
* January 17, 2001: Version 1.0 Created by JB
* July 13, 2001 Version 1.2 JB
* - Changed to IAR compiler V2.25
* - Renamed flash file functions to avoid conflict with
* standard file I/O names
* - Bug fixes in HTTP
* - Speed optimization in TCP
*
*
*******************************************************************/
#include "comp_a90.h"
#include "main.h"
#include "tcp.h"
#include "ip.h"
#include <ina90.h>
#include <pgmspace.h>
#include "ethernet.h"
#include "iom103.h"
/* The frame received */
extern unsigned int frame[FRAME_SIZE];
//extern unsigned int IP0, IP1;
extern config_type ID;
LISTEN listenList[TCP_MAX_CONNECTIONS];
RT RTframes[TCP_NUMBER_RT_BUF];
SOCKET sockets[TCP_MAX_SOCKETS];
TCB tcb[TCP_MAX_SOCKETS];
/* ticker is a counter counting each time
* checkTCP is called. Used to control
* retransmission timeouts.
*/
unsigned int ticker;
/*receiveTCP is called by the IP when a TCP frame is received.
the function handles the TCP state machine, extracts data and send
a response to the sender if necessary*/
void receiveTCP(int length, unsigned int ip0, unsigned int ip1)
{
unsigned char socketNr;
TCB *tcbptr;
unsigned int *frameptr = &frame[TCP_SENDER_PORT-6];
*frameptr++ = ip0; //Add pseudo header for
*frameptr++ = ip1; //checksum calculation.
*frameptr++ = ID.IP0;
*frameptr++ = ID.IP1;
*frameptr++ = 6;
*frameptr++ = length;
if ( !(checksum(&frame[TCP_SENDER_PORT-6], (length+12))) )
{
socketNr = checkProtocol(ip0, ip1, frame[TCP_SENDER_PORT], frame[TCP_TARGET_PORT]);
if (socketNr != 0xff) // If 0<socketNr<TCP_MAX_SOCKETS, there is a socket
{
tcbptr = &tcb[socketNr];
frameptr = &frame[TCP_SEQ0]; //Get information about the segment.
tcbptr->segSEQ = frame[TCP_SEQ1] + ((unsigned long)frame[TCP_SEQ0]<<16);
tcbptr->segACK = frame[TCP_ACK1] + ((unsigned long)frame[TCP_ACK0]<<16);
tcbptr->segLEN = length;
tcbptr->segWND = frame[TCP_WINDOW];
tcbptr->segHdrLEN = ((frame[TCP_FLAGS]>>10)&0x3c);
tcbptr->segCTL = frame[TCP_FLAGS]&0x3f;
/*Check state machine*/
switch(tcbptr->state)
{
case(TCP_STATE_LISTEN):
TCPlisten(socketNr);
break;
case(TCP_STATE_SYN_RCVD):
TCPsyn_rcvd(socketNr);
break;
case(TCP_STATE_SYN_SENT):
TCPsyn_sent(socketNr);
break;
case(TCP_STATE_ESTABLISHED):
TCPestablished(socketNr);
break;
case(TCP_STATE_FIN_WAIT1):
TCPfin_wait1(socketNr);
break;
case(TCP_STATE_FIN_WAIT2):
TCPfin_wait2(socketNr);
break;
case(TCP_STATE_CLOSE_WAIT):
TCPclose_wait(socketNr);
break;
case(TCP_STATE_LAST_ACK):
TCPlast_ack(socketNr);
break;
case(TCP_STATE_CLOSING):
break;
case(TCP_STATE_TIME_WAIT):
break;
}
}
}
}
/*TCPlisten is called by receiveTCP when TCP state is LISTEN.
checks if the frame contain a SYN and respond to the frame.*/
void TCPlisten (unsigned char socketNr)
{
unsigned int *frameptr=&frame[TCP_SENDER_PORT-6];
unsigned int tmp;
SOCKET *socketptr = &sockets[socketNr];
TCB *tcbptr = &tcb[socketNr];
if ( tcbptr->segCTL & TCP_RST ) //If the segment contains a reset
{
*frameptr++ = ID.IP0; //Make a response. Make new pseudo header
*frameptr++ = ID.IP1;
*frameptr++ = socketptr->hisIP0;
*frameptr++ = socketptr->hisIP1;
*frameptr++ = 6;
*frameptr++ = 20;
tmp = *frameptr;
*frameptr++ = *(frameptr+1); //TCP_SENDER_PORT = TCP_TARGET_PORT
*frameptr++ = tmp; //TCP_TARGET_PORT = TCP_SENDER_PORT
*frameptr++ = *(frameptr+2); //TCP_SEQ = TCP_ACK
*frameptr++ = *(frameptr+2);
frameptr++; //Move to TCP_FLAGS
frameptr++;
*frameptr++ = 0x5000 | TCP_ACK | TCP_RST;
*frameptr++ = TCP_WIN_SIZE;
*frameptr = 0; //Checksum=0
*(frameptr+1) = 0; // Urgent = 0
*frameptr = checksum(&frame[TCP_SENDER_PORT-6], 32); // Calculate new checksum
transmitIP(20, socketptr->hisIP0, socketptr->hisIP1, 6); // Send message
}
else if ( tcbptr->segCTL & TCP_SYN ) //If the segment contains a SYN
{
tcbptr->IRS = tcbptr->segSEQ; //Set new information in TCB
tcbptr->rcvWND = tcbptr->segWND;
tcbptr->rcvNXT = tcbptr->IRS+1;
tcbptr->open = TRUE;
tcbptr->sndWND = TCP_WIN_SIZE;
tcbptr->ISS = tcbptr->sndNXT; // Use old value of sequencenr.
tcbptr->sndUNA = tcbptr->ISS;
tcbptr->sndWL1 = tcbptr->IRS;
tcbptr->sndWL2 = tcbptr->sndUNA;
tcbptr->CTL = TCP_SYN | TCP_ACK;
frameptr = &frame[TCP_DATA];
tcbptr->MSS = ((20 < tcbptr->segHdrLEN) && (*frameptr == 0x0204) )?*(frameptr+1):560;
*frameptr++ = 0x0204;
*frameptr++ = (TCP_WIN_SIZE > 1460)?1460:TCP_WIN_SIZE;
*frameptr++ = 0x0101;
*frameptr++ = 0x0101;
tcbptr->segLEN = 0x1c;
tcbptr->segHdrLEN = 0x1c;
prepareFrame(socketNr); // Send SYN|ACK to client
transmitIP(tcbptr->segLEN, socketptr->hisIP0, socketptr->hisIP1, 6);
tcbptr->sndNXT++;
tcbptr->state = TCP_STATE_SYN_RCVD;
}
}
/*TCPsyn_rcvd is called when in SYN_RCVD state. If frame is
acceptable and contains an ACK enter ESTABLISHED.*/
void TCPsyn_rcvd ( unsigned char socketNr )
{
SOCKET *socketptr = &sockets[socketNr];
TCB *tcbptr = &tcb[socketNr];
if ( (acceptable (socketNr) == TRUE) )
{
if ( (tcbptr->segCTL & (TCP_RST | TCP_SYN)) )
{
deleteSocket(socketNr); //If the segment contains RST|SYN, delete the socket
}
else if ( (tcbptr->segCTL & TCP_ACK) ) // Contains an ACK to our SYN
{
tcbptr->sndUNA = tcbptr->segACK;
updateRT(socketNr);
tcbptr->state = TCP_STATE_ESTABLISHED;
socketptr->state = OPEN;
}
else // Something went wrong, send a reset and delete socket
{
tcbptr->segHdrLEN = 20;
tcbptr->segLEN = 20;
tcbptr->CTL = TCP_RST;
prepareFrame(socketNr);
transmitIP(tcbptr->segLEN, socketptr->hisIP0, socketptr->hisIP1, 6);
deleteSocket(socketNr);
}
}
}
/*TCPsyn_sent is called by receiveTCP when TCP state is SYN_SENT.
and handles the frame according to the spesifications*/
void TCPsyn_sent(unsigned char socketNr)
{
unsigned int *frameptr;
SOCKET *socketptr = &sockets[socketNr];
TCB *tcbptr = &tcb[socketNr];
if ( ((tcbptr->segACK <= tcbptr->ISS) || (tcbptr->segACK > tcbptr->sndNXT)) &&
(tcbptr->segCTL & TCP_ACK) ) //Check ACKnr to see that the segment is correct.
{
if ( !(tcbptr->segCTL & TCP_RST) ) // The ACKnr is not correct and frame does
{ // contain a RST. Send RST and delete socket
tcbptr->segSEQ = tcbptr->segACK;
tcbptr->CTL = TCP_RST;
tcbptr->segLEN = 20;
tcbptr->segHdrLEN = 20;
prepareFrame(socketNr);
transmitIP(tcbptr->segLEN, socketptr->hisIP0, socketptr->hisIP1, 6);
deleteSocket(socketNr);
}
else
{
deleteSocket(socketNr);
}
}
else if ( (tcbptr->sndUNA <= tcbptr->segACK) && (tcbptr->segACK <= tcbptr->sndNXT) )
{
if ( (tcbptr->segCTL & TCP_RST) )
{
deleteSocket(socketNr);
}
else if ( (tcbptr->segCTL & TCP_SYN) )//Segment contains a SYN
{
tcbptr->rcvNXT = tcbptr->segSEQ+1;
tcbptr->IRS = tcbptr->segSEQ;
if ( (tcbptr->segCTL & TCP_ACK) ) //If segment contains ACK, update
{ //retransmission buffer
tcbptr->sndUNA = tcbptr->segACK;
updateRT(socketNr);
}
if (tcbptr->sndUNA >= tcbptr->ISS) // Is this an ACK to our SYN?
{
if ( (20 < tcbptr->segHdrLEN) && (frame[TCP_DATA] == 0x0204) )
{
tcbptr->MSS = frame[TCP_DATA+1]; //Extract MSS info.
}
else
{
tcbptr->MSS = 560;
}
tcbptr->IRS = tcbptr->segSEQ; //Set new information in TCB
tcbptr->rcvWND = tcbptr->segWND;
tcbptr->rcvNXT = tcbptr->IRS+1;
tcbptr->sndUNA = tcbptr->ISS;
tcbptr->sndWL1 = tcbptr->IRS;
tcbptr->sndWL2 = tcbptr->sndUNA;
tcbptr->state = TCP_STATE_ESTABLISHED;
socketptr->state = OPEN;
tcbptr->CTL = TCP_ACK;
tcbptr->segLEN = 20;
tcbptr->segHdrLEN = 20;
prepareFrame(socketNr); //Send ACK to client and go to established
transmitIP(tcbptr->segLEN, socketptr->hisIP0, socketptr->hisIP1, 6);
}
else //The client tries to open a connection at the same time as we do.
{
frameptr = &frame[TCP_DATA];
tcbptr->state = TCP_STATE_SYN_RCVD;
socketptr->state = HALF_OPEN;
tcbptr->segLEN = 0x1c;
tcbptr->segHdrLEN = 0x1c;
tcbptr->CTL = TCP_ACK | TCP_SYN;
*frameptr++ = 0x0204;
*frameptr++ = (TCP_WIN_SIZE > 1460)?1460:TCP_WIN_SIZE;
*frameptr++ = 0x0101;
*frameptr = 0x0101;
prepareFrame(socketNr);
transmitIP(tcbptr->segLEN, socketptr->hisIP0, socketptr->hisIP1, 6);
}
}
}
}
/*TCPestablished is called by receiveTCP when TCP state is ESTABLISHED.
TCPestablished extracts data and ACK received segments. If the
segment contains a RST, the connection is deleted. If the segment
contains a FIN, the next state is CLOSE_WAIT.*/
void TCPestablished ( unsigned char socketNr )
{
SOCKET *socketptr = &sockets[socketNr];
TCB *tcbptr = &tcb[socketNr];
if ( (acceptable (socketNr) == TRUE) ) //Is the segment acceptable?
{
if ( tcbptr->segHdrLEN < tcbptr->segLEN ) //Does it contain any data?
{
extractData(socketNr);
}
if ( (tcbptr->segCTL & TCP_FIN) )
{
tcbptr->state = TCP_STATE_CLOSE_WAIT;
socketptr->state = HALF_CLOSED;
tcbptr->rcvNXT++;
}
if ( (tcbptr->segCTL & (TCP_RST|TCP_SYN)) )//Does it contain illegal flag?
{
deleteSocket(socketNr);
}
else if ( (tcbptr->segCTL & TCP_ACK) ) //Does it acknowledge our segments?
{
if ( (tcbptr->sndUNA <= tcbptr->segACK) && (tcbptr->segACK <= tcbptr->sndNXT) )//Does it ACK unACKed data?
{
tcbptr->sndUNA = tcbptr->segACK; //Update TCB and retransmission buffer
updateRT(socketNr);
if ( (tcbptr->segHdrLEN < tcbptr->segLEN) || (tcbptr->state == TCP_STATE_CLOSE_WAIT) ) //If there were data, ACK it!
{
tcbptr->segLEN = 20;
tcbptr->segHdrLEN = 20;
tcbptr->CTL = TCP_ACK;
prepareFrame(socketNr);
transmitIP(tcbptr->segLEN, socketptr->hisIP0, socketptr->hisIP1, 6);
}
if ( ((tcbptr->sndWL1 < tcbptr->segSEQ) || //Update window information
((tcbptr->sndWL1 == tcbptr->segSEQ) && (tcbptr->sndWL2 <= tcbptr->segACK))) )
{
tcbptr->rcvWND = tcbptr->segWND;
tcbptr->sndWL1 = tcbptr->segSEQ;
tcbptr->sndWL2 = tcbptr->segACK;
}
}
}
}
}
/*TCPfin_wait1 does almost the same as TCPestablished. This state
is entered when we have sent a FIN to the client. If our
FIN is ACKed, go to FIN_WAIT2. Extract data if any.`*/
void TCPfin_wait1 ( unsigned char socketNr )
{
SOCKET *socketptr = &sockets[socketNr];
TCB *tcbptr = &tcb[socketNr];
if ( (acceptable(socketNr) == TRUE) ) //If segment is acceptable.
{
if ( tcbptr->segHdrLEN < tcbptr->segLEN )//Extract any data
{
extractData ( socketNr );
}
if ( (tcbptr->segCTL & (TCP_RST|TCP_SYN|TCP_FIN)) ) //Delete if illegal flag.
{
deleteSocket(socketNr);
}
else if ( tcbptr->segCTL & TCP_ACK ) //If there is an ACK, update window information
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -