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
tcp/tcp.cpp@52:fbc5a46b5e16, 2017-11-08 (annotated)
- Committer:
- andrewboyson
- Date:
- Wed Nov 08 20:46:36 2017 +0000
- Revision:
- 52:fbc5a46b5e16
- Parent:
- 49:1a6336f2b3f9
- Child:
- 54:84ef2b29cf7e
Fixed bug in NDP options decoder which was crashing the system
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 | 52:fbc5a46b5e16 | 14 | |
andrewboyson | 10:f0854784e960 | 15 | __packed struct header |
andrewboyson | 10:f0854784e960 | 16 | { |
andrewboyson | 10:f0854784e960 | 17 | uint16_t srcPort; |
andrewboyson | 10:f0854784e960 | 18 | uint16_t dstPort; |
andrewboyson | 10:f0854784e960 | 19 | uint32_t seqnum; |
andrewboyson | 10:f0854784e960 | 20 | uint32_t acknum; |
andrewboyson | 10:f0854784e960 | 21 | uint8_t dataOffset; |
andrewboyson | 10:f0854784e960 | 22 | uint8_t flags; |
andrewboyson | 10:f0854784e960 | 23 | uint16_t window; |
andrewboyson | 10:f0854784e960 | 24 | uint16_t checksum; |
andrewboyson | 10:f0854784e960 | 25 | uint16_t urgent; |
andrewboyson | 10:f0854784e960 | 26 | }; |
andrewboyson | 10:f0854784e960 | 27 | |
andrewboyson | 10:f0854784e960 | 28 | //Header variables |
andrewboyson | 10:f0854784e960 | 29 | |
andrewboyson | 10:f0854784e960 | 30 | static uint16_t srcPort; |
andrewboyson | 10:f0854784e960 | 31 | static uint16_t dstPort; |
andrewboyson | 10:f0854784e960 | 32 | static uint32_t seqnum; |
andrewboyson | 10:f0854784e960 | 33 | static uint32_t acknum; |
andrewboyson | 10:f0854784e960 | 34 | static int headersize; |
andrewboyson | 10:f0854784e960 | 35 | static uint8_t flags; |
andrewboyson | 10:f0854784e960 | 36 | static bool URG; //indicates that the Urgent pointer field is significant |
andrewboyson | 10:f0854784e960 | 37 | 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 | 10:f0854784e960 | 38 | static bool PSH; //Push function. Asks to push the buffered data to the receiving application. |
andrewboyson | 10:f0854784e960 | 39 | static bool RST; //Reset the connection |
andrewboyson | 10:f0854784e960 | 40 | 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 | 10:f0854784e960 | 41 | static bool FIN; //No more data from sender |
andrewboyson | 10:f0854784e960 | 42 | |
andrewboyson | 10:f0854784e960 | 43 | static uint16_t window; |
andrewboyson | 10:f0854784e960 | 44 | static uint16_t checksum; |
andrewboyson | 10:f0854784e960 | 45 | static uint16_t urgent; |
andrewboyson | 10:f0854784e960 | 46 | static int optionLength; |
andrewboyson | 10:f0854784e960 | 47 | |
andrewboyson | 10:f0854784e960 | 48 | static char* pOptions; |
andrewboyson | 10:f0854784e960 | 49 | static void* pData; |
andrewboyson | 10:f0854784e960 | 50 | static int dataLength; |
andrewboyson | 10:f0854784e960 | 51 | static uint16_t mss; |
andrewboyson | 52:fbc5a46b5e16 | 52 | static void logFlags() |
andrewboyson | 52:fbc5a46b5e16 | 53 | { |
andrewboyson | 52:fbc5a46b5e16 | 54 | if (URG) Log(" URG"); |
andrewboyson | 52:fbc5a46b5e16 | 55 | if (ACK) Log(" ACK"); |
andrewboyson | 52:fbc5a46b5e16 | 56 | if (PSH) Log(" PSH"); |
andrewboyson | 52:fbc5a46b5e16 | 57 | if (RST) Log(" RST"); |
andrewboyson | 52:fbc5a46b5e16 | 58 | if (SYN) Log(" SYN"); |
andrewboyson | 52:fbc5a46b5e16 | 59 | if (FIN) Log(" FIN"); |
andrewboyson | 52:fbc5a46b5e16 | 60 | } |
andrewboyson | 37:793b39683406 | 61 | void TcpLogHeader(uint16_t calculatedChecksum) |
andrewboyson | 43:bc028d5a6424 | 62 | { |
andrewboyson | 43:bc028d5a6424 | 63 | if (NetTraceVerbose) |
andrewboyson | 43:bc028d5a6424 | 64 | { |
andrewboyson | 43:bc028d5a6424 | 65 | Log("TCP header\r\n"); |
andrewboyson | 43:bc028d5a6424 | 66 | LogF(" Source port %hu\r\n", srcPort); |
andrewboyson | 43:bc028d5a6424 | 67 | LogF(" Destination port %hu\r\n", dstPort); |
andrewboyson | 43:bc028d5a6424 | 68 | LogF(" Sequence number %u\r\n", seqnum); |
andrewboyson | 43:bc028d5a6424 | 69 | LogF(" Ack number %u\r\n", acknum); |
andrewboyson | 43:bc028d5a6424 | 70 | LogF(" Header size %u\r\n", headersize); |
andrewboyson | 52:fbc5a46b5e16 | 71 | Log (" Flags "); logFlags(); Log("\r\n"); |
andrewboyson | 43:bc028d5a6424 | 72 | LogF(" Window %hu\r\n", window); |
andrewboyson | 43:bc028d5a6424 | 73 | LogF(" Checksum (hex) %04hX\r\n", checksum); |
andrewboyson | 43:bc028d5a6424 | 74 | LogF(" Calculated (hex) %04hX\r\n", calculatedChecksum); |
andrewboyson | 43:bc028d5a6424 | 75 | LogF(" Urgent pointer %hu\r\n", urgent); |
andrewboyson | 43:bc028d5a6424 | 76 | LogF(" Option length %d\r\n", optionLength); |
andrewboyson | 43:bc028d5a6424 | 77 | LogF(" Data length %d\r\n", dataLength); |
andrewboyson | 43:bc028d5a6424 | 78 | } |
andrewboyson | 43:bc028d5a6424 | 79 | else |
andrewboyson | 43:bc028d5a6424 | 80 | { |
andrewboyson | 44:83ce5ace337b | 81 | LogF("TCP header %hu >>> %hu", srcPort, dstPort); |
andrewboyson | 52:fbc5a46b5e16 | 82 | logFlags(); |
andrewboyson | 52:fbc5a46b5e16 | 83 | Log("\r\n"); |
andrewboyson | 43:bc028d5a6424 | 84 | } |
andrewboyson | 10:f0854784e960 | 85 | } |
andrewboyson | 10:f0854784e960 | 86 | void TcpAddChecksum(void* pPacket, uint16_t checksum) |
andrewboyson | 10:f0854784e960 | 87 | { |
andrewboyson | 10:f0854784e960 | 88 | struct header* pHeader = (header*)pPacket; |
andrewboyson | 10:f0854784e960 | 89 | pHeader->checksum = checksum; |
andrewboyson | 10:f0854784e960 | 90 | } |
andrewboyson | 10:f0854784e960 | 91 | static void readOptions() |
andrewboyson | 10:f0854784e960 | 92 | { |
andrewboyson | 10:f0854784e960 | 93 | mss = 536; //default MSS for IPv4 [576 - 20(TCP) - 20(IP)]; |
andrewboyson | 10:f0854784e960 | 94 | for (char* p = pOptions; p < pOptions + optionLength; p++) |
andrewboyson | 10:f0854784e960 | 95 | { |
andrewboyson | 10:f0854784e960 | 96 | switch (*p) |
andrewboyson | 10:f0854784e960 | 97 | { |
andrewboyson | 10:f0854784e960 | 98 | case 0: break; //End of options - used to pad to 32 bit boundary |
andrewboyson | 10:f0854784e960 | 99 | case 1: break; //NOP, padding - optional |
andrewboyson | 10:f0854784e960 | 100 | case 2: |
andrewboyson | 10:f0854784e960 | 101 | p++; |
andrewboyson | 10:f0854784e960 | 102 | if (*p != 4) LogTimeF("MSS option width %d when expected 4\r\n", *p); |
andrewboyson | 10:f0854784e960 | 103 | p++; |
andrewboyson | 10:f0854784e960 | 104 | mss = ((uint16_t)*p) << 8; |
andrewboyson | 10:f0854784e960 | 105 | p++; |
andrewboyson | 10:f0854784e960 | 106 | mss += *p; |
andrewboyson | 10:f0854784e960 | 107 | return; |
andrewboyson | 10:f0854784e960 | 108 | default: LogTimeF("Unrecognised TCP option %d\r\n", *p); |
andrewboyson | 10:f0854784e960 | 109 | } |
andrewboyson | 10:f0854784e960 | 110 | } |
andrewboyson | 10:f0854784e960 | 111 | if (mss > MAX_MSS) mss = MAX_MSS; |
andrewboyson | 10:f0854784e960 | 112 | } |
andrewboyson | 10:f0854784e960 | 113 | static void writeOptions() |
andrewboyson | 10:f0854784e960 | 114 | { |
andrewboyson | 10:f0854784e960 | 115 | pOptions[0] = 2; |
andrewboyson | 10:f0854784e960 | 116 | pOptions[1] = 4; |
andrewboyson | 10:f0854784e960 | 117 | pOptions[2] = mss >> 8; |
andrewboyson | 10:f0854784e960 | 118 | pOptions[3] = mss & 0xFF; |
andrewboyson | 10:f0854784e960 | 119 | optionLength = 4; |
andrewboyson | 10:f0854784e960 | 120 | } |
andrewboyson | 10:f0854784e960 | 121 | |
andrewboyson | 10:f0854784e960 | 122 | void TcpReadHeader(void* pPacket, uint16_t size) |
andrewboyson | 10:f0854784e960 | 123 | { |
andrewboyson | 10:f0854784e960 | 124 | struct header* pHeader = (header*)pPacket; |
andrewboyson | 10:f0854784e960 | 125 | |
andrewboyson | 10:f0854784e960 | 126 | srcPort = NetToHost16(pHeader->srcPort); |
andrewboyson | 10:f0854784e960 | 127 | dstPort = NetToHost16(pHeader->dstPort); |
andrewboyson | 10:f0854784e960 | 128 | seqnum = NetToHost32(pHeader->seqnum); |
andrewboyson | 10:f0854784e960 | 129 | acknum = NetToHost32(pHeader->acknum); |
andrewboyson | 10:f0854784e960 | 130 | headersize = (pHeader->dataOffset >> 2) & 0xFC; //Same as right shifting by 4 bits and multiplying by 4 |
andrewboyson | 10:f0854784e960 | 131 | flags = pHeader->flags; |
andrewboyson | 10:f0854784e960 | 132 | URG = flags & 0x20; //indicates that the Urgent pointer field is significant |
andrewboyson | 10:f0854784e960 | 133 | 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 | 10:f0854784e960 | 134 | PSH = flags & 0x08; //Push function. Asks to push the buffered data to the receiving application. |
andrewboyson | 10:f0854784e960 | 135 | RST = flags & 0x04; //Reset the connection |
andrewboyson | 10:f0854784e960 | 136 | 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 | 10:f0854784e960 | 137 | FIN = flags & 0x01; //No more data from sender |
andrewboyson | 10:f0854784e960 | 138 | |
andrewboyson | 10:f0854784e960 | 139 | window = NetToHost16(pHeader->window); |
andrewboyson | 10:f0854784e960 | 140 | checksum = NetToHost16(pHeader->checksum); |
andrewboyson | 10:f0854784e960 | 141 | urgent = NetToHost16(pHeader->urgent); |
andrewboyson | 10:f0854784e960 | 142 | pOptions = (char*)pPacket + 20; |
andrewboyson | 10:f0854784e960 | 143 | optionLength = headersize - 20; |
andrewboyson | 10:f0854784e960 | 144 | |
andrewboyson | 10:f0854784e960 | 145 | pData = (char*)pPacket + headersize; |
andrewboyson | 10:f0854784e960 | 146 | dataLength = size - headersize; |
andrewboyson | 10:f0854784e960 | 147 | } |
andrewboyson | 10:f0854784e960 | 148 | |
andrewboyson | 10:f0854784e960 | 149 | void TcpMakeHeader(int size, void* pPacket) |
andrewboyson | 10:f0854784e960 | 150 | { |
andrewboyson | 10:f0854784e960 | 151 | struct header* pHeader = (header*)pPacket; |
andrewboyson | 10:f0854784e960 | 152 | |
andrewboyson | 10:f0854784e960 | 153 | pHeader->dstPort = NetToHost16(dstPort); |
andrewboyson | 10:f0854784e960 | 154 | pHeader->srcPort = NetToHost16(srcPort); |
andrewboyson | 10:f0854784e960 | 155 | pHeader->seqnum = NetToHost32(seqnum); //This is the sequence number of the first byte of this message |
andrewboyson | 10:f0854784e960 | 156 | pHeader->acknum = NetToHost32(acknum); //This is the sequence number we expect in the next message |
andrewboyson | 10:f0854784e960 | 157 | pHeader->dataOffset = headersize << 2; //Same as dividing by 4 to get bytes and left shifting by 4 bits |
andrewboyson | 10:f0854784e960 | 158 | flags = 0; |
andrewboyson | 10:f0854784e960 | 159 | if(URG) flags |= 0x20; //indicates that the Urgent pointer field is significant |
andrewboyson | 10:f0854784e960 | 160 | 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 | 10:f0854784e960 | 161 | if(PSH) flags |= 0x08; //Push function. Asks to push the buffered data to the receiving application. |
andrewboyson | 10:f0854784e960 | 162 | if(RST) flags |= 0x04; //Reset the connection |
andrewboyson | 10:f0854784e960 | 163 | 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 | 10:f0854784e960 | 164 | if(FIN) flags |= 0x01; //No more data from sender |
andrewboyson | 10:f0854784e960 | 165 | pHeader->flags = flags; |
andrewboyson | 10:f0854784e960 | 166 | pHeader->window = NetToHost16(window); |
andrewboyson | 10:f0854784e960 | 167 | pHeader->urgent = NetToHost16(urgent); |
andrewboyson | 10:f0854784e960 | 168 | |
andrewboyson | 10:f0854784e960 | 169 | pHeader->checksum = 0; |
andrewboyson | 10:f0854784e960 | 170 | } |
andrewboyson | 10:f0854784e960 | 171 | static int stateClosed(struct tcb* pTcb) |
andrewboyson | 10:f0854784e960 | 172 | { |
andrewboyson | 10:f0854784e960 | 173 | if (!SYN) //Reset if anything other than a request to establish conection from client |
andrewboyson | 10:f0854784e960 | 174 | { |
andrewboyson | 10:f0854784e960 | 175 | dataLength = 0; |
andrewboyson | 10:f0854784e960 | 176 | headersize = 20; |
andrewboyson | 10:f0854784e960 | 177 | seqnum = acknum; |
andrewboyson | 10:f0854784e960 | 178 | acknum = 0; |
andrewboyson | 10:f0854784e960 | 179 | ACK = false; //Send RST |
andrewboyson | 10:f0854784e960 | 180 | PSH = false; |
andrewboyson | 10:f0854784e960 | 181 | RST = true; |
andrewboyson | 10:f0854784e960 | 182 | SYN = false; |
andrewboyson | 10:f0854784e960 | 183 | FIN = false; |
andrewboyson | 10:f0854784e960 | 184 | return 1; |
andrewboyson | 10:f0854784e960 | 185 | } |
andrewboyson | 10:f0854784e960 | 186 | |
andrewboyson | 10:f0854784e960 | 187 | readOptions(); //Get the MSS |
andrewboyson | 52:fbc5a46b5e16 | 188 | pTcb->mss = mss; |
andrewboyson | 52:fbc5a46b5e16 | 189 | pTcb->state = TCB_SYN_RECEIVED; |
andrewboyson | 52:fbc5a46b5e16 | 190 | pTcb->elapsed = TcbElapsed; |
andrewboyson | 52:fbc5a46b5e16 | 191 | pTcb->port = srcPort; |
andrewboyson | 52:fbc5a46b5e16 | 192 | pTcb->locIsn = TcbGetIsn(); |
andrewboyson | 52:fbc5a46b5e16 | 193 | pTcb->locSeq = pTcb->locIsn; |
andrewboyson | 52:fbc5a46b5e16 | 194 | pTcb->remIsn = seqnum; |
andrewboyson | 52:fbc5a46b5e16 | 195 | pTcb->remSeq = pTcb->remIsn; |
andrewboyson | 10:f0854784e960 | 196 | |
andrewboyson | 10:f0854784e960 | 197 | pTcb->remSeq += 1; //Add one to acknowledge the SYN |
andrewboyson | 10:f0854784e960 | 198 | acknum = pTcb->remSeq; |
andrewboyson | 10:f0854784e960 | 199 | |
andrewboyson | 10:f0854784e960 | 200 | seqnum = pTcb->locSeq; //Set the sequence number to the first byte of this message |
andrewboyson | 10:f0854784e960 | 201 | pTcb->locSeq += 1; //Add one to the next sequence number as we are sending a SYN |
andrewboyson | 10:f0854784e960 | 202 | |
andrewboyson | 10:f0854784e960 | 203 | dataLength = 0; |
andrewboyson | 10:f0854784e960 | 204 | |
andrewboyson | 10:f0854784e960 | 205 | mss = MAX_MSS; //Ethernet 1500 - 20 - 20; or, in our case 768 - 20 - 20 |
andrewboyson | 10:f0854784e960 | 206 | writeOptions(); |
andrewboyson | 10:f0854784e960 | 207 | headersize = 24; //20 header plus 4 option |
andrewboyson | 10:f0854784e960 | 208 | |
andrewboyson | 10:f0854784e960 | 209 | ACK = true; //Send ACK and SYN |
andrewboyson | 10:f0854784e960 | 210 | PSH = false; |
andrewboyson | 10:f0854784e960 | 211 | RST = false; |
andrewboyson | 10:f0854784e960 | 212 | SYN = true; |
andrewboyson | 10:f0854784e960 | 213 | FIN = false; |
andrewboyson | 10:f0854784e960 | 214 | |
andrewboyson | 10:f0854784e960 | 215 | return 1; |
andrewboyson | 10:f0854784e960 | 216 | } |
andrewboyson | 10:f0854784e960 | 217 | static int stateSynReceived(struct tcb* pTcb) |
andrewboyson | 10:f0854784e960 | 218 | { |
andrewboyson | 10:f0854784e960 | 219 | if (dataLength) LogTimeF("%d bytes data received before TCB established\r\n", dataLength); |
andrewboyson | 10:f0854784e960 | 220 | if (ACK) |
andrewboyson | 10:f0854784e960 | 221 | { |
andrewboyson | 52:fbc5a46b5e16 | 222 | pTcb->state = TCB_ESTABLISHED; |
andrewboyson | 52:fbc5a46b5e16 | 223 | pTcb->elapsed = TcbElapsed; |
andrewboyson | 52:fbc5a46b5e16 | 224 | pTcb->tag = 0; |
andrewboyson | 10:f0854784e960 | 225 | } |
andrewboyson | 10:f0854784e960 | 226 | return 0; |
andrewboyson | 10:f0854784e960 | 227 | } |
andrewboyson | 10:f0854784e960 | 228 | static int stateEstablished(struct tcb* pTcb) |
andrewboyson | 10:f0854784e960 | 229 | { |
andrewboyson | 10:f0854784e960 | 230 | if (!ACK) return 0; //Ignore any packets which don't contain an ACK |
andrewboyson | 10:f0854784e960 | 231 | |
andrewboyson | 10:f0854784e960 | 232 | //Handle reception of data |
andrewboyson | 10:f0854784e960 | 233 | if (dataLength) |
andrewboyson | 10:f0854784e960 | 234 | { |
andrewboyson | 10:f0854784e960 | 235 | pTcb->tag = HttpRequest(seqnum - pTcb->remIsn - 1, dataLength, (char*)pData); |
andrewboyson | 10:f0854784e960 | 236 | pTcb->remSeq = seqnum + dataLength; |
andrewboyson | 10:f0854784e960 | 237 | } |
andrewboyson | 10:f0854784e960 | 238 | acknum = pTcb->remSeq; //Set the ack num to the next byte expected from the client |
andrewboyson | 10:f0854784e960 | 239 | |
andrewboyson | 10:f0854784e960 | 240 | |
andrewboyson | 10:f0854784e960 | 241 | //Rearrange the buffers |
andrewboyson | 10:f0854784e960 | 242 | headersize = 20; |
andrewboyson | 10:f0854784e960 | 243 | pData = pOptions; |
andrewboyson | 10:f0854784e960 | 244 | |
andrewboyson | 10:f0854784e960 | 245 | //Handle sending of any data |
andrewboyson | 21:02c82594c8c0 | 246 | dataLength = HttpReply(pTcb->locSeq - pTcb->locIsn - 1, mss, (char*)pData, pTcb->tag); |
andrewboyson | 10:f0854784e960 | 247 | |
andrewboyson | 10:f0854784e960 | 248 | seqnum = pTcb->locSeq; //Set the sequence number to the first byte of this message |
andrewboyson | 10:f0854784e960 | 249 | |
andrewboyson | 10:f0854784e960 | 250 | ACK = true; //Send ACK |
andrewboyson | 10:f0854784e960 | 251 | RST = false; |
andrewboyson | 10:f0854784e960 | 252 | SYN = false; |
andrewboyson | 22:914b970356f0 | 253 | PSH = false; |
andrewboyson | 10:f0854784e960 | 254 | |
andrewboyson | 22:914b970356f0 | 255 | pTcb->locSeq += dataLength; //Record the next sequence number |
andrewboyson | 22:914b970356f0 | 256 | |
andrewboyson | 22:914b970356f0 | 257 | if (dataLength < mss) //If a part packet then there can be no more to send |
andrewboyson | 10:f0854784e960 | 258 | { |
andrewboyson | 22:914b970356f0 | 259 | FIN = true; //Inform the client that we have no more to send after this |
andrewboyson | 22:914b970356f0 | 260 | pTcb->locSeq += 1; //Record the FIN in the sequence |
andrewboyson | 10:f0854784e960 | 261 | pTcb->state = TCB_CLOSING; //Start closing |
andrewboyson | 10:f0854784e960 | 262 | } |
andrewboyson | 22:914b970356f0 | 263 | |
andrewboyson | 52:fbc5a46b5e16 | 264 | pTcb->elapsed = TcbElapsed; |
andrewboyson | 10:f0854784e960 | 265 | return 1; |
andrewboyson | 10:f0854784e960 | 266 | } |
andrewboyson | 10:f0854784e960 | 267 | static int stateClosing(struct tcb* pTcb) |
andrewboyson | 10:f0854784e960 | 268 | { |
andrewboyson | 10:f0854784e960 | 269 | if (!FIN) return 0; //Ignore any packets which don't contain a FIN |
andrewboyson | 10:f0854784e960 | 270 | |
andrewboyson | 10:f0854784e960 | 271 | pTcb->remSeq += 1; //Add one to acknowledge the FIN |
andrewboyson | 10:f0854784e960 | 272 | acknum = pTcb->remSeq; |
andrewboyson | 10:f0854784e960 | 273 | |
andrewboyson | 10:f0854784e960 | 274 | seqnum = pTcb->locSeq; //Set the sequence number to the first byte of this message |
andrewboyson | 10:f0854784e960 | 275 | //but don't change it for the next |
andrewboyson | 10:f0854784e960 | 276 | |
andrewboyson | 10:f0854784e960 | 277 | ACK = true; //Send ACK |
andrewboyson | 10:f0854784e960 | 278 | PSH = false; |
andrewboyson | 10:f0854784e960 | 279 | RST = false; |
andrewboyson | 10:f0854784e960 | 280 | SYN = false; |
andrewboyson | 10:f0854784e960 | 281 | FIN = false; |
andrewboyson | 10:f0854784e960 | 282 | |
andrewboyson | 10:f0854784e960 | 283 | headersize = 20; |
andrewboyson | 10:f0854784e960 | 284 | dataLength = 0; |
andrewboyson | 10:f0854784e960 | 285 | |
andrewboyson | 10:f0854784e960 | 286 | pTcb->state = TCB_CLOSED; |
andrewboyson | 10:f0854784e960 | 287 | |
andrewboyson | 10:f0854784e960 | 288 | return 1; |
andrewboyson | 10:f0854784e960 | 289 | } |
andrewboyson | 10:f0854784e960 | 290 | |
andrewboyson | 37:793b39683406 | 291 | int TcpHandleReceivedPacket(void (*traceback)(void), int* pSize, void* pPacket) |
andrewboyson | 10:f0854784e960 | 292 | { |
andrewboyson | 10:f0854784e960 | 293 | struct tcb* pTcb = TcbGetExisting(srcPort); |
andrewboyson | 10:f0854784e960 | 294 | if (!pTcb) pTcb = TcbGetEmpty(); |
andrewboyson | 52:fbc5a46b5e16 | 295 | if (!pTcb) |
andrewboyson | 52:fbc5a46b5e16 | 296 | { |
andrewboyson | 52:fbc5a46b5e16 | 297 | if (TcpTrace) |
andrewboyson | 52:fbc5a46b5e16 | 298 | { |
andrewboyson | 52:fbc5a46b5e16 | 299 | LogTime("TCP no more tcbs are available\r\n"); |
andrewboyson | 52:fbc5a46b5e16 | 300 | traceback(); //This will already include the TCP header |
andrewboyson | 52:fbc5a46b5e16 | 301 | } |
andrewboyson | 52:fbc5a46b5e16 | 302 | return DO_NOTHING; //Bomb out if no more tcbs are available |
andrewboyson | 52:fbc5a46b5e16 | 303 | } |
andrewboyson | 10:f0854784e960 | 304 | |
andrewboyson | 10:f0854784e960 | 305 | if (RST) |
andrewboyson | 10:f0854784e960 | 306 | { |
andrewboyson | 10:f0854784e960 | 307 | pTcb->state = TCB_CLOSED; //Reset connection |
andrewboyson | 10:f0854784e960 | 308 | return DO_NOTHING; //Bomb out |
andrewboyson | 10:f0854784e960 | 309 | } |
andrewboyson | 10:f0854784e960 | 310 | |
andrewboyson | 52:fbc5a46b5e16 | 311 | //Filter out unwanted links |
andrewboyson | 10:f0854784e960 | 312 | switch (dstPort) |
andrewboyson | 10:f0854784e960 | 313 | { |
andrewboyson | 10:f0854784e960 | 314 | case 80: break; |
andrewboyson | 52:fbc5a46b5e16 | 315 | default: |
andrewboyson | 52:fbc5a46b5e16 | 316 | if (TcpTrace) |
andrewboyson | 52:fbc5a46b5e16 | 317 | { |
andrewboyson | 52:fbc5a46b5e16 | 318 | LogTimeF("TCP unknown port %d\r\n", dstPort); |
andrewboyson | 52:fbc5a46b5e16 | 319 | traceback(); //This will already include the TCP header |
andrewboyson | 52:fbc5a46b5e16 | 320 | } |
andrewboyson | 52:fbc5a46b5e16 | 321 | return DO_NOTHING; //This needs to become a reset |
andrewboyson | 10:f0854784e960 | 322 | } |
andrewboyson | 10:f0854784e960 | 323 | |
andrewboyson | 52:fbc5a46b5e16 | 324 | if (TcpTrace) |
andrewboyson | 52:fbc5a46b5e16 | 325 | { |
andrewboyson | 52:fbc5a46b5e16 | 326 | if (!SYN && (int32_t)(seqnum - pTcb->remSeq)) |
andrewboyson | 52:fbc5a46b5e16 | 327 | { |
andrewboyson | 52:fbc5a46b5e16 | 328 | LogTime("TCP"); |
andrewboyson | 52:fbc5a46b5e16 | 329 | logFlags(); |
andrewboyson | 52:fbc5a46b5e16 | 330 | LogF(" off=%d seq num=%u expected=%u packet length %d from port %u\r\n", (int32_t)(seqnum - pTcb->remSeq), seqnum, pTcb->remSeq, *pSize, srcPort); |
andrewboyson | 52:fbc5a46b5e16 | 331 | } |
andrewboyson | 52:fbc5a46b5e16 | 332 | } |
andrewboyson | 10:f0854784e960 | 333 | //Drop duplicate packets |
andrewboyson | 52:fbc5a46b5e16 | 334 | /* |
andrewboyson | 52:fbc5a46b5e16 | 335 | if (!TCB_CLOSED && (int32_t)(seqnum - pTcb->remSeq) < 0) |
andrewboyson | 52:fbc5a46b5e16 | 336 | { |
andrewboyson | 52:fbc5a46b5e16 | 337 | if (TcpTrace) |
andrewboyson | 52:fbc5a46b5e16 | 338 | { |
andrewboyson | 52:fbc5a46b5e16 | 339 | LogTimeF("TCP Dropped duplicate seq num=%d expected=%d packet length %d from port %u\r\n", seqnum, pTcb->remSeq, *pSize, srcPort); |
andrewboyson | 52:fbc5a46b5e16 | 340 | traceback(); |
andrewboyson | 52:fbc5a46b5e16 | 341 | } |
andrewboyson | 52:fbc5a46b5e16 | 342 | return DO_NOTHING; |
andrewboyson | 52:fbc5a46b5e16 | 343 | } |
andrewboyson | 52:fbc5a46b5e16 | 344 | */ |
andrewboyson | 10:f0854784e960 | 345 | |
andrewboyson | 10:f0854784e960 | 346 | switch (pTcb->state) |
andrewboyson | 10:f0854784e960 | 347 | { |
andrewboyson | 10:f0854784e960 | 348 | case TCB_CLOSED: if (stateClosed (pTcb)) break; return DO_NOTHING; |
andrewboyson | 10:f0854784e960 | 349 | case TCB_SYN_RECEIVED: if (stateSynReceived(pTcb)) break; return DO_NOTHING; |
andrewboyson | 10:f0854784e960 | 350 | case TCB_ESTABLISHED: if (stateEstablished(pTcb)) break; return DO_NOTHING; |
andrewboyson | 10:f0854784e960 | 351 | case TCB_CLOSING: if (stateClosing (pTcb)) break; return DO_NOTHING; |
andrewboyson | 10:f0854784e960 | 352 | } |
andrewboyson | 10:f0854784e960 | 353 | |
andrewboyson | 10:f0854784e960 | 354 | srcPort = dstPort; |
andrewboyson | 10:f0854784e960 | 355 | dstPort = pTcb->port; |
andrewboyson | 10:f0854784e960 | 356 | |
andrewboyson | 10:f0854784e960 | 357 | *pSize = dataLength + headersize; |
andrewboyson | 10:f0854784e960 | 358 | return UNICAST; |
andrewboyson | 10:f0854784e960 | 359 | |
andrewboyson | 10:f0854784e960 | 360 | } |