Andrew Boyson / net

Dependents:   oldheating gps motorhome heating

tcp/tcphdr.c

Committer:
andrewboyson
Date:
2018-10-23
Revision:
73:43e3d7fb3d60
Child:
74:c3756bfa960e

File content as of revision 73:43e3d7fb3d60:

#include <stdint.h>
#include <stdbool.h>

#include    "log.h"
#include    "net.h"

__packed struct header
{
    uint16_t srcPort;
    uint16_t dstPort;
    uint32_t seqnum;
    uint32_t acknum;
    uint8_t  dataOffset;
    uint8_t  flags;
    uint16_t window; 
    uint16_t checksum;
    uint16_t urgent;
};

//Header variables
uint16_t TcpHdrSrcPort;
uint16_t TcpHdrDstPort;
uint32_t TcpHdrSeqNum;
uint32_t TcpHdrAckNum;
int      TcpHdrSize;
bool     TcpHdrURG; //indicates that the Urgent pointer field is significant
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.
bool     TcpHdrPSH; //Push function. Asks to push the buffered data to the receiving application.
bool     TcpHdrRST; //Reset the connection
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.
bool     TcpHdrFIN; //No more data from sender
uint16_t TcpHdrWindow;
uint16_t TcpHdrChecksum;
uint16_t TcpHdrUrgent;

//Option variables
uint16_t TcpHdrMss;

void TcpHdrRead(void* pPacket)
{
    struct header* pHeader = (struct header*)pPacket;
                        
    TcpHdrSrcPort = NetToHost16(pHeader->srcPort);
    TcpHdrDstPort = NetToHost16(pHeader->dstPort);
    TcpHdrSeqNum  = NetToHost32(pHeader->seqnum);
    TcpHdrAckNum  = NetToHost32(pHeader->acknum);
    TcpHdrSize    =            (pHeader->dataOffset >> 2) & 0xFC; //Same as right shifting by 4 bits and multiplying by 4
    uint8_t flags =             pHeader->flags;
        TcpHdrURG = flags & 0x20; //indicates that the Urgent pointer field is significant
        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.
        TcpHdrPSH = flags & 0x08; //Push function. Asks to push the buffered data to the receiving application.
        TcpHdrRST = flags & 0x04; //Reset the connection
        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.
        TcpHdrFIN = flags & 0x01; //No more data from sender
    TcpHdrWindow   = NetToHost16(pHeader->window);
    TcpHdrChecksum = NetToHost16(pHeader->checksum);
    TcpHdrUrgent   = NetToHost16(pHeader->urgent);
}

static void logFlags()
{
    if (TcpHdrURG) Log(" URG");
    if (TcpHdrACK) Log(" ACK");
    if (TcpHdrPSH) Log(" PSH");
    if (TcpHdrRST) Log(" RST");
    if (TcpHdrSYN) Log(" SYN");
    if (TcpHdrFIN) Log(" FIN");
}
void TcpHdrLog(uint16_t calculatedChecksum)
{
    if (NetTraceVerbose)
    {
        Log("TCP header\r\n");
        Log("  Source port      "); LogF("%hu",     TcpHdrSrcPort          ); Log("\r\n");
        Log("  Destination port "); LogF("%hu",     TcpHdrDstPort          ); Log("\r\n");
        Log("  Seq number       "); LogF("%u",      TcpHdrSeqNum           ); Log("\r\n");
        Log("  Ack number       "); LogF("%u",      TcpHdrAckNum           ); Log("\r\n");
        Log("  Header size      "); LogF("%u",      TcpHdrSize             ); Log("\r\n");
        Log("  Flags           " ); logFlags(                              ); Log("\r\n");
        Log("  Window           "); LogF("%hu",     TcpHdrWindow           ); Log("\r\n");
        Log("  Checksum (hex)   "); LogF("%04hX",   TcpHdrChecksum         ); Log("\r\n");
        Log("  Calculated (hex) "); LogF("%04hX",   calculatedChecksum     ); Log("\r\n");
        Log("  Urgent pointer   "); LogF("%hu",     TcpHdrUrgent           ); Log("\r\n");

    }
    else
    {
        LogF("TCP   header %hu >>> %hu", TcpHdrSrcPort, TcpHdrDstPort);
        logFlags();
        Log("\r\n");
    }
}
void TcpHdrAddChecksum(void* pPacket, uint16_t checksum)
{
    struct header* pHeader = (struct header*)pPacket;
    pHeader->checksum    = checksum;
}
void TcpHdrReadOptions(void* pPacket)
{
    char* pOptions     = (char*)pPacket + sizeof(struct header);
    int   optionLength =     TcpHdrSize - sizeof(struct header);

    TcpHdrMss = 536; //default MSS for IPv4 [576 - 20(TCP) - 20(IP)];
    for (char* p = pOptions; p < pOptions + optionLength; p++)
    {
        switch (*p)
        {
            case 0: break; //End of options - used to pad to 32 bit boundary
            case 1: break; //NOP, padding - optional
            case 2:
                p++;
                if (*p != 4) LogTimeF("MSS option width %d when expected 4\r\n", *p);
                p++;
                TcpHdrMss = ((uint16_t)*p) << 8;
                p++;
                TcpHdrMss += *p;
                return;
            default: LogTimeF("Unrecognised TCP option %d\r\n", *p);
        }
    }
}
void TcpHdrWriteOptions(void* pPacket)
{
    char* pOptions = (char*)pPacket + sizeof(struct header);
    pOptions[0]  = 2;
    pOptions[1]  = 4;
    pOptions[2]  = TcpHdrMss >> 8;
    pOptions[3]  = TcpHdrMss & 0xFF;
    TcpHdrSize += sizeof(struct header) + 4;
}
void TcpHdrClearOptions()
{
    TcpHdrSize = sizeof(struct header);
}

void TcpHdrWrite(int size, void* pPacket)
{
    struct header* pHeader = (struct header*)pPacket;
    
    pHeader->dstPort    = NetToHost16(TcpHdrDstPort);
    pHeader->srcPort    = NetToHost16(TcpHdrSrcPort);
    pHeader->seqnum     = NetToHost32(TcpHdrSeqNum); //This is the sequence number of the first byte of this message
    pHeader->acknum     = NetToHost32(TcpHdrAckNum); //This is the sequence number we expect in the next message
    pHeader->dataOffset = TcpHdrSize << 2;           //Same as dividing by 4 to get bytes and left shifting by 4 bits
    uint8_t flags = 0;
    if (TcpHdrURG) flags |= 0x20; //indicates that the Urgent pointer field is significant
    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.
    if (TcpHdrPSH) flags |= 0x08; //Push function. Asks to push the buffered data to the receiving application.
    if (TcpHdrRST) flags |= 0x04; //Reset the connection
    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.
    if (TcpHdrFIN) flags |= 0x01; //No more data from sender
    pHeader->flags      = flags;
    pHeader->window     = NetToHost16(TcpHdrWindow);
    pHeader->urgent     = NetToHost16(TcpHdrUrgent);
    
    pHeader->checksum   = 0;
}