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 20 17:21:38 2018 +0000
Revision:
88:1ba13e6062a3
Parent:
86:55bc5ddac16c
Child:
89:9b765a67699b
Increased TCB pool from 10 to 20.

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