This is a low-level network debugging utility that utilizes raw packet i/o to construct and deconstruct tcp, udp, ipv4, arp, and icmp packets over ethernet.

Dependencies:   mbed

net/tcp.h

Committer:
etherealflaim
Date:
2010-10-12
Revision:
8:1c1f6ce348c6
Parent:
6:66c4cd9073aa

File content as of revision 8:1c1f6ce348c6:

#ifndef TCP_H
#define TCP_H

#include "net.h"

/**
  \file tcp.h
  \brief TCP segment header
  
  This file contains the memory map and associated functions for TCP segment header
  creation and deconstruction. 
*/

#define IPPROTO_TCP 0x06

/// TCP Segment memory map
typedef struct {
  u16 source_port;         ///< Source port (1-65535)
  u16 destination_port;    ///< Destination port (1-65535)
  u32 sequence_number;     ///< TCP Sequence number (initial one if SYN set)
  u32 acknowledge_number;  ///< TCP Acknowledge number (valid if ACK set)
  
  unsigned data_offset_bytes_div4:4; ///< Length of this header (20) divided by 4 (should be 5)
  unsigned unused_0:4;               ///< Unused, should be zero
  
  unsigned fin:1; ///< connection FINished (no more data from sender)
  unsigned syn:1; ///< SYNchronize sequence numbers
  unsigned rst:1; ///< ReSeT the connection
  unsigned psh:1; ///< PuSH to receiving application
  unsigned ack:1; ///< ACKnowledge fiend is significant
  unsigned urg:1; ///< URGent field is significant
  unsigned ece:1; ///< ECn Echo
  unsigned cwr:1; ///< Congestion Window Reduced
  
  u16 window_size;    ///< TCP Maxumum window size (8192 is good)
  u16 checksum;       ///< TCP checksum (computed with pseudo header)
  u16 urgent_pointer; ///< Urgent pointer (valid if URG set)
  
  /// Memory map for data if no options are set
  unsigned char data[];
} TCP_SegmentHeader;

/// Convert from wire to host or host to wire endianness
inline void fix_endian_tcp(TCP_SegmentHeader *segment)
{
  segment->unused_0 ^= segment->data_offset_bytes_div4;
  segment->data_offset_bytes_div4 ^= segment->unused_0;
  segment->unused_0 ^= segment->data_offset_bytes_div4;
  fix_endian_u16(&segment->source_port);
  fix_endian_u16(&segment->destination_port);
  fix_endian_u16(&segment->window_size);
  // No fixing checksums
  fix_endian_u16(&segment->urgent_pointer);
  fix_endian_u32(&segment->sequence_number);
  fix_endian_u32(&segment->acknowledge_number);
}

/// Print the TCP segment header
inline void print_tcp(TCP_SegmentHeader *segment)
{
  main_log.printf("TCP Segment:");
  main_log.printf("  Source:    PORT %d", segment->source_port);
  main_log.printf("  Dest:      PORT %d", segment->destination_port);
  main_log.printf("  TCP Seqno: 0x%08X", segment->sequence_number);
  main_log.printf("  TCP Ackno: 0x%08X", segment->acknowledge_number);
  main_log.printf("  Header:    %d bytes", segment->data_offset_bytes_div4*4);
  if (segment->cwr) main_log.printf("  Flag:      CWR");
  if (segment->ece) main_log.printf("  Flag:      ECE");
  if (segment->urg) main_log.printf("  Flag:      URG");
  if (segment->ack) main_log.printf("  Flag:      ACK");
  if (segment->psh) main_log.printf("  Flag:      PSH");
  if (segment->rst) main_log.printf("  Flag:      RST");
  if (segment->syn) main_log.printf("  Flag:      SYN");
  if (segment->fin) main_log.printf("  Flag:      FIN");
}

/// Compute the pseudo header checksum with the given source, destination, and length
inline u16 pseudo_header_checksum(IP_Address source, IP_Address destination, u16 length)
{
  struct {
    IP_Address src, dst;
    u8 zeros;
    u8 proto;
    u16 length;
  } pseudoheader = {source, destination, 0, IPPROTO_TCP, length};
  fix_endian_u16(&pseudoheader.length);
  return checksum(&pseudoheader, sizeof(pseudoheader));
}

#endif