Andrew Boyson / net

Dependents:   oldheating gps motorhome heating

Committer:
andrewboyson
Date:
Thu Dec 14 20:55:40 2017 +0000
Revision:
59:e0e556c8bd46
Parent:
57:e0fb648acf48
Added buffer length to help avoid over runs

Who changed what in which revision?

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