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

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers tcprecv.c Source File

tcprecv.c

00001 #include <stdint.h>
00002 #include <stdbool.h>
00003 #include <stdarg.h>
00004 
00005 #include     "log.h"
00006 #include     "net.h"
00007 #include  "action.h"
00008 #include     "tcp.h"
00009 #include  "tcphdr.h"
00010 #include "tcpsend.h"
00011 #include     "tcb.h"
00012 #include     "ip4.h"
00013 #include    "dhcp.h"
00014 #include   "httpv.h"
00015 #include   "https.h"
00016 #include     "led.h"
00017 #include "mstimer.h"
00018 #include "restart.h"
00019 
00020 
00021 static void log(void (*traceback)(void), char* fmt, ...)
00022 {
00023     if (TcpTrace)
00024     {
00025         if (NetTraceNewLine) Log("\r\n");
00026         LogTimeF("TCP port %hu - ", TcpHdrSrcPort);
00027         va_list argptr;
00028         va_start(argptr, fmt);
00029         LogV(fmt, argptr);
00030         va_end(argptr);
00031         Log("\r\n");
00032         if (NetTraceStack) traceback();
00033     }
00034 }
00035 static void handleSyn(void *pPacket, int ipType, int remArIndex, int locMss, struct tcb* pTcb)
00036 {
00037     //Get the MSS to use for sends - it is the lower of the MSS advertised by the remote host and our local MSS
00038     int remMss = TcpHdrMssGet();
00039     pTcb->remMss = remMss ? remMss : 536; //default MSS for IPv4 [576 - 20(TCP) - 20(IP)];
00040     if (pTcb->remMss > locMss) pTcb->remMss = locMss;
00041     
00042     pTcb->timeSendsBeingAcked = MsTimerCount;
00043     pTcb->countSendsNotAcked  = 0;
00044     pTcb->rcvdFin             = false;
00045     pTcb->sentFin             = false;
00046     pTcb->remIsn              = TcpHdrSeqNum;
00047     pTcb->locIsn              = TcbGetIsn();
00048     pTcb->bytesRcvdFromRem    = 0;
00049     pTcb->bytesAckdByRem      = 0;
00050     pTcb->bytesAckdToRem      = 0;
00051     pTcb->bytesSentToRem      = 0;
00052     switch (pTcb->locPort) //Reset the application
00053     {
00054         case  80: HttpvReset(TcbGetId(pTcb)); break;
00055         case 443: HttpsReset(TcbGetId(pTcb)); break;
00056     }
00057 }
00058 static void handleReceivedData(void* pPacket, int dataLength, uint32_t position, struct tcb* pTcb)
00059 {
00060     pTcb->window = TcpHdrWindow;
00061     uint8_t* pData = (uint8_t*)pPacket + TcpHdrSizeGet();
00062     switch (pTcb->locPort)
00063     {
00064         case  80: HttpvRequest(TcbGetId(pTcb), dataLength, pData, position); break;
00065         case 443: HttpsRequest(TcbGetId(pTcb), dataLength, pData, position); break;
00066     }
00067 }
00068 static int sendResetFromPacket(int* pSizeTx, void* pPacketTx, int ipType, int remArIndex, int locIpScope, int seqLengthRcvd)
00069 {
00070     /*RFC793 p36 If the connection does not exist (CLOSED) then a reset is sent
00071     in response to any incoming segment except another reset.
00072     If the incoming segment has an ACK field, the reset takes its sequence number from the ACK field of the segment,
00073     otherwise                                 the reset has sequence number zero
00074     and
00075     the ACK field is set to the sum of the sequence number and segment length of the incoming segment.
00076     The connection remains in the CLOSED state.
00077     In TcpSendReset TcpHdrAckNum = pTcb->bytesAckdToRem + pTcb->remIsn;  //Set up the acknowledgement field ready to send
00078                     TcpHdrSeqNum = pTcb->bytesSentToRem + pTcb->locIsn;  //Set up the start of the message before adding the bytes sent
00079     */
00080     
00081     struct tcb tcb;
00082     struct tcb* pTcb = &tcb;
00083     pTcb->timeLastRcvd     = MsTimerCount;
00084     pTcb->remArIndex       = remArIndex;
00085     pTcb->ipType           = ipType;
00086     pTcb->locIpScope       = locIpScope;
00087     pTcb->remPort          = TcpHdrSrcPort;
00088     pTcb->locPort          = TcpHdrDstPort;
00089     pTcb->window           = TcpHdrWindow;
00090     pTcb->state            = TCB_EMPTY;
00091 
00092     pTcb->timeSendsBeingAcked = MsTimerCount;
00093     pTcb->countSendsNotAcked  = 0;
00094     pTcb->rcvdFin             = false;
00095     pTcb->sentFin             = false;
00096     pTcb->remIsn              = TcpHdrSeqNum + seqLengthRcvd; //Ack number
00097     pTcb->locIsn              = TcpHdrACK ? TcpHdrAckNum : 0; //Seq number
00098     pTcb->bytesRcvdFromRem    = 0;
00099     pTcb->bytesAckdByRem      = 0;
00100     pTcb->bytesAckdToRem      = 0;
00101     pTcb->bytesSentToRem      = 0;
00102     
00103     return TcpSendReset(pSizeTx, pPacketTx, pTcb);
00104 }
00105 
00106 int TcpHandleReceivedPacket(void (*traceback)(void), int sizeRx, void* pPacketRx, int* pSizeTx, void* pPacketTx, int ipType, int remArIndex, int locIpScope)
00107 {
00108     int lastRestartPoint = RestartPoint;
00109     RestartPoint = FAULT_POINT_TcpHandleReceivedPacket;
00110     
00111     int action = DO_NOTHING;
00112     bool traceRequested = false;
00113     
00114     TcpHdrReadFromPacket(pPacketRx);
00115     
00116     if (remArIndex < 0)
00117     {
00118         log(traceback, "invalid remote AR index %d -> ignored packet", remArIndex);
00119         RestartPoint = lastRestartPoint;
00120         return DO_NOTHING;
00121     }
00122     RestartPoint += 100;
00123     
00124     int dataLength =   sizeRx - TcpHdrSizeGet();
00125     int locMss     = *pSizeTx - TcpHdrSizeGet();
00126     
00127     //Calculate the sequence length of the received packet
00128     int seqLengthRcvd = 0;
00129     if (TcpHdrSYN) seqLengthRcvd += 1;          //Add one to acknowledge the SYN
00130                    seqLengthRcvd += dataLength; //Add the number of bytes received
00131     if (TcpHdrFIN) seqLengthRcvd += 1;          //Add one to acknowledge the FIN
00132     
00133     //Filter out unwanted links
00134     RestartPoint++;
00135     switch (TcpHdrDstPort)
00136     {
00137         case 80:
00138             if (HttpvGetTrace())
00139             {
00140                 if (NetTraceNewLine) Log("\r\n");
00141                 LogTime("HTTP server request\r\n");
00142                 traceRequested = true;
00143             }
00144             break;
00145             
00146         case 443:
00147             if (HttpsGetTrace())
00148             {
00149                 if (NetTraceNewLine) Log("\r\n");
00150                 LogTimeF("HTTPS server request of %d bytes\r\n", dataLength);
00151                 traceRequested = true;
00152             }
00153             break;
00154             
00155         default: //Send reset if unknown port
00156             log(traceback, "unhandled local port %hu -> sent reset", TcpHdrDstPort);
00157             action = sendResetFromPacket(pSizeTx, pPacketTx, ipType, remArIndex, locIpScope, seqLengthRcvd);
00158             RestartPoint = lastRestartPoint;
00159             return action;
00160     }
00161     
00162     //Get the Transmission Control Block
00163     RestartPoint++;
00164     struct tcb* pTcb = TcbGetExisting(ipType, remArIndex, locIpScope, TcpHdrSrcPort, TcpHdrDstPort);
00165     if (!pTcb) pTcb = TcbGetEmpty();
00166     if (!pTcb) //send reset if no more tcbs are available
00167     {
00168         log(traceback, "no more tcbs available -> sent reset");
00169         action = sendResetFromPacket(pSizeTx, pPacketTx, ipType, remArIndex, locIpScope, seqLengthRcvd);
00170         RestartPoint = lastRestartPoint;
00171         return action;
00172     }
00173     pTcb->timeLastRcvd     = MsTimerCount;
00174     pTcb->remArIndex       = remArIndex;
00175     pTcb->ipType           = ipType;
00176     pTcb->locIpScope       = locIpScope;
00177     pTcb->remPort          = TcpHdrSrcPort;
00178     pTcb->locPort          = TcpHdrDstPort;
00179     pTcb->window           = TcpHdrWindow;
00180     
00181     //Handle request to reset
00182     RestartPoint++;
00183     if (TcpHdrRST)
00184     {
00185         if (pTcb->state)
00186         {
00187             log(traceback, "received reset -> reaped TCB");
00188             pTcb->state = TCB_EMPTY;
00189         }
00190         RestartPoint = lastRestartPoint;
00191         return DO_NOTHING;        //Don't reply
00192     }
00193     
00194     //Handle request to synchronise
00195     RestartPoint++;
00196     if (TcpHdrSYN)
00197     {
00198         if (pTcb->state)
00199         {
00200             log(traceback, "received a SYN on an open connection -> sent reset");
00201             pTcb->state = TCB_EMPTY;
00202             action = TcpSendReset(pSizeTx, pPacketTx, pTcb);
00203             RestartPoint = lastRestartPoint;
00204             return action;
00205         }
00206         else
00207         {
00208             handleSyn(pPacketRx, ipType, remArIndex, locMss, pTcb);
00209         }
00210     }
00211     
00212     //Handle non SYN packet on an empty connection
00213     RestartPoint++;
00214     if (!TcpHdrSYN && !pTcb->state)
00215     {
00216 
00217         log(traceback, "non SYN packet received on a closed connection -> sent reset");
00218         pTcb->state = TCB_EMPTY;
00219         action = sendResetFromPacket(pSizeTx, pPacketTx, ipType, remArIndex, locIpScope, seqLengthRcvd);
00220         RestartPoint = lastRestartPoint;
00221         return action;
00222     }
00223     
00224     //Check if the acks of bytes sent has progressed and reset the timer
00225     RestartPoint++;
00226     uint32_t ackRcvdFromRem = TcpHdrACK ? TcpHdrAckNum - pTcb->locIsn : 0;
00227     if (ackRcvdFromRem > pTcb->bytesAckdByRem)
00228     {
00229         pTcb->timeSendsBeingAcked = MsTimerCount;
00230         pTcb->countSendsNotAcked  = 0;
00231     }
00232 
00233     //Record the number of bytes acked by the remote host
00234     RestartPoint++;
00235     pTcb->bytesAckdByRem = ackRcvdFromRem;
00236 
00237     /* If the connection is in a synchronized state
00238     any unacceptable segment (out of window sequence number or
00239     unacceptible acknowledgment number) must elicit only an empty
00240     acknowledgment segment containing the current send-sequence number
00241     and an acknowledgment indicating the next sequence number expected
00242     to be received, and the connection remains in the same state.*/
00243     RestartPoint++;
00244     uint32_t seqRcvdFromRem = TcpHdrSeqNum - pTcb->remIsn;
00245     if (seqRcvdFromRem != pTcb->bytesAckdToRem)
00246     {
00247         //Only warn non keep-alives
00248         if (seqRcvdFromRem != 0 || pTcb->bytesAckdToRem != 1)
00249         {
00250             log(traceback, "seq rcvd is %d and last seq ackd was %d -> resent last ACK", seqRcvdFromRem, pTcb->bytesAckdToRem);
00251         }
00252         action = TcpResendLastAck(pSizeTx, pPacketTx, pTcb);
00253         RestartPoint = lastRestartPoint;
00254         return action;
00255     }
00256     //Ignore data before established
00257     RestartPoint++;
00258     if (pTcb->state != TCB_ESTABLISHED && dataLength)
00259     {
00260         log(traceback, "data received before connection established -> sent reset");
00261         pTcb->state = TCB_EMPTY;
00262         action = TcpSendReset(pSizeTx, pPacketTx, pTcb);
00263         RestartPoint = lastRestartPoint;
00264         return action;
00265     }
00266     
00267     //Handle FIN
00268     RestartPoint++;
00269     if (TcpHdrFIN) pTcb->rcvdFin = true; //When reply is all sent only a passive close is needed
00270     
00271     //From now on there are no errors so display traceback if requested
00272     RestartPoint++;
00273     if (traceRequested && NetTraceStack) traceback();
00274     
00275     //Record the number of bytes received from the remote host
00276     RestartPoint++;
00277     pTcb->bytesRcvdFromRem += seqLengthRcvd;
00278 
00279     switch (pTcb->state) //This is the state of the connection BEFORE this packet arrived
00280     {
00281         case TCB_EMPTY:
00282             pTcb->state = TCB_SYN_RECEIVED;
00283             break;
00284             
00285         case TCB_SYN_RECEIVED:
00286             pTcb->state = TCB_ESTABLISHED;
00287             break;
00288             
00289         case TCB_ESTABLISHED:
00290             if (dataLength)
00291             {
00292                 handleReceivedData(pPacketRx, dataLength, seqRcvdFromRem - 1, pTcb);
00293             }
00294             if (pTcb->sentFin)
00295             {
00296                 pTcb->state = pTcb->rcvdFin ? TCB_EMPTY : TCB_CLOSE_FIN_WAIT;
00297             }
00298             break;
00299             
00300         case TCB_CLOSE_FIN_WAIT: //End of active close
00301             if (TcpHdrFIN)
00302             {
00303                 pTcb->state = TCB_EMPTY;//Ignore ACK to our FIN. Wait for FIN then close.
00304             }
00305             break;
00306             
00307     }
00308     
00309     RestartPoint++;
00310     action = TcpSend(pSizeTx, pPacketTx, pTcb);
00311 
00312     RestartPoint = lastRestartPoint;
00313     return action;
00314 }