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:
Thu Apr 02 19:08:25 2020 +0000
Revision:
167:3ba4e3c49631
Parent:
166:89e3ce39b31b
Modified resolution cache ajaxs to include the index

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 90:955f4c6e18a9 3 #include <stdarg.h>
andrewboyson 74:c3756bfa960e 4
andrewboyson 93:580fc113d9e9 5 #include "log.h"
andrewboyson 93:580fc113d9e9 6 #include "net.h"
andrewboyson 93:580fc113d9e9 7 #include "action.h"
andrewboyson 93:580fc113d9e9 8 #include "tcp.h"
andrewboyson 93:580fc113d9e9 9 #include "tcphdr.h"
andrewboyson 93:580fc113d9e9 10 #include "tcb.h"
andrewboyson 93:580fc113d9e9 11 #include "ip4.h"
andrewboyson 93:580fc113d9e9 12 #include "dhcp.h"
andrewboyson 166:89e3ce39b31b 13 #include "httpv.h"
andrewboyson 159:3ebef2d02f7f 14 #include "https.h"
andrewboyson 93:580fc113d9e9 15 #include "led.h"
andrewboyson 74:c3756bfa960e 16 #include "tcpsend.h"
andrewboyson 93:580fc113d9e9 17 #include "mstimer.h"
andrewboyson 74:c3756bfa960e 18
andrewboyson 120:05b6d67a0cec 19 #define TIMEOUT_RETRANSMISSION_MS 700
andrewboyson 120:05b6d67a0cec 20 #define MAX_RETRANSMISSIONS 5
andrewboyson 120:05b6d67a0cec 21 #define TIMEOUT_BROKEN_LINK_MS 600000
andrewboyson 74:c3756bfa960e 22
andrewboyson 90:955f4c6e18a9 23 static void log(uint16_t remPort, char* fmt, ...)
andrewboyson 90:955f4c6e18a9 24 {
andrewboyson 90:955f4c6e18a9 25 if (TcpTrace)
andrewboyson 90:955f4c6e18a9 26 {
andrewboyson 90:955f4c6e18a9 27 if (NetTraceNewLine) Log("\r\n");
andrewboyson 90:955f4c6e18a9 28 LogTimeF("TCP port %hu - ", remPort);
andrewboyson 90:955f4c6e18a9 29 va_list argptr;
andrewboyson 90:955f4c6e18a9 30 va_start(argptr, fmt);
andrewboyson 90:955f4c6e18a9 31 LogV(fmt, argptr);
andrewboyson 90:955f4c6e18a9 32 va_end(argptr);
andrewboyson 90:955f4c6e18a9 33 Log("\r\n");
andrewboyson 90:955f4c6e18a9 34 }
andrewboyson 90:955f4c6e18a9 35 }
andrewboyson 90:955f4c6e18a9 36
andrewboyson 88:1ba13e6062a3 37 static bool doTrace(uint16_t port)
andrewboyson 88:1ba13e6062a3 38 {
andrewboyson 88:1ba13e6062a3 39 switch (port)
andrewboyson 88:1ba13e6062a3 40 {
andrewboyson 166:89e3ce39b31b 41 case 80: return HttpvGetTrace();
andrewboyson 159:3ebef2d02f7f 42 case 443: return HttpsGetTrace();
andrewboyson 146:0fc66d610fd6 43 default: return false;
andrewboyson 88:1ba13e6062a3 44 }
andrewboyson 88:1ba13e6062a3 45 }
andrewboyson 147:a6093b52e654 46
andrewboyson 159:3ebef2d02f7f 47 static bool addAppData(int *pDataLength, void* pPacket, int connection, uint16_t port, uint32_t windowPositionInStream, int windowSize, bool clientFinished)
andrewboyson 147:a6093b52e654 48 {
andrewboyson 159:3ebef2d02f7f 49 uint8_t* pWindow = (uint8_t*)pPacket + TcpHdrSizeGet();
andrewboyson 145:206bf0d073c7 50 bool finished = false;
andrewboyson 159:3ebef2d02f7f 51 *pDataLength = windowSize;
andrewboyson 75:603b10404183 52 switch (port)
andrewboyson 74:c3756bfa960e 53 {
andrewboyson 166:89e3ce39b31b 54 case 80: finished = HttpvResponse(connection, clientFinished, pDataLength, pWindow, windowPositionInStream); break;
andrewboyson 166:89e3ce39b31b 55 case 443: finished = HttpsResponse(connection, clientFinished, pDataLength, pWindow, windowPositionInStream); break;
andrewboyson 144:6bd5c54efc7d 56 }
andrewboyson 145:206bf0d073c7 57 return finished;
andrewboyson 75:603b10404183 58 }
andrewboyson 89:9b765a67699b 59 static int preparePacket(void* pPacket, struct tcb* pTcb, int dataLength, int* pSize)
andrewboyson 75:603b10404183 60 {
andrewboyson 75:603b10404183 61 //Set the acknowledge flag
andrewboyson 75:603b10404183 62 TcpHdrACK = true;
andrewboyson 74:c3756bfa960e 63
andrewboyson 75:603b10404183 64 //Swap the ports for the reply
andrewboyson 89:9b765a67699b 65 TcpHdrSrcPort = pTcb->locPort;
andrewboyson 89:9b765a67699b 66 TcpHdrDstPort = pTcb->remPort;
andrewboyson 75:603b10404183 67
andrewboyson 75:603b10404183 68 //Specify the receive window size to not throttle
andrewboyson 75:603b10404183 69 TcpHdrWindow = 4000;
andrewboyson 75:603b10404183 70
andrewboyson 75:603b10404183 71 //Write the header
andrewboyson 75:603b10404183 72 TcpHdrWriteToPacket(pPacket);
andrewboyson 75:603b10404183 73
andrewboyson 75:603b10404183 74 //Calculate the size of the reply
andrewboyson 75:603b10404183 75 *pSize = TcpHdrSizeGet() + dataLength;
andrewboyson 75:603b10404183 76
andrewboyson 89:9b765a67699b 77 return ActionMakeFromDestAndTrace(UNICAST, doTrace(pTcb->locPort) && NetTraceStack);
andrewboyson 74:c3756bfa960e 78 }
andrewboyson 75:603b10404183 79 int TcpSend(int* pSize, void* pPacket, struct tcb* pTcb)
andrewboyson 74:c3756bfa960e 80 {
andrewboyson 74:c3756bfa960e 81 int dataLength = 0;
andrewboyson 74:c3756bfa960e 82 TcpHdrMakeEmpty();
andrewboyson 74:c3756bfa960e 83 int locMss = *pSize - TcpHdrSizeGet();
andrewboyson 74:c3756bfa960e 84 switch (pTcb->state)
andrewboyson 74:c3756bfa960e 85 {
andrewboyson 74:c3756bfa960e 86 case TCB_SYN_RECEIVED:
andrewboyson 74:c3756bfa960e 87 if (pTcb->bytesSentToRem == 0)
andrewboyson 74:c3756bfa960e 88 {
andrewboyson 74:c3756bfa960e 89 TcpHdrMssSet(locMss);
andrewboyson 74:c3756bfa960e 90 TcpHdrSYN = true;
andrewboyson 74:c3756bfa960e 91 }
andrewboyson 74:c3756bfa960e 92 break;
andrewboyson 74:c3756bfa960e 93
andrewboyson 74:c3756bfa960e 94 case TCB_ESTABLISHED:
andrewboyson 74:c3756bfa960e 95 if (!pTcb->sentFin)
andrewboyson 74:c3756bfa960e 96 {
andrewboyson 74:c3756bfa960e 97 if (pTcb->bytesSentToRem - pTcb->bytesAckdByRem < pTcb->window)
andrewboyson 74:c3756bfa960e 98 {
andrewboyson 156:be12b8fd5b21 99 bool finished = addAppData(&dataLength, pPacket, TcbGetId(pTcb), pTcb->locPort, pTcb->bytesSentToRem - 1, pTcb->remMss, pTcb->rcvdFin);
andrewboyson 145:206bf0d073c7 100 if (finished)
andrewboyson 74:c3756bfa960e 101 {
andrewboyson 144:6bd5c54efc7d 102 TcpHdrFIN = true;
andrewboyson 144:6bd5c54efc7d 103 pTcb->sentFin = true;
andrewboyson 74:c3756bfa960e 104 }
andrewboyson 74:c3756bfa960e 105 }
andrewboyson 74:c3756bfa960e 106 }
andrewboyson 74:c3756bfa960e 107 break;
andrewboyson 74:c3756bfa960e 108 }
andrewboyson 74:c3756bfa960e 109
andrewboyson 79:f50e02fb5c94 110 //Handle the acknowledgement of received bytes
andrewboyson 74:c3756bfa960e 111 bool rcvdSeqHasAdvanced = pTcb->bytesRcvdFromRem > pTcb->bytesAckdToRem;
andrewboyson 74:c3756bfa960e 112 pTcb->bytesAckdToRem = pTcb->bytesRcvdFromRem;
andrewboyson 79:f50e02fb5c94 113 TcpHdrAckNum = pTcb->bytesAckdToRem + pTcb->remIsn; //Set up the acknowledgement field ready to send
andrewboyson 74:c3756bfa960e 114
andrewboyson 79:f50e02fb5c94 115 //Specify the start of the data being sent
andrewboyson 79:f50e02fb5c94 116 uint32_t seqToSend = pTcb->bytesSentToRem;
andrewboyson 79:f50e02fb5c94 117 TcpHdrSeqNum = seqToSend + pTcb->locIsn; //Set up the start of the message before adding the bytes sent
andrewboyson 74:c3756bfa960e 118
andrewboyson 74:c3756bfa960e 119 //Record the number of bytes sent
andrewboyson 74:c3756bfa960e 120 uint32_t bytesToSend = 0;
andrewboyson 74:c3756bfa960e 121 if (TcpHdrSYN) bytesToSend += 1; //Add one to acknowledge the SYN
andrewboyson 74:c3756bfa960e 122 bytesToSend += dataLength; //Add the number of bytes received
andrewboyson 74:c3756bfa960e 123 if (TcpHdrFIN) bytesToSend += 1; //Add one to acknowledge the FIN
andrewboyson 74:c3756bfa960e 124
andrewboyson 74:c3756bfa960e 125 pTcb->bytesSentToRem += bytesToSend;
andrewboyson 74:c3756bfa960e 126
andrewboyson 79:f50e02fb5c94 127 //Only send a packet if have bytes or an acknowledgement to send
andrewboyson 75:603b10404183 128 if (!rcvdSeqHasAdvanced && !bytesToSend) return DO_NOTHING;
andrewboyson 79:f50e02fb5c94 129
andrewboyson 89:9b765a67699b 130 return preparePacket(pPacket, pTcb, dataLength, pSize);
andrewboyson 75:603b10404183 131 }
andrewboyson 75:603b10404183 132 int TcpResendLastUnAcked(int* pSize, void *pPacket, struct tcb* pTcb)
andrewboyson 75:603b10404183 133 {
andrewboyson 75:603b10404183 134 int dataLength = 0;
andrewboyson 75:603b10404183 135 TcpHdrMakeEmpty();
andrewboyson 75:603b10404183 136 int locMss = *pSize - TcpHdrSizeGet();
andrewboyson 79:f50e02fb5c94 137 uint32_t seqNum = pTcb->bytesAckdByRem;
andrewboyson 75:603b10404183 138 switch (pTcb->state)
andrewboyson 74:c3756bfa960e 139 {
andrewboyson 75:603b10404183 140 case TCB_SYN_RECEIVED:
andrewboyson 75:603b10404183 141 TcpHdrMssSet(locMss);
andrewboyson 75:603b10404183 142 TcpHdrSYN = true;
andrewboyson 75:603b10404183 143 break;
andrewboyson 74:c3756bfa960e 144
andrewboyson 75:603b10404183 145 case TCB_ESTABLISHED:
andrewboyson 79:f50e02fb5c94 146 case TCB_CLOSE_FIN_WAIT:
andrewboyson 75:603b10404183 147 {
andrewboyson 156:be12b8fd5b21 148 bool finished = addAppData(&dataLength, pPacket, TcbGetId(pTcb), pTcb->locPort, seqNum - 1, pTcb->remMss, pTcb->rcvdFin);
andrewboyson 145:206bf0d073c7 149 if (finished)
andrewboyson 75:603b10404183 150 {
andrewboyson 75:603b10404183 151 TcpHdrFIN = true;
andrewboyson 75:603b10404183 152 pTcb->sentFin = true;
andrewboyson 75:603b10404183 153 }
andrewboyson 145:206bf0d073c7 154 break;
andrewboyson 75:603b10404183 155 }
andrewboyson 74:c3756bfa960e 156 }
andrewboyson 75:603b10404183 157
andrewboyson 75:603b10404183 158 TcpHdrAckNum = pTcb->bytesAckdToRem + pTcb->remIsn; //Set up the acknowledgement field ready to send
andrewboyson 75:603b10404183 159 TcpHdrSeqNum = seqNum + pTcb->locIsn; //Set up the start of the message before adding the bytes sent
andrewboyson 79:f50e02fb5c94 160
andrewboyson 89:9b765a67699b 161 return preparePacket(pPacket, pTcb, dataLength, pSize);
andrewboyson 75:603b10404183 162 }
andrewboyson 75:603b10404183 163 int TcpResendLastAck(int* pSize, void *pPacket, struct tcb* pTcb)
andrewboyson 75:603b10404183 164 {
andrewboyson 75:603b10404183 165 int dataLength = 0;
andrewboyson 75:603b10404183 166 TcpHdrMakeEmpty();
andrewboyson 75:603b10404183 167 TcpHdrAckNum = pTcb->bytesAckdToRem + pTcb->remIsn; //Set up the acknowledgement field ready to send
andrewboyson 75:603b10404183 168 TcpHdrSeqNum = pTcb->bytesSentToRem + pTcb->locIsn; //Set up the start of the message before adding the bytes sent
andrewboyson 75:603b10404183 169
andrewboyson 89:9b765a67699b 170 return preparePacket(pPacket, pTcb, dataLength, pSize);
andrewboyson 75:603b10404183 171 }
andrewboyson 75:603b10404183 172 int TcpSendReset(int* pSize, void *pPacket, struct tcb* pTcb)
andrewboyson 75:603b10404183 173 {
andrewboyson 75:603b10404183 174 int dataLength = 0;
andrewboyson 75:603b10404183 175 TcpHdrMakeEmpty();
andrewboyson 75:603b10404183 176 TcpHdrAckNum = pTcb->bytesAckdToRem + pTcb->remIsn; //Set up the acknowledgement field ready to send
andrewboyson 75:603b10404183 177 TcpHdrSeqNum = pTcb->bytesSentToRem + pTcb->locIsn; //Set up the start of the message before adding the bytes sent
andrewboyson 75:603b10404183 178
andrewboyson 75:603b10404183 179 TcpHdrRST = true;
andrewboyson 75:603b10404183 180
andrewboyson 89:9b765a67699b 181 return preparePacket(pPacket, pTcb, dataLength, pSize);
andrewboyson 74:c3756bfa960e 182 }
andrewboyson 79:f50e02fb5c94 183 int TcpSendClose(int* pSize, void *pPacket, struct tcb* pTcb)
andrewboyson 79:f50e02fb5c94 184 {
andrewboyson 79:f50e02fb5c94 185 int dataLength = 0;
andrewboyson 79:f50e02fb5c94 186 TcpHdrMakeEmpty();
andrewboyson 79:f50e02fb5c94 187 TcpHdrFIN = true;
andrewboyson 79:f50e02fb5c94 188 pTcb->sentFin = true;
andrewboyson 79:f50e02fb5c94 189 pTcb->bytesSentToRem += 1; //For the FIN
andrewboyson 79:f50e02fb5c94 190 TcpHdrAckNum = pTcb->bytesAckdToRem + pTcb->remIsn; //Set up the acknowledgement field ready to send
andrewboyson 79:f50e02fb5c94 191 TcpHdrSeqNum = pTcb->bytesSentToRem + pTcb->locIsn; //Set up the start of the message before adding the bytes sent
andrewboyson 79:f50e02fb5c94 192
andrewboyson 89:9b765a67699b 193 return preparePacket(pPacket, pTcb, dataLength, pSize);
andrewboyson 79:f50e02fb5c94 194 }
andrewboyson 79:f50e02fb5c94 195
andrewboyson 80:4ef1500fca1d 196 int TcpPollForPacketToSend(int* pSize, void* pPacket, int ipType, int* pRemArIndex, int* pLocIpScope)
andrewboyson 74:c3756bfa960e 197 {
andrewboyson 83:08c983006a6e 198 //Loops around the TCBs, moving on if empty but staying if not the right type
andrewboyson 79:f50e02fb5c94 199 static struct tcb* pTcb = NULL; //Passing a pointer containing NULL to TcbGetNext causes it to return the first TCB
andrewboyson 79:f50e02fb5c94 200 static bool stay = false;
andrewboyson 83:08c983006a6e 201 if (!stay) pTcb = TcbGetNext(pTcb);
andrewboyson 79:f50e02fb5c94 202 stay = false;
andrewboyson 78:9d8fc88df405 203 if (!pTcb->state) return DO_NOTHING;
andrewboyson 79:f50e02fb5c94 204 if (pTcb->ipType != ipType)
andrewboyson 79:f50e02fb5c94 205 {
andrewboyson 79:f50e02fb5c94 206 stay = true;
andrewboyson 79:f50e02fb5c94 207 return DO_NOTHING;
andrewboyson 79:f50e02fb5c94 208 }
andrewboyson 79:f50e02fb5c94 209
andrewboyson 163:f063e374cf2a 210 //Return the remote AR index and the local IP scope
andrewboyson 163:f063e374cf2a 211 if (pRemArIndex) *pRemArIndex = pTcb->remArIndex;
andrewboyson 80:4ef1500fca1d 212 if (pLocIpScope) *pLocIpScope = pTcb->locIpScope;
andrewboyson 87:40d46a979cdb 213
andrewboyson 163:f063e374cf2a 214 //Reap broken links
andrewboyson 133:a37eb35a03f1 215 if (MsTimerRelative(pTcb->timeLastRcvd, TIMEOUT_BROKEN_LINK_MS))
andrewboyson 79:f50e02fb5c94 216 {
andrewboyson 90:955f4c6e18a9 217 log(pTcb->remPort, "broken link -> reaping TCB");
andrewboyson 79:f50e02fb5c94 218 pTcb->state = TCB_EMPTY;
andrewboyson 79:f50e02fb5c94 219 return DO_NOTHING;
andrewboyson 79:f50e02fb5c94 220 }
andrewboyson 78:9d8fc88df405 221
andrewboyson 79:f50e02fb5c94 222 //Reset the RTO if all bytes are acknowledged
andrewboyson 79:f50e02fb5c94 223 if (pTcb->bytesSentToRem == pTcb->bytesAckdByRem)
andrewboyson 79:f50e02fb5c94 224 {
andrewboyson 93:580fc113d9e9 225 pTcb->timeSendsBeingAcked = MsTimerCount;
andrewboyson 82:20781198d26d 226 pTcb->countSendsNotAcked = 0;
andrewboyson 79:f50e02fb5c94 227 }
andrewboyson 75:603b10404183 228
andrewboyson 79:f50e02fb5c94 229 //Check if have unacknowledged send bytes after the RTO
andrewboyson 133:a37eb35a03f1 230 if (MsTimerRelative(pTcb->timeSendsBeingAcked, TIMEOUT_RETRANSMISSION_MS))
andrewboyson 75:603b10404183 231 {
andrewboyson 82:20781198d26d 232 pTcb->countSendsNotAcked++;
andrewboyson 82:20781198d26d 233 if (pTcb->countSendsNotAcked > MAX_RETRANSMISSIONS)
andrewboyson 82:20781198d26d 234 {
andrewboyson 164:84b20bcd0941 235 log(pTcb->remPort, "reached maximum retransmissions -> reaping TCB");
andrewboyson 90:955f4c6e18a9 236 pTcb->state = TCB_EMPTY;
andrewboyson 164:84b20bcd0941 237 return DO_NOTHING;
andrewboyson 82:20781198d26d 238 }
andrewboyson 90:955f4c6e18a9 239 else
andrewboyson 79:f50e02fb5c94 240 {
andrewboyson 90:955f4c6e18a9 241 log(pTcb->remPort, "only had ack of %lu while sent %lu -> resending", pTcb->bytesAckdByRem, pTcb->bytesSentToRem);
andrewboyson 93:580fc113d9e9 242 pTcb->timeSendsBeingAcked = MsTimerCount;
andrewboyson 90:955f4c6e18a9 243 return TcpResendLastUnAcked(pSize, pPacket, pTcb);
andrewboyson 79:f50e02fb5c94 244 }
andrewboyson 75:603b10404183 245 }
andrewboyson 90:955f4c6e18a9 246 else
andrewboyson 90:955f4c6e18a9 247 {
andrewboyson 90:955f4c6e18a9 248 //If haven't had to do anything else then do a normal send
andrewboyson 90:955f4c6e18a9 249 return TcpSend(pSize, pPacket, pTcb);
andrewboyson 90:955f4c6e18a9 250 }
andrewboyson 74:c3756bfa960e 251 }
andrewboyson 74:c3756bfa960e 252