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
tcp/tcprecv.c
- Committer:
- andrewboyson
- Date:
- 2018-10-30
- Revision:
- 75:603b10404183
- Parent:
- 74:c3756bfa960e
- Child:
- 76:17534bde28d3
File content as of revision 75:603b10404183:
#include <stdint.h> #include <stdbool.h> #include <stdarg.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 logTraceBack(void (*traceback)(void), char* fmt, ...) { if (TcpTrace) { if (NetTraceNewLine) Log("\r\n"); va_list argptr; va_start(argptr, fmt); LogV(fmt, argptr); va_end(argptr); Log("\r\n"); if (NetTraceStack) traceback(); } } 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; pTcb->remIsn = TcpHdrSeqNum; pTcb->locIsn = TcbGetIsn(); pTcb->bytesRcvdFromRem = 0; pTcb->bytesAckdByRem = 0; pTcb->bytesAckdToRem = 0; pTcb->bytesSentToRem = 0; } static void handleReceivedData(void* pPacket, int dataLength, uint32_t position) { pTcb->window = TcpHdrWindow; char* pData = (char*)pPacket + TcpHdrSizeGet(); switch (pTcb->locPort) { case 80: HttpHandleRequest(dataLength, pData, position, &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: logTraceBack(traceback, "TCP - unknown port %d\r\n", TcpHdrDstPort); return DO_NOTHING; //Ignore unknown ports } //Get the existing Transmission Control Block pTcb = TcbGetExisting(TcpHdrSrcPort); //Handle request to reset if (TcpHdrRST) { if (pTcb) { logTraceBack(traceback, "TCP - received reset - resetting TCB\r\n"); pTcb->state = TCB_EMPTY; } return DO_NOTHING; //Don't reply } //Handle request to synchronise if (TcpHdrSYN) { if (pTcb) { logReset("received a SYN when connection open"); pTcb->state = TCB_EMPTY; return TcpSendReset(pSizeTx, pPacketTx, pTcb); } pTcb = TcbGetEmpty(); if (!pTcb) //Bomb out if no more tcbs are available { logTraceBack(traceback, "TCP - no more tcbs are available\r\n"); return DO_NOTHING; } startConnection(pPacketRx, ipType, remArIndex, locMss); } //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 TcpResendLastAck(pSizeTx, pPacketTx, pTcb); //Record the number of bytes acked by the remote host 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 //Record the number of bytes received from the remote host 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: pTcb->state = TCB_SYN_RECEIVED; break; case TCB_SYN_RECEIVED: if (dataLength) { logReset("data received before connection established"); pTcb->state = TCB_EMPTY; return TcpSendReset(pSizeTx, pPacketTx, pTcb); } pTcb->state = TCB_ESTABLISHED; break; case TCB_ESTABLISHED: if (dataLength) handleReceivedData (pPacketRx, dataLength, seqRcvdFromRem - 1); 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); }