📄 tcpip.c
字号:
}
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 + -