📄 tcpip.c
字号:
/******************************************************************
***** *****
***** Name: tcpip.c *****
***** Ver.: 1.0 *****
***** Date: November 2001 *****
***** Auth: Andreas Dannenberg *****
***** Func: implements the TCP/IP-stack and provides a *****
***** simple API to the user *****
***** *****
******************************************************************/
#include "tcpip.h"
// easyWEB-API function
// initalizes the LAN-controller, reset flags, starts timer-ISR
inline unsigned int SwapBytes(unsigned int Data)
{
return (Data >> 8) | (Data << 8);
}
void TCPLowLevelInit(void)
{
BCSCTL1 &= ~DIVA0; // ACLK = XT1 / 4 = 2 MHz
BCSCTL1 |= DIVA1;
TACTL = ID1 | ID0 | TASSEL0 | TAIE; // stop timer, use ACLK / 8 = 250 kHz, gen. int.
TACTL |= MC1; // start timer in continuous up-mode
_EINT(); // enable interrupts
Init8900();
TransmitControl = 0;
TCPFlags = 0;
TCPStateMachine = CLOSED;
SocketStatus = 0;
}
// easyWEB-API function
// does a passive open (listen on 'MyIP:TCPLocalPort' for an incoming
// connection)
void TCPPassiveOpen(void)
{
if (TCPStateMachine == CLOSED)
{
TCPFlags &= ~TCP_ACTIVE_OPEN; // let's do a passive open!
TCPStateMachine = LISTENING;
SocketStatus = SOCK_ACTIVE; // reset, socket now active
}
}
// easyWEB-API function
// does an active open (tries to establish a connection between
// 'MyIP:TCPLocalPort' and 'RemoteIP:TCPRemotePort')
void TCPActiveOpen(void)
{
if ((TCPStateMachine == CLOSED) || (TCPStateMachine == LISTENING))
{
TCPFlags |= TCP_ACTIVE_OPEN; // let's do an active open!
TCPFlags &= ~IP_ADDR_RESOLVED; // we haven't opponents MAC yet
PrepareARP_REQUEST(); // ask for MAC by sending a broadcast
LastFrameSent = ARP_REQUEST;
TCPStartRetryTimer();
SocketStatus = SOCK_ACTIVE; // reset, socket now active
}
}
// easyWEB-API function
// closes an open connection
void TCPClose(void)
{
switch (TCPStateMachine)
{
case LISTENING :
case SYN_SENT :
{
TCPStateMachine = CLOSED;
TCPFlags = 0;
SocketStatus = 0;
break;
}
case SYN_RECD :
case ESTABLISHED :
{
TCPFlags |= TCP_CLOSE_REQUESTED;
break;
}
}
}
// easyWEB-API function
// releases the receive-buffer and allows easyWEB to store new data
// NOTE: rx-buffer MUST be released periodically, else the other TCP
// get no ACKs for the data it sent
void TCPReleaseRxBuffer(void)
{
SocketStatus &= ~SOCK_DATA_AVAILABLE;
}
// easyWEB-API function
// transmitts data stored in 'TCP_TX_BUF'
// NOTE: * number of bytes to transmit must have been written to 'TCPTxDataCount'
// * data-count MUST NOT exceed 'MAX_TCP_TX_DATA_SIZE'
void TCPTransmitTxBuffer(void)
{
if ((TCPStateMachine == ESTABLISHED) || (TCPStateMachine == CLOSE_WAIT))
if (SocketStatus & SOCK_TX_BUF_RELEASED)
{
SocketStatus &= ~SOCK_TX_BUF_RELEASED; // occupy tx-buffer
TCPUNASeqNr += TCPTxDataCount; // advance UNA
TxFrame1Size = ETH_HEADER_SIZE + IP_HEADER_SIZE + TCP_HEADER_SIZE + TCPTxDataCount;
TransmitControl |= SEND_FRAME1;
LastFrameSent = TCP_DATA_FRAME;
TCPStartRetryTimer();
}
}
// easyWEB's 'main()'-function
// must be called from user program periodically (the often - the better)
// handles network, TCP/IP-stack and user events
void DoNetworkStuff(void)
{
unsigned int ActRxEvent; // copy of cs8900's RxEvent-Register
Write8900(ADD_PORT, PP_RxEvent); // point to RxEvent
ActRxEvent = Read8900(DATA_PORT); // read, implied skip the last frame
if (ActRxEvent & RX_OK)
{
if (ActRxEvent & RX_IA) ProcessEthIAFrame();
if (ActRxEvent & RX_BROADCAST) ProcessEthBroadcastFrame();
}
if (TCPFlags & TCP_TIMER_RUNNING)
{
if (TCPFlags & TIMER_TYPE_RETRY)
{
if (TCPTimer > RETRY_TIMEOUT)
{
TCPRestartTimer(); // set a new timeout
if (RetryCounter)
{
TCPHandleRetransmission(); // resend last frame
RetryCounter--;
}
else
{
TCPStopTimer();
TCPHandleTimeout();
}
}
}
else if (TCPTimer > FIN_TIMEOUT)
{
TCPStateMachine = CLOSED;
TCPFlags = 0; // reset all flags, stop retransmission...
SocketStatus &= SOCK_DATA_AVAILABLE; // clear all flags but data available
}
}
switch (TCPStateMachine)
{
case CLOSED :
case LISTENING :
{
if (TCPFlags & TCP_ACTIVE_OPEN) // stack has to open a connection?
if (TCPFlags & IP_ADDR_RESOLVED) // IP resolved?
if (!(TransmitControl & SEND_FRAME2)) // buffer free?
{
TCPSeqNr = ((unsigned long)ISNGenHigh << 16) | TAR; // set local ISN
TCPUNASeqNr = TCPSeqNr;
TCPAckNr = 0; // we don't know what to ACK!
TCPUNASeqNr++; // count SYN as a byte
PrepareTCP_FRAME(TCP_CODE_SYN); // send SYN frame
LastFrameSent = TCP_SYN_FRAME;
TCPStartRetryTimer(); // we NEED a retry-timeout
TCPStateMachine = SYN_SENT;
}
break;
}
case SYN_RECD :
case ESTABLISHED :
{
if (TCPFlags & TCP_CLOSE_REQUESTED) // user has user initated a close?
if (!(TransmitControl & (SEND_FRAME2 | SEND_FRAME1))) // buffers free?
if (TCPSeqNr == TCPUNASeqNr) // all data ACKed?
{
TCPUNASeqNr++;
PrepareTCP_FRAME(TCP_CODE_FIN | TCP_CODE_ACK);
LastFrameSent = TCP_FIN_FRAME;
TCPStartRetryTimer();
TCPStateMachine = FIN_WAIT_1;
}
break;
}
case CLOSE_WAIT :
{
if (!(TransmitControl & (SEND_FRAME2 | SEND_FRAME1))) // buffers free?
if (TCPSeqNr == TCPUNASeqNr) // all data ACKed?
{
TCPUNASeqNr++; // count FIN as a byte
PrepareTCP_FRAME(TCP_CODE_FIN | TCP_CODE_ACK); // we NEED a retry-timeout
LastFrameSent = TCP_FIN_FRAME; // time to say goodbye...
TCPStartRetryTimer();
TCPStateMachine = LAST_ACK;
}
break;
}
}
if (TransmitControl & SEND_FRAME2)
{
RequestSend(TxFrame2Size);
if (Rdy4Tx()) // NOTE: when using a very fast MCU, maybe
SendFrame2(); // the CS8900 isn't ready yet, include
else { // a kind of timer or counter here
TCPStateMachine = CLOSED;
SocketStatus = SOCK_ERR_ETHERNET; // indicate an error to user
TCPFlags = 0; // clear all flags, stop timers etc.
}
TransmitControl &= ~SEND_FRAME2; // clear tx-flag
}
if (TransmitControl & SEND_FRAME1)
{
PrepareTCP_DATA_FRAME(); // build frame w/ actual SEQ, ACK....
RequestSend(TxFrame1Size);
if (Rdy4Tx()) // CS8900 ready to accept our frame?
SendFrame1(); // (see note above)
else {
TCPStateMachine = CLOSED;
SocketStatus = SOCK_ERR_ETHERNET; // indicate an error to user
TCPFlags = 0; // clear all flags, stop timers etc.
}
TransmitControl &= ~SEND_FRAME1; // clear tx-flag
}
}
// easyWEB internal function
// handles an incoming broadcast frame
void ProcessEthBroadcastFrame(void)
{
unsigned int TargetIP[2];
// 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 (FF-FF-FF-FF-FF-FF)
CopyFromFrame8900(&RecdFrameMAC, 6); // store SA (for our answer)
if (ReadFrameBE8900() == FRAME_ARP) // get frame type, check for ARP
if (ReadFrameBE8900() == HARDW_ETH10) // Ethernet frame
if (ReadFrameBE8900() == FRAME_IP) // check protocol
if (ReadFrameBE8900() == IP_HLEN_PLEN) // check HLEN, PLEN
if (ReadFrameBE8900() == OP_ARP_REQUEST)
{
DummyReadFrame8900(6); // ignore sender's hardware address
CopyFromFrame8900(&RecdFrameIP, 4); // read sender's protocol address
DummyReadFrame8900(6); // ignore target's hardware address
CopyFromFrame8900(&TargetIP, 4); // read target's protocol address
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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -