⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tcp.c

📁 ATmega103、ATmega128做的开发板web server源码
💻 C
📖 第 1 页 / 共 4 页
字号:
/******************************************************************
* 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 + -