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:
Wed Nov 21 17:13:04 2018 +0000
Revision:
89:9b765a67699b
Parent:
88:1ba13e6062a3
Child:
90:955f4c6e18a9
Tidied up the stack traces

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