code_red's port of EasyWeb server for LPC1768, made to compile with mbed's online compiler.
tcpip.c
- Committer:
- igorsk
- Date:
- 2010-01-29
- Revision:
- 0:12b53511e212
File content as of revision 0:12b53511e212:
/******************************************************************
***** *****
***** Name: tcpip.c *****
***** Ver.: 1.0 *****
***** Date: 07/05/2001 *****
***** Auth: Andreas Dannenberg *****
***** HTWK Leipzig *****
***** university of applied sciences *****
***** Germany *****
***** adannenb@et.htwk-leipzig.de *****
***** Func: implements the TCP/IP-stack and provides a *****
***** simple API to the user *****
***** *****
******************************************************************/
// Modifications by Code Red Technologies for NXP LPC1768
// Throughout file, functions of form xxx8900() renamed xxx_EthMAC()
// Other changes commented in place
#include "tcpip.h"
//CodeRed - added header for LPC ethernet controller
#include "ethmac.h"
// CodeRed - added library string handling header
#include <string.h>
// CodeRed - added NXP LPC register definitions header
//#include "LPC17xx.h"
#include "mbed.h"
unsigned short MyIP[] = // "MYIP1.MYIP2.MYIP3.MYIP4"
{
MYIP_1 + (MYIP_2 << 8),
MYIP_3 + (MYIP_4 << 8)
};
unsigned short SubnetMask[] = // "SUBMASK1.SUBMASK2.SUBMASK3.SUBMASK4"
{
SUBMASK_1 + (SUBMASK_2 << 8),
SUBMASK_3 + (SUBMASK_4 << 8)
};
unsigned short GatewayIP[] = // "GWIP1.GWIP2.GWIP3.GWIP4"
{
GWIP_1 + (GWIP_2 << 8),
GWIP_3 + (GWIP_4 << 8)
};
// the next 3 buffers must be word-aligned!
// (here the 'RecdIPFrameLength' above does that)
unsigned short _TxFrame1[(ETH_HEADER_SIZE + IP_HEADER_SIZE + TCP_HEADER_SIZE + MAX_TCP_TX_DATA_SIZE)/2];
unsigned short _TxFrame2[(ETH_HEADER_SIZE + MAX_ETH_TX_DATA_SIZE)/2];
unsigned short _RxTCPBuffer[MAX_TCP_RX_DATA_SIZE/2]; // space for incoming TCP-data
unsigned short TxFrame1Size; // bytes to send in TxFrame1
unsigned char TxFrame2Size; // bytes to send in TxFrame2
unsigned char TransmitControl;
#define SEND_FRAME1 0x01
#define SEND_FRAME2 0x02
unsigned char TCPFlags;
#define TCP_ACTIVE_OPEN 0x01 // easyWEB shall initiate a connection
#define IP_ADDR_RESOLVED 0x02 // IP sucessfully resolved to MAC
#define TCP_TIMER_RUNNING 0x04
#define TIMER_TYPE_RETRY 0x08
#define TCP_CLOSE_REQUESTED 0x10
// easyWEB's internal variables
TTCPStateMachine TCPStateMachine; // perhaps the most important var at all ;-)
TLastFrameSent LastFrameSent; // retransmission type
unsigned short ISNGenHigh; // upper word of our Initial Sequence Number
unsigned long TCPSeqNr; // next sequence number to send
unsigned long TCPUNASeqNr; // last unaknowledged sequence number
// incremented AFTER sending data
unsigned long TCPAckNr; // next seq to receive and ack to send
// incremented AFTER receiving data
unsigned char TCPTimer; // inc'd each 262ms
unsigned char RetryCounter; // nr. of retransmissions
// properties of the just received frame
unsigned short RecdFrameLength; // EMAC reported frame length
unsigned short RecdFrameMAC[3]; // 48 bit MAC
unsigned short RecdFrameIP[2]; // 32 bit IP
unsigned short RecdIPFrameLength; // 16 bit IP packet length
// easyWEB-API global vars and flags
unsigned short TCPRxDataCount; // nr. of bytes rec'd
unsigned short TCPTxDataCount; // nr. of bytes to send
unsigned short TCPLocalPort; // TCP ports
unsigned short TCPRemotePort;
unsigned short RemoteMAC[3]; // MAC and IP of current TCP-session
unsigned short RemoteIP[2];
unsigned char SocketStatus;
void Start_SysTick10ms(void);
// Code Red - moved myMAC definition in from original cs8900.h
unsigned char MyMAC[6] = // "M1-M2-M3-M4-M5-M6"
{
MYMAC_6, MYMAC_5, MYMAC_4,
MYMAC_3, MYMAC_2, MYMAC_1
};
// easyWEB-API function
// initalizes the LAN-controller, reset flags, starts timer-ISR
void TCPLowLevelInit(void)
{
// CodeRed - comment out original 8900 specific code
/*
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();
*/
LPC_GPIO1->FIODIR = 1 << 25; // P1.25 defined as Output (LED)
Start_SysTick10ms(); // Start SysTick timer running (10ms ticks)
Init_EthMAC();
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();
}
}
// CodeRed - New function to check if received frame
// was a broadcast message
// Reads the length of the received ethernet frame and checks if the
// destination address is a broadcast message or not
unsigned int BroadcastMessage(void)
{
unsigned short FrameDestination[3]; // to hold 48 bit MAC address
RecdFrameLength = StartReadingFrame();
// Read destination address
CopyFromFrame_EthMAC(&FrameDestination, 6);
// Save it for reply
CopyFromFrame_EthMAC(&RecdFrameMAC, 6);
if ((FrameDestination[0] == 0xFFFF) &&
(FrameDestination[1] == 0xFFFF) &&
(FrameDestination[2] == 0xFFFF)) {
return(1); // Broadcast message
} else {
return (0);
}
}
// 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)
{
// CodeRed - comment out original cs8900 code
/*
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();
}
*/
// Check to see if packet received
if (CheckIfFrameReceived())
{
// Was it a broadcast message?
if (BroadcastMessage()) {
ProcessEthBroadcastFrame();
}
else {
ProcessEthIAFrame();
}
// now release ethernet controller buffer
StopReadingFrame();
}
// CodeRed - now back to original code
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?
{
// CodeRed - change TAR -> TOTC to use LPC1768 clock
// TCPSeqNr = ((unsigned long)ISNGenHigh << 16) | TAR; // set local ISN
TCPSeqNr = ((unsigned long)ISNGenHigh << 16) | (LPC_TIM0->TC & 0xFFFF); // 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)
{
// CodeRed - change from int to short
// unsigned int TargetIP[2];
unsigned short TargetIP[2];
// CodeRed - remove CS8900 specific code block
/*
// 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)
// Code Red - end of CS8900 specific block
*/
if (ReadFrameBE_EthMAC() == FRAME_ARP) // get frame type, check for ARP
if (ReadFrameBE_EthMAC() == HARDW_ETH10) // Ethernet frame
if (ReadFrameBE_EthMAC() == FRAME_IP) // check protocol
if (ReadFrameBE_EthMAC() == IP_HLEN_PLEN) // check HLEN, PLEN
if (ReadFrameBE_EthMAC() == OP_ARP_REQUEST)
{
DummyReadFrame_EthMAC(6); // ignore sender's hardware address
CopyFromFrame_EthMAC(&RecdFrameIP, 4); // read sender's protocol address
DummyReadFrame_EthMAC(6); // ignore target's hardware address
CopyFromFrame_EthMAC(&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)
{
// CodeRed - change from int to short
//unsigned int TargetIP[2];
unsigned short TargetIP[2];
unsigned char ProtocolType;
// CodeRed - next few lines not needed for LPC1768 port
/*
// next two words MUST be read with High-Byte 1st (CS8900 AN181 Page 2)
ReadHB1ST_EthMAC(RX_FRAME_PORT); // ignore RxStatus Word
RecdFrameLength = ReadHB1ST_EthMAC(RX_FRAME_PORT);// get real length of frame
DummyReadFrame_EthMAC(6); // ignore DA
CopyFromFrame_EthMAC(&RecdFrameMAC, 6); // store SA (for our answer)
*/
switch (ReadFrameBE_EthMAC()) // get frame type
{
case FRAME_ARP : // check for ARP
{
if ((TCPFlags & (TCP_ACTIVE_OPEN | IP_ADDR_RESOLVED)) == TCP_ACTIVE_OPEN)
if (ReadFrameBE_EthMAC() == HARDW_ETH10) // check for the right prot. etc.
if (ReadFrameBE_EthMAC() == FRAME_IP)
if (ReadFrameBE_EthMAC() == IP_HLEN_PLEN)
if (ReadFrameBE_EthMAC() == OP_ARP_ANSWER)
{
TCPStopTimer(); // OK, now we've the MAC we wanted ;-)
CopyFromFrame_EthMAC(&RemoteMAC, 6); // extract opponents MAC
TCPFlags |= IP_ADDR_RESOLVED;
}
break;
}
case FRAME_IP : // check for IP-type
{
if ((ReadFrameBE_EthMAC() & 0xFF00 ) == IP_VER_IHL) // IPv4, IHL=5 (20 Bytes Header)
{ // ignore Type Of Service
RecdIPFrameLength = ReadFrameBE_EthMAC(); // get IP frame's length
ReadFrameBE_EthMAC(); // ignore identification
if (!(ReadFrameBE_EthMAC() & (IP_FLAG_MOREFRAG | IP_FRAGOFS_MASK))) // only unfragm. frames
{
// CodeRed - add mask
// ProtocolType = ReadFrameBE_EthMAC() ; // get protocol, ignore TTL
ProtocolType = ReadFrameBE_EthMAC() & 0xFF ; // get protocol, ignore TTL
ReadFrameBE_EthMAC(); // ignore checksum
CopyFromFrame_EthMAC(&RecdFrameIP, 4); // get source IP
CopyFromFrame_EthMAC(&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)
{
// CodeRed - change from int to short
//unsigned int ICMPTypeAndCode;
unsigned short ICMPTypeAndCode;
ICMPTypeAndCode = ReadFrameBE_EthMAC(); // get Message Type and Code
ReadFrameBE_EthMAC(); // 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)
{
// CodeRed - change from int to short
/* 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
*/
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_EthMAC(); // get ports
TCPSegDestPort = ReadFrameBE_EthMAC();
if (TCPSegDestPort != TCPLocalPort) return; // drop segment if port doesn't match
TCPSegSeq = (unsigned long)ReadFrameBE_EthMAC() << 16; // get segment sequence nr.
TCPSegSeq |= ReadFrameBE_EthMAC();
TCPSegAck = (unsigned long)ReadFrameBE_EthMAC() << 16; // get segment acknowledge nr.
TCPSegAck |= ReadFrameBE_EthMAC();
TCPCode = ReadFrameBE_EthMAC(); // 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_EthMAC(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
// CodeRed - change TAR -> TOTC to use LPC1768 clock
// TCPSeqNr = ((unsigned long)ISNGenHigh << 16) | TAR; // set local ISN
TCPSeqNr = ((unsigned long)ISNGenHigh << 16) | (LPC_TIM0->TC & 0xFFFF); // 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_EthMAC(6); // ignore window, checksum, urgent pointer
// CodeRed - removed unrequired &
// CopyFromFrame_EthMAC(&RxTCPBuffer, NrOfDataBytes);// fetch data and
CopyFromFrame_EthMAC(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
// CodeRed - added char cast
// memset(&TxFrame2[ETH_DA_OFS], 0xFF, 6);
memset(&TxFrame2[ETH_DA_OFS], (char)0xFF, 6); // we don't know opposites MAC!
memcpy(&TxFrame2[ETH_SA_OFS], &MyMAC, 6);
// Code Red - int-> short
// *(unsigned int *)&TxFrame2[ETH_TYPE_OFS] = SWAPB(FRAME_ARP);
*(unsigned short *)&TxFrame2[ETH_TYPE_OFS] = SWAPB(FRAME_ARP);
// ARP
// CodeRed - int-> short
/* *(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);
*/
*(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
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;
}
// easyWEB internal function
// prepares the TxFrame2-buffer to send an ARP-answer (reply)
void PrepareARP_ANSWER(void)
{
// Ethernet
memcpy(&TxFrame2[ETH_DA_OFS], &RecdFrameMAC, 6);
memcpy(&TxFrame2[ETH_SA_OFS], &MyMAC, 6);
// CodeRed - int-> short
// *(unsigned int *)&TxFrame2[ETH_TYPE_OFS] = SWAPB(FRAME_ARP);
*(unsigned short *)&TxFrame2[ETH_TYPE_OFS] = SWAPB(FRAME_ARP);
// ARP
// CodeRed - int-> short
/* *(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_ANSWER);
*/
*(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_ANSWER);
memcpy(&TxFrame2[ARP_SENDER_HA_OFS], &MyMAC, 6);
memcpy(&TxFrame2[ARP_SENDER_IP_OFS], &MyIP, 4);
memcpy(&TxFrame2[ARP_TARGET_HA_OFS], &RecdFrameMAC, 6);
memcpy(&TxFrame2[ARP_TARGET_IP_OFS], &RecdFrameIP, 4);
TxFrame2Size = ETH_HEADER_SIZE + ARP_FRAME_SIZE;
TransmitControl |= SEND_FRAME2;
}
// easyWEB internal function
// prepares the TxFrame2-buffer to send an ICMP-echo-reply
void PrepareICMP_ECHO_REPLY(void)
{
// CodeRed - int-> short
// unsigned int ICMPDataCount;
unsigned short ICMPDataCount;
if (RecdIPFrameLength > MAX_ETH_TX_DATA_SIZE) // don't overload TX-buffer
ICMPDataCount = MAX_ETH_TX_DATA_SIZE - IP_HEADER_SIZE - ICMP_HEADER_SIZE;
else
ICMPDataCount = RecdIPFrameLength - IP_HEADER_SIZE - ICMP_HEADER_SIZE;
// Ethernet
memcpy(&TxFrame2[ETH_DA_OFS], &RecdFrameMAC, 6);
memcpy(&TxFrame2[ETH_SA_OFS], &MyMAC, 6);
// CodeRed - int-> short
// *(unsigned int *)&TxFrame2[ETH_TYPE_OFS] = SWAPB(FRAME_IP);
*(unsigned short *)&TxFrame2[ETH_TYPE_OFS] = SWAPB(FRAME_IP);
// IP
// CodeRed - int-> short
/* *(unsigned int *)&TxFrame2[IP_VER_IHL_TOS_OFS] = SWAPB(IP_VER_IHL);
WriteWBE(&TxFrame2[IP_TOTAL_LENGTH_OFS], IP_HEADER_SIZE + ICMP_HEADER_SIZE + ICMPDataCount);
*(unsigned int *)&TxFrame2[IP_IDENT_OFS] = 0;
*(unsigned int *)&TxFrame2[IP_FLAGS_FRAG_OFS] = 0;
*(unsigned int *)&TxFrame2[IP_TTL_PROT_OFS] = SWAPB((DEFAULT_TTL << 8) | PROT_ICMP);
*(unsigned int *)&TxFrame2[IP_HEAD_CHKSUM_OFS] = 0;
memcpy(&TxFrame2[IP_SOURCE_OFS], &MyIP, 4);
memcpy(&TxFrame2[IP_DESTINATION_OFS], &RecdFrameIP, 4);
*(unsigned int *)&TxFrame2[IP_HEAD_CHKSUM_OFS] = CalcChecksum(&TxFrame2[IP_VER_IHL_TOS_OFS], IP_HEADER_SIZE, 0);
*/
*(unsigned short *)&TxFrame2[IP_VER_IHL_TOS_OFS] = SWAPB(IP_VER_IHL);
WriteWBE(&TxFrame2[IP_TOTAL_LENGTH_OFS], IP_HEADER_SIZE + ICMP_HEADER_SIZE + ICMPDataCount);
*(unsigned short *)&TxFrame2[IP_IDENT_OFS] = 0;
*(unsigned short *)&TxFrame2[IP_FLAGS_FRAG_OFS] = 0;
*(unsigned short *)&TxFrame2[IP_TTL_PROT_OFS] = SWAPB((DEFAULT_TTL << 8) | PROT_ICMP);
*(unsigned short *)&TxFrame2[IP_HEAD_CHKSUM_OFS] = 0;
memcpy(&TxFrame2[IP_SOURCE_OFS], &MyIP, 4);
memcpy(&TxFrame2[IP_DESTINATION_OFS], &RecdFrameIP, 4);
*(unsigned short *)&TxFrame2[IP_HEAD_CHKSUM_OFS] = CalcChecksum(&TxFrame2[IP_VER_IHL_TOS_OFS], IP_HEADER_SIZE, 0);
// ICMP
// CodeRed - int-> short
/* *(unsigned int *)&TxFrame2[ICMP_TYPE_CODE_OFS] = SWAPB(ICMP_ECHO_REPLY << 8);
*(unsigned int *)&TxFrame2[ICMP_CHKSUM_OFS] = 0; // initialize checksum field
CopyFromFrame8900(&TxFrame2[ICMP_DATA_OFS], ICMPDataCount); // get data to echo...
*(unsigned int *)&TxFrame2[ICMP_CHKSUM_OFS] = CalcChecksum(&TxFrame2[IP_DATA_OFS], ICMPDataCount + ICMP_HEADER_SIZE, 0);
*/
*(unsigned short *)&TxFrame2[ICMP_TYPE_CODE_OFS] = SWAPB(ICMP_ECHO_REPLY << 8);
*(unsigned short *)&TxFrame2[ICMP_CHKSUM_OFS] = 0; // initialize checksum field
CopyFromFrame_EthMAC(&TxFrame2[ICMP_DATA_OFS], ICMPDataCount); // get data to echo...
*(unsigned short *)&TxFrame2[ICMP_CHKSUM_OFS] = CalcChecksum(&TxFrame2[IP_DATA_OFS], ICMPDataCount + ICMP_HEADER_SIZE, 0);
// ICMP
// Code Red - int-> short
/* *(unsigned int *)&TxFrame2[ICMP_TYPE_CODE_OFS] = SWAPB(ICMP_ECHO_REPLY << 8);
*(unsigned int *)&TxFrame2[ICMP_CHKSUM_OFS] = 0; // initialize checksum field
CopyFromFrame8900(&TxFrame2[ICMP_DATA_OFS], ICMPDataCount); // get data to echo...
*(unsigned int *)&TxFrame2[ICMP_CHKSUM_OFS] = CalcChecksum(&TxFrame2[IP_DATA_OFS], ICMPDataCount + ICMP_HEADER_SIZE, 0);
*/
*(unsigned short *)&TxFrame2[ICMP_TYPE_CODE_OFS] = SWAPB(ICMP_ECHO_REPLY << 8);
*(unsigned short *)&TxFrame2[ICMP_CHKSUM_OFS] = 0; // initialize checksum field
CopyFromFrame_EthMAC(&TxFrame2[ICMP_DATA_OFS], ICMPDataCount); // get data to echo...
*(unsigned short *)&TxFrame2[ICMP_CHKSUM_OFS] = CalcChecksum(&TxFrame2[IP_DATA_OFS], ICMPDataCount + ICMP_HEADER_SIZE, 0);
TxFrame2Size = ETH_HEADER_SIZE + IP_HEADER_SIZE + ICMP_HEADER_SIZE + ICMPDataCount;
TransmitControl |= SEND_FRAME2;
}
// easyWEB internal function
// prepares the TxFrame2-buffer to send a general TCP frame
// the TCPCode-field is passed as an argument
// CodeRed - int-> short
//void PrepareTCP_FRAME(unsigned int TCPCode)
void PrepareTCP_FRAME(unsigned short TCPCode)
{
// Ethernet
memcpy(&TxFrame2[ETH_DA_OFS], &RemoteMAC, 6);
memcpy(&TxFrame2[ETH_SA_OFS], &MyMAC, 6);
// CodeRed - int-> short
// *(unsigned int *)&TxFrame2[ETH_TYPE_OFS] = SWAPB(FRAME_IP);
*(unsigned short *)&TxFrame2[ETH_TYPE_OFS] = SWAPB(FRAME_IP);
// IP
// Code Red - int-> short
/* *(unsigned int *)&TxFrame2[IP_VER_IHL_TOS_OFS] = SWAPB(IP_VER_IHL | IP_TOS_D);
if (TCPCode & TCP_CODE_SYN) // if SYN, we want to use the MSS option
*(unsigned int *)&TxFrame2[IP_TOTAL_LENGTH_OFS] = SWAPB(IP_HEADER_SIZE + TCP_HEADER_SIZE + TCP_OPT_MSS_SIZE);
else
*(unsigned int *)&TxFrame2[IP_TOTAL_LENGTH_OFS] = SWAPB(IP_HEADER_SIZE + TCP_HEADER_SIZE);
*(unsigned int *)&TxFrame2[IP_IDENT_OFS] = 0;
*(unsigned int *)&TxFrame2[IP_FLAGS_FRAG_OFS] = 0;
*(unsigned int *)&TxFrame2[IP_TTL_PROT_OFS] = SWAPB((DEFAULT_TTL << 8) | PROT_TCP);
*(unsigned int *)&TxFrame2[IP_HEAD_CHKSUM_OFS] = 0;
memcpy(&TxFrame2[IP_SOURCE_OFS], &MyIP, 4);
memcpy(&TxFrame2[IP_DESTINATION_OFS], &RemoteIP, 4);
*(unsigned int *)&TxFrame2[IP_HEAD_CHKSUM_OFS] = CalcChecksum(&TxFrame2[IP_VER_IHL_TOS_OFS], IP_HEADER_SIZE, 0);
*/
*(unsigned short *)&TxFrame2[IP_VER_IHL_TOS_OFS] = SWAPB(IP_VER_IHL | IP_TOS_D);
if (TCPCode & TCP_CODE_SYN) // if SYN, we want to use the MSS option
*(unsigned short *)&TxFrame2[IP_TOTAL_LENGTH_OFS] = SWAPB(IP_HEADER_SIZE + TCP_HEADER_SIZE + TCP_OPT_MSS_SIZE);
else
*(unsigned short *)&TxFrame2[IP_TOTAL_LENGTH_OFS] = SWAPB(IP_HEADER_SIZE + TCP_HEADER_SIZE);
*(unsigned short *)&TxFrame2[IP_IDENT_OFS] = 0;
*(unsigned short *)&TxFrame2[IP_FLAGS_FRAG_OFS] = 0;
*(unsigned short *)&TxFrame2[IP_TTL_PROT_OFS] = SWAPB((DEFAULT_TTL << 8) | PROT_TCP);
*(unsigned short *)&TxFrame2[IP_HEAD_CHKSUM_OFS] = 0;
memcpy(&TxFrame2[IP_SOURCE_OFS], &MyIP, 4);
memcpy(&TxFrame2[IP_DESTINATION_OFS], &RemoteIP, 4);
*(unsigned short *)&TxFrame2[IP_HEAD_CHKSUM_OFS] = CalcChecksum(&TxFrame2[IP_VER_IHL_TOS_OFS], IP_HEADER_SIZE, 0);
// TCP
WriteWBE(&TxFrame2[TCP_SRCPORT_OFS], TCPLocalPort);
WriteWBE(&TxFrame2[TCP_DESTPORT_OFS], TCPRemotePort);
WriteDWBE(&TxFrame2[TCP_SEQNR_OFS], TCPSeqNr);
WriteDWBE(&TxFrame2[TCP_ACKNR_OFS], TCPAckNr);
// CodeRed - int-> short
/* *(unsigned int *)&TxFrame2[TCP_WINDOW_OFS] = SWAPB(MAX_TCP_RX_DATA_SIZE); // data bytes to accept
*(unsigned int *)&TxFrame2[TCP_CHKSUM_OFS] = 0; // initalize checksum
*(unsigned int *)&TxFrame2[TCP_URGENT_OFS] = 0;
if (TCPCode & TCP_CODE_SYN) // if SYN, we want to use the MSS option
{
*(unsigned int *)&TxFrame2[TCP_DATA_CODE_OFS] = SWAPB(0x6000 | TCPCode); // TCP header length = 24
*(unsigned int *)&TxFrame2[TCP_DATA_OFS] = SWAPB(TCP_OPT_MSS); // MSS option
*(unsigned int *)&TxFrame2[TCP_DATA_OFS + 2] = SWAPB(MAX_TCP_RX_DATA_SIZE);// max. length of TCP-data we accept
*(unsigned int *)&TxFrame2[TCP_CHKSUM_OFS] = CalcChecksum(&TxFrame2[TCP_SRCPORT_OFS], TCP_HEADER_SIZE + TCP_OPT_MSS_SIZE, 1);
TxFrame2Size = ETH_HEADER_SIZE + IP_HEADER_SIZE + TCP_HEADER_SIZE + TCP_OPT_MSS_SIZE;
}
else
{
*(unsigned int *)&TxFrame2[TCP_DATA_CODE_OFS] = SWAPB(0x5000 | TCPCode); // TCP header length = 20
*(unsigned int *)&TxFrame2[TCP_CHKSUM_OFS] = CalcChecksum(&TxFrame2[TCP_SRCPORT_OFS], TCP_HEADER_SIZE, 1);
TxFrame2Size = ETH_HEADER_SIZE + IP_HEADER_SIZE + TCP_HEADER_SIZE;
}
*/
*(unsigned short *)&TxFrame2[TCP_WINDOW_OFS] = SWAPB(MAX_TCP_RX_DATA_SIZE); // data bytes to accept
*(unsigned short *)&TxFrame2[TCP_CHKSUM_OFS] = 0; // initalize checksum
*(unsigned short *)&TxFrame2[TCP_URGENT_OFS] = 0;
if (TCPCode & TCP_CODE_SYN) // if SYN, we want to use the MSS option
{
*(unsigned short *)&TxFrame2[TCP_DATA_CODE_OFS] = SWAPB(0x6000 | TCPCode); // TCP header length = 24
*(unsigned short *)&TxFrame2[TCP_DATA_OFS] = SWAPB(TCP_OPT_MSS); // MSS option
*(unsigned short *)&TxFrame2[TCP_DATA_OFS + 2] = SWAPB(MAX_TCP_RX_DATA_SIZE);// max. length of TCP-data we accept
*(unsigned short *)&TxFrame2[TCP_CHKSUM_OFS] = CalcChecksum(&TxFrame2[TCP_SRCPORT_OFS], TCP_HEADER_SIZE + TCP_OPT_MSS_SIZE, 1);
TxFrame2Size = ETH_HEADER_SIZE + IP_HEADER_SIZE + TCP_HEADER_SIZE + TCP_OPT_MSS_SIZE;
}
else
{
*(unsigned short *)&TxFrame2[TCP_DATA_CODE_OFS] = SWAPB(0x5000 | TCPCode); // TCP header length = 20
*(unsigned short *)&TxFrame2[TCP_CHKSUM_OFS] = CalcChecksum(&TxFrame2[TCP_SRCPORT_OFS], TCP_HEADER_SIZE, 1);
TxFrame2Size = ETH_HEADER_SIZE + IP_HEADER_SIZE + TCP_HEADER_SIZE;
}
TransmitControl |= SEND_FRAME2;
}
// easyWEB internal function
// prepares the TxFrame1-buffer to send a payload-packet
void PrepareTCP_DATA_FRAME(void)
{
// Ethernet
memcpy(&TxFrame1[ETH_DA_OFS], &RemoteMAC, 6);
memcpy(&TxFrame1[ETH_SA_OFS], &MyMAC, 6);
// Code Red - int-> short
// *(unsigned int *)&TxFrame1[ETH_TYPE_OFS] = SWAPB(FRAME_IP);
*(unsigned short *)&TxFrame1[ETH_TYPE_OFS] = SWAPB(FRAME_IP);
// IP
// CodeRed - int-> short
/* *(unsigned int *)&TxFrame1[IP_VER_IHL_TOS_OFS] = SWAPB(IP_VER_IHL | IP_TOS_D);
WriteWBE(&TxFrame1[IP_TOTAL_LENGTH_OFS], IP_HEADER_SIZE + TCP_HEADER_SIZE + TCPTxDataCount);
*(unsigned int *)&TxFrame1[IP_IDENT_OFS] = 0;
*(unsigned int *)&TxFrame1[IP_FLAGS_FRAG_OFS] = 0;
*(unsigned int *)&TxFrame1[IP_TTL_PROT_OFS] = SWAPB((DEFAULT_TTL << 8) | PROT_TCP);
*(unsigned int *)&TxFrame1[IP_HEAD_CHKSUM_OFS] = 0;
memcpy(&TxFrame1[IP_SOURCE_OFS], &MyIP, 4);
memcpy(&TxFrame1[IP_DESTINATION_OFS], &RemoteIP, 4);
*(unsigned int *)&TxFrame1[IP_HEAD_CHKSUM_OFS] = CalcChecksum(&TxFrame1[IP_VER_IHL_TOS_OFS], IP_HEADER_SIZE, 0);
*/
*(unsigned short *)&TxFrame1[IP_VER_IHL_TOS_OFS] = SWAPB(IP_VER_IHL | IP_TOS_D);
WriteWBE(&TxFrame1[IP_TOTAL_LENGTH_OFS], IP_HEADER_SIZE + TCP_HEADER_SIZE + TCPTxDataCount);
*(unsigned short *)&TxFrame1[IP_IDENT_OFS] = 0;
*(unsigned short *)&TxFrame1[IP_FLAGS_FRAG_OFS] = 0;
*(unsigned short *)&TxFrame1[IP_TTL_PROT_OFS] = SWAPB((DEFAULT_TTL << 8) | PROT_TCP);
*(unsigned short *)&TxFrame1[IP_HEAD_CHKSUM_OFS] = 0;
memcpy(&TxFrame1[IP_SOURCE_OFS], &MyIP, 4);
memcpy(&TxFrame1[IP_DESTINATION_OFS], &RemoteIP, 4);
*(unsigned short *)&TxFrame1[IP_HEAD_CHKSUM_OFS] = CalcChecksum(&TxFrame1[IP_VER_IHL_TOS_OFS], IP_HEADER_SIZE, 0);
// TCP
WriteWBE(&TxFrame1[TCP_SRCPORT_OFS], TCPLocalPort);
WriteWBE(&TxFrame1[TCP_DESTPORT_OFS], TCPRemotePort);
WriteDWBE(&TxFrame1[TCP_SEQNR_OFS], TCPSeqNr);
WriteDWBE(&TxFrame1[TCP_ACKNR_OFS], TCPAckNr);
// CodeRed - int-> short
/* *(unsigned int *)&TxFrame1[TCP_DATA_CODE_OFS] = SWAPB(0x5000 | TCP_CODE_ACK); // TCP header length = 20
*(unsigned int *)&TxFrame1[TCP_WINDOW_OFS] = SWAPB(MAX_TCP_RX_DATA_SIZE); // data bytes to accept
*(unsigned int *)&TxFrame1[TCP_CHKSUM_OFS] = 0;
*(unsigned int *)&TxFrame1[TCP_URGENT_OFS] = 0;
*(unsigned int *)&TxFrame1[TCP_CHKSUM_OFS] = CalcChecksum(&TxFrame1[TCP_SRCPORT_OFS], TCP_HEADER_SIZE + TCPTxDataCount, 1);
*/
*(unsigned short *)&TxFrame1[TCP_DATA_CODE_OFS] = SWAPB(0x5000 | TCP_CODE_ACK); // TCP header length = 20
*(unsigned short *)&TxFrame1[TCP_WINDOW_OFS] = SWAPB(MAX_TCP_RX_DATA_SIZE); // data bytes to accept
*(unsigned short *)&TxFrame1[TCP_CHKSUM_OFS] = 0;
*(unsigned short *)&TxFrame1[TCP_URGENT_OFS] = 0;
*(unsigned short *)&TxFrame1[TCP_CHKSUM_OFS] = CalcChecksum(&TxFrame1[TCP_SRCPORT_OFS], TCP_HEADER_SIZE + TCPTxDataCount, 1);
}
// easyWEB internal function
// calculates the TCP/IP checksum. if 'IsTCP != 0', the TCP pseudo-header
// will be included.
// CodeRed - int-> short
//unsigned int CalcChecksum(void *Start, unsigned int Count, unsigned char IsTCP)
unsigned short CalcChecksum(void *Start, unsigned short Count, unsigned char IsTCP)
{
// Code Red - added pStart
unsigned short *pStart;
unsigned long Sum = 0;
if (IsTCP) { // if we've a TCP frame...
Sum += MyIP[0]; // ...include TCP pseudo-header
Sum += MyIP[1];
Sum += RemoteIP[0];
Sum += RemoteIP[1];
Sum += SwapBytes(Count); // TCP header length plus data length
Sum += SWAPB(PROT_TCP);
}
// Code Red - modified to correct expression
/* while (Count > 1) { // sum words
Sum += *((unsigned int *)Start)++;
Count -= 2;
}
if (Count) // add left-over byte, if any
Sum += *(unsigned char *)Start;
*/
pStart = (unsigned short *)Start;
while (Count > 1) { // sum words
Sum += *pStart++;
Count -= 2;
}
if (Count) // add left-over byte, if any
Sum += *(unsigned char *)pStart;
while (Sum >> 16) // fold 32-bit sum to 16 bits
Sum = (Sum & 0xFFFF) + (Sum >> 16);
return ~Sum;
}
// easyWEB internal function
// starts the timer as a retry-timer (used for retransmission-timeout)
void TCPStartRetryTimer(void)
{
TCPTimer = 0;
RetryCounter = MAX_RETRYS;
TCPFlags |= TCP_TIMER_RUNNING;
TCPFlags |= TIMER_TYPE_RETRY;
}
// easyWEB internal function
// starts the timer as a 'TIME_WAIT'-timer (used to finish a TCP-session)
void TCPStartTimeWaitTimer(void)
{
TCPTimer = 0;
TCPFlags |= TCP_TIMER_RUNNING;
TCPFlags &= ~TIMER_TYPE_RETRY;
}
// easyWEB internal function
// restarts the timer
void TCPRestartTimer(void)
{
TCPTimer = 0;
}
// easyWEB internal function
// stopps the timer
void TCPStopTimer(void)
{
TCPFlags &= ~TCP_TIMER_RUNNING;
}
// easyWEB internal function
// if a retransmission-timeout occured, check which packet
// to resend.
void TCPHandleRetransmission(void)
{
switch (LastFrameSent)
{
case ARP_REQUEST : { PrepareARP_REQUEST(); break; }
case TCP_SYN_FRAME : { PrepareTCP_FRAME(TCP_CODE_SYN); break; }
case TCP_SYN_ACK_FRAME : { PrepareTCP_FRAME(TCP_CODE_SYN | TCP_CODE_ACK); break; }
case TCP_FIN_FRAME : { PrepareTCP_FRAME(TCP_CODE_FIN | TCP_CODE_ACK); break; }
case TCP_DATA_FRAME : { TransmitControl |= SEND_FRAME1; break; }
}
}
// easyWEB internal function
// if all retransmissions failed, close connection and indicate an error
void TCPHandleTimeout(void)
{
TCPStateMachine = CLOSED;
if ((TCPFlags & (TCP_ACTIVE_OPEN | IP_ADDR_RESOLVED)) == TCP_ACTIVE_OPEN)
SocketStatus = SOCK_ERR_ARP_TIMEOUT; // indicate an error to user
else
SocketStatus = SOCK_ERR_TCP_TIMEOUT;
TCPFlags = 0; // clear all flags
}
// CodeRed - TCPClockHandler() replaced
/*
// easyWEB internal function
// function executed every 0.262s by the MCU. used for the
// inital sequence number generator (ISN) and the TCP-timer
interrupt [TIMERA1_VECTOR] void TCPClockHandler(void)
{
if (TAIV == 10) // check for timer overflow, reset int.-flag
{
ISNGenHigh++; // upper 16 bits of initial sequence number
TCPTimer++; // timer for retransmissions
}
}
*/
// easyWEB internal function
// function executed every 0.210s by the MCU. used for the
// inital sequence number generator (ISN) and the TCP-timer
void TCPClockHandler(void)
{
ISNGenHigh++; // upper 16 bits of initial sequence number
TCPTimer++; // timer for retransmissions
}
// easyWEB internal function
// transfers the contents of 'TxFrame1'-Buffer to the CS8900A
void SendFrame1(void)
{
// CodeRed - updated for LPC1768 port
// CopyToFrame8900(&TxFrame1, TxFrame1Size);
CopyToFrame_EthMAC(TxFrame1, TxFrame1Size);
}
// easyWEB internal function
// transfers the contents of 'TxFrame2'-Buffer to the CS8900A
void SendFrame2(void)
{
// CodeRed - updated for LPC1768 port
// CopyToFrame8900(&TxFrame2, TxFrame2Size);
CopyToFrame_EthMAC(TxFrame2, TxFrame2Size);
}
// easyWEB internal function
// help function to write a WORD in big-endian byte-order
// to MCU-memory
// CodeRed - int->short
//void WriteWBE(unsigned char *Add, unsigned int Data)
void WriteWBE(unsigned char *Add, unsigned short Data)
{
*Add++ = Data >> 8;
// Code Red - added cast
// *Add = Data;
*Add = (char)Data;
}
// easyWEB internal function
// help function to write a DWORD in big-endian byte-order
// to MCU-memory
void WriteDWBE(unsigned char *Add, unsigned long Data)
{
*Add++ = Data >> 24;
*Add++ = Data >> 16;
*Add++ = Data >> 8;
*Add = Data;
}
// easyWEB internal function
// help function to swap the byte order of a WORD
// CodeRed - int->short
//unsigned int SwapBytes(unsigned int Data)
unsigned short SwapBytes(unsigned short Data)
{
return (Data >> 8) | (Data << 8);
}