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

📄 tcpip.c

📁 IARSOURCECODE是基于LPC2478嵌入式软件IAR EWARM V4.42的应用实例代码
💻 C
📖 第 1 页 / 共 3 页
字号:
              }
      break;
    }
    case FRAME_IP :                                        // check for IP-type
    {
      if ((ReadFrameBE_EMAC() & 0xFF00 ) == IP_VER_IHL)     // IPv4, IHL=5 (20 Bytes Header)
      {                                                    // ignore Type Of Service
        RecdIPFrameLength = ReadFrameBE_EMAC();             // get IP frame's length
        ReadFrameBE_EMAC();                                 // ignore identification

        if (!(ReadFrameBE_EMAC() & (IP_FLAG_MOREFRAG | IP_FRAGOFS_MASK)))  // only unfragm. frames
        {
          ProtocolType = ReadFrameBE_EMAC() & 0xFF;         // get protocol, ignore TTL
          ReadFrameBE_EMAC();                               // ignore checksum
          CopyFromFrame_EMAC(&RecdFrameIP, 4);              // get source IP
          CopyFromFrame_EMAC(&TargetIP, 4);                 // get destination IP

          if (!memcmp(&MyIP, &TargetIP, 4))                // is it for us?
            switch (ProtocolType) {
              case PROT_ICMP : { ProcessICMPFrame(); break; }
              case PROT_TCP  : { ProcessTCPFrame(); break; }
              case PROT_UDP  : break;                      // not implemented!
            }
        }      
      }
      break;
    }
  }
}

// easyWEB internal function
// we've just rec'd an ICMP-frame (Internet Control Message Protocol)
// check what to do and branch to the appropriate sub-function

void ProcessICMPFrame(void)
{
  unsigned short ICMPTypeAndCode;

  ICMPTypeAndCode = ReadFrameBE_EMAC();           // get Message Type and Code
  ReadFrameBE_EMAC();                             // ignore ICMP checksum

  switch (ICMPTypeAndCode >> 8) {                // check type
    case ICMP_ECHO :                             // is echo request?
    {
      PrepareICMP_ECHO_REPLY();                  // echo as much as we can...
      break;
    }
  }
}

// easyWEB internal function
// we've just rec'd an TCP-frame (Transmission Control Protocol)
// this function mainly implements the TCP state machine according to RFC793

