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/tcphdr.c@125:8c84daac38ab, 2019-02-22 (annotated)
- Committer:
- andrewboyson
- Date:
- Fri Feb 22 11:26:55 2019 +0000
- Revision:
- 125:8c84daac38ab
- Parent:
- 98:b977424ec7f7
- Child:
- 137:cf6e7db0e985
tidied up ntp data types for calculating ms from clktime.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
andrewboyson | 73:43e3d7fb3d60 | 1 | #include <stdint.h> |
andrewboyson | 73:43e3d7fb3d60 | 2 | #include <stdbool.h> |
andrewboyson | 73:43e3d7fb3d60 | 3 | |
andrewboyson | 98:b977424ec7f7 | 4 | #include "log.h" |
andrewboyson | 98:b977424ec7f7 | 5 | #include "net.h" |
andrewboyson | 98:b977424ec7f7 | 6 | #include "fault.h" |
andrewboyson | 73:43e3d7fb3d60 | 7 | |
andrewboyson | 73:43e3d7fb3d60 | 8 | __packed struct header |
andrewboyson | 73:43e3d7fb3d60 | 9 | { |
andrewboyson | 73:43e3d7fb3d60 | 10 | uint16_t srcPort; |
andrewboyson | 73:43e3d7fb3d60 | 11 | uint16_t dstPort; |
andrewboyson | 73:43e3d7fb3d60 | 12 | uint32_t seqnum; |
andrewboyson | 73:43e3d7fb3d60 | 13 | uint32_t acknum; |
andrewboyson | 73:43e3d7fb3d60 | 14 | uint8_t dataOffset; |
andrewboyson | 73:43e3d7fb3d60 | 15 | uint8_t flags; |
andrewboyson | 73:43e3d7fb3d60 | 16 | uint16_t window; |
andrewboyson | 73:43e3d7fb3d60 | 17 | uint16_t checksum; |
andrewboyson | 73:43e3d7fb3d60 | 18 | uint16_t urgent; |
andrewboyson | 73:43e3d7fb3d60 | 19 | }; |
andrewboyson | 73:43e3d7fb3d60 | 20 | |
andrewboyson | 73:43e3d7fb3d60 | 21 | //Header variables |
andrewboyson | 73:43e3d7fb3d60 | 22 | uint16_t TcpHdrSrcPort; |
andrewboyson | 73:43e3d7fb3d60 | 23 | uint16_t TcpHdrDstPort; |
andrewboyson | 73:43e3d7fb3d60 | 24 | uint32_t TcpHdrSeqNum; |
andrewboyson | 73:43e3d7fb3d60 | 25 | uint32_t TcpHdrAckNum; |
andrewboyson | 73:43e3d7fb3d60 | 26 | bool TcpHdrURG; //indicates that the Urgent pointer field is significant |
andrewboyson | 73:43e3d7fb3d60 | 27 | bool TcpHdrACK; //indicates that the Acknowledgment field is significant. All packets after the initial SYN packet sent by the client should have this flag set. |
andrewboyson | 73:43e3d7fb3d60 | 28 | bool TcpHdrPSH; //Push function. Asks to push the buffered data to the receiving application. |
andrewboyson | 73:43e3d7fb3d60 | 29 | bool TcpHdrRST; //Reset the connection |
andrewboyson | 73:43e3d7fb3d60 | 30 | bool TcpHdrSYN; //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 | 73:43e3d7fb3d60 | 31 | bool TcpHdrFIN; //No more data from sender |
andrewboyson | 73:43e3d7fb3d60 | 32 | uint16_t TcpHdrWindow; |
andrewboyson | 73:43e3d7fb3d60 | 33 | uint16_t TcpHdrChecksum; |
andrewboyson | 73:43e3d7fb3d60 | 34 | uint16_t TcpHdrUrgent; |
andrewboyson | 73:43e3d7fb3d60 | 35 | |
andrewboyson | 74:c3756bfa960e | 36 | //Side effects |
andrewboyson | 74:c3756bfa960e | 37 | static int headerSize; |
andrewboyson | 74:c3756bfa960e | 38 | int TcpHdrSizeGet() { return headerSize; } |
andrewboyson | 73:43e3d7fb3d60 | 39 | |
andrewboyson | 74:c3756bfa960e | 40 | static uint16_t mss = 0; |
andrewboyson | 74:c3756bfa960e | 41 | void TcpHdrMssSet(uint16_t value) |
andrewboyson | 73:43e3d7fb3d60 | 42 | { |
andrewboyson | 74:c3756bfa960e | 43 | mss = value; |
andrewboyson | 74:c3756bfa960e | 44 | headerSize = sizeof (struct header); |
andrewboyson | 74:c3756bfa960e | 45 | if (mss) headerSize += 4; |
andrewboyson | 73:43e3d7fb3d60 | 46 | } |
andrewboyson | 74:c3756bfa960e | 47 | uint16_t TcpHdrMssGet() { return mss; } |
andrewboyson | 73:43e3d7fb3d60 | 48 | |
andrewboyson | 73:43e3d7fb3d60 | 49 | static void logFlags() |
andrewboyson | 73:43e3d7fb3d60 | 50 | { |
andrewboyson | 73:43e3d7fb3d60 | 51 | if (TcpHdrURG) Log(" URG"); |
andrewboyson | 73:43e3d7fb3d60 | 52 | if (TcpHdrACK) Log(" ACK"); |
andrewboyson | 73:43e3d7fb3d60 | 53 | if (TcpHdrPSH) Log(" PSH"); |
andrewboyson | 73:43e3d7fb3d60 | 54 | if (TcpHdrRST) Log(" RST"); |
andrewboyson | 73:43e3d7fb3d60 | 55 | if (TcpHdrSYN) Log(" SYN"); |
andrewboyson | 73:43e3d7fb3d60 | 56 | if (TcpHdrFIN) Log(" FIN"); |
andrewboyson | 73:43e3d7fb3d60 | 57 | } |
andrewboyson | 73:43e3d7fb3d60 | 58 | void TcpHdrLog(uint16_t calculatedChecksum) |
andrewboyson | 73:43e3d7fb3d60 | 59 | { |
andrewboyson | 73:43e3d7fb3d60 | 60 | if (NetTraceVerbose) |
andrewboyson | 73:43e3d7fb3d60 | 61 | { |
andrewboyson | 73:43e3d7fb3d60 | 62 | Log("TCP header\r\n"); |
andrewboyson | 73:43e3d7fb3d60 | 63 | Log(" Source port "); LogF("%hu", TcpHdrSrcPort ); Log("\r\n"); |
andrewboyson | 73:43e3d7fb3d60 | 64 | Log(" Destination port "); LogF("%hu", TcpHdrDstPort ); Log("\r\n"); |
andrewboyson | 73:43e3d7fb3d60 | 65 | Log(" Seq number "); LogF("%u", TcpHdrSeqNum ); Log("\r\n"); |
andrewboyson | 73:43e3d7fb3d60 | 66 | Log(" Ack number "); LogF("%u", TcpHdrAckNum ); Log("\r\n"); |
andrewboyson | 74:c3756bfa960e | 67 | Log(" Header size "); LogF("%u", headerSize ); Log("\r\n"); |
andrewboyson | 73:43e3d7fb3d60 | 68 | Log(" Flags " ); logFlags( ); Log("\r\n"); |
andrewboyson | 73:43e3d7fb3d60 | 69 | Log(" Window "); LogF("%hu", TcpHdrWindow ); Log("\r\n"); |
andrewboyson | 73:43e3d7fb3d60 | 70 | Log(" Checksum (hex) "); LogF("%04hX", TcpHdrChecksum ); Log("\r\n"); |
andrewboyson | 73:43e3d7fb3d60 | 71 | Log(" Calculated (hex) "); LogF("%04hX", calculatedChecksum ); Log("\r\n"); |
andrewboyson | 73:43e3d7fb3d60 | 72 | Log(" Urgent pointer "); LogF("%hu", TcpHdrUrgent ); Log("\r\n"); |
andrewboyson | 73:43e3d7fb3d60 | 73 | |
andrewboyson | 73:43e3d7fb3d60 | 74 | } |
andrewboyson | 73:43e3d7fb3d60 | 75 | else |
andrewboyson | 73:43e3d7fb3d60 | 76 | { |
andrewboyson | 73:43e3d7fb3d60 | 77 | LogF("TCP header %hu >>> %hu", TcpHdrSrcPort, TcpHdrDstPort); |
andrewboyson | 73:43e3d7fb3d60 | 78 | logFlags(); |
andrewboyson | 73:43e3d7fb3d60 | 79 | Log("\r\n"); |
andrewboyson | 73:43e3d7fb3d60 | 80 | } |
andrewboyson | 73:43e3d7fb3d60 | 81 | } |
andrewboyson | 74:c3756bfa960e | 82 | void TcpHdrReadFromPacket(void* pPacket) |
andrewboyson | 73:43e3d7fb3d60 | 83 | { |
andrewboyson | 98:b977424ec7f7 | 84 | int lastFaultPoint = FaultPoint; |
andrewboyson | 98:b977424ec7f7 | 85 | FaultPoint = FAULT_POINT_TcpHdrReadFromPacket; |
andrewboyson | 98:b977424ec7f7 | 86 | |
andrewboyson | 73:43e3d7fb3d60 | 87 | struct header* pHeader = (struct header*)pPacket; |
andrewboyson | 74:c3756bfa960e | 88 | |
andrewboyson | 74:c3756bfa960e | 89 | TcpHdrSrcPort = NetToHost16(pHeader->srcPort); |
andrewboyson | 74:c3756bfa960e | 90 | TcpHdrDstPort = NetToHost16(pHeader->dstPort); |
andrewboyson | 74:c3756bfa960e | 91 | TcpHdrSeqNum = NetToHost32(pHeader->seqnum); |
andrewboyson | 74:c3756bfa960e | 92 | TcpHdrAckNum = NetToHost32(pHeader->acknum); |
andrewboyson | 74:c3756bfa960e | 93 | headerSize = (pHeader->dataOffset >> 2) & 0xFC; //Same as right shifting by 4 bits and multiplying by 4 |
andrewboyson | 74:c3756bfa960e | 94 | uint8_t flags = pHeader->flags; |
andrewboyson | 74:c3756bfa960e | 95 | TcpHdrURG = flags & 0x20; //indicates that the Urgent pointer field is significant |
andrewboyson | 74:c3756bfa960e | 96 | TcpHdrACK = 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 | 74:c3756bfa960e | 97 | TcpHdrPSH = flags & 0x08; //Push function. Asks to push the buffered data to the receiving application. |
andrewboyson | 74:c3756bfa960e | 98 | TcpHdrRST = flags & 0x04; //Reset the connection |
andrewboyson | 74:c3756bfa960e | 99 | TcpHdrSYN = 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 | 74:c3756bfa960e | 100 | TcpHdrFIN = flags & 0x01; //No more data from sender |
andrewboyson | 74:c3756bfa960e | 101 | TcpHdrWindow = NetToHost16(pHeader->window); |
andrewboyson | 74:c3756bfa960e | 102 | TcpHdrChecksum = NetToHost16(pHeader->checksum); |
andrewboyson | 74:c3756bfa960e | 103 | TcpHdrUrgent = NetToHost16(pHeader->urgent); |
andrewboyson | 74:c3756bfa960e | 104 | |
andrewboyson | 73:43e3d7fb3d60 | 105 | char* pOptions = (char*)pPacket + sizeof(struct header); |
andrewboyson | 74:c3756bfa960e | 106 | int optionLength = headerSize - sizeof(struct header); |
andrewboyson | 73:43e3d7fb3d60 | 107 | |
andrewboyson | 74:c3756bfa960e | 108 | mss = 0; |
andrewboyson | 88:1ba13e6062a3 | 109 | for (char* p = pOptions; p < pOptions + optionLength; p++) //If the header size is zero then optionLength will be negative and the for loop will do nothing. |
andrewboyson | 73:43e3d7fb3d60 | 110 | { |
andrewboyson | 73:43e3d7fb3d60 | 111 | switch (*p) |
andrewboyson | 73:43e3d7fb3d60 | 112 | { |
andrewboyson | 98:b977424ec7f7 | 113 | case 0: FaultPoint = lastFaultPoint; return; //End of options so stop |
andrewboyson | 88:1ba13e6062a3 | 114 | case 1: break; //NOP, padding - optional used to pad to 32 bit boundary |
andrewboyson | 73:43e3d7fb3d60 | 115 | case 2: |
andrewboyson | 73:43e3d7fb3d60 | 116 | p++; |
andrewboyson | 73:43e3d7fb3d60 | 117 | if (*p != 4) LogTimeF("MSS option width %d when expected 4\r\n", *p); |
andrewboyson | 73:43e3d7fb3d60 | 118 | p++; |
andrewboyson | 74:c3756bfa960e | 119 | mss = ((uint16_t)*p) << 8; |
andrewboyson | 73:43e3d7fb3d60 | 120 | p++; |
andrewboyson | 74:c3756bfa960e | 121 | mss += *p; |
andrewboyson | 98:b977424ec7f7 | 122 | FaultPoint = lastFaultPoint; |
andrewboyson | 88:1ba13e6062a3 | 123 | return; //Got what we want so stop |
andrewboyson | 73:43e3d7fb3d60 | 124 | default: LogTimeF("Unrecognised TCP option %d\r\n", *p); |
andrewboyson | 73:43e3d7fb3d60 | 125 | } |
andrewboyson | 73:43e3d7fb3d60 | 126 | } |
andrewboyson | 98:b977424ec7f7 | 127 | FaultPoint = lastFaultPoint; |
andrewboyson | 73:43e3d7fb3d60 | 128 | } |
andrewboyson | 73:43e3d7fb3d60 | 129 | |
andrewboyson | 74:c3756bfa960e | 130 | void TcpHdrWriteToPacket(void* pPacket) |
andrewboyson | 73:43e3d7fb3d60 | 131 | { |
andrewboyson | 73:43e3d7fb3d60 | 132 | struct header* pHeader = (struct header*)pPacket; |
andrewboyson | 73:43e3d7fb3d60 | 133 | |
andrewboyson | 74:c3756bfa960e | 134 | headerSize = sizeof(struct header); |
andrewboyson | 74:c3756bfa960e | 135 | if (TcpHdrMssGet()) |
andrewboyson | 74:c3756bfa960e | 136 | { |
andrewboyson | 74:c3756bfa960e | 137 | char* pOptions = (char*)pPacket + headerSize; |
andrewboyson | 74:c3756bfa960e | 138 | pOptions[0] = 2; |
andrewboyson | 74:c3756bfa960e | 139 | pOptions[1] = 4; |
andrewboyson | 74:c3756bfa960e | 140 | pOptions[2] = mss >> 8; |
andrewboyson | 74:c3756bfa960e | 141 | pOptions[3] = mss & 0xFF; |
andrewboyson | 74:c3756bfa960e | 142 | headerSize += 4; |
andrewboyson | 74:c3756bfa960e | 143 | } |
andrewboyson | 74:c3756bfa960e | 144 | |
andrewboyson | 73:43e3d7fb3d60 | 145 | pHeader->dstPort = NetToHost16(TcpHdrDstPort); |
andrewboyson | 73:43e3d7fb3d60 | 146 | pHeader->srcPort = NetToHost16(TcpHdrSrcPort); |
andrewboyson | 73:43e3d7fb3d60 | 147 | pHeader->seqnum = NetToHost32(TcpHdrSeqNum); //This is the sequence number of the first byte of this message |
andrewboyson | 73:43e3d7fb3d60 | 148 | pHeader->acknum = NetToHost32(TcpHdrAckNum); //This is the sequence number we expect in the next message |
andrewboyson | 74:c3756bfa960e | 149 | pHeader->dataOffset = headerSize << 2; //Same as dividing by 4 to get bytes and left shifting by 4 bits |
andrewboyson | 73:43e3d7fb3d60 | 150 | uint8_t flags = 0; |
andrewboyson | 73:43e3d7fb3d60 | 151 | if (TcpHdrURG) flags |= 0x20; //indicates that the Urgent pointer field is significant |
andrewboyson | 73:43e3d7fb3d60 | 152 | if (TcpHdrACK) 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 | 73:43e3d7fb3d60 | 153 | if (TcpHdrPSH) flags |= 0x08; //Push function. Asks to push the buffered data to the receiving application. |
andrewboyson | 73:43e3d7fb3d60 | 154 | if (TcpHdrRST) flags |= 0x04; //Reset the connection |
andrewboyson | 73:43e3d7fb3d60 | 155 | if (TcpHdrSYN) 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 | 73:43e3d7fb3d60 | 156 | if (TcpHdrFIN) flags |= 0x01; //No more data from sender |
andrewboyson | 73:43e3d7fb3d60 | 157 | pHeader->flags = flags; |
andrewboyson | 73:43e3d7fb3d60 | 158 | pHeader->window = NetToHost16(TcpHdrWindow); |
andrewboyson | 73:43e3d7fb3d60 | 159 | pHeader->urgent = NetToHost16(TcpHdrUrgent); |
andrewboyson | 73:43e3d7fb3d60 | 160 | |
andrewboyson | 73:43e3d7fb3d60 | 161 | pHeader->checksum = 0; |
andrewboyson | 74:c3756bfa960e | 162 | } |
andrewboyson | 74:c3756bfa960e | 163 | void TcpHdrAddChecksumToPacket(void* pPacket, uint16_t checksum) |
andrewboyson | 74:c3756bfa960e | 164 | { |
andrewboyson | 74:c3756bfa960e | 165 | struct header* pHeader = (struct header*)pPacket; |
andrewboyson | 74:c3756bfa960e | 166 | pHeader->checksum = checksum; |
andrewboyson | 74:c3756bfa960e | 167 | } |
andrewboyson | 74:c3756bfa960e | 168 | |
andrewboyson | 74:c3756bfa960e | 169 | void TcpHdrMakeEmpty() |
andrewboyson | 74:c3756bfa960e | 170 | { |
andrewboyson | 74:c3756bfa960e | 171 | TcpHdrSrcPort = 0; |
andrewboyson | 74:c3756bfa960e | 172 | TcpHdrDstPort = 0; |
andrewboyson | 74:c3756bfa960e | 173 | TcpHdrSeqNum = 0; |
andrewboyson | 74:c3756bfa960e | 174 | TcpHdrAckNum = 0; |
andrewboyson | 74:c3756bfa960e | 175 | headerSize = sizeof(struct header); |
andrewboyson | 74:c3756bfa960e | 176 | TcpHdrURG = 0; |
andrewboyson | 74:c3756bfa960e | 177 | TcpHdrACK = 0; |
andrewboyson | 74:c3756bfa960e | 178 | TcpHdrPSH = 0; |
andrewboyson | 74:c3756bfa960e | 179 | TcpHdrRST = 0; |
andrewboyson | 74:c3756bfa960e | 180 | TcpHdrSYN = 0; |
andrewboyson | 74:c3756bfa960e | 181 | TcpHdrFIN = 0; |
andrewboyson | 74:c3756bfa960e | 182 | TcpHdrWindow = 0; |
andrewboyson | 74:c3756bfa960e | 183 | TcpHdrChecksum = 0; |
andrewboyson | 74:c3756bfa960e | 184 | TcpHdrUrgent = 0; |
andrewboyson | 74:c3756bfa960e | 185 | mss = 0; |
andrewboyson | 74:c3756bfa960e | 186 | |
andrewboyson | 73:43e3d7fb3d60 | 187 | } |