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-31
- Revision:
- 76:17534bde28d3
- Parent:
- 75:603b10404183
- Child:
- 77:6cb7d92c37f3
File content as of revision 76:17534bde28d3:
#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->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) { 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 Transmission Control Block pTcb = TcbGetExisting(TcpHdrSrcPort); if (!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; } pTcb->remArIndex = remArIndex; pTcb->ipType = ipType; 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\r\n"); pTcb->state = TCB_EMPTY; } return DO_NOTHING; //Don't reply } //Handle request to synchronise if (TcpHdrSYN) { if (pTcb->state) { logReset("received a SYN when connection open"); pTcb->state = TCB_EMPTY; return TcpSendReset(pSizeTx, pPacketTx, pTcb); } else { startConnection(pPacketRx, ipType, remArIndex, locMss); } } //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("TCP - non SYN packet received on a closed connection"); return TcpSendReset(pSizeTx, pPacketTx, pTcb); } /* 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; 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 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; 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); }