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

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers tcphdr.c Source File

tcphdr.c

00001 #include <stdint.h>
00002 #include <stdbool.h>
00003 
00004 #include   "log.h"
00005 #include   "net.h"
00006 #include "restart.h"
00007 
00008 static char* hdrPtrSrcPort   (char* pPacket) { return pPacket +  0; } //2
00009 static char* hdrPtrDstPort   (char* pPacket) { return pPacket +  2; } //2
00010 static char* hdrPtrSeqnum    (char* pPacket) { return pPacket +  4; } //4
00011 static char* hdrPtrAcknum    (char* pPacket) { return pPacket +  8; } //4
00012 static char* hdrPtrDataOffset(char* pPacket) { return pPacket + 12; } //1
00013 static char* hdrPtrFlags     (char* pPacket) { return pPacket + 13; } //1
00014 static char* hdrPtrWindow    (char* pPacket) { return pPacket + 14; } //2
00015 static char* hdrPtrChecksum  (char* pPacket) { return pPacket + 16; } //2
00016 static char* hdrPtrUrgent    (char* pPacket) { return pPacket + 18; } //2
00017 static const int HEADER_LENGTH = 20;
00018 
00019 void    TcpHdrSetChecksum (char* pPacket, uint16_t value) { NetDirect16(hdrPtrChecksum  (pPacket), &value);        } //The checksum is calculated inverted so don't re-invert here
00020 
00021 //Header variables
00022 uint16_t TcpHdrSrcPort;
00023 uint16_t TcpHdrDstPort;
00024 uint32_t TcpHdrSeqNum;
00025 uint32_t TcpHdrAckNum;
00026 bool     TcpHdrURG; //indicates that the Urgent pointer field is significant
00027 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.
00028 bool     TcpHdrPSH; //Push function. Asks to push the buffered data to the receiving application.
00029 bool     TcpHdrRST; //Reset the connection
00030 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.
00031 bool     TcpHdrFIN; //No more data from sender
00032 uint16_t TcpHdrWindow;
00033 uint16_t TcpHdrChecksum;
00034 uint16_t TcpHdrUrgent;
00035 
00036 //Side effects
00037 static int      headerSize;
00038 int TcpHdrSizeGet() { return headerSize; }
00039 
00040 static uint16_t mss = 0;
00041 void TcpHdrMssSet(uint16_t value)
00042 {
00043     mss = value;
00044     headerSize = HEADER_LENGTH;
00045     if (mss) headerSize += 4;
00046 }
00047 uint16_t TcpHdrMssGet() { return mss; }
00048 
00049 static void logFlags()
00050 {
00051     if (TcpHdrURG) Log(" URG");
00052     if (TcpHdrACK) Log(" ACK");
00053     if (TcpHdrPSH) Log(" PSH");
00054     if (TcpHdrRST) Log(" RST");
00055     if (TcpHdrSYN) Log(" SYN");
00056     if (TcpHdrFIN) Log(" FIN");
00057 }
00058 void TcpHdrLog(uint16_t calculatedChecksum)
00059 {
00060     if (NetTraceVerbose)
00061     {
00062         Log("TCP header\r\n");
00063         Log("  Source port      "); LogF("%hu",     TcpHdrSrcPort          ); Log("\r\n");
00064         Log("  Destination port "); LogF("%hu",     TcpHdrDstPort          ); Log("\r\n");
00065         Log("  Seq number       "); LogF("%u",      TcpHdrSeqNum           ); Log("\r\n");
00066         Log("  Ack number       "); LogF("%u",      TcpHdrAckNum           ); Log("\r\n");
00067         Log("  Header size      "); LogF("%u",      headerSize             ); Log("\r\n");
00068         Log("  Flags           " ); logFlags(                              ); Log("\r\n");
00069         Log("  Window           "); LogF("%hu",     TcpHdrWindow           ); Log("\r\n");
00070         Log("  Checksum (hex)   "); LogF("%04hX",   TcpHdrChecksum         ); Log("\r\n");
00071         Log("  Calculated (hex) "); LogF("%04hX",   calculatedChecksum     ); Log("\r\n");
00072         Log("  Urgent pointer   "); LogF("%hu",     TcpHdrUrgent           ); Log("\r\n");
00073 
00074     }
00075     else
00076     {
00077         LogF("TCP   header %hu >>> %hu", TcpHdrSrcPort, TcpHdrDstPort);
00078         logFlags();
00079         Log("\r\n");
00080     }
00081 }
00082 void TcpHdrReadFromPacket(char* pPacket)
00083 {
00084     int lastRestartPoint = RestartPoint;
00085     RestartPoint = FAULT_POINT_TcpHdrReadFromPacket;
00086                         
00087     NetInvert16(&TcpHdrSrcPort,  hdrPtrSrcPort   (pPacket));
00088     NetInvert16(&TcpHdrDstPort,  hdrPtrDstPort   (pPacket));
00089     NetInvert32(&TcpHdrSeqNum,   hdrPtrSeqnum    (pPacket));
00090     NetInvert32(&TcpHdrAckNum,   hdrPtrAcknum    (pPacket));
00091     headerSize    =            (*hdrPtrDataOffset(pPacket) >> 2) & 0xFC; //Same as right shifting by 4 bits and multiplying by 4
00092     uint8_t flags =             *hdrPtrFlags     (pPacket);
00093         TcpHdrURG = flags & 0x20; //indicates that the Urgent pointer field is significant
00094         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.
00095         TcpHdrPSH = flags & 0x08; //Push function. Asks to push the buffered data to the receiving application.
00096         TcpHdrRST = flags & 0x04; //Reset the connection
00097         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.
00098         TcpHdrFIN = flags & 0x01; //No more data from sender
00099     NetInvert16(&TcpHdrWindow,   hdrPtrWindow   (pPacket));
00100     NetInvert16(&TcpHdrChecksum, hdrPtrChecksum (pPacket));
00101     NetInvert16(&TcpHdrUrgent,   hdrPtrUrgent   (pPacket));
00102     
00103     char* pOptions     = pPacket    + HEADER_LENGTH;
00104     int   optionLength = headerSize - HEADER_LENGTH;
00105 
00106     mss = 0;
00107     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.
00108     {
00109         switch (*p)
00110         {
00111             case 0: RestartPoint = lastRestartPoint; return; //End of options so stop
00112             case 1: break;  //NOP, padding - optional used to pad to 32 bit boundary
00113             case 2:
00114                 p++;
00115                 if (*p != 4) LogTimeF("MSS option width %d when expected 4\r\n", *p);
00116                 p++;
00117                 mss = ((uint16_t)*p) << 8;
00118                 p++;
00119                 mss += *p;
00120                 RestartPoint = lastRestartPoint;
00121                 return;     //Got what we want so stop
00122             default: LogTimeF("Unrecognised TCP option %d\r\n", *p);
00123         }
00124     }
00125     RestartPoint = lastRestartPoint;
00126 }
00127 
00128 void TcpHdrWriteToPacket(char* pPacket)
00129 {
00130     headerSize = HEADER_LENGTH;
00131     if (mss)
00132     {
00133         char* pOptions = pPacket + headerSize;
00134         pOptions[0]  = 2;
00135         pOptions[1]  = 4;
00136         pOptions[2]  = mss >> 8;
00137         pOptions[3]  = mss & 0xFF;
00138         headerSize += 4;
00139     }
00140     
00141     NetInvert16(hdrPtrDstPort   (pPacket), &TcpHdrDstPort);
00142     NetInvert16(hdrPtrSrcPort   (pPacket), &TcpHdrSrcPort);
00143     NetInvert32(hdrPtrSeqnum    (pPacket), &TcpHdrSeqNum );  //This is the sequence number of the first byte of this message
00144     NetInvert32(hdrPtrAcknum    (pPacket), &TcpHdrAckNum );  //This is the sequence number we expect in the next message
00145                *hdrPtrDataOffset(pPacket) = headerSize << 2; //Same as dividing by 4 to get bytes and left shifting by 4 bits
00146     uint8_t flags = 0;
00147     if (TcpHdrURG) flags |= 0x20; //indicates that the Urgent pointer field is significant
00148     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.
00149     if (TcpHdrPSH) flags |= 0x08; //Push function. Asks to push the buffered data to the receiving application.
00150     if (TcpHdrRST) flags |= 0x04; //Reset the connection
00151     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.
00152     if (TcpHdrFIN) flags |= 0x01; //No more data from sender
00153                *hdrPtrFlags     (pPacket) = flags;
00154     NetInvert16(hdrPtrWindow    (pPacket), &TcpHdrWindow);
00155     NetInvert16(hdrPtrUrgent    (pPacket), &TcpHdrUrgent);
00156     TcpHdrSetChecksum( pPacket, 0);
00157 }
00158 
00159 void TcpHdrMakeEmpty()
00160 {
00161     TcpHdrSrcPort  = 0;
00162     TcpHdrDstPort  = 0;
00163     TcpHdrSeqNum   = 0;
00164     TcpHdrAckNum   = 0;
00165     headerSize     = HEADER_LENGTH;
00166     TcpHdrURG      = 0;
00167     TcpHdrACK      = 0;
00168     TcpHdrPSH      = 0;
00169     TcpHdrRST      = 0;
00170     TcpHdrSYN      = 0;
00171     TcpHdrFIN      = 0;
00172     TcpHdrWindow   = 0;
00173     TcpHdrChecksum = 0;
00174     TcpHdrUrgent   = 0;
00175     mss            = 0;
00176 
00177 }