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 Jan 16 17:35:16 2018 +0000
Revision:
62:9b8c1e1761b6
Parent:
61:aad055f1b0d1
Child:
71:736a5747ade1
Added window size of 4000 to prevent throttling

Who changed what in which revision?

UserRevisionLine numberNew contents of line
andrewboyson 61:aad055f1b0d1 1 #include <stdint.h>
andrewboyson 61:aad055f1b0d1 2 #include <stdbool.h>
andrewboyson 61:aad055f1b0d1 3
andrewboyson 37:793b39683406 4 #include "log.h"
andrewboyson 37:793b39683406 5 #include "net.h"
andrewboyson 37:793b39683406 6 #include "action.h"
andrewboyson 37:793b39683406 7 #include "tcp.h"
andrewboyson 37:793b39683406 8 #include "tcb.h"
andrewboyson 37:793b39683406 9 #include "ip4.h"
andrewboyson 37:793b39683406 10 #include "dhcp.h"
andrewboyson 49:1a6336f2b3f9 11 #include "http.h"
andrewboyson 10:f0854784e960 12
andrewboyson 59:e0e556c8bd46 13 static int maxMss = 0;
andrewboyson 10:f0854784e960 14
andrewboyson 52:fbc5a46b5e16 15 bool TcpTrace = false;
andrewboyson 55:e64b8b47a2b6 16 static bool doTrace = false;
andrewboyson 52:fbc5a46b5e16 17
andrewboyson 10:f0854784e960 18 __packed struct header
andrewboyson 10:f0854784e960 19 {
andrewboyson 10:f0854784e960 20 uint16_t srcPort;
andrewboyson 10:f0854784e960 21 uint16_t dstPort;
andrewboyson 10:f0854784e960 22 uint32_t seqnum;
andrewboyson 10:f0854784e960 23 uint32_t acknum;
andrewboyson 10:f0854784e960 24 uint8_t dataOffset;
andrewboyson 10:f0854784e960 25 uint8_t flags;
andrewboyson 10:f0854784e960 26 uint16_t window;
andrewboyson 10:f0854784e960 27 uint16_t checksum;
andrewboyson 10:f0854784e960 28 uint16_t urgent;
andrewboyson 10:f0854784e960 29 };
andrewboyson 10:f0854784e960 30
andrewboyson 10:f0854784e960 31 //Header variables
andrewboyson 10:f0854784e960 32
andrewboyson 54:84ef2b29cf7e 33 static uint16_t srcPort;
andrewboyson 54:84ef2b29cf7e 34 static uint16_t dstPort;
andrewboyson 54:84ef2b29cf7e 35 static uint32_t seqnum;
andrewboyson 54:84ef2b29cf7e 36 static uint32_t acknum;
andrewboyson 54:84ef2b29cf7e 37 static int headersize;
andrewboyson 54:84ef2b29cf7e 38 static uint8_t flags;
andrewboyson 54:84ef2b29cf7e 39 static bool URG; //indicates that the Urgent pointer field is significant
andrewboyson 54:84ef2b29cf7e 40 static bool ACK; //indicates that the Acknowledgment field is significant. All packets after the initial SYN packet sent by the client should have this flag set.
andrewboyson 54:84ef2b29cf7e 41 static bool PSH; //Push function. Asks to push the buffered data to the receiving application.
andrewboyson 54:84ef2b29cf7e 42 static bool RST; //Reset the connection
andrewboyson 54:84ef2b29cf7e 43 static bool SYN; //Synchronize sequence numbers. Only the first packet sent from each end should have this flag set. Some other flags and fields change meaning based on this flag, and some are only valid for when it is set, and others when it is clear.
andrewboyson 54:84ef2b29cf7e 44 static bool FIN; //No more data from sender
andrewboyson 54:84ef2b29cf7e 45 static uint16_t window;
andrewboyson 54:84ef2b29cf7e 46 static uint16_t checksum;
andrewboyson 54:84ef2b29cf7e 47 static uint16_t urgent;
andrewboyson 59:e0e556c8bd46 48
andrewboyson 59:e0e556c8bd46 49 //Payload variables
andrewboyson 59:e0e556c8bd46 50 static char* pOptionsRx;
andrewboyson 59:e0e556c8bd46 51 static char* pOptionsTx;
andrewboyson 59:e0e556c8bd46 52 static int optionLength;
andrewboyson 59:e0e556c8bd46 53 static char* pDataRx;
andrewboyson 59:e0e556c8bd46 54 static char* pDataTx;
andrewboyson 54:84ef2b29cf7e 55 static int dataLength;
andrewboyson 59:e0e556c8bd46 56
andrewboyson 59:e0e556c8bd46 57
andrewboyson 59:e0e556c8bd46 58 static void readHeader(void* pPacket, uint16_t size)
andrewboyson 59:e0e556c8bd46 59 {
andrewboyson 61:aad055f1b0d1 60 struct header* pHeader = (struct header*)pPacket;
andrewboyson 59:e0e556c8bd46 61
andrewboyson 59:e0e556c8bd46 62 srcPort = NetToHost16(pHeader->srcPort);
andrewboyson 59:e0e556c8bd46 63 dstPort = NetToHost16(pHeader->dstPort);
andrewboyson 59:e0e556c8bd46 64 seqnum = NetToHost32(pHeader->seqnum);
andrewboyson 59:e0e556c8bd46 65 acknum = NetToHost32(pHeader->acknum);
andrewboyson 59:e0e556c8bd46 66 headersize = (pHeader->dataOffset >> 2) & 0xFC; //Same as right shifting by 4 bits and multiplying by 4
andrewboyson 59:e0e556c8bd46 67 flags = pHeader->flags;
andrewboyson 59:e0e556c8bd46 68 URG = flags & 0x20; //indicates that the Urgent pointer field is significant
andrewboyson 59:e0e556c8bd46 69 ACK = flags & 0x10; //indicates that the Acknowledgment field is significant. All packets after the initial SYN packet sent by the client should have this flag set.
andrewboyson 59:e0e556c8bd46 70 PSH = flags & 0x08; //Push function. Asks to push the buffered data to the receiving application.
andrewboyson 59:e0e556c8bd46 71 RST = flags & 0x04; //Reset the connection
andrewboyson 59:e0e556c8bd46 72 SYN = flags & 0x02; //Synchronize sequence numbers. Only the first packet sent from each end should have this flag set. Some other flags and fields change meaning based on this flag, and some are only valid for when it is set, and others when it is clear.
andrewboyson 59:e0e556c8bd46 73 FIN = flags & 0x01; //No more data from sender
andrewboyson 59:e0e556c8bd46 74
andrewboyson 59:e0e556c8bd46 75 window = NetToHost16(pHeader->window);
andrewboyson 59:e0e556c8bd46 76 checksum = NetToHost16(pHeader->checksum);
andrewboyson 59:e0e556c8bd46 77 urgent = NetToHost16(pHeader->urgent);
andrewboyson 59:e0e556c8bd46 78 }
andrewboyson 59:e0e556c8bd46 79
andrewboyson 56:35117a8b5c65 80 static int positionInQuery;
andrewboyson 56:35117a8b5c65 81 static int positionInReply;
andrewboyson 54:84ef2b29cf7e 82
andrewboyson 55:e64b8b47a2b6 83 static uint16_t mss;
andrewboyson 54:84ef2b29cf7e 84
andrewboyson 54:84ef2b29cf7e 85 static struct tcb* pTcb;
andrewboyson 54:84ef2b29cf7e 86
andrewboyson 52:fbc5a46b5e16 87 static void logFlags()
andrewboyson 52:fbc5a46b5e16 88 {
andrewboyson 52:fbc5a46b5e16 89 if (URG) Log(" URG");
andrewboyson 52:fbc5a46b5e16 90 if (ACK) Log(" ACK");
andrewboyson 52:fbc5a46b5e16 91 if (PSH) Log(" PSH");
andrewboyson 52:fbc5a46b5e16 92 if (RST) Log(" RST");
andrewboyson 52:fbc5a46b5e16 93 if (SYN) Log(" SYN");
andrewboyson 52:fbc5a46b5e16 94 if (FIN) Log(" FIN");
andrewboyson 52:fbc5a46b5e16 95 }
andrewboyson 56:35117a8b5c65 96 void TcpLogHeader(uint16_t calculatedChecksum)
andrewboyson 43:bc028d5a6424 97 {
andrewboyson 43:bc028d5a6424 98 if (NetTraceVerbose)
andrewboyson 43:bc028d5a6424 99 {
andrewboyson 43:bc028d5a6424 100 Log("TCP header\r\n");
andrewboyson 57:e0fb648acf48 101 Log(" Source port "); LogF("%hu", srcPort ); Log("\r\n");
andrewboyson 57:e0fb648acf48 102 Log(" Destination port "); LogF("%hu", dstPort ); Log("\r\n");
andrewboyson 57:e0fb648acf48 103 Log(" Seq number "); LogF("%u (%u)", positionInQuery, seqnum); Log("\r\n");
andrewboyson 57:e0fb648acf48 104 Log(" Ack number "); LogF("%u (%u)", positionInReply, acknum); Log("\r\n");
andrewboyson 57:e0fb648acf48 105 Log(" Header size "); LogF("%u", headersize ); Log("\r\n");
andrewboyson 57:e0fb648acf48 106 Log(" Flags " ); logFlags( ); Log("\r\n");
andrewboyson 57:e0fb648acf48 107 Log(" Window "); LogF("%hu", window ); Log("\r\n");
andrewboyson 57:e0fb648acf48 108 Log(" Checksum (hex) "); LogF("%04hX", checksum ); Log("\r\n");
andrewboyson 57:e0fb648acf48 109 Log(" Calculated (hex) "); LogF("%04hX", calculatedChecksum ); Log("\r\n");
andrewboyson 57:e0fb648acf48 110 Log(" Urgent pointer "); LogF("%hu", urgent ); Log("\r\n");
andrewboyson 57:e0fb648acf48 111 Log(" Option length "); LogF("%d", optionLength ); Log("\r\n");
andrewboyson 57:e0fb648acf48 112 Log(" Data length "); LogF("%u", dataLength ); Log("\r\n");
andrewboyson 57:e0fb648acf48 113 Log(" sendIsn "); LogF("%u", pTcb->sendIsn ); Log("\r\n");
andrewboyson 57:e0fb648acf48 114 Log(" recvIsn "); LogF("%u", pTcb->recvIsn ); Log("\r\n");
andrewboyson 57:e0fb648acf48 115 Log(" sentBytes "); LogF("%u", pTcb->sentBytes ); Log("\r\n");
andrewboyson 57:e0fb648acf48 116 Log(" recdBytes "); LogF("%u", pTcb->recdBytes ); Log("\r\n");
andrewboyson 54:84ef2b29cf7e 117
andrewboyson 43:bc028d5a6424 118 }
andrewboyson 43:bc028d5a6424 119 else
andrewboyson 43:bc028d5a6424 120 {
andrewboyson 44:83ce5ace337b 121 LogF("TCP header %hu >>> %hu", srcPort, dstPort);
andrewboyson 52:fbc5a46b5e16 122 logFlags();
andrewboyson 57:e0fb648acf48 123 LogF(", query %u, reply %u", positionInQuery, positionInReply);
andrewboyson 52:fbc5a46b5e16 124 Log("\r\n");
andrewboyson 43:bc028d5a6424 125 }
andrewboyson 10:f0854784e960 126 }
andrewboyson 10:f0854784e960 127 void TcpAddChecksum(void* pPacket, uint16_t checksum)
andrewboyson 10:f0854784e960 128 {
andrewboyson 61:aad055f1b0d1 129 struct header* pHeader = (struct header*)pPacket;
andrewboyson 10:f0854784e960 130 pHeader->checksum = checksum;
andrewboyson 10:f0854784e960 131 }
andrewboyson 10:f0854784e960 132 static void readOptions()
andrewboyson 10:f0854784e960 133 {
andrewboyson 10:f0854784e960 134 mss = 536; //default MSS for IPv4 [576 - 20(TCP) - 20(IP)];
andrewboyson 59:e0e556c8bd46 135 for (char* p = pOptionsRx; p < pOptionsRx + optionLength; p++)
andrewboyson 10:f0854784e960 136 {
andrewboyson 10:f0854784e960 137 switch (*p)
andrewboyson 10:f0854784e960 138 {
andrewboyson 10:f0854784e960 139 case 0: break; //End of options - used to pad to 32 bit boundary
andrewboyson 10:f0854784e960 140 case 1: break; //NOP, padding - optional
andrewboyson 10:f0854784e960 141 case 2:
andrewboyson 10:f0854784e960 142 p++;
andrewboyson 10:f0854784e960 143 if (*p != 4) LogTimeF("MSS option width %d when expected 4\r\n", *p);
andrewboyson 10:f0854784e960 144 p++;
andrewboyson 10:f0854784e960 145 mss = ((uint16_t)*p) << 8;
andrewboyson 10:f0854784e960 146 p++;
andrewboyson 10:f0854784e960 147 mss += *p;
andrewboyson 10:f0854784e960 148 return;
andrewboyson 10:f0854784e960 149 default: LogTimeF("Unrecognised TCP option %d\r\n", *p);
andrewboyson 10:f0854784e960 150 }
andrewboyson 10:f0854784e960 151 }
andrewboyson 59:e0e556c8bd46 152 if (mss > maxMss) mss = maxMss;
andrewboyson 10:f0854784e960 153 }
andrewboyson 10:f0854784e960 154 static void writeOptions()
andrewboyson 10:f0854784e960 155 {
andrewboyson 59:e0e556c8bd46 156 pOptionsTx[0] = 2;
andrewboyson 59:e0e556c8bd46 157 pOptionsTx[1] = 4;
andrewboyson 59:e0e556c8bd46 158 pOptionsTx[2] = mss >> 8;
andrewboyson 59:e0e556c8bd46 159 pOptionsTx[3] = mss & 0xFF;
andrewboyson 10:f0854784e960 160 optionLength = 4;
andrewboyson 10:f0854784e960 161 }
andrewboyson 10:f0854784e960 162
andrewboyson 10:f0854784e960 163 void TcpMakeHeader(int size, void* pPacket)
andrewboyson 10:f0854784e960 164 {
andrewboyson 61:aad055f1b0d1 165 struct header* pHeader = (struct header*)pPacket;
andrewboyson 10:f0854784e960 166
andrewboyson 10:f0854784e960 167 pHeader->dstPort = NetToHost16(dstPort);
andrewboyson 10:f0854784e960 168 pHeader->srcPort = NetToHost16(srcPort);
andrewboyson 10:f0854784e960 169 pHeader->seqnum = NetToHost32(seqnum); //This is the sequence number of the first byte of this message
andrewboyson 10:f0854784e960 170 pHeader->acknum = NetToHost32(acknum); //This is the sequence number we expect in the next message
andrewboyson 10:f0854784e960 171 pHeader->dataOffset = headersize << 2; //Same as dividing by 4 to get bytes and left shifting by 4 bits
andrewboyson 10:f0854784e960 172 flags = 0;
andrewboyson 56:35117a8b5c65 173 if (URG) flags |= 0x20; //indicates that the Urgent pointer field is significant
andrewboyson 56:35117a8b5c65 174 if (ACK) flags |= 0x10; //indicates that the Acknowledgment field is significant. All packets after the initial SYN packet sent by the client should have this flag set.
andrewboyson 56:35117a8b5c65 175 if (PSH) flags |= 0x08; //Push function. Asks to push the buffered data to the receiving application.
andrewboyson 56:35117a8b5c65 176 if (RST) flags |= 0x04; //Reset the connection
andrewboyson 56:35117a8b5c65 177 if (SYN) flags |= 0x02; //Synchronize sequence numbers. Only the first packet sent from each end should have this flag set. Some other flags and fields change meaning based on this flag, and some are only valid for when it is set, and others when it is clear.
andrewboyson 56:35117a8b5c65 178 if (FIN) flags |= 0x01; //No more data from sender
andrewboyson 10:f0854784e960 179 pHeader->flags = flags;
andrewboyson 10:f0854784e960 180 pHeader->window = NetToHost16(window);
andrewboyson 10:f0854784e960 181 pHeader->urgent = NetToHost16(urgent);
andrewboyson 10:f0854784e960 182
andrewboyson 10:f0854784e960 183 pHeader->checksum = 0;
andrewboyson 10:f0854784e960 184 }
andrewboyson 56:35117a8b5c65 185 static void resetConnection(char* message)
andrewboyson 55:e64b8b47a2b6 186 {
andrewboyson 56:35117a8b5c65 187 if (TcpTrace)
andrewboyson 56:35117a8b5c65 188 {
andrewboyson 56:35117a8b5c65 189 LogTime("TCP ");
andrewboyson 56:35117a8b5c65 190 Log(message);
andrewboyson 56:35117a8b5c65 191 Log("\r\n");
andrewboyson 56:35117a8b5c65 192 }
andrewboyson 55:e64b8b47a2b6 193 dataLength = 0;
andrewboyson 61:aad055f1b0d1 194 headersize = sizeof(struct header);
andrewboyson 55:e64b8b47a2b6 195 ACK = false;
andrewboyson 55:e64b8b47a2b6 196 PSH = false;
andrewboyson 55:e64b8b47a2b6 197 RST = true;
andrewboyson 55:e64b8b47a2b6 198 SYN = false;
andrewboyson 55:e64b8b47a2b6 199 FIN = false;
andrewboyson 61:aad055f1b0d1 200
andrewboyson 61:aad055f1b0d1 201 pTcb->state = TCB_EMPTY;
andrewboyson 55:e64b8b47a2b6 202 }
andrewboyson 56:35117a8b5c65 203 static void startConnection()
andrewboyson 10:f0854784e960 204 {
andrewboyson 10:f0854784e960 205 readOptions(); //Get the MSS
andrewboyson 52:fbc5a46b5e16 206 pTcb->mss = mss;
andrewboyson 52:fbc5a46b5e16 207 pTcb->state = TCB_SYN_RECEIVED;
andrewboyson 52:fbc5a46b5e16 208 pTcb->elapsed = TcbElapsed;
andrewboyson 52:fbc5a46b5e16 209 pTcb->port = srcPort;
andrewboyson 57:e0fb648acf48 210 pTcb->hadFin = false;
andrewboyson 55:e64b8b47a2b6 211
andrewboyson 59:e0e556c8bd46 212 mss = maxMss; //Ethernet 1500 - 20 - 20; or, in our case 768 - 20 - 20
andrewboyson 59:e0e556c8bd46 213 writeOptions();
andrewboyson 61:aad055f1b0d1 214 headersize = sizeof(struct header) + optionLength;
andrewboyson 10:f0854784e960 215 dataLength = 0;
andrewboyson 10:f0854784e960 216
andrewboyson 10:f0854784e960 217 ACK = true; //Send ACK and SYN
andrewboyson 10:f0854784e960 218 PSH = false;
andrewboyson 10:f0854784e960 219 RST = false;
andrewboyson 10:f0854784e960 220 SYN = true;
andrewboyson 10:f0854784e960 221 FIN = false;
andrewboyson 10:f0854784e960 222 }
andrewboyson 56:35117a8b5c65 223 static void establishConnection()
andrewboyson 10:f0854784e960 224 {
andrewboyson 56:35117a8b5c65 225 pTcb->state = TCB_ESTABLISHED;
andrewboyson 56:35117a8b5c65 226 pTcb->elapsed = TcbElapsed;
andrewboyson 57:e0fb648acf48 227 pTcb->todo = 0;
andrewboyson 10:f0854784e960 228 }
andrewboyson 56:35117a8b5c65 229 static void handleEstablishedConnection()
andrewboyson 56:35117a8b5c65 230 {
andrewboyson 59:e0e556c8bd46 231 pDataTx = pOptionsTx; //No options
andrewboyson 61:aad055f1b0d1 232 headersize = sizeof(struct header);
andrewboyson 54:84ef2b29cf7e 233
andrewboyson 59:e0e556c8bd46 234 HttpHandleRequest(&dataLength, pDataRx, positionInQuery - 1, pDataTx, positionInReply - 1, mss, &pTcb->todo);
andrewboyson 10:f0854784e960 235
andrewboyson 10:f0854784e960 236 ACK = true; //Send ACK
andrewboyson 10:f0854784e960 237 RST = false;
andrewboyson 10:f0854784e960 238 SYN = false;
andrewboyson 22:914b970356f0 239 PSH = false;
andrewboyson 10:f0854784e960 240
andrewboyson 22:914b970356f0 241 if (dataLength < mss) //If a part packet then there can be no more to send
andrewboyson 10:f0854784e960 242 {
andrewboyson 57:e0fb648acf48 243 FIN = true; //Inform the client that we have no more to send after this
andrewboyson 57:e0fb648acf48 244 if (pTcb->hadFin) pTcb->state = TCB_ACK_WAIT; //Passive close
andrewboyson 57:e0fb648acf48 245 else pTcb->state = TCB_FIN_WAIT; //Active close
andrewboyson 10:f0854784e960 246 }
andrewboyson 56:35117a8b5c65 247 else
andrewboyson 56:35117a8b5c65 248 {
andrewboyson 56:35117a8b5c65 249 FIN = false;
andrewboyson 56:35117a8b5c65 250 }
andrewboyson 22:914b970356f0 251
andrewboyson 52:fbc5a46b5e16 252 pTcb->elapsed = TcbElapsed;
andrewboyson 10:f0854784e960 253 }
andrewboyson 56:35117a8b5c65 254 static void closeConnection()
andrewboyson 56:35117a8b5c65 255 {
andrewboyson 10:f0854784e960 256 ACK = true; //Send ACK
andrewboyson 10:f0854784e960 257 PSH = false;
andrewboyson 10:f0854784e960 258 RST = false;
andrewboyson 10:f0854784e960 259 SYN = false;
andrewboyson 10:f0854784e960 260 FIN = false;
andrewboyson 10:f0854784e960 261
andrewboyson 61:aad055f1b0d1 262 headersize = sizeof(struct header);
andrewboyson 10:f0854784e960 263 dataLength = 0;
andrewboyson 10:f0854784e960 264
andrewboyson 57:e0fb648acf48 265 pTcb->state = TCB_EMPTY;
andrewboyson 10:f0854784e960 266 }
andrewboyson 10:f0854784e960 267
andrewboyson 59:e0e556c8bd46 268 int TcpHandleReceivedPacket(void (*traceback)(void), int sizeRx, void* pPacketRx, int* pSizeTx, void* pPacketTx)
andrewboyson 10:f0854784e960 269 {
andrewboyson 59:e0e556c8bd46 270 readHeader(pPacketRx, sizeRx);
andrewboyson 59:e0e556c8bd46 271
andrewboyson 59:e0e556c8bd46 272 pDataRx = (char*)pPacketRx + headersize;
andrewboyson 59:e0e556c8bd46 273 dataLength = sizeRx - headersize;
andrewboyson 61:aad055f1b0d1 274 maxMss = *pSizeTx - sizeof(struct header);
andrewboyson 59:e0e556c8bd46 275
andrewboyson 61:aad055f1b0d1 276 pOptionsRx = (char*)pPacketRx + sizeof(struct header);
andrewboyson 61:aad055f1b0d1 277 pOptionsTx = (char*)pPacketTx + sizeof(struct header);
andrewboyson 61:aad055f1b0d1 278 optionLength = headersize - sizeof(struct header);
andrewboyson 59:e0e556c8bd46 279
andrewboyson 57:e0fb648acf48 280 doTrace = false;
andrewboyson 57:e0fb648acf48 281
andrewboyson 57:e0fb648acf48 282 //Filter out unwanted links
andrewboyson 57:e0fb648acf48 283 switch (dstPort)
andrewboyson 57:e0fb648acf48 284 {
andrewboyson 57:e0fb648acf48 285 case 80:
andrewboyson 57:e0fb648acf48 286 if (HttpTrace)
andrewboyson 57:e0fb648acf48 287 {
andrewboyson 57:e0fb648acf48 288 if (NetTraceNewLine) Log("\r\n");
andrewboyson 57:e0fb648acf48 289 LogTime("HTTP server request\r\n");
andrewboyson 57:e0fb648acf48 290 doTrace = true;
andrewboyson 57:e0fb648acf48 291 }
andrewboyson 57:e0fb648acf48 292 break;
andrewboyson 57:e0fb648acf48 293
andrewboyson 57:e0fb648acf48 294 default:
andrewboyson 57:e0fb648acf48 295 if (TcpTrace)
andrewboyson 57:e0fb648acf48 296 {
andrewboyson 57:e0fb648acf48 297 if (NetTraceNewLine) Log("\r\n");
andrewboyson 57:e0fb648acf48 298 LogTimeF("TCP unknown port %d\r\n", dstPort);
andrewboyson 59:e0e556c8bd46 299 if (NetTraceStack) traceback();
andrewboyson 57:e0fb648acf48 300 }
andrewboyson 57:e0fb648acf48 301 return DO_NOTHING; //Ignore unknown ports
andrewboyson 57:e0fb648acf48 302 }
andrewboyson 55:e64b8b47a2b6 303
andrewboyson 55:e64b8b47a2b6 304 //Get the Transmission Control Block
andrewboyson 54:84ef2b29cf7e 305 pTcb = TcbGetExisting(srcPort);
andrewboyson 10:f0854784e960 306 if (!pTcb) pTcb = TcbGetEmpty();
andrewboyson 52:fbc5a46b5e16 307 if (!pTcb)
andrewboyson 52:fbc5a46b5e16 308 {
andrewboyson 52:fbc5a46b5e16 309 if (TcpTrace)
andrewboyson 52:fbc5a46b5e16 310 {
andrewboyson 57:e0fb648acf48 311 if (NetTraceNewLine) Log("\r\n");
andrewboyson 52:fbc5a46b5e16 312 LogTime("TCP no more tcbs are available\r\n");
andrewboyson 59:e0e556c8bd46 313 if (NetTraceStack) traceback();
andrewboyson 52:fbc5a46b5e16 314 }
andrewboyson 52:fbc5a46b5e16 315 return DO_NOTHING; //Bomb out if no more tcbs are available
andrewboyson 52:fbc5a46b5e16 316 }
andrewboyson 10:f0854784e960 317
andrewboyson 55:e64b8b47a2b6 318 //Handle request to reset
andrewboyson 10:f0854784e960 319 if (RST)
andrewboyson 10:f0854784e960 320 {
andrewboyson 57:e0fb648acf48 321 if (TcpTrace)
andrewboyson 57:e0fb648acf48 322 {
andrewboyson 57:e0fb648acf48 323 if (NetTraceNewLine) Log("\r\n");
andrewboyson 57:e0fb648acf48 324 LogTime("TCP received reset - resetting TCB\r\n");
andrewboyson 59:e0e556c8bd46 325 if (NetTraceStack) traceback();
andrewboyson 57:e0fb648acf48 326 }
andrewboyson 57:e0fb648acf48 327 pTcb->state = TCB_EMPTY; //Reset connection
andrewboyson 57:e0fb648acf48 328 return DO_NOTHING; //Don't reply
andrewboyson 10:f0854784e960 329 }
andrewboyson 55:e64b8b47a2b6 330
andrewboyson 55:e64b8b47a2b6 331 //Handle request to synchronise
andrewboyson 55:e64b8b47a2b6 332 if (SYN)
andrewboyson 55:e64b8b47a2b6 333 {
andrewboyson 57:e0fb648acf48 334 pTcb->recvIsn = seqnum;
andrewboyson 57:e0fb648acf48 335 pTcb->recdBytes = 0;
andrewboyson 57:e0fb648acf48 336 pTcb->sendIsn = TcbGetIsn();
andrewboyson 57:e0fb648acf48 337 pTcb->sentBytes = 0;
andrewboyson 57:e0fb648acf48 338 acknum = pTcb->sendIsn;
andrewboyson 55:e64b8b47a2b6 339 }
andrewboyson 55:e64b8b47a2b6 340
andrewboyson 57:e0fb648acf48 341 //Calculate positions
andrewboyson 57:e0fb648acf48 342 positionInQuery = seqnum - pTcb->recvIsn;
andrewboyson 57:e0fb648acf48 343 positionInReply = acknum - pTcb->sendIsn;
andrewboyson 57:e0fb648acf48 344
andrewboyson 57:e0fb648acf48 345 //Check packet sequences
andrewboyson 57:e0fb648acf48 346 if (positionInQuery != pTcb->recdBytes || positionInReply != pTcb->sentBytes)
andrewboyson 10:f0854784e960 347 {
andrewboyson 57:e0fb648acf48 348 if (TcpTrace)
andrewboyson 57:e0fb648acf48 349 {
andrewboyson 57:e0fb648acf48 350 if (NetTraceNewLine) Log("\r\n");
andrewboyson 57:e0fb648acf48 351 LogTime("TCP received packet");
andrewboyson 57:e0fb648acf48 352 if (positionInQuery != pTcb->recdBytes) LogF(": starting at byte %u rather than %u so data reread" , positionInQuery, pTcb->recdBytes);
andrewboyson 57:e0fb648acf48 353 if (positionInReply != pTcb->sentBytes) LogF(": acknowledging byte %u rather than %u so data resent", positionInReply, pTcb->sentBytes);
andrewboyson 57:e0fb648acf48 354 Log("\r\n");
andrewboyson 55:e64b8b47a2b6 355
andrewboyson 57:e0fb648acf48 356 doTrace = true;
andrewboyson 57:e0fb648acf48 357 }
andrewboyson 57:e0fb648acf48 358 pTcb->recdBytes = positionInQuery;
andrewboyson 57:e0fb648acf48 359 pTcb->sentBytes = positionInReply;
andrewboyson 52:fbc5a46b5e16 360 }
andrewboyson 59:e0e556c8bd46 361 if (doTrace && NetTraceStack) traceback(); //This will already include the TCP header
andrewboyson 55:e64b8b47a2b6 362
andrewboyson 57:e0fb648acf48 363 if (SYN) pTcb->recdBytes += 1; //Add one to acknowledge the SYN
andrewboyson 57:e0fb648acf48 364 pTcb->recdBytes += dataLength; //Add the number of bytes received
andrewboyson 57:e0fb648acf48 365 if (FIN) pTcb->recdBytes += 1; //Add one to acknowledge the FIN
andrewboyson 10:f0854784e960 366
andrewboyson 10:f0854784e960 367 switch (pTcb->state)
andrewboyson 10:f0854784e960 368 {
andrewboyson 57:e0fb648acf48 369 case TCB_EMPTY:
andrewboyson 56:35117a8b5c65 370 if (!SYN) { resetConnection("received other than a SYN when connection closed"); break; }
andrewboyson 56:35117a8b5c65 371 startConnection();
andrewboyson 56:35117a8b5c65 372 break;
andrewboyson 56:35117a8b5c65 373
andrewboyson 56:35117a8b5c65 374 case TCB_SYN_RECEIVED:
andrewboyson 56:35117a8b5c65 375 if (dataLength) { resetConnection("data received before connection established"); break; }
andrewboyson 56:35117a8b5c65 376 if (!ACK) { resetConnection("received other than an ACK before connection established"); break; }
andrewboyson 56:35117a8b5c65 377 establishConnection();
andrewboyson 56:35117a8b5c65 378 return DO_NOTHING;
andrewboyson 56:35117a8b5c65 379
andrewboyson 56:35117a8b5c65 380 case TCB_ESTABLISHED:
andrewboyson 57:e0fb648acf48 381 if (!ACK) { resetConnection("received other than an ACK during established conection"); break; }
andrewboyson 57:e0fb648acf48 382 if (FIN) pTcb->hadFin = true; //When reply is all sent only a passive close is needed
andrewboyson 56:35117a8b5c65 383 handleEstablishedConnection();
andrewboyson 56:35117a8b5c65 384 break;
andrewboyson 56:35117a8b5c65 385
andrewboyson 57:e0fb648acf48 386 case TCB_FIN_WAIT: //End of active close
andrewboyson 56:35117a8b5c65 387 if (!FIN) return DO_NOTHING; //Ignore ACK to our FIN. Wait for FIN then close.
andrewboyson 56:35117a8b5c65 388 closeConnection();
andrewboyson 56:35117a8b5c65 389 break;
andrewboyson 57:e0fb648acf48 390
andrewboyson 57:e0fb648acf48 391 case TCB_ACK_WAIT: //End of passive close
andrewboyson 57:e0fb648acf48 392 if (!ACK) { resetConnection("received other than an ACK when closing half open connection"); break; }
andrewboyson 57:e0fb648acf48 393 pTcb->state = TCB_EMPTY;
andrewboyson 57:e0fb648acf48 394 return DO_NOTHING;
andrewboyson 10:f0854784e960 395 }
andrewboyson 10:f0854784e960 396
andrewboyson 57:e0fb648acf48 397 positionInReply = pTcb->recdBytes; //Set up the acknowledgement field ready to send
andrewboyson 57:e0fb648acf48 398 positionInQuery = pTcb->sentBytes; //Record the start of the query before adding the bytes sent
andrewboyson 57:e0fb648acf48 399
andrewboyson 57:e0fb648acf48 400 //Keep a record of where we expect the next packet send to start
andrewboyson 57:e0fb648acf48 401 if (SYN) pTcb->sentBytes += 1; //Add one to acknowledge the SYN
andrewboyson 57:e0fb648acf48 402 pTcb->sentBytes += dataLength; //Record the next sequence number
andrewboyson 57:e0fb648acf48 403 if (FIN) pTcb->sentBytes += 1; //Add one to acknowledge the FIN
andrewboyson 55:e64b8b47a2b6 404
andrewboyson 57:e0fb648acf48 405 //Specify the start of the data being sent and acknowledge the data received
andrewboyson 57:e0fb648acf48 406 seqnum = positionInQuery + pTcb->sendIsn;
andrewboyson 57:e0fb648acf48 407 acknum = positionInReply + pTcb->recvIsn;
andrewboyson 55:e64b8b47a2b6 408
andrewboyson 57:e0fb648acf48 409 //Swap the ports for the reply
andrewboyson 10:f0854784e960 410 srcPort = dstPort;
andrewboyson 10:f0854784e960 411 dstPort = pTcb->port;
andrewboyson 10:f0854784e960 412
andrewboyson 62:9b8c1e1761b6 413 //Specify the receive window size to not throttle
andrewboyson 62:9b8c1e1761b6 414 window = 4000;
andrewboyson 62:9b8c1e1761b6 415
andrewboyson 57:e0fb648acf48 416 //Calculate the size of the reply
andrewboyson 59:e0e556c8bd46 417 *pSizeTx = dataLength + headersize;
andrewboyson 54:84ef2b29cf7e 418
andrewboyson 55:e64b8b47a2b6 419 return ActionMakeFromDestAndTrace(UNICAST, doTrace && NetTraceStack);
andrewboyson 10:f0854784e960 420
andrewboyson 10:f0854784e960 421 }