void ProcessTCPFrame(void)
{
  unsigned short TCPSegSourcePort;               // segment's source port
  unsigned short TCPSegDestPort;                 // segment's destination port
  unsigned long TCPSegSeq;                       // segment's sequence number
  unsigned long TCPSegAck;                       // segment's acknowledge number
  unsigned short TCPCode;                        // TCP code and header length
  unsigned char TCPHeaderSize;                   // real TCP header length
  unsigned short NrOfDataBytes;                  // real number of data
    
  TCPSegSourcePort = ReadFrameBE_EMAC();                    // get ports
  TCPSegDestPort = ReadFrameBE_EMAC();

  if (TCPSegDestPort != TCPLocalPort) return;              // drop segment if port doesn't match

  TCPSegSeq = (unsigned long)ReadFrameBE_EMAC() << 16;      // get segment sequence nr.
  TCPSegSeq |= ReadFrameBE_EMAC();

  TCPSegAck = (unsigned long)ReadFrameBE_EMAC() << 16;      // get segment acknowledge nr.
  TCPSegAck |= ReadFrameBE_EMAC();

  TCPCode = ReadFrameBE_EMAC();                             // get control bits, header length...

  TCPHeaderSize = (TCPCode & DATA_OFS_MASK) >> 10;         // header length in bytes
  NrOfDataBytes = RecdIPFrameLength - IP_HEADER_SIZE - TCPHeaderSize;     // seg. text length

  if (NrOfDataBytes > MAX_TCP_RX_DATA_SIZE) return;        // packet too large for us :...-(

  if (TCPHeaderSize > TCP_HEADER_SIZE)                     // ignore options if any
    DummyReadFrame_EMAC(TCPHeaderSize - TCP_HEADER_SIZE);

  switch (TCPStateMachine)                                 // implement the TCP state machine
  {
    case CLOSED :
    {
      if (!(TCPCode & TCP_CODE_RST))
      {
        TCPRemotePort = TCPSegSourcePort;
        memcpy(&RemoteMAC, &RecdFrameMAC, 6);              // save opponents MAC and IP
        memcpy(&RemoteIP, &RecdFrameIP, 4);                // for later use

        if (TCPCode & TCP_CODE_ACK)                        // make the reset sequence
        {                                                  // acceptable to the other
          TCPSeqNr = TCPSegAck;                            // TCP
          PrepareTCP_FRAME(TCP_CODE_RST);
        }
        else
        {
          TCPSeqNr = 0;
          TCPAckNr = TCPSegSeq + NrOfDataBytes;
          if (TCPCode & (TCP_CODE_SYN | TCP_CODE_FIN)) TCPAckNr++;
          PrepareTCP_FRAME(TCP_CODE_RST | TCP_CODE_ACK);
        }
      }
      break;
    }  
    case LISTENING :
    {
      if (!(TCPCode & TCP_CODE_RST))                       // ignore segment containing RST
      {
        TCPRemotePort = TCPSegSourcePort;
        memcpy(&RemoteMAC, &RecdFrameMAC, 6);              // save opponents MAC and IP
        memcpy(&RemoteIP, &RecdFrameIP, 4);                // for later use

        if (TCPCode & TCP_CODE_ACK)                        // reset a bad
        {                                                  // acknowledgement
          TCPSeqNr = TCPSegAck;
          PrepareTCP_FRAME(TCP_CODE_RST);
        }
        else if (TCPCode & TCP_CODE_SYN)
        {
          TCPAckNr = TCPSegSeq + 1;                           // get remote ISN, next byte we expect
            TCPSeqNr = ((unsigned long)ISNGenHigh << 16) | (T0TC & 0xFFFF);  // Keil: changed from TAR to T0TC; 
                                                              // set local ISN
          TCPUNASeqNr = TCPSeqNr + 1;                         // one byte out -> increase by one
          PrepareTCP_FRAME(TCP_CODE_SYN | TCP_CODE_ACK);
          LastFrameSent = TCP_SYN_ACK_FRAME;
          TCPStartRetryTimer();
          TCPStateMachine = SYN_RECD;
        }
      }
      break;
    }
    case SYN_SENT :
    {
      if (memcmp(&RemoteIP, &RecdFrameIP, 4)) break;  // drop segment if its IP doesn't belong
                                                      // to current session

      if (TCPSegSourcePort != TCPRemotePort) break;   // drop segment if port doesn't match
      
      if (TCPCode & TCP_CODE_ACK)                // ACK field significant?
        if (TCPSegAck != TCPUNASeqNr)            // is our ISN ACKed?
        {
          if (!(TCPCode & TCP_CODE_RST))
          {
            TCPSeqNr = TCPSegAck;
            PrepareTCP_FRAME(TCP_CODE_RST);
          }
          break;                                 // drop segment
        }

      if (TCPCode & TCP_CODE_RST)                // RST??
      {
        if (TCPCode & TCP_CODE_ACK)              // if ACK was acceptable, reset
        {                                        // connection
          TCPStateMachine = CLOSED;
          TCPFlags = 0;                          // reset all flags, stop retransmission...
          SocketStatus = SOCK_ERR_CONN_RESET;
        }
        break;                                   // drop segment
      }
        
      if (TCPCode & TCP_CODE_SYN)                // SYN??
      {
        TCPAckNr = TCPSegSeq;                    // get opponents ISN
        TCPAckNr++;                              // inc. by one...

        if (TCPCode & TCP_CODE_ACK)
        {
          TCPStopTimer();                        // stop retransmission, other TCP got our SYN
          TCPSeqNr = TCPUNASeqNr;                // advance our sequence number

          PrepareTCP_FRAME(TCP_CODE_ACK);        // ACK this ISN
          TCPStateMachine = ESTABLISHED;
          SocketStatus |= SOCK_CONNECTED;
          SocketStatus |= SOCK_TX_BUF_RELEASED;  // user may send data now :-)
        }
        else
        {
          TCPStopTimer();
          PrepareTCP_FRAME(TCP_CODE_SYN | TCP_CODE_ACK);   // our SYN isn't ACKed yet,
          LastFrameSent = TCP_SYN_ACK_FRAME;               // now continue with sending
          TCPStartRetryTimer();                            // SYN_ACK frames
          TCPStateMachine = SYN_RECD;
        }
      }
      break;
    }
    default :
    {
      if (memcmp(&RemoteIP, &RecdFrameIP, 4)) break;  // drop segment if IP doesn't belong
                                                      // to current session

      if (TCPSegSourcePort != TCPRemotePort) break;   // drop segment if port doesn't match

      if (TCPSegSeq != TCPAckNr) break;               // drop if it's not the segment we expect
            
      if (TCPCode & TCP_CODE_RST)                // RST??
      {
        TCPStateMachine = CLOSED;                // close the state machine
        TCPFlags = 0;                            // reset all flags, stop retransmission...
        SocketStatus = SOCK_ERR_CONN_RESET;      // indicate an error to user
        break;
      }

      if (TCPCode & TCP_CODE_SYN)                // SYN??
      {
        PrepareTCP_FRAME(TCP_CODE_RST);          // is NOT allowed here! send a reset,
        TCPStateMachine = CLOSED;                // close connection...
        TCPFlags = 0;                            // reset all flags, stop retransmission...
        SocketStatus = SOCK_ERR_REMOTE;          // fatal error!
        break;                                   // ...and drop the frame
      }

      if (!(TCPCode & TCP_CODE_ACK)) break;      // drop segment if the ACK bit is off

      if (TCPSegAck == TCPUNASeqNr)              // is our last data sent ACKed?
      {
        TCPStopTimer();                          // stop retransmission
        TCPSeqNr = TCPUNASeqNr;                  // advance our sequence number

        switch (TCPStateMachine)                 // change state if necessary
        {
          case SYN_RECD :                        // ACK of our SYN?
          {
            TCPStateMachine = ESTABLISHED;       // user may send data now :-)
            SocketStatus |= SOCK_CONNECTED;
            break;
          }
          case FIN_WAIT_1 : { TCPStateMachine = FIN_WAIT_2; break; } // ACK of our FIN?
          case CLOSING :    { TCPStateMachine = TIME_WAIT; break; }  // ACK of our FIN?
          case LAST_ACK :                                            // ACK of our FIN?
          {
            TCPStateMachine = CLOSED;
            TCPFlags = 0;                        // reset all flags, stop retransmission...
            SocketStatus &= SOCK_DATA_AVAILABLE; // clear all flags but data available
            break;
          }
          case TIME_WAIT :
          {
            PrepareTCP_FRAME(TCP_CODE_ACK);      // ACK a retransmission of remote FIN
            TCPRestartTimer();                   // restart TIME_WAIT timeout
            break;
          }
        }
        
        if (TCPStateMachine == ESTABLISHED)      // if true, give the frame buffer back
          SocketStatus |= SOCK_TX_BUF_RELEASED;  // to user
      }

      if ((TCPStateMachine == ESTABLISHED) || (TCPStateMachine == FIN_WAIT_1) || (TCPStateMachine == FIN_WAIT_2))
        if (NrOfDataBytes)                                 // data available?
          if (!(SocketStatus & SOCK_DATA_AVAILABLE))       // rx data-buffer empty?
          {
            DummyReadFrame_EMAC(6);                        // ignore window, checksum, urgent pointer
            CopyFromFrame_EMAC(RxTCPBuffer, NrOfDataBytes);// fetch data and
            TCPRxDataCount = NrOfDataBytes;                // ...tell the user...
            SocketStatus |= SOCK_DATA_AVAILABLE;           // indicate the new data to user
            TCPAckNr += NrOfDataBytes;
            PrepareTCP_FRAME(TCP_CODE_ACK);                // ACK rec'd data
          }
              
      if (TCPCode & TCP_CODE_FIN)                // FIN??
      {
        switch (TCPStateMachine)
        {
          case SYN_RECD :
          case ESTABLISHED :
          {
            TCPStateMachine = CLOSE_WAIT;
            break;
          }
          case FIN_WAIT_1 :
          {                                      // if our FIN was ACKed, we automatically
            TCPStateMachine = CLOSING;           // enter FIN_WAIT_2 (look above) and therefore
            SocketStatus &= ~SOCK_CONNECTED;     // TIME_WAIT
            break;
          }
          case FIN_WAIT_2 :
          {
            TCPStartTimeWaitTimer();
            TCPStateMachine = TIME_WAIT;
            SocketStatus &= ~SOCK_CONNECTED;            
            break;
          }
          case TIME_WAIT :
          {
            TCPRestartTimer();
            break;
          }
        }
        TCPAckNr++;                              // ACK remote's FIN flag
        PrepareTCP_FRAME(TCP_CODE_ACK);
      }
    }
  }
}

