Webserver basic for CDU
Dependencies: mbed
Fork of EasyWebCR by
Diff: tcpip.c
- Revision:
- 0:12b53511e212
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tcpip.c Fri Jan 29 21:46:31 2010 +0000 @@ -0,0 +1,1291 @@ +/****************************************************************** + ***** ***** + ***** 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); +} +