Andrew Boyson / net

Dependents:   oldheating gps motorhome heating

Committer:
andrewboyson
Date:
Sat Oct 20 18:56:13 2018 +0000
Revision:
71:736a5747ade1
Parent:
62:9b8c1e1761b6
Child:
72:19457bba58d0
Started process of making TCP pollable

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