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@76:17534bde28d3, 2018-10-31 (annotated)
- Committer:
- andrewboyson
- Date:
- Wed Oct 31 19:41:04 2018 +0000
- Revision:
- 76:17534bde28d3
- Parent:
- 75:603b10404183
- Child:
- 77:6cb7d92c37f3
Tidied up the TCB to ensure there always was one even for a closed connection
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
andrewboyson | 74:c3756bfa960e | 1 | #include <stdint.h> |
andrewboyson | 74:c3756bfa960e | 2 | #include <stdbool.h> |
andrewboyson | 75:603b10404183 | 3 | #include <stdarg.h> |
andrewboyson | 74:c3756bfa960e | 4 | |
andrewboyson | 74:c3756bfa960e | 5 | #include "log.h" |
andrewboyson | 74:c3756bfa960e | 6 | #include "net.h" |
andrewboyson | 74:c3756bfa960e | 7 | #include "action.h" |
andrewboyson | 74:c3756bfa960e | 8 | #include "tcp.h" |
andrewboyson | 74:c3756bfa960e | 9 | #include "tcphdr.h" |
andrewboyson | 74:c3756bfa960e | 10 | #include "tcpsend.h" |
andrewboyson | 74:c3756bfa960e | 11 | #include "tcb.h" |
andrewboyson | 74:c3756bfa960e | 12 | #include "ip4.h" |
andrewboyson | 74:c3756bfa960e | 13 | #include "dhcp.h" |
andrewboyson | 74:c3756bfa960e | 14 | #include "http.h" |
andrewboyson | 74:c3756bfa960e | 15 | #include "led.h" |
andrewboyson | 74:c3756bfa960e | 16 | |
andrewboyson | 74:c3756bfa960e | 17 | //Payload variables |
andrewboyson | 74:c3756bfa960e | 18 | static struct tcb* pTcb; |
andrewboyson | 74:c3756bfa960e | 19 | |
andrewboyson | 74:c3756bfa960e | 20 | static void logReset(char* message) |
andrewboyson | 74:c3756bfa960e | 21 | { |
andrewboyson | 74:c3756bfa960e | 22 | if (TcpTrace) { LogTime("TCP sent RST - "); Log(message); Log("\r\n"); } |
andrewboyson | 74:c3756bfa960e | 23 | } |
andrewboyson | 74:c3756bfa960e | 24 | |
andrewboyson | 75:603b10404183 | 25 | static void logTraceBack(void (*traceback)(void), char* fmt, ...) |
andrewboyson | 75:603b10404183 | 26 | { |
andrewboyson | 75:603b10404183 | 27 | if (TcpTrace) |
andrewboyson | 75:603b10404183 | 28 | { |
andrewboyson | 75:603b10404183 | 29 | if (NetTraceNewLine) Log("\r\n"); |
andrewboyson | 75:603b10404183 | 30 | va_list argptr; |
andrewboyson | 75:603b10404183 | 31 | va_start(argptr, fmt); |
andrewboyson | 75:603b10404183 | 32 | LogV(fmt, argptr); |
andrewboyson | 75:603b10404183 | 33 | va_end(argptr); |
andrewboyson | 75:603b10404183 | 34 | Log("\r\n"); |
andrewboyson | 75:603b10404183 | 35 | if (NetTraceStack) traceback(); |
andrewboyson | 75:603b10404183 | 36 | } |
andrewboyson | 75:603b10404183 | 37 | } |
andrewboyson | 75:603b10404183 | 38 | |
andrewboyson | 74:c3756bfa960e | 39 | static void startConnection(void *pPacket, int ipType, int remArIndex, int locMss) |
andrewboyson | 74:c3756bfa960e | 40 | { |
andrewboyson | 74:c3756bfa960e | 41 | //Get the MSS to use for sends - it is the lower of the MSS advertised by the remote host and our local MSS |
andrewboyson | 74:c3756bfa960e | 42 | int remMss = TcpHdrMssGet(); |
andrewboyson | 74:c3756bfa960e | 43 | pTcb->remMss = remMss ? remMss : 536; //default MSS for IPv4 [576 - 20(TCP) - 20(IP)]; |
andrewboyson | 74:c3756bfa960e | 44 | if (pTcb->remMss > locMss) pTcb->remMss = locMss; |
andrewboyson | 74:c3756bfa960e | 45 | |
andrewboyson | 75:603b10404183 | 46 | pTcb->lastSendTime = TcbElapsed; |
andrewboyson | 75:603b10404183 | 47 | pTcb->rcvdFin = false; |
andrewboyson | 75:603b10404183 | 48 | pTcb->sentFin = false; |
andrewboyson | 75:603b10404183 | 49 | pTcb->todo = 0; |
andrewboyson | 75:603b10404183 | 50 | pTcb->remIsn = TcpHdrSeqNum; |
andrewboyson | 75:603b10404183 | 51 | pTcb->locIsn = TcbGetIsn(); |
andrewboyson | 75:603b10404183 | 52 | pTcb->bytesRcvdFromRem = 0; |
andrewboyson | 75:603b10404183 | 53 | pTcb->bytesAckdByRem = 0; |
andrewboyson | 75:603b10404183 | 54 | pTcb->bytesAckdToRem = 0; |
andrewboyson | 75:603b10404183 | 55 | pTcb->bytesSentToRem = 0; |
andrewboyson | 74:c3756bfa960e | 56 | } |
andrewboyson | 75:603b10404183 | 57 | static void handleReceivedData(void* pPacket, int dataLength, uint32_t position) |
andrewboyson | 74:c3756bfa960e | 58 | { |
andrewboyson | 74:c3756bfa960e | 59 | pTcb->window = TcpHdrWindow; |
andrewboyson | 74:c3756bfa960e | 60 | char* pData = (char*)pPacket + TcpHdrSizeGet(); |
andrewboyson | 74:c3756bfa960e | 61 | switch (pTcb->locPort) |
andrewboyson | 74:c3756bfa960e | 62 | { |
andrewboyson | 74:c3756bfa960e | 63 | case 80: |
andrewboyson | 75:603b10404183 | 64 | HttpHandleRequest(dataLength, pData, position, &pTcb->todo); |
andrewboyson | 74:c3756bfa960e | 65 | break; |
andrewboyson | 74:c3756bfa960e | 66 | default: |
andrewboyson | 74:c3756bfa960e | 67 | break; |
andrewboyson | 74:c3756bfa960e | 68 | } |
andrewboyson | 74:c3756bfa960e | 69 | } |
andrewboyson | 74:c3756bfa960e | 70 | |
andrewboyson | 74:c3756bfa960e | 71 | int TcpHandleReceivedPacket(void (*traceback)(void), int sizeRx, void* pPacketRx, int* pSizeTx, void* pPacketTx, int ipType, int remArIndex) |
andrewboyson | 74:c3756bfa960e | 72 | { |
andrewboyson | 74:c3756bfa960e | 73 | TcpHdrReadFromPacket(pPacketRx); |
andrewboyson | 74:c3756bfa960e | 74 | |
andrewboyson | 74:c3756bfa960e | 75 | int dataLength = sizeRx - TcpHdrSizeGet(); |
andrewboyson | 74:c3756bfa960e | 76 | int locMss = *pSizeTx - TcpHdrSizeGet(); |
andrewboyson | 74:c3756bfa960e | 77 | |
andrewboyson | 74:c3756bfa960e | 78 | TcpDoTrace = false; |
andrewboyson | 74:c3756bfa960e | 79 | |
andrewboyson | 74:c3756bfa960e | 80 | //Filter out unwanted links |
andrewboyson | 74:c3756bfa960e | 81 | switch (TcpHdrDstPort) |
andrewboyson | 74:c3756bfa960e | 82 | { |
andrewboyson | 74:c3756bfa960e | 83 | case 80: |
andrewboyson | 74:c3756bfa960e | 84 | if (HttpTrace) |
andrewboyson | 74:c3756bfa960e | 85 | { |
andrewboyson | 74:c3756bfa960e | 86 | if (NetTraceNewLine) Log("\r\n"); |
andrewboyson | 74:c3756bfa960e | 87 | LogTime("HTTP server request\r\n"); |
andrewboyson | 74:c3756bfa960e | 88 | TcpDoTrace = true; |
andrewboyson | 74:c3756bfa960e | 89 | } |
andrewboyson | 74:c3756bfa960e | 90 | break; |
andrewboyson | 74:c3756bfa960e | 91 | |
andrewboyson | 74:c3756bfa960e | 92 | default: |
andrewboyson | 75:603b10404183 | 93 | logTraceBack(traceback, "TCP - unknown port %d\r\n", TcpHdrDstPort); |
andrewboyson | 74:c3756bfa960e | 94 | return DO_NOTHING; //Ignore unknown ports |
andrewboyson | 74:c3756bfa960e | 95 | } |
andrewboyson | 74:c3756bfa960e | 96 | |
andrewboyson | 76:17534bde28d3 | 97 | //Get the Transmission Control Block |
andrewboyson | 74:c3756bfa960e | 98 | pTcb = TcbGetExisting(TcpHdrSrcPort); |
andrewboyson | 76:17534bde28d3 | 99 | if (!pTcb) pTcb = TcbGetEmpty(); |
andrewboyson | 76:17534bde28d3 | 100 | if (!pTcb) //Bomb out if no more tcbs are available |
andrewboyson | 76:17534bde28d3 | 101 | { |
andrewboyson | 76:17534bde28d3 | 102 | logTraceBack(traceback, "TCP - no more tcbs are available\r\n"); |
andrewboyson | 76:17534bde28d3 | 103 | return DO_NOTHING; |
andrewboyson | 76:17534bde28d3 | 104 | } |
andrewboyson | 76:17534bde28d3 | 105 | pTcb->remArIndex = remArIndex; |
andrewboyson | 76:17534bde28d3 | 106 | pTcb->ipType = ipType; |
andrewboyson | 76:17534bde28d3 | 107 | pTcb->remPort = TcpHdrSrcPort; |
andrewboyson | 76:17534bde28d3 | 108 | pTcb->locPort = TcpHdrDstPort; |
andrewboyson | 76:17534bde28d3 | 109 | pTcb->window = TcpHdrWindow; |
andrewboyson | 75:603b10404183 | 110 | |
andrewboyson | 74:c3756bfa960e | 111 | //Handle request to reset |
andrewboyson | 74:c3756bfa960e | 112 | if (TcpHdrRST) |
andrewboyson | 74:c3756bfa960e | 113 | { |
andrewboyson | 76:17534bde28d3 | 114 | if (pTcb->state) |
andrewboyson | 74:c3756bfa960e | 115 | { |
andrewboyson | 75:603b10404183 | 116 | logTraceBack(traceback, "TCP - received reset - resetting TCB\r\n"); |
andrewboyson | 75:603b10404183 | 117 | pTcb->state = TCB_EMPTY; |
andrewboyson | 74:c3756bfa960e | 118 | } |
andrewboyson | 74:c3756bfa960e | 119 | return DO_NOTHING; //Don't reply |
andrewboyson | 74:c3756bfa960e | 120 | } |
andrewboyson | 74:c3756bfa960e | 121 | |
andrewboyson | 74:c3756bfa960e | 122 | //Handle request to synchronise |
andrewboyson | 74:c3756bfa960e | 123 | if (TcpHdrSYN) |
andrewboyson | 74:c3756bfa960e | 124 | { |
andrewboyson | 76:17534bde28d3 | 125 | if (pTcb->state) |
andrewboyson | 75:603b10404183 | 126 | { |
andrewboyson | 75:603b10404183 | 127 | logReset("received a SYN when connection open"); |
andrewboyson | 75:603b10404183 | 128 | pTcb->state = TCB_EMPTY; |
andrewboyson | 75:603b10404183 | 129 | return TcpSendReset(pSizeTx, pPacketTx, pTcb); |
andrewboyson | 75:603b10404183 | 130 | } |
andrewboyson | 76:17534bde28d3 | 131 | else |
andrewboyson | 75:603b10404183 | 132 | { |
andrewboyson | 76:17534bde28d3 | 133 | startConnection(pPacketRx, ipType, remArIndex, locMss); |
andrewboyson | 75:603b10404183 | 134 | } |
andrewboyson | 74:c3756bfa960e | 135 | } |
andrewboyson | 74:c3756bfa960e | 136 | |
andrewboyson | 76:17534bde28d3 | 137 | //Calculate the sequence length of the received packet |
andrewboyson | 76:17534bde28d3 | 138 | int seqLengthRcvd = 0; |
andrewboyson | 76:17534bde28d3 | 139 | if (TcpHdrSYN) seqLengthRcvd += 1; //Add one to acknowledge the SYN |
andrewboyson | 76:17534bde28d3 | 140 | seqLengthRcvd += dataLength; //Add the number of bytes received |
andrewboyson | 76:17534bde28d3 | 141 | if (TcpHdrFIN) seqLengthRcvd += 1; //Add one to acknowledge the FIN |
andrewboyson | 76:17534bde28d3 | 142 | |
andrewboyson | 76:17534bde28d3 | 143 | /*RFC793 p36 If the connection does not exist (CLOSED) then a reset is sent |
andrewboyson | 76:17534bde28d3 | 144 | in response to any incoming segment except another reset. |
andrewboyson | 76:17534bde28d3 | 145 | If the incoming segment has an ACK field, the reset takes its sequence number from the ACK field of the segment, |
andrewboyson | 76:17534bde28d3 | 146 | otherwise the reset has sequence number zero |
andrewboyson | 76:17534bde28d3 | 147 | and |
andrewboyson | 76:17534bde28d3 | 148 | the ACK field is set to the sum of the sequence number and segment length of the incoming segment. |
andrewboyson | 76:17534bde28d3 | 149 | The connection remains in the CLOSED state. |
andrewboyson | 76:17534bde28d3 | 150 | In TcpSendReset TcpHdrAckNum = pTcb->bytesAckdToRem + pTcb->remIsn; //Set up the acknowledgement field ready to send |
andrewboyson | 76:17534bde28d3 | 151 | TcpHdrSeqNum = pTcb->bytesSentToRem + pTcb->locIsn; //Set up the start of the message before adding the bytes sent |
andrewboyson | 76:17534bde28d3 | 152 | */ |
andrewboyson | 76:17534bde28d3 | 153 | if (!TcpHdrSYN && !pTcb->state) |
andrewboyson | 76:17534bde28d3 | 154 | { |
andrewboyson | 76:17534bde28d3 | 155 | pTcb->remIsn = 0; |
andrewboyson | 76:17534bde28d3 | 156 | pTcb->locIsn = 0; |
andrewboyson | 76:17534bde28d3 | 157 | pTcb->bytesRcvdFromRem = 0; |
andrewboyson | 76:17534bde28d3 | 158 | pTcb->bytesAckdByRem = 0; |
andrewboyson | 76:17534bde28d3 | 159 | |
andrewboyson | 76:17534bde28d3 | 160 | pTcb->bytesSentToRem = TcpHdrACK ? TcpHdrAckNum : 0; //Seq number |
andrewboyson | 76:17534bde28d3 | 161 | pTcb->bytesAckdToRem = TcpHdrSeqNum + seqLengthRcvd; //Ack number |
andrewboyson | 76:17534bde28d3 | 162 | logReset("TCP - non SYN packet received on a closed connection"); |
andrewboyson | 76:17534bde28d3 | 163 | return TcpSendReset(pSizeTx, pPacketTx, pTcb); |
andrewboyson | 76:17534bde28d3 | 164 | } |
andrewboyson | 76:17534bde28d3 | 165 | |
andrewboyson | 76:17534bde28d3 | 166 | /* If the connection is in a synchronized state |
andrewboyson | 76:17534bde28d3 | 167 | any unacceptable segment (out of window sequence number or |
andrewboyson | 76:17534bde28d3 | 168 | unacceptible acknowledgment number) must elicit only an empty |
andrewboyson | 76:17534bde28d3 | 169 | acknowledgment segment containing the current send-sequence number |
andrewboyson | 76:17534bde28d3 | 170 | and an acknowledgment indicating the next sequence number expected |
andrewboyson | 76:17534bde28d3 | 171 | to be received, and the connection remains in the same state.*/ |
andrewboyson | 74:c3756bfa960e | 172 | uint32_t seqRcvdFromRem = TcpHdrSeqNum - pTcb->remIsn; |
andrewboyson | 74:c3756bfa960e | 173 | bool resendAck = seqRcvdFromRem != pTcb->bytesAckdToRem; |
andrewboyson | 75:603b10404183 | 174 | if (resendAck) return TcpResendLastAck(pSizeTx, pPacketTx, pTcb); |
andrewboyson | 74:c3756bfa960e | 175 | |
andrewboyson | 75:603b10404183 | 176 | //Record the number of bytes acked by the remote host |
andrewboyson | 75:603b10404183 | 177 | pTcb->bytesAckdByRem = TcpHdrAckNum - pTcb->locIsn; |
andrewboyson | 74:c3756bfa960e | 178 | |
andrewboyson | 74:c3756bfa960e | 179 | //Handle FIN |
andrewboyson | 74:c3756bfa960e | 180 | if (TcpHdrFIN) pTcb->rcvdFin = true; //When reply is all sent only a passive close is needed |
andrewboyson | 74:c3756bfa960e | 181 | |
andrewboyson | 74:c3756bfa960e | 182 | if (TcpDoTrace && NetTraceStack) traceback(); //This will already include the TCP header |
andrewboyson | 74:c3756bfa960e | 183 | |
andrewboyson | 75:603b10404183 | 184 | //Record the number of bytes received from the remote host |
andrewboyson | 76:17534bde28d3 | 185 | pTcb->bytesRcvdFromRem += seqLengthRcvd; |
andrewboyson | 74:c3756bfa960e | 186 | |
andrewboyson | 76:17534bde28d3 | 187 | switch (pTcb->state) //This is the state of the connection BEFORE this packet arrived |
andrewboyson | 74:c3756bfa960e | 188 | { |
andrewboyson | 74:c3756bfa960e | 189 | case TCB_EMPTY: |
andrewboyson | 74:c3756bfa960e | 190 | pTcb->state = TCB_SYN_RECEIVED; |
andrewboyson | 74:c3756bfa960e | 191 | break; |
andrewboyson | 74:c3756bfa960e | 192 | |
andrewboyson | 74:c3756bfa960e | 193 | case TCB_SYN_RECEIVED: |
andrewboyson | 74:c3756bfa960e | 194 | if (dataLength) |
andrewboyson | 74:c3756bfa960e | 195 | { |
andrewboyson | 74:c3756bfa960e | 196 | logReset("data received before connection established"); |
andrewboyson | 74:c3756bfa960e | 197 | pTcb->state = TCB_EMPTY; |
andrewboyson | 75:603b10404183 | 198 | return TcpSendReset(pSizeTx, pPacketTx, pTcb); |
andrewboyson | 74:c3756bfa960e | 199 | } |
andrewboyson | 74:c3756bfa960e | 200 | pTcb->state = TCB_ESTABLISHED; |
andrewboyson | 74:c3756bfa960e | 201 | break; |
andrewboyson | 74:c3756bfa960e | 202 | |
andrewboyson | 74:c3756bfa960e | 203 | case TCB_ESTABLISHED: |
andrewboyson | 75:603b10404183 | 204 | if (dataLength) handleReceivedData (pPacketRx, dataLength, seqRcvdFromRem - 1); |
andrewboyson | 74:c3756bfa960e | 205 | if (pTcb->sentFin) |
andrewboyson | 74:c3756bfa960e | 206 | { |
andrewboyson | 74:c3756bfa960e | 207 | pTcb->state = pTcb->rcvdFin ? TCB_CLOSE_ACK_WAIT : TCB_CLOSE_FIN_WAIT; |
andrewboyson | 74:c3756bfa960e | 208 | } |
andrewboyson | 74:c3756bfa960e | 209 | break; |
andrewboyson | 74:c3756bfa960e | 210 | |
andrewboyson | 74:c3756bfa960e | 211 | case TCB_CLOSE_FIN_WAIT: //End of active close |
andrewboyson | 74:c3756bfa960e | 212 | if (TcpHdrFIN) |
andrewboyson | 74:c3756bfa960e | 213 | { |
andrewboyson | 74:c3756bfa960e | 214 | pTcb->state = TCB_EMPTY;//Ignore ACK to our FIN. Wait for FIN then close. |
andrewboyson | 74:c3756bfa960e | 215 | } |
andrewboyson | 74:c3756bfa960e | 216 | break; |
andrewboyson | 74:c3756bfa960e | 217 | |
andrewboyson | 74:c3756bfa960e | 218 | case TCB_CLOSE_ACK_WAIT: //End of passive close |
andrewboyson | 74:c3756bfa960e | 219 | pTcb->state = TCB_EMPTY; |
andrewboyson | 74:c3756bfa960e | 220 | break; |
andrewboyson | 74:c3756bfa960e | 221 | } |
andrewboyson | 74:c3756bfa960e | 222 | |
andrewboyson | 75:603b10404183 | 223 | return TcpSend(pSizeTx, pPacketTx, pTcb); |
andrewboyson | 74:c3756bfa960e | 224 | } |