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

Committer:
andrewboyson
Date:
Tue Nov 27 11:18:06 2018 +0000
Revision:
91:879545b19260
Parent:
90:955f4c6e18a9
Child:
93:580fc113d9e9
In TCP checked for presence of ACK flag before using ACK NUM when working out the bytes acked by the remote.

Who changed what in which revision?

UserRevisionLine numberNew 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 89:9b765a67699b 17
andrewboyson 89:9b765a67699b 18 static void log(void (*traceback)(void), char* fmt, ...)
andrewboyson 74:c3756bfa960e 19 {
andrewboyson 78:9d8fc88df405 20 if (TcpTrace)
andrewboyson 78:9d8fc88df405 21 {
andrewboyson 78:9d8fc88df405 22 if (NetTraceNewLine) Log("\r\n");
andrewboyson 89:9b765a67699b 23 LogTimeF("TCP port %hu - ", TcpHdrSrcPort);
andrewboyson 75:603b10404183 24 va_list argptr;
andrewboyson 75:603b10404183 25 va_start(argptr, fmt);
andrewboyson 75:603b10404183 26 LogV(fmt, argptr);
andrewboyson 75:603b10404183 27 va_end(argptr);
andrewboyson 75:603b10404183 28 Log("\r\n");
andrewboyson 75:603b10404183 29 if (NetTraceStack) traceback();
andrewboyson 75:603b10404183 30 }
andrewboyson 75:603b10404183 31 }
andrewboyson 75:603b10404183 32
andrewboyson 88:1ba13e6062a3 33 static void handleSyn(void *pPacket, int ipType, int remArIndex, int locMss, struct tcb* pTcb)
andrewboyson 74:c3756bfa960e 34 {
andrewboyson 74:c3756bfa960e 35 //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 36 int remMss = TcpHdrMssGet();
andrewboyson 74:c3756bfa960e 37 pTcb->remMss = remMss ? remMss : 536; //default MSS for IPv4 [576 - 20(TCP) - 20(IP)];
andrewboyson 74:c3756bfa960e 38 if (pTcb->remMss > locMss) pTcb->remMss = locMss;
andrewboyson 74:c3756bfa960e 39
andrewboyson 79:f50e02fb5c94 40 pTcb->timeSendsBeingAcked = TcbElapsed;
andrewboyson 82:20781198d26d 41 pTcb->countSendsNotAcked = 0;
andrewboyson 79:f50e02fb5c94 42 pTcb->rcvdFin = false;
andrewboyson 79:f50e02fb5c94 43 pTcb->sentFin = false;
andrewboyson 79:f50e02fb5c94 44 pTcb->todo = 0;
andrewboyson 79:f50e02fb5c94 45 pTcb->remIsn = TcpHdrSeqNum;
andrewboyson 79:f50e02fb5c94 46 pTcb->locIsn = TcbGetIsn();
andrewboyson 79:f50e02fb5c94 47 pTcb->bytesRcvdFromRem = 0;
andrewboyson 79:f50e02fb5c94 48 pTcb->bytesAckdByRem = 0;
andrewboyson 79:f50e02fb5c94 49 pTcb->bytesAckdToRem = 0;
andrewboyson 79:f50e02fb5c94 50 pTcb->bytesSentToRem = 0;
andrewboyson 74:c3756bfa960e 51 }
andrewboyson 88:1ba13e6062a3 52 static void handleReceivedData(void* pPacket, int dataLength, uint32_t position, struct tcb* pTcb)
andrewboyson 74:c3756bfa960e 53 {
andrewboyson 74:c3756bfa960e 54 pTcb->window = TcpHdrWindow;
andrewboyson 74:c3756bfa960e 55 char* pData = (char*)pPacket + TcpHdrSizeGet();
andrewboyson 74:c3756bfa960e 56 switch (pTcb->locPort)
andrewboyson 74:c3756bfa960e 57 {
andrewboyson 74:c3756bfa960e 58 case 80:
andrewboyson 75:603b10404183 59 HttpHandleRequest(dataLength, pData, position, &pTcb->todo);
andrewboyson 74:c3756bfa960e 60 break;
andrewboyson 74:c3756bfa960e 61 default:
andrewboyson 74:c3756bfa960e 62 break;
andrewboyson 74:c3756bfa960e 63 }
andrewboyson 74:c3756bfa960e 64 }
andrewboyson 90:955f4c6e18a9 65 static int sendResetFromPacket(int* pSizeTx, void* pPacketTx, int ipType, int remArIndex, int locIpScope, int seqLengthRcvd)
andrewboyson 89:9b765a67699b 66 {
andrewboyson 90:955f4c6e18a9 67 /*RFC793 p36 If the connection does not exist (CLOSED) then a reset is sent
andrewboyson 90:955f4c6e18a9 68 in response to any incoming segment except another reset.
andrewboyson 90:955f4c6e18a9 69 If the incoming segment has an ACK field, the reset takes its sequence number from the ACK field of the segment,
andrewboyson 90:955f4c6e18a9 70 otherwise the reset has sequence number zero
andrewboyson 90:955f4c6e18a9 71 and
andrewboyson 90:955f4c6e18a9 72 the ACK field is set to the sum of the sequence number and segment length of the incoming segment.
andrewboyson 90:955f4c6e18a9 73 The connection remains in the CLOSED state.
andrewboyson 90:955f4c6e18a9 74 In TcpSendReset TcpHdrAckNum = pTcb->bytesAckdToRem + pTcb->remIsn; //Set up the acknowledgement field ready to send
andrewboyson 90:955f4c6e18a9 75 TcpHdrSeqNum = pTcb->bytesSentToRem + pTcb->locIsn; //Set up the start of the message before adding the bytes sent
andrewboyson 90:955f4c6e18a9 76 */
andrewboyson 90:955f4c6e18a9 77
andrewboyson 89:9b765a67699b 78 struct tcb tcb;
andrewboyson 89:9b765a67699b 79 struct tcb* pTcb = &tcb;
andrewboyson 89:9b765a67699b 80 pTcb->timeLastRcvd = TcbElapsed;
andrewboyson 89:9b765a67699b 81 pTcb->remArIndex = remArIndex;
andrewboyson 89:9b765a67699b 82 pTcb->ipType = ipType;
andrewboyson 89:9b765a67699b 83 pTcb->locIpScope = locIpScope;
andrewboyson 89:9b765a67699b 84 pTcb->remPort = TcpHdrSrcPort;
andrewboyson 89:9b765a67699b 85 pTcb->locPort = TcpHdrDstPort;
andrewboyson 89:9b765a67699b 86 pTcb->window = TcpHdrWindow;
andrewboyson 89:9b765a67699b 87 pTcb->state = TCB_EMPTY;
andrewboyson 89:9b765a67699b 88
andrewboyson 90:955f4c6e18a9 89 pTcb->timeSendsBeingAcked = TcbElapsed;
andrewboyson 90:955f4c6e18a9 90 pTcb->countSendsNotAcked = 0;
andrewboyson 90:955f4c6e18a9 91 pTcb->rcvdFin = false;
andrewboyson 90:955f4c6e18a9 92 pTcb->sentFin = false;
andrewboyson 90:955f4c6e18a9 93 pTcb->todo = 0;
andrewboyson 90:955f4c6e18a9 94 pTcb->remIsn = TcpHdrSeqNum + seqLengthRcvd; //Ack number
andrewboyson 90:955f4c6e18a9 95 pTcb->locIsn = TcpHdrACK ? TcpHdrAckNum : 0; //Seq number
andrewboyson 90:955f4c6e18a9 96 pTcb->bytesRcvdFromRem = 0;
andrewboyson 90:955f4c6e18a9 97 pTcb->bytesAckdByRem = 0;
andrewboyson 90:955f4c6e18a9 98 pTcb->bytesAckdToRem = 0;
andrewboyson 90:955f4c6e18a9 99 pTcb->bytesSentToRem = 0;
andrewboyson 90:955f4c6e18a9 100
andrewboyson 89:9b765a67699b 101 return TcpSendReset(pSizeTx, pPacketTx, pTcb);
andrewboyson 89:9b765a67699b 102 }
andrewboyson 74:c3756bfa960e 103
andrewboyson 80:4ef1500fca1d 104 int TcpHandleReceivedPacket(void (*traceback)(void), int sizeRx, void* pPacketRx, int* pSizeTx, void* pPacketTx, int ipType, int remArIndex, int locIpScope)
andrewboyson 74:c3756bfa960e 105 {
andrewboyson 90:955f4c6e18a9 106 int action = DO_NOTHING;
andrewboyson 89:9b765a67699b 107 bool traceRequested = false;
andrewboyson 86:55bc5ddac16c 108
andrewboyson 86:55bc5ddac16c 109 Led1Set(true);
andrewboyson 89:9b765a67699b 110
andrewboyson 89:9b765a67699b 111 TcpHdrReadFromPacket(pPacketRx);
andrewboyson 89:9b765a67699b 112
andrewboyson 78:9d8fc88df405 113 if (remArIndex < 0)
andrewboyson 78:9d8fc88df405 114 {
andrewboyson 89:9b765a67699b 115 log(traceback, "invalid remote AR index %d -> ignored packet", remArIndex);
andrewboyson 86:55bc5ddac16c 116 Led1Set(false);
andrewboyson 78:9d8fc88df405 117 return DO_NOTHING;
andrewboyson 78:9d8fc88df405 118 }
andrewboyson 78:9d8fc88df405 119
andrewboyson 74:c3756bfa960e 120 int dataLength = sizeRx - TcpHdrSizeGet();
andrewboyson 74:c3756bfa960e 121 int locMss = *pSizeTx - TcpHdrSizeGet();
andrewboyson 74:c3756bfa960e 122
andrewboyson 90:955f4c6e18a9 123 //Calculate the sequence length of the received packet
andrewboyson 90:955f4c6e18a9 124 int seqLengthRcvd = 0;
andrewboyson 90:955f4c6e18a9 125 if (TcpHdrSYN) seqLengthRcvd += 1; //Add one to acknowledge the SYN
andrewboyson 90:955f4c6e18a9 126 seqLengthRcvd += dataLength; //Add the number of bytes received
andrewboyson 90:955f4c6e18a9 127 if (TcpHdrFIN) seqLengthRcvd += 1; //Add one to acknowledge the FIN
andrewboyson 90:955f4c6e18a9 128
andrewboyson 74:c3756bfa960e 129 //Filter out unwanted links
andrewboyson 74:c3756bfa960e 130 switch (TcpHdrDstPort)
andrewboyson 74:c3756bfa960e 131 {
andrewboyson 74:c3756bfa960e 132 case 80:
andrewboyson 74:c3756bfa960e 133 if (HttpTrace)
andrewboyson 74:c3756bfa960e 134 {
andrewboyson 74:c3756bfa960e 135 if (NetTraceNewLine) Log("\r\n");
andrewboyson 74:c3756bfa960e 136 LogTime("HTTP server request\r\n");
andrewboyson 89:9b765a67699b 137 traceRequested = true;
andrewboyson 74:c3756bfa960e 138 }
andrewboyson 74:c3756bfa960e 139 break;
andrewboyson 74:c3756bfa960e 140
andrewboyson 89:9b765a67699b 141 default: //Send reset if unknown port
andrewboyson 89:9b765a67699b 142 log(traceback, "unhandled local port %hu -> sent reset", TcpHdrDstPort);
andrewboyson 90:955f4c6e18a9 143 action = sendResetFromPacket(pSizeTx, pPacketTx, ipType, remArIndex, locIpScope, seqLengthRcvd);
andrewboyson 86:55bc5ddac16c 144 Led1Set(false);
andrewboyson 90:955f4c6e18a9 145 return action;
andrewboyson 74:c3756bfa960e 146 }
andrewboyson 74:c3756bfa960e 147
andrewboyson 76:17534bde28d3 148 //Get the Transmission Control Block
andrewboyson 88:1ba13e6062a3 149 struct tcb* pTcb = TcbGetExisting(ipType, remArIndex, locIpScope, TcpHdrSrcPort, TcpHdrDstPort);
andrewboyson 76:17534bde28d3 150 if (!pTcb) pTcb = TcbGetEmpty();
andrewboyson 89:9b765a67699b 151 if (!pTcb) //send reset if no more tcbs are available
andrewboyson 76:17534bde28d3 152 {
andrewboyson 89:9b765a67699b 153 log(traceback, "no more tcbs available -> sent reset");
andrewboyson 90:955f4c6e18a9 154 action = sendResetFromPacket(pSizeTx, pPacketTx, ipType, remArIndex, locIpScope, seqLengthRcvd);
andrewboyson 86:55bc5ddac16c 155 Led1Set(false);
andrewboyson 90:955f4c6e18a9 156 return action;
andrewboyson 76:17534bde28d3 157 }
andrewboyson 79:f50e02fb5c94 158 pTcb->timeLastRcvd = TcbElapsed;
andrewboyson 76:17534bde28d3 159 pTcb->remArIndex = remArIndex;
andrewboyson 76:17534bde28d3 160 pTcb->ipType = ipType;
andrewboyson 81:50bfdd512f23 161 pTcb->locIpScope = locIpScope;
andrewboyson 76:17534bde28d3 162 pTcb->remPort = TcpHdrSrcPort;
andrewboyson 76:17534bde28d3 163 pTcb->locPort = TcpHdrDstPort;
andrewboyson 76:17534bde28d3 164 pTcb->window = TcpHdrWindow;
andrewboyson 75:603b10404183 165
andrewboyson 74:c3756bfa960e 166 //Handle request to reset
andrewboyson 74:c3756bfa960e 167 if (TcpHdrRST)
andrewboyson 74:c3756bfa960e 168 {
andrewboyson 76:17534bde28d3 169 if (pTcb->state)
andrewboyson 74:c3756bfa960e 170 {
andrewboyson 89:9b765a67699b 171 log(traceback, "received reset -> reaped TCB");
andrewboyson 75:603b10404183 172 pTcb->state = TCB_EMPTY;
andrewboyson 74:c3756bfa960e 173 }
andrewboyson 86:55bc5ddac16c 174 Led1Set(false);
andrewboyson 74:c3756bfa960e 175 return DO_NOTHING; //Don't reply
andrewboyson 74:c3756bfa960e 176 }
andrewboyson 74:c3756bfa960e 177
andrewboyson 74:c3756bfa960e 178 //Handle request to synchronise
andrewboyson 74:c3756bfa960e 179 if (TcpHdrSYN)
andrewboyson 74:c3756bfa960e 180 {
andrewboyson 76:17534bde28d3 181 if (pTcb->state)
andrewboyson 75:603b10404183 182 {
andrewboyson 89:9b765a67699b 183 log(traceback, "received a SYN on an open connection -> sent reset");
andrewboyson 75:603b10404183 184 pTcb->state = TCB_EMPTY;
andrewboyson 90:955f4c6e18a9 185 action = TcpSendReset(pSizeTx, pPacketTx, pTcb);
andrewboyson 86:55bc5ddac16c 186 Led1Set(false);
andrewboyson 90:955f4c6e18a9 187 return action;
andrewboyson 75:603b10404183 188 }
andrewboyson 76:17534bde28d3 189 else
andrewboyson 75:603b10404183 190 {
andrewboyson 88:1ba13e6062a3 191 handleSyn(pPacketRx, ipType, remArIndex, locMss, pTcb);
andrewboyson 75:603b10404183 192 }
andrewboyson 74:c3756bfa960e 193 }
andrewboyson 74:c3756bfa960e 194
andrewboyson 90:955f4c6e18a9 195 //Handle non SYN packet on an empty connection
andrewboyson 76:17534bde28d3 196 if (!TcpHdrSYN && !pTcb->state)
andrewboyson 76:17534bde28d3 197 {
andrewboyson 90:955f4c6e18a9 198
andrewboyson 89:9b765a67699b 199 log(traceback, "non SYN packet received on a closed connection -> sent reset");
andrewboyson 78:9d8fc88df405 200 pTcb->state = TCB_EMPTY;
andrewboyson 90:955f4c6e18a9 201 action = sendResetFromPacket(pSizeTx, pPacketTx, ipType, remArIndex, locIpScope, seqLengthRcvd);
andrewboyson 86:55bc5ddac16c 202 Led1Set(false);
andrewboyson 90:955f4c6e18a9 203 return action;
andrewboyson 76:17534bde28d3 204 }
andrewboyson 76:17534bde28d3 205
andrewboyson 79:f50e02fb5c94 206 //Check if the acks of bytes sent has progressed and reset the timer
andrewboyson 91:879545b19260 207 uint32_t ackRcvdFromRem = TcpHdrACK ? TcpHdrAckNum - pTcb->locIsn : 0;
andrewboyson 82:20781198d26d 208 if (ackRcvdFromRem > pTcb->bytesAckdByRem)
andrewboyson 82:20781198d26d 209 {
andrewboyson 82:20781198d26d 210 pTcb->timeSendsBeingAcked = TcbElapsed;
andrewboyson 82:20781198d26d 211 pTcb->countSendsNotAcked = 0;
andrewboyson 82:20781198d26d 212 }
andrewboyson 79:f50e02fb5c94 213
andrewboyson 79:f50e02fb5c94 214 //Record the number of bytes acked by the remote host
andrewboyson 79:f50e02fb5c94 215 pTcb->bytesAckdByRem = ackRcvdFromRem;
andrewboyson 79:f50e02fb5c94 216
andrewboyson 76:17534bde28d3 217 /* If the connection is in a synchronized state
andrewboyson 76:17534bde28d3 218 any unacceptable segment (out of window sequence number or
andrewboyson 76:17534bde28d3 219 unacceptible acknowledgment number) must elicit only an empty
andrewboyson 76:17534bde28d3 220 acknowledgment segment containing the current send-sequence number
andrewboyson 76:17534bde28d3 221 and an acknowledgment indicating the next sequence number expected
andrewboyson 76:17534bde28d3 222 to be received, and the connection remains in the same state.*/
andrewboyson 74:c3756bfa960e 223 uint32_t seqRcvdFromRem = TcpHdrSeqNum - pTcb->remIsn;
andrewboyson 78:9d8fc88df405 224 if (seqRcvdFromRem != pTcb->bytesAckdToRem)
andrewboyson 78:9d8fc88df405 225 {
andrewboyson 79:f50e02fb5c94 226 //Only warn non keep-alives
andrewboyson 79:f50e02fb5c94 227 if (seqRcvdFromRem != 0 || pTcb->bytesAckdToRem != 1)
andrewboyson 79:f50e02fb5c94 228 {
andrewboyson 89:9b765a67699b 229 log(traceback, "seq rcvd is %d and last seq ackd was %d -> resent last ACK", seqRcvdFromRem, pTcb->bytesAckdToRem);
andrewboyson 79:f50e02fb5c94 230 }
andrewboyson 90:955f4c6e18a9 231 action = TcpResendLastAck(pSizeTx, pPacketTx, pTcb);
andrewboyson 86:55bc5ddac16c 232 Led1Set(false);
andrewboyson 90:955f4c6e18a9 233 return action;
andrewboyson 78:9d8fc88df405 234 }
andrewboyson 90:955f4c6e18a9 235 //Ignore data before established
andrewboyson 90:955f4c6e18a9 236 if (pTcb->state != TCB_ESTABLISHED && dataLength)
andrewboyson 90:955f4c6e18a9 237 {
andrewboyson 90:955f4c6e18a9 238 log(traceback, "data received before connection established -> sent reset");
andrewboyson 90:955f4c6e18a9 239 pTcb->state = TCB_EMPTY;
andrewboyson 90:955f4c6e18a9 240 action = TcpSendReset(pSizeTx, pPacketTx, pTcb);
andrewboyson 90:955f4c6e18a9 241 Led1Set(false);
andrewboyson 90:955f4c6e18a9 242 return action;
andrewboyson 90:955f4c6e18a9 243 }
andrewboyson 90:955f4c6e18a9 244
andrewboyson 86:55bc5ddac16c 245 Led2Set(true);
andrewboyson 90:955f4c6e18a9 246
andrewboyson 74:c3756bfa960e 247 //Handle FIN
andrewboyson 74:c3756bfa960e 248 if (TcpHdrFIN) pTcb->rcvdFin = true; //When reply is all sent only a passive close is needed
andrewboyson 90:955f4c6e18a9 249
andrewboyson 90:955f4c6e18a9 250 //From now on there are no errors so display traceback if requested
andrewboyson 90:955f4c6e18a9 251 if (traceRequested && NetTraceStack) traceback();
andrewboyson 74:c3756bfa960e 252
andrewboyson 75:603b10404183 253 //Record the number of bytes received from the remote host
andrewboyson 76:17534bde28d3 254 pTcb->bytesRcvdFromRem += seqLengthRcvd;
andrewboyson 74:c3756bfa960e 255
andrewboyson 76:17534bde28d3 256 switch (pTcb->state) //This is the state of the connection BEFORE this packet arrived
andrewboyson 74:c3756bfa960e 257 {
andrewboyson 74:c3756bfa960e 258 case TCB_EMPTY:
andrewboyson 74:c3756bfa960e 259 pTcb->state = TCB_SYN_RECEIVED;
andrewboyson 74:c3756bfa960e 260 break;
andrewboyson 74:c3756bfa960e 261
andrewboyson 74:c3756bfa960e 262 case TCB_SYN_RECEIVED:
andrewboyson 74:c3756bfa960e 263 pTcb->state = TCB_ESTABLISHED;
andrewboyson 74:c3756bfa960e 264 break;
andrewboyson 74:c3756bfa960e 265
andrewboyson 74:c3756bfa960e 266 case TCB_ESTABLISHED:
andrewboyson 88:1ba13e6062a3 267 if (dataLength) handleReceivedData (pPacketRx, dataLength, seqRcvdFromRem - 1, pTcb);
andrewboyson 74:c3756bfa960e 268 if (pTcb->sentFin)
andrewboyson 74:c3756bfa960e 269 {
andrewboyson 77:6cb7d92c37f3 270 pTcb->state = pTcb->rcvdFin ? TCB_EMPTY : TCB_CLOSE_FIN_WAIT;
andrewboyson 74:c3756bfa960e 271 }
andrewboyson 74:c3756bfa960e 272 break;
andrewboyson 74:c3756bfa960e 273
andrewboyson 74:c3756bfa960e 274 case TCB_CLOSE_FIN_WAIT: //End of active close
andrewboyson 74:c3756bfa960e 275 if (TcpHdrFIN)
andrewboyson 74:c3756bfa960e 276 {
andrewboyson 74:c3756bfa960e 277 pTcb->state = TCB_EMPTY;//Ignore ACK to our FIN. Wait for FIN then close.
andrewboyson 74:c3756bfa960e 278 }
andrewboyson 74:c3756bfa960e 279 break;
andrewboyson 74:c3756bfa960e 280
andrewboyson 74:c3756bfa960e 281 }
andrewboyson 74:c3756bfa960e 282
andrewboyson 90:955f4c6e18a9 283 action = TcpSend(pSizeTx, pPacketTx, pTcb);
andrewboyson 86:55bc5ddac16c 284 Led1Set(false);
andrewboyson 86:55bc5ddac16c 285 Led2Set(false);
andrewboyson 86:55bc5ddac16c 286
andrewboyson 90:955f4c6e18a9 287 return action;
andrewboyson 74:c3756bfa960e 288 }