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

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);
+}