📄 tcpip.c
字号:
ReadFrameBE8900(); // ignore checksum CopyFromFrame8900(&RecdFrameIP, 4); // get source IP CopyFromFrame8900(&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-functionvoid ProcessICMPFrame(void){ unsigned int ICMPTypeAndCode; ICMPTypeAndCode = ReadFrameBE8900(); // get Message Type and Code ReadFrameBE8900(); // 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 RFC793void ProcessTCPFrame(void){ unsigned int TCPSegSourcePort; // segment's source port unsigned int TCPSegDestPort; // segment's destination port unsigned long TCPSegSeq; // segment's sequence number unsigned long TCPSegAck; // segment's acknowledge number unsigned int TCPCode; // TCP code and header length unsigned char TCPHeaderSize; // real TCP header length unsigned int NrOfDataBytes; // real number of data TCPSegSourcePort = ReadFrameBE8900(); // get ports TCPSegDestPort = ReadFrameBE8900(); if (TCPSegDestPort != TCPLocalPort) return; // drop segment if port doesn't match TCPSegSeq = (unsigned long)ReadFrameBE8900() << 16; // get segment sequence nr. TCPSegSeq |= ReadFrameBE8900(); TCPSegAck = (unsigned long)ReadFrameBE8900() << 16; // get segment acknowledge nr. TCPSegAck |= ReadFrameBE8900(); TCPCode = ReadFrameBE8900(); // 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 DummyReadFrame8900(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) | TAR; // 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? { DummyReadFrame8900(6); // ignore window, checksum, urgent pointer CopyFromFrame8900(&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-requestvoid PrepareARP_REQUEST(void){ // Ethernet memset(&TxFrame2[ETH_DA_OFS], 0xFF, 6); // we don't know opposites MAC! memcpy(&TxFrame2[ETH_SA_OFS], &MyMAC, 6); *(unsigned int *)&TxFrame2[ETH_TYPE_OFS] = SWAPB(FRAME_ARP); // ARP *(unsigned int *)&TxFrame2[ARP_HARDW_OFS] = SWAPB(HARDW_ETH10); *(unsigned int *)&TxFrame2[ARP_PROT_OFS] = SWAPB(FRAME_IP); *(unsigned int *)&TxFrame2[ARP_HLEN_PLEN_OFS] = SWAPB(IP_HLEN_PLEN); *(unsigned int *)&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 else memcpy(&TxFrame2[ARP_TARGET_IP_OFS], &RemoteIP, 4); // other IP is next to us... TxFrame2Size = ETH_HEADER_SIZE + ARP_FRAME_SIZE; TransmitControl |= SEND_FRAME2;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -