tcpip.c
来自「An example of TCP/IP stuff on msp430, ta」· C语言 代码 · 共 1,022 行 · 第 1/3 页
C
1,022 行
if (!memcmp(&MyIP, &TargetIP, 4)) // is it for us? PrepareARP_ANSWER(); // yes->create ARP_ANSWER frame }}// easyWEB internal function// handles an incoming frame that passed CS8900's address filter// (individual addressed = IA)void ProcessEthIAFrame(void){ unsigned int TargetIP[2]; unsigned char ProtocolType; // next two words MUST be read with High-Byte 1st (CS8900 AN181 Page 2) ReadHB1ST8900(RX_FRAME_PORT); // ignore RxStatus Word RecdFrameLength = ReadHB1ST8900(RX_FRAME_PORT);// get real length of frame DummyReadFrame8900(6); // ignore DA CopyFromFrame8900(&RecdFrameMAC, 6); // store SA (for our answer) switch (ReadFrameBE8900()) // get frame type { case FRAME_ARP : // check for ARP { if ((TCPFlags & (TCP_ACTIVE_OPEN | IP_ADDR_RESOLVED)) == TCP_ACTIVE_OPEN) if (ReadFrameBE8900() == HARDW_ETH10) // check for the right prot. etc. if (ReadFrameBE8900() == FRAME_IP) if (ReadFrameBE8900() == IP_HLEN_PLEN) if (ReadFrameBE8900() == OP_ARP_ANSWER) { TCPStopTimer(); // OK, now we've the MAC we wanted ;-) CopyFromFrame8900(&RemoteMAC, 6); // extract opponents MAC TCPFlags |= IP_ADDR_RESOLVED; } break; } case FRAME_IP : // check for IP-type { if ((ReadFrameBE8900() & 0xFF00 ) == IP_VER_IHL) // IPv4, IHL=5 (20 Bytes Header) { // ignore Type Of Service RecdIPFrameLength = ReadFrameBE8900(); // get IP frame's length ReadFrameBE8900(); // ignore identification if (!(ReadFrameBE8900() & (IP_FLAG_MOREFRAG | IP_FRAGOFS_MASK))) // only unfragm. frames { ProtocolType = ReadFrameBE8900(); // get protocol, ignore TTL 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 : // ACK of our FIN? { TCPStateMachine = FIN_WAIT_2; // Note from FreeBSD sources (/usr/src/sys/netinet/tcp_input.c): // "If we can't receive any more data, then closing user can proceed. // Starting the timer is contrary to the specification, but if // we don't get a FIN we'll hang forever." TCPStartTimeWaitTimer(); break; } 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 (TCPStateMachine == FIN_WAIT_2) // we can receive data while waiting for FIN TCPRestartTimer(); } 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);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?