Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: oldheating gps motorhome heating
tcp/tcp.cpp@57:e0fb648acf48, 2017-11-28 (annotated)
- Committer:
- andrewboyson
- Date:
- Tue Nov 28 17:05:46 2017 +0000
- Revision:
- 57:e0fb648acf48
- Parent:
- 56:35117a8b5c65
- Child:
- 59:e0e556c8bd46
Added TFTP
Who changed what in which revision?
User | Revision | Line number | New 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 | 10:f0854784e960 | 11 | #define MAX_MSS 536 //This is 576 - 20 - 20 |
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 | 10:f0854784e960 | 43 | |
andrewboyson | 54:84ef2b29cf7e | 44 | static uint16_t window; |
andrewboyson | 54:84ef2b29cf7e | 45 | static uint16_t checksum; |
andrewboyson | 54:84ef2b29cf7e | 46 | static uint16_t urgent; |
andrewboyson | 54:84ef2b29cf7e | 47 | static int optionLength; |
andrewboyson | 10:f0854784e960 | 48 | |
andrewboyson | 54:84ef2b29cf7e | 49 | static char* pOptions; |
andrewboyson | 54:84ef2b29cf7e | 50 | static char* pData; |
andrewboyson | 54:84ef2b29cf7e | 51 | static int dataLength; |
andrewboyson | 56:35117a8b5c65 | 52 | static int positionInQuery; |
andrewboyson | 56:35117a8b5c65 | 53 | static int positionInReply; |
andrewboyson | 54:84ef2b29cf7e | 54 | |
andrewboyson | 55:e64b8b47a2b6 | 55 | static uint16_t mss; |
andrewboyson | 54:84ef2b29cf7e | 56 | |
andrewboyson | 54:84ef2b29cf7e | 57 | static void (*pTraceback)(void); |
andrewboyson | 54:84ef2b29cf7e | 58 | |
andrewboyson | 54:84ef2b29cf7e | 59 | static struct tcb* pTcb; |
andrewboyson | 54:84ef2b29cf7e | 60 | |
andrewboyson | 52:fbc5a46b5e16 | 61 | static void logFlags() |
andrewboyson | 52:fbc5a46b5e16 | 62 | { |
andrewboyson | 52:fbc5a46b5e16 | 63 | if (URG) Log(" URG"); |
andrewboyson | 52:fbc5a46b5e16 | 64 | if (ACK) Log(" ACK"); |
andrewboyson | 52:fbc5a46b5e16 | 65 | if (PSH) Log(" PSH"); |
andrewboyson | 52:fbc5a46b5e16 | 66 | if (RST) Log(" RST"); |
andrewboyson | 52:fbc5a46b5e16 | 67 | if (SYN) Log(" SYN"); |
andrewboyson | 52:fbc5a46b5e16 | 68 | if (FIN) Log(" FIN"); |
andrewboyson | 52:fbc5a46b5e16 | 69 | } |
andrewboyson | 56:35117a8b5c65 | 70 | void TcpLogHeader(uint16_t calculatedChecksum) |
andrewboyson | 43:bc028d5a6424 | 71 | { |
andrewboyson | 43:bc028d5a6424 | 72 | if (NetTraceVerbose) |
andrewboyson | 43:bc028d5a6424 | 73 | { |
andrewboyson | 43:bc028d5a6424 | 74 | Log("TCP header\r\n"); |
andrewboyson | 57:e0fb648acf48 | 75 | Log(" Source port "); LogF("%hu", srcPort ); Log("\r\n"); |
andrewboyson | 57:e0fb648acf48 | 76 | Log(" Destination port "); LogF("%hu", dstPort ); Log("\r\n"); |
andrewboyson | 57:e0fb648acf48 | 77 | Log(" Seq number "); LogF("%u (%u)", positionInQuery, seqnum); Log("\r\n"); |
andrewboyson | 57:e0fb648acf48 | 78 | Log(" Ack number "); LogF("%u (%u)", positionInReply, acknum); Log("\r\n"); |
andrewboyson | 57:e0fb648acf48 | 79 | Log(" Header size "); LogF("%u", headersize ); Log("\r\n"); |
andrewboyson | 57:e0fb648acf48 | 80 | Log(" Flags " ); logFlags( ); Log("\r\n"); |
andrewboyson | 57:e0fb648acf48 | 81 | Log(" Window "); LogF("%hu", window ); Log("\r\n"); |
andrewboyson | 57:e0fb648acf48 | 82 | Log(" Checksum (hex) "); LogF("%04hX", checksum ); Log("\r\n"); |
andrewboyson | 57:e0fb648acf48 | 83 | Log(" Calculated (hex) "); LogF("%04hX", calculatedChecksum ); Log("\r\n"); |
andrewboyson | 57:e0fb648acf48 | 84 | Log(" Urgent pointer "); LogF("%hu", urgent ); Log("\r\n"); |
andrewboyson | 57:e0fb648acf48 | 85 | Log(" Option length "); LogF("%d", optionLength ); Log("\r\n"); |
andrewboyson | 57:e0fb648acf48 | 86 | Log(" Data length "); LogF("%u", dataLength ); Log("\r\n"); |
andrewboyson | 57:e0fb648acf48 | 87 | Log(" sendIsn "); LogF("%u", pTcb->sendIsn ); Log("\r\n"); |
andrewboyson | 57:e0fb648acf48 | 88 | Log(" recvIsn "); LogF("%u", pTcb->recvIsn ); Log("\r\n"); |
andrewboyson | 57:e0fb648acf48 | 89 | Log(" sentBytes "); LogF("%u", pTcb->sentBytes ); Log("\r\n"); |
andrewboyson | 57:e0fb648acf48 | 90 | Log(" recdBytes "); LogF("%u", pTcb->recdBytes ); Log("\r\n"); |
andrewboyson | 54:84ef2b29cf7e | 91 | |
andrewboyson | 43:bc028d5a6424 | 92 | } |
andrewboyson | 43:bc028d5a6424 | 93 | else |
andrewboyson | 43:bc028d5a6424 | 94 | { |
andrewboyson | 44:83ce5ace337b | 95 | LogF("TCP header %hu >>> %hu", srcPort, dstPort); |
andrewboyson | 52:fbc5a46b5e16 | 96 | logFlags(); |
andrewboyson | 57:e0fb648acf48 | 97 | LogF(", query %u, reply %u", positionInQuery, positionInReply); |
andrewboyson | 52:fbc5a46b5e16 | 98 | Log("\r\n"); |
andrewboyson | 43:bc028d5a6424 | 99 | } |
andrewboyson | 10:f0854784e960 | 100 | } |
andrewboyson | 10:f0854784e960 | 101 | void TcpAddChecksum(void* pPacket, uint16_t checksum) |
andrewboyson | 10:f0854784e960 | 102 | { |
andrewboyson | 10:f0854784e960 | 103 | struct header* pHeader = (header*)pPacket; |
andrewboyson | 10:f0854784e960 | 104 | pHeader->checksum = checksum; |
andrewboyson | 10:f0854784e960 | 105 | } |
andrewboyson | 10:f0854784e960 | 106 | static void readOptions() |
andrewboyson | 10:f0854784e960 | 107 | { |
andrewboyson | 10:f0854784e960 | 108 | mss = 536; //default MSS for IPv4 [576 - 20(TCP) - 20(IP)]; |
andrewboyson | 10:f0854784e960 | 109 | for (char* p = pOptions; p < pOptions + optionLength; p++) |
andrewboyson | 10:f0854784e960 | 110 | { |
andrewboyson | 10:f0854784e960 | 111 | switch (*p) |
andrewboyson | 10:f0854784e960 | 112 | { |
andrewboyson | 10:f0854784e960 | 113 | case 0: break; //End of options - used to pad to 32 bit boundary |
andrewboyson | 10:f0854784e960 | 114 | case 1: break; //NOP, padding - optional |
andrewboyson | 10:f0854784e960 | 115 | case 2: |
andrewboyson | 10:f0854784e960 | 116 | p++; |
andrewboyson | 10:f0854784e960 | 117 | if (*p != 4) LogTimeF("MSS option width %d when expected 4\r\n", *p); |
andrewboyson | 10:f0854784e960 | 118 | p++; |
andrewboyson | 10:f0854784e960 | 119 | mss = ((uint16_t)*p) << 8; |
andrewboyson | 10:f0854784e960 | 120 | p++; |
andrewboyson | 10:f0854784e960 | 121 | mss += *p; |
andrewboyson | 10:f0854784e960 | 122 | return; |
andrewboyson | 10:f0854784e960 | 123 | default: LogTimeF("Unrecognised TCP option %d\r\n", *p); |
andrewboyson | 10:f0854784e960 | 124 | } |
andrewboyson | 10:f0854784e960 | 125 | } |
andrewboyson | 10:f0854784e960 | 126 | if (mss > MAX_MSS) mss = MAX_MSS; |
andrewboyson | 10:f0854784e960 | 127 | } |
andrewboyson | 10:f0854784e960 | 128 | static void writeOptions() |
andrewboyson | 10:f0854784e960 | 129 | { |
andrewboyson | 10:f0854784e960 | 130 | pOptions[0] = 2; |
andrewboyson | 10:f0854784e960 | 131 | pOptions[1] = 4; |
andrewboyson | 10:f0854784e960 | 132 | pOptions[2] = mss >> 8; |
andrewboyson | 10:f0854784e960 | 133 | pOptions[3] = mss & 0xFF; |
andrewboyson | 10:f0854784e960 | 134 | optionLength = 4; |
andrewboyson | 10:f0854784e960 | 135 | } |
andrewboyson | 10:f0854784e960 | 136 | |
andrewboyson | 10:f0854784e960 | 137 | void TcpReadHeader(void* pPacket, uint16_t size) |
andrewboyson | 10:f0854784e960 | 138 | { |
andrewboyson | 10:f0854784e960 | 139 | struct header* pHeader = (header*)pPacket; |
andrewboyson | 10:f0854784e960 | 140 | |
andrewboyson | 56:35117a8b5c65 | 141 | srcPort = NetToHost16(pHeader->srcPort); |
andrewboyson | 56:35117a8b5c65 | 142 | dstPort = NetToHost16(pHeader->dstPort); |
andrewboyson | 56:35117a8b5c65 | 143 | seqnum = NetToHost32(pHeader->seqnum); |
andrewboyson | 56:35117a8b5c65 | 144 | acknum = NetToHost32(pHeader->acknum); |
andrewboyson | 56:35117a8b5c65 | 145 | headersize = (pHeader->dataOffset >> 2) & 0xFC; //Same as right shifting by 4 bits and multiplying by 4 |
andrewboyson | 56:35117a8b5c65 | 146 | flags = pHeader->flags; |
andrewboyson | 56:35117a8b5c65 | 147 | URG = flags & 0x20; //indicates that the Urgent pointer field is significant |
andrewboyson | 56:35117a8b5c65 | 148 | 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 | 149 | PSH = flags & 0x08; //Push function. Asks to push the buffered data to the receiving application. |
andrewboyson | 56:35117a8b5c65 | 150 | RST = flags & 0x04; //Reset the connection |
andrewboyson | 56:35117a8b5c65 | 151 | 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 | 152 | FIN = flags & 0x01; //No more data from sender |
andrewboyson | 10:f0854784e960 | 153 | |
andrewboyson | 56:35117a8b5c65 | 154 | window = NetToHost16(pHeader->window); |
andrewboyson | 56:35117a8b5c65 | 155 | checksum = NetToHost16(pHeader->checksum); |
andrewboyson | 56:35117a8b5c65 | 156 | urgent = NetToHost16(pHeader->urgent); |
andrewboyson | 56:35117a8b5c65 | 157 | pOptions = (char*)pPacket + 20; |
andrewboyson | 57:e0fb648acf48 | 158 | optionLength = headersize - 20; |
andrewboyson | 56:35117a8b5c65 | 159 | pData = (char*)pPacket + headersize; |
andrewboyson | 56:35117a8b5c65 | 160 | dataLength = size - headersize; |
andrewboyson | 10:f0854784e960 | 161 | } |
andrewboyson | 10:f0854784e960 | 162 | |
andrewboyson | 10:f0854784e960 | 163 | void TcpMakeHeader(int size, void* pPacket) |
andrewboyson | 10:f0854784e960 | 164 | { |
andrewboyson | 10:f0854784e960 | 165 | struct header* pHeader = (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 | 55:e64b8b47a2b6 | 194 | headersize = 20; |
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 | 55:e64b8b47a2b6 | 200 | } |
andrewboyson | 56:35117a8b5c65 | 201 | static void startConnection() |
andrewboyson | 10:f0854784e960 | 202 | { |
andrewboyson | 10:f0854784e960 | 203 | readOptions(); //Get the MSS |
andrewboyson | 52:fbc5a46b5e16 | 204 | pTcb->mss = mss; |
andrewboyson | 52:fbc5a46b5e16 | 205 | pTcb->state = TCB_SYN_RECEIVED; |
andrewboyson | 52:fbc5a46b5e16 | 206 | pTcb->elapsed = TcbElapsed; |
andrewboyson | 52:fbc5a46b5e16 | 207 | pTcb->port = srcPort; |
andrewboyson | 57:e0fb648acf48 | 208 | pTcb->hadFin = false; |
andrewboyson | 55:e64b8b47a2b6 | 209 | |
andrewboyson | 10:f0854784e960 | 210 | dataLength = 0; |
andrewboyson | 10:f0854784e960 | 211 | |
andrewboyson | 10:f0854784e960 | 212 | mss = MAX_MSS; //Ethernet 1500 - 20 - 20; or, in our case 768 - 20 - 20 |
andrewboyson | 10:f0854784e960 | 213 | writeOptions(); |
andrewboyson | 10:f0854784e960 | 214 | headersize = 24; //20 header plus 4 option |
andrewboyson | 10:f0854784e960 | 215 | |
andrewboyson | 10:f0854784e960 | 216 | ACK = true; //Send ACK and SYN |
andrewboyson | 10:f0854784e960 | 217 | PSH = false; |
andrewboyson | 10:f0854784e960 | 218 | RST = false; |
andrewboyson | 10:f0854784e960 | 219 | SYN = true; |
andrewboyson | 10:f0854784e960 | 220 | FIN = false; |
andrewboyson | 10:f0854784e960 | 221 | } |
andrewboyson | 56:35117a8b5c65 | 222 | static void establishConnection() |
andrewboyson | 10:f0854784e960 | 223 | { |
andrewboyson | 56:35117a8b5c65 | 224 | pTcb->state = TCB_ESTABLISHED; |
andrewboyson | 56:35117a8b5c65 | 225 | pTcb->elapsed = TcbElapsed; |
andrewboyson | 57:e0fb648acf48 | 226 | pTcb->todo = 0; |
andrewboyson | 10:f0854784e960 | 227 | } |
andrewboyson | 56:35117a8b5c65 | 228 | static void handleEstablishedConnection() |
andrewboyson | 56:35117a8b5c65 | 229 | { |
andrewboyson | 54:84ef2b29cf7e | 230 | char* pRequestStream = pData; |
andrewboyson | 54:84ef2b29cf7e | 231 | char* pReplyStream = pOptions; |
andrewboyson | 54:84ef2b29cf7e | 232 | |
andrewboyson | 56:35117a8b5c65 | 233 | HttpHandleRequest(&dataLength, pRequestStream, positionInQuery - 1, pReplyStream, positionInReply - 1, mss, &pTcb->todo); |
andrewboyson | 10:f0854784e960 | 234 | |
andrewboyson | 10:f0854784e960 | 235 | headersize = 20; |
andrewboyson | 54:84ef2b29cf7e | 236 | pData = pReplyStream; |
andrewboyson | 55:e64b8b47a2b6 | 237 | |
andrewboyson | 10:f0854784e960 | 238 | ACK = true; //Send ACK |
andrewboyson | 10:f0854784e960 | 239 | RST = false; |
andrewboyson | 10:f0854784e960 | 240 | SYN = false; |
andrewboyson | 22:914b970356f0 | 241 | PSH = false; |
andrewboyson | 10:f0854784e960 | 242 | |
andrewboyson | 22:914b970356f0 | 243 | if (dataLength < mss) //If a part packet then there can be no more to send |
andrewboyson | 10:f0854784e960 | 244 | { |
andrewboyson | 57:e0fb648acf48 | 245 | FIN = true; //Inform the client that we have no more to send after this |
andrewboyson | 57:e0fb648acf48 | 246 | if (pTcb->hadFin) pTcb->state = TCB_ACK_WAIT; //Passive close |
andrewboyson | 57:e0fb648acf48 | 247 | else pTcb->state = TCB_FIN_WAIT; //Active close |
andrewboyson | 10:f0854784e960 | 248 | } |
andrewboyson | 56:35117a8b5c65 | 249 | else |
andrewboyson | 56:35117a8b5c65 | 250 | { |
andrewboyson | 56:35117a8b5c65 | 251 | FIN = false; |
andrewboyson | 56:35117a8b5c65 | 252 | } |
andrewboyson | 22:914b970356f0 | 253 | |
andrewboyson | 52:fbc5a46b5e16 | 254 | pTcb->elapsed = TcbElapsed; |
andrewboyson | 10:f0854784e960 | 255 | } |
andrewboyson | 56:35117a8b5c65 | 256 | static void closeConnection() |
andrewboyson | 56:35117a8b5c65 | 257 | { |
andrewboyson | 10:f0854784e960 | 258 | ACK = true; //Send ACK |
andrewboyson | 10:f0854784e960 | 259 | PSH = false; |
andrewboyson | 10:f0854784e960 | 260 | RST = false; |
andrewboyson | 10:f0854784e960 | 261 | SYN = false; |
andrewboyson | 10:f0854784e960 | 262 | FIN = false; |
andrewboyson | 10:f0854784e960 | 263 | |
andrewboyson | 10:f0854784e960 | 264 | headersize = 20; |
andrewboyson | 10:f0854784e960 | 265 | dataLength = 0; |
andrewboyson | 10:f0854784e960 | 266 | |
andrewboyson | 57:e0fb648acf48 | 267 | pTcb->state = TCB_EMPTY; |
andrewboyson | 10:f0854784e960 | 268 | } |
andrewboyson | 10:f0854784e960 | 269 | |
andrewboyson | 37:793b39683406 | 270 | int TcpHandleReceivedPacket(void (*traceback)(void), int* pSize, void* pPacket) |
andrewboyson | 10:f0854784e960 | 271 | { |
andrewboyson | 54:84ef2b29cf7e | 272 | pTraceback = traceback; |
andrewboyson | 57:e0fb648acf48 | 273 | doTrace = false; |
andrewboyson | 57:e0fb648acf48 | 274 | |
andrewboyson | 57:e0fb648acf48 | 275 | //Filter out unwanted links |
andrewboyson | 57:e0fb648acf48 | 276 | switch (dstPort) |
andrewboyson | 57:e0fb648acf48 | 277 | { |
andrewboyson | 57:e0fb648acf48 | 278 | case 80: |
andrewboyson | 57:e0fb648acf48 | 279 | if (HttpTrace) |
andrewboyson | 57:e0fb648acf48 | 280 | { |
andrewboyson | 57:e0fb648acf48 | 281 | if (NetTraceNewLine) Log("\r\n"); |
andrewboyson | 57:e0fb648acf48 | 282 | LogTime("HTTP server request\r\n"); |
andrewboyson | 57:e0fb648acf48 | 283 | doTrace = true; |
andrewboyson | 57:e0fb648acf48 | 284 | } |
andrewboyson | 57:e0fb648acf48 | 285 | break; |
andrewboyson | 57:e0fb648acf48 | 286 | |
andrewboyson | 57:e0fb648acf48 | 287 | default: |
andrewboyson | 57:e0fb648acf48 | 288 | if (TcpTrace) |
andrewboyson | 57:e0fb648acf48 | 289 | { |
andrewboyson | 57:e0fb648acf48 | 290 | if (NetTraceNewLine) Log("\r\n"); |
andrewboyson | 57:e0fb648acf48 | 291 | LogTimeF("TCP unknown port %d\r\n", dstPort); |
andrewboyson | 57:e0fb648acf48 | 292 | if (NetTraceStack) pTraceback(); |
andrewboyson | 57:e0fb648acf48 | 293 | } |
andrewboyson | 57:e0fb648acf48 | 294 | return DO_NOTHING; //Ignore unknown ports |
andrewboyson | 57:e0fb648acf48 | 295 | } |
andrewboyson | 55:e64b8b47a2b6 | 296 | |
andrewboyson | 55:e64b8b47a2b6 | 297 | //Get the Transmission Control Block |
andrewboyson | 54:84ef2b29cf7e | 298 | pTcb = TcbGetExisting(srcPort); |
andrewboyson | 10:f0854784e960 | 299 | if (!pTcb) pTcb = TcbGetEmpty(); |
andrewboyson | 52:fbc5a46b5e16 | 300 | if (!pTcb) |
andrewboyson | 52:fbc5a46b5e16 | 301 | { |
andrewboyson | 52:fbc5a46b5e16 | 302 | if (TcpTrace) |
andrewboyson | 52:fbc5a46b5e16 | 303 | { |
andrewboyson | 57:e0fb648acf48 | 304 | if (NetTraceNewLine) Log("\r\n"); |
andrewboyson | 52:fbc5a46b5e16 | 305 | LogTime("TCP no more tcbs are available\r\n"); |
andrewboyson | 57:e0fb648acf48 | 306 | if (NetTraceStack) pTraceback(); |
andrewboyson | 52:fbc5a46b5e16 | 307 | } |
andrewboyson | 52:fbc5a46b5e16 | 308 | return DO_NOTHING; //Bomb out if no more tcbs are available |
andrewboyson | 52:fbc5a46b5e16 | 309 | } |
andrewboyson | 10:f0854784e960 | 310 | |
andrewboyson | 55:e64b8b47a2b6 | 311 | //Handle request to reset |
andrewboyson | 10:f0854784e960 | 312 | if (RST) |
andrewboyson | 10:f0854784e960 | 313 | { |
andrewboyson | 57:e0fb648acf48 | 314 | if (TcpTrace) |
andrewboyson | 57:e0fb648acf48 | 315 | { |
andrewboyson | 57:e0fb648acf48 | 316 | if (NetTraceNewLine) Log("\r\n"); |
andrewboyson | 57:e0fb648acf48 | 317 | LogTime("TCP received reset - resetting TCB\r\n"); |
andrewboyson | 57:e0fb648acf48 | 318 | if (NetTraceStack) pTraceback(); |
andrewboyson | 57:e0fb648acf48 | 319 | } |
andrewboyson | 57:e0fb648acf48 | 320 | pTcb->state = TCB_EMPTY; //Reset connection |
andrewboyson | 57:e0fb648acf48 | 321 | return DO_NOTHING; //Don't reply |
andrewboyson | 10:f0854784e960 | 322 | } |
andrewboyson | 55:e64b8b47a2b6 | 323 | |
andrewboyson | 55:e64b8b47a2b6 | 324 | //Handle request to synchronise |
andrewboyson | 55:e64b8b47a2b6 | 325 | if (SYN) |
andrewboyson | 55:e64b8b47a2b6 | 326 | { |
andrewboyson | 57:e0fb648acf48 | 327 | pTcb->recvIsn = seqnum; |
andrewboyson | 57:e0fb648acf48 | 328 | pTcb->recdBytes = 0; |
andrewboyson | 57:e0fb648acf48 | 329 | pTcb->sendIsn = TcbGetIsn(); |
andrewboyson | 57:e0fb648acf48 | 330 | pTcb->sentBytes = 0; |
andrewboyson | 57:e0fb648acf48 | 331 | acknum = pTcb->sendIsn; |
andrewboyson | 55:e64b8b47a2b6 | 332 | } |
andrewboyson | 55:e64b8b47a2b6 | 333 | |
andrewboyson | 57:e0fb648acf48 | 334 | //Calculate positions |
andrewboyson | 57:e0fb648acf48 | 335 | positionInQuery = seqnum - pTcb->recvIsn; |
andrewboyson | 57:e0fb648acf48 | 336 | positionInReply = acknum - pTcb->sendIsn; |
andrewboyson | 57:e0fb648acf48 | 337 | |
andrewboyson | 57:e0fb648acf48 | 338 | //Check packet sequences |
andrewboyson | 57:e0fb648acf48 | 339 | if (positionInQuery != pTcb->recdBytes || positionInReply != pTcb->sentBytes) |
andrewboyson | 10:f0854784e960 | 340 | { |
andrewboyson | 57:e0fb648acf48 | 341 | if (TcpTrace) |
andrewboyson | 57:e0fb648acf48 | 342 | { |
andrewboyson | 57:e0fb648acf48 | 343 | if (NetTraceNewLine) Log("\r\n"); |
andrewboyson | 57:e0fb648acf48 | 344 | LogTime("TCP received packet"); |
andrewboyson | 57:e0fb648acf48 | 345 | if (positionInQuery != pTcb->recdBytes) LogF(": starting at byte %u rather than %u so data reread" , positionInQuery, pTcb->recdBytes); |
andrewboyson | 57:e0fb648acf48 | 346 | if (positionInReply != pTcb->sentBytes) LogF(": acknowledging byte %u rather than %u so data resent", positionInReply, pTcb->sentBytes); |
andrewboyson | 57:e0fb648acf48 | 347 | Log("\r\n"); |
andrewboyson | 55:e64b8b47a2b6 | 348 | |
andrewboyson | 57:e0fb648acf48 | 349 | if (NetTraceStack) pTraceback(); |
andrewboyson | 57:e0fb648acf48 | 350 | doTrace = true; |
andrewboyson | 57:e0fb648acf48 | 351 | } |
andrewboyson | 57:e0fb648acf48 | 352 | pTcb->recdBytes = positionInQuery; |
andrewboyson | 57:e0fb648acf48 | 353 | pTcb->sentBytes = positionInReply; |
andrewboyson | 52:fbc5a46b5e16 | 354 | } |
andrewboyson | 55:e64b8b47a2b6 | 355 | if (doTrace && NetTraceStack) pTraceback(); //This will already include the TCP header |
andrewboyson | 55:e64b8b47a2b6 | 356 | |
andrewboyson | 57:e0fb648acf48 | 357 | if (SYN) pTcb->recdBytes += 1; //Add one to acknowledge the SYN |
andrewboyson | 57:e0fb648acf48 | 358 | pTcb->recdBytes += dataLength; //Add the number of bytes received |
andrewboyson | 57:e0fb648acf48 | 359 | if (FIN) pTcb->recdBytes += 1; //Add one to acknowledge the FIN |
andrewboyson | 10:f0854784e960 | 360 | |
andrewboyson | 10:f0854784e960 | 361 | switch (pTcb->state) |
andrewboyson | 10:f0854784e960 | 362 | { |
andrewboyson | 57:e0fb648acf48 | 363 | case TCB_EMPTY: |
andrewboyson | 56:35117a8b5c65 | 364 | if (!SYN) { resetConnection("received other than a SYN when connection closed"); break; } |
andrewboyson | 56:35117a8b5c65 | 365 | startConnection(); |
andrewboyson | 56:35117a8b5c65 | 366 | break; |
andrewboyson | 56:35117a8b5c65 | 367 | |
andrewboyson | 56:35117a8b5c65 | 368 | case TCB_SYN_RECEIVED: |
andrewboyson | 56:35117a8b5c65 | 369 | if (dataLength) { resetConnection("data received before connection established"); break; } |
andrewboyson | 56:35117a8b5c65 | 370 | if (!ACK) { resetConnection("received other than an ACK before connection established"); break; } |
andrewboyson | 56:35117a8b5c65 | 371 | establishConnection(); |
andrewboyson | 56:35117a8b5c65 | 372 | return DO_NOTHING; |
andrewboyson | 56:35117a8b5c65 | 373 | |
andrewboyson | 56:35117a8b5c65 | 374 | case TCB_ESTABLISHED: |
andrewboyson | 57:e0fb648acf48 | 375 | if (!ACK) { resetConnection("received other than an ACK during established conection"); break; } |
andrewboyson | 57:e0fb648acf48 | 376 | if (FIN) pTcb->hadFin = true; //When reply is all sent only a passive close is needed |
andrewboyson | 56:35117a8b5c65 | 377 | handleEstablishedConnection(); |
andrewboyson | 56:35117a8b5c65 | 378 | break; |
andrewboyson | 56:35117a8b5c65 | 379 | |
andrewboyson | 57:e0fb648acf48 | 380 | case TCB_FIN_WAIT: //End of active close |
andrewboyson | 56:35117a8b5c65 | 381 | if (!FIN) return DO_NOTHING; //Ignore ACK to our FIN. Wait for FIN then close. |
andrewboyson | 56:35117a8b5c65 | 382 | closeConnection(); |
andrewboyson | 56:35117a8b5c65 | 383 | break; |
andrewboyson | 57:e0fb648acf48 | 384 | |
andrewboyson | 57:e0fb648acf48 | 385 | case TCB_ACK_WAIT: //End of passive close |
andrewboyson | 57:e0fb648acf48 | 386 | if (!ACK) { resetConnection("received other than an ACK when closing half open connection"); break; } |
andrewboyson | 57:e0fb648acf48 | 387 | pTcb->state = TCB_EMPTY; |
andrewboyson | 57:e0fb648acf48 | 388 | return DO_NOTHING; |
andrewboyson | 10:f0854784e960 | 389 | } |
andrewboyson | 10:f0854784e960 | 390 | |
andrewboyson | 57:e0fb648acf48 | 391 | positionInReply = pTcb->recdBytes; //Set up the acknowledgement field ready to send |
andrewboyson | 57:e0fb648acf48 | 392 | positionInQuery = pTcb->sentBytes; //Record the start of the query before adding the bytes sent |
andrewboyson | 57:e0fb648acf48 | 393 | |
andrewboyson | 57:e0fb648acf48 | 394 | //Keep a record of where we expect the next packet send to start |
andrewboyson | 57:e0fb648acf48 | 395 | if (SYN) pTcb->sentBytes += 1; //Add one to acknowledge the SYN |
andrewboyson | 57:e0fb648acf48 | 396 | pTcb->sentBytes += dataLength; //Record the next sequence number |
andrewboyson | 57:e0fb648acf48 | 397 | if (FIN) pTcb->sentBytes += 1; //Add one to acknowledge the FIN |
andrewboyson | 55:e64b8b47a2b6 | 398 | |
andrewboyson | 57:e0fb648acf48 | 399 | //Specify the start of the data being sent and acknowledge the data received |
andrewboyson | 57:e0fb648acf48 | 400 | seqnum = positionInQuery + pTcb->sendIsn; |
andrewboyson | 57:e0fb648acf48 | 401 | acknum = positionInReply + pTcb->recvIsn; |
andrewboyson | 55:e64b8b47a2b6 | 402 | |
andrewboyson | 57:e0fb648acf48 | 403 | //Swap the ports for the reply |
andrewboyson | 10:f0854784e960 | 404 | srcPort = dstPort; |
andrewboyson | 10:f0854784e960 | 405 | dstPort = pTcb->port; |
andrewboyson | 10:f0854784e960 | 406 | |
andrewboyson | 57:e0fb648acf48 | 407 | //Calculate the size of the reply |
andrewboyson | 10:f0854784e960 | 408 | *pSize = dataLength + headersize; |
andrewboyson | 54:84ef2b29cf7e | 409 | |
andrewboyson | 55:e64b8b47a2b6 | 410 | return ActionMakeFromDestAndTrace(UNICAST, doTrace && NetTraceStack); |
andrewboyson | 10:f0854784e960 | 411 | |
andrewboyson | 10:f0854784e960 | 412 | } |