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-11-20
- Revision:
- 88:1ba13e6062a3
- Parent:
- 86:55bc5ddac16c
- Child:
- 89:9b765a67699b
File content as of revision 88:1ba13e6062a3:
#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" static void logReset(char* fmt, ...) { if (TcpTrace) { if (NetTraceNewLine) Log("\r\n"); LogTime("TCP sent RST - "); va_list argptr; va_start(argptr, fmt); LogV(fmt, argptr); Log("\r\n"); va_end(argptr); } } 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 handleSyn(void *pPacket, int ipType, int remArIndex, int locMss, struct tcb* pTcb) { //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->timeSendsBeingAcked = TcbElapsed; pTcb->countSendsNotAcked = 0; pTcb->rcvdFin = false; pTcb->sentFin = false; 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, struct tcb* pTcb) { 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, int locIpScope) { int action = DO_NOTHING; bool doTrace = false; Led1Set(true); if (remArIndex < 0) { LogTimeF("Invalid remote AR index %d", remArIndex); Led1Set(false); return DO_NOTHING; } TcpHdrReadFromPacket(pPacketRx); int dataLength = sizeRx - TcpHdrSizeGet(); int locMss = *pSizeTx - TcpHdrSizeGet(); //Filter out unwanted links switch (TcpHdrDstPort) { case 80: if (HttpTrace) { if (NetTraceNewLine) Log("\r\n"); LogTime("HTTP server request\r\n"); doTrace = true; } break; default: logTraceBack(traceback, "TCP - unknown port %d", TcpHdrDstPort); Led1Set(false); return DO_NOTHING; //Ignore unknown ports } //Get the Transmission Control Block struct tcb* pTcb = TcbGetExisting(ipType, remArIndex, locIpScope, TcpHdrSrcPort, TcpHdrDstPort); if (!pTcb) pTcb = TcbGetEmpty(); if (!pTcb) //Bomb out if no more tcbs are available { logTraceBack(traceback, "TCP - no more tcbs are available"); Led1Set(false); return DO_NOTHING; } pTcb->timeLastRcvd = TcbElapsed; pTcb->remArIndex = remArIndex; pTcb->ipType = ipType; pTcb->locIpScope = locIpScope; pTcb->remPort = TcpHdrSrcPort; pTcb->locPort = TcpHdrDstPort; pTcb->window = TcpHdrWindow; //Handle request to reset if (TcpHdrRST) { if (pTcb->state) { logTraceBack(traceback, "TCP - received reset - resetting TCB"); pTcb->state = TCB_EMPTY; } Led1Set(false); return DO_NOTHING; //Don't reply } //Handle request to synchronise if (TcpHdrSYN) { if (pTcb->state) { logReset("received a SYN on port %d when connection open", TcpHdrSrcPort); pTcb->state = TCB_EMPTY; action = TcpSendReset(pSizeTx, pPacketTx, pTcb); Led1Set(false); return action; } else { handleSyn(pPacketRx, ipType, remArIndex, locMss, pTcb); } } //Calculate the sequence length of the received packet int seqLengthRcvd = 0; if (TcpHdrSYN) seqLengthRcvd += 1; //Add one to acknowledge the SYN seqLengthRcvd += dataLength; //Add the number of bytes received if (TcpHdrFIN) seqLengthRcvd += 1; //Add one to acknowledge the FIN /*RFC793 p36 If the connection does not exist (CLOSED) then a reset is sent in response to any incoming segment except another reset. If the incoming segment has an ACK field, the reset takes its sequence number from the ACK field of the segment, otherwise the reset has sequence number zero and the ACK field is set to the sum of the sequence number and segment length of the incoming segment. The connection remains in the CLOSED state. In TcpSendReset TcpHdrAckNum = pTcb->bytesAckdToRem + pTcb->remIsn; //Set up the acknowledgement field ready to send TcpHdrSeqNum = pTcb->bytesSentToRem + pTcb->locIsn; //Set up the start of the message before adding the bytes sent */ if (!TcpHdrSYN && !pTcb->state) { pTcb->remIsn = 0; pTcb->locIsn = 0; pTcb->bytesRcvdFromRem = 0; pTcb->bytesAckdByRem = 0; pTcb->bytesSentToRem = TcpHdrACK ? TcpHdrAckNum : 0; //Seq number pTcb->bytesAckdToRem = TcpHdrSeqNum + seqLengthRcvd; //Ack number logReset("non SYN packet received on a closed connection"); pTcb->state = TCB_EMPTY; action = TcpSendReset(pSizeTx, pPacketTx, pTcb); Led1Set(false); return action; } //Check if the acks of bytes sent has progressed and reset the timer uint32_t ackRcvdFromRem = TcpHdrAckNum - pTcb->locIsn; if (ackRcvdFromRem > pTcb->bytesAckdByRem) { pTcb->timeSendsBeingAcked = TcbElapsed; pTcb->countSendsNotAcked = 0; } //Record the number of bytes acked by the remote host pTcb->bytesAckdByRem = ackRcvdFromRem; /* If the connection is in a synchronized state any unacceptable segment (out of window sequence number or unacceptible acknowledgment number) must elicit only an empty acknowledgment segment containing the current send-sequence number and an acknowledgment indicating the next sequence number expected to be received, and the connection remains in the same state.*/ uint32_t seqRcvdFromRem = TcpHdrSeqNum - pTcb->remIsn; if (seqRcvdFromRem != pTcb->bytesAckdToRem) { //Only warn non keep-alives if (seqRcvdFromRem != 0 || pTcb->bytesAckdToRem != 1) { logTraceBack(traceback, "TCP - resending last ACK on port %d as seq rcvd is %d and last seq ackd was %d", TcpHdrSrcPort, seqRcvdFromRem, pTcb->bytesAckdToRem); } action = TcpResendLastAck(pSizeTx, pPacketTx, pTcb); Led1Set(false); return action; } Led2Set(true); //Handle FIN if (TcpHdrFIN) pTcb->rcvdFin = true; //When reply is all sent only a passive close is needed if (doTrace && NetTraceStack) traceback(); //This will already include the TCP header //Record the number of bytes received from the remote host pTcb->bytesRcvdFromRem += seqLengthRcvd; switch (pTcb->state) //This is the state of the connection BEFORE this packet arrived { 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; action = TcpSendReset(pSizeTx, pPacketTx, pTcb); Led1Set(false); Led2Set(false); return action; } pTcb->state = TCB_ESTABLISHED; break; case TCB_ESTABLISHED: if (dataLength) handleReceivedData (pPacketRx, dataLength, seqRcvdFromRem - 1, pTcb); if (pTcb->sentFin) { pTcb->state = pTcb->rcvdFin ? TCB_EMPTY : 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; } action = TcpSend(pSizeTx, pPacketTx, pTcb); Led1Set(false); Led2Set(false); return action; }