Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
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;
}