// easyWEB internal function
// prepares the TxFrame2-buffer to send an ARP-request

void PrepareARP_REQUEST(void)
{
  // Ethernet
  memset(&TxFrame2[ETH_DA_OFS], (char)0xFF, 6);                  // we don't know opposites MAC!
  memcpy(&TxFrame2[ETH_SA_OFS], &MyMAC, 6);
  *(unsigned short *)&TxFrame2[ETH_TYPE_OFS] = SWAPB(FRAME_ARP);

  // ARP
  *(unsigned short *)&TxFrame2[ARP_HARDW_OFS] = SWAPB(HARDW_ETH10);
  *(unsigned short *)&TxFrame2[ARP_PROT_OFS] = SWAPB(FRAME_IP);
  *(unsigned short *)&TxFrame2[ARP_HLEN_PLEN_OFS] = SWAPB(IP_HLEN_PLEN);
  *(unsigned short *)&TxFrame2[ARP_OPCODE_OFS] = SWAPB(OP_ARP_REQUEST);
  memcpy(&TxFrame2[ARP_SENDER_HA_OFS], &MyMAC, 6);
  memcpy(&TxFrame2[ARP_SENDER_IP_OFS], &MyIP, 4);
  memset(&TxFrame2[ARP_TARGET_HA_OFS], 0x00, 6);           // we don't know opposites MAC!

  if (((RemoteIP[0] ^ MyIP[0]) & SubnetMask[0]) || ((RemoteIP[1] ^ MyIP[1]) & SubnetMask[1]))
    memcpy(&TxFrame2[ARP_TARGET_IP_OFS], &GatewayIP, 4);   // IP not in subnet, use gateway

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -