A stack which works with or without an Mbed os library. Provides IPv4 or IPv6 with a full 1500 byte buffer.
Dependents: oldheating gps motorhome heating
Diff: tcp/tcprecv.c
- Revision:
- 74:c3756bfa960e
- Child:
- 75:603b10404183
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tcp/tcprecv.c Mon Oct 29 09:33:44 2018 +0000 @@ -0,0 +1,186 @@ +#include <stdint.h> +#include <stdbool.h> + +#include "log.h" +#include "net.h" +#include "action.h" +#include "tcp.h" +#include "tcphdr.h" +#include "tcpsend.h" +#include "tcb.h" +#include "ip4.h" +#include "dhcp.h" +#include "http.h" +#include "led.h" + +//Payload variables +static struct tcb* pTcb; + +static void logReset(char* message) +{ + if (TcpTrace) { LogTime("TCP sent RST - "); Log(message); Log("\r\n"); } +} + +static void startConnection(void *pPacket, int ipType, int remArIndex, int locMss) +{ + //Get the MSS to use for sends - it is the lower of the MSS advertised by the remote host and our local MSS + int remMss = TcpHdrMssGet(); + pTcb->remMss = remMss ? remMss : 536; //default MSS for IPv4 [576 - 20(TCP) - 20(IP)]; + if (pTcb->remMss > locMss) pTcb->remMss = locMss; + + pTcb->lastSendTime = TcbElapsed; + pTcb->remArIndex = remArIndex; + pTcb->ipType = ipType; + pTcb->remPort = TcpHdrSrcPort; + pTcb->locPort = TcpHdrDstPort; + pTcb->rcvdFin = false; + pTcb->sentFin = false; + pTcb->window = TcpHdrWindow; + pTcb->todo = 0; +} +static void handleReceivedData(void* pPacket, int dataLength) +{ + pTcb->window = TcpHdrWindow; + char* pData = (char*)pPacket + TcpHdrSizeGet(); + switch (pTcb->locPort) + { + case 80: + HttpHandleRequest(dataLength, pData, pTcb->bytesRcvdFromRem - 1, &pTcb->todo); + break; + default: + break; + } +} + +int TcpHandleReceivedPacket(void (*traceback)(void), int sizeRx, void* pPacketRx, int* pSizeTx, void* pPacketTx, int ipType, int remArIndex) +{ + TcpHdrReadFromPacket(pPacketRx); + + int dataLength = sizeRx - TcpHdrSizeGet(); + int locMss = *pSizeTx - TcpHdrSizeGet(); + + TcpDoTrace = false; + + //Filter out unwanted links + switch (TcpHdrDstPort) + { + case 80: + if (HttpTrace) + { + if (NetTraceNewLine) Log("\r\n"); + LogTime("HTTP server request\r\n"); + TcpDoTrace = true; + } + break; + + default: + if (TcpTrace) + { + if (NetTraceNewLine) Log("\r\n"); + LogTimeF("TCP unknown port %d\r\n", TcpHdrDstPort); + if (NetTraceStack) traceback(); + } + return DO_NOTHING; //Ignore unknown ports + } + + //Get the Transmission Control Block + pTcb = TcbGetExisting(TcpHdrSrcPort); + if (!pTcb) pTcb = TcbGetEmpty(); + if (!pTcb) + { + if (TcpTrace) + { + if (NetTraceNewLine) Log("\r\n"); + LogTime("TCP no more tcbs are available\r\n"); + if (NetTraceStack) traceback(); + } + return DO_NOTHING; //Bomb out if no more tcbs are available + } + + //Handle request to reset + if (TcpHdrRST) + { + if (TcpTrace) + { + if (NetTraceNewLine) Log("\r\n"); + LogTime("TCP received reset - resetting TCB\r\n"); + if (NetTraceStack) traceback(); + } + pTcb->state = TCB_EMPTY; + return DO_NOTHING; //Don't reply + } + + //Handle request to synchronise + if (TcpHdrSYN) + { + pTcb->remIsn = TcpHdrSeqNum; + pTcb->locIsn = TcbGetIsn(); + pTcb->bytesRcvdFromRem = 0; + pTcb->bytesAckdByRem = 0; + pTcb->bytesAckdToRem = 0; + pTcb->bytesSentToRem = 0; + } + + //Check window and just resend the last ACK if not good + uint32_t seqRcvdFromRem = TcpHdrSeqNum - pTcb->remIsn; + bool resendAck = seqRcvdFromRem != pTcb->bytesAckdToRem; + if (resendAck) return TcpSend(pSizeTx, pPacketTx, pTcb, TCP_RESEND_ACK); + + pTcb->bytesRcvdFromRem = TcpHdrSeqNum - pTcb->remIsn; + pTcb->bytesAckdByRem = TcpHdrAckNum - pTcb->locIsn; + + + //Handle FIN + if (TcpHdrFIN) pTcb->rcvdFin = true; //When reply is all sent only a passive close is needed + + if (TcpDoTrace && NetTraceStack) traceback(); //This will already include the TCP header + + if (TcpHdrSYN) pTcb->bytesRcvdFromRem += 1; //Add one to acknowledge the SYN + pTcb->bytesRcvdFromRem += dataLength; //Add the number of bytes received + if (TcpHdrFIN) pTcb->bytesRcvdFromRem += 1; //Add one to acknowledge the FIN + + switch (pTcb->state) + { + case TCB_EMPTY: + if (!TcpHdrSYN) + { + logReset("received other than a SYN when connection closed"); + pTcb->state = TCB_EMPTY; + return TcpSend(pSizeTx, pPacketTx, pTcb, TCP_SEND_RESET); + } + startConnection(pPacketRx, ipType, remArIndex, locMss); + pTcb->state = TCB_SYN_RECEIVED; + break; + + case TCB_SYN_RECEIVED: + if (dataLength) + { + logReset("data received before connection established"); + pTcb->state = TCB_EMPTY; + return TcpSend(pSizeTx, pPacketTx, pTcb, TCP_SEND_RESET); + } + pTcb->state = TCB_ESTABLISHED; + break; + + case TCB_ESTABLISHED: + if (dataLength) handleReceivedData (pPacketRx, dataLength); + if (pTcb->sentFin) + { + pTcb->state = pTcb->rcvdFin ? TCB_CLOSE_ACK_WAIT : TCB_CLOSE_FIN_WAIT; + } + break; + + case TCB_CLOSE_FIN_WAIT: //End of active close + if (TcpHdrFIN) + { + pTcb->state = TCB_EMPTY;//Ignore ACK to our FIN. Wait for FIN then close. + } + break; + + case TCB_CLOSE_ACK_WAIT: //End of passive close + pTcb->state = TCB_EMPTY; + break; + } + + return TcpSend(pSizeTx, pPacketTx, pTcb, TCP_SEND_NORMAL); +}