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

Committer:
andrewboyson
Date:
Wed Dec 05 18:30:37 2018 +0000
Revision:
94:e2973a2c488e
Parent:
88:1ba13e6062a3
Child:
98:b977424ec7f7
Fixed bug - incorrect MSS being sent from a polled sync: expected 1440 but had -60. Traced to buffer datalength in EthPollForPacketToSend being set to zero instead of being calculated from the buffer length - headersize.

Who changed what in which revision?

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