Commit d94a228b authored by Dominik Widhalm's avatar Dominik Widhalm
Browse files

Added example solutions for task 6.13

parent 8bf59fa1
/******************************************************************************
* C PROGRAMMING *
* BASIC EXERCISES - EXAMPLE SOLUTIONS *
* *
* Task_6.13: TCP/IP Parser *
* Author: Dominik Widhalm *
* Email: dominik.widhalm@technikum-wien.at *
* Date: 2017-08-30 *
* *
******************************************************************************/
/***** INCLUDES ***************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
/***** MACROS *****************************************************************/
/*** ETH Protocol ***/
// Internet Protocol Version 4
#define ETHERTYPE_IP4 0x0800
// Address Resolution Protocol
#define ETHERTYPE_ARP 0x0806
// Internet Protocol Version 6
#define ETHERTYPE_IP6 0x86DD
// Precision Time Protocol
#define ETHERTYPE_PTP 0x88F7
/*** IP Protocol ***/
// Internet Control Message Protocol
#define IPTYPE_ICMP 0x01
// Internet Group Management Protocol
#define IPTYPE_IGMP 0x02
// Transmission Control Protocol
#define IPTYPE_TCP 0x06
// User Datagram Protocol
#define IPTYPE_UDP 0x11
/*** TCP Flag Offsets & Masks ***/
// Urgent Flag
#define TCP_OSET_URG 5
#define TCP_MASK_URG (1<<TCP_OSET_URG)
// Acknowledgement Flag
#define TCP_OSET_ACK 4
#define TCP_MASK_ACK (1<<TCP_OSET_ACK)
// Push Flag
#define TCP_OSET_PSH 3
#define TCP_MASK_PSH (1<<TCP_OSET_PSH)
// Reset Flag
#define TCP_OSET_RST 2
#define TCP_MASK_RST (1<<TCP_OSET_RST)
// Synchronise Flag
#define TCP_OSET_SYN 1
#define TCP_MASK_SYN (1<<TCP_OSET_SYN)
// Finish Flag
#define TCP_OSET_FIN 0
#define TCP_MASK_FIN (1<<TCP_OSET_FIN)
/*** Macro Functions ***/
// Macro to convert between little and big endian
#define LITTLE2BIG16(x) ((uint16_t)((x>>8) | (x<<8)))
/***** TYPEDEFS ***************************************************************/
/*** Unions ***/
/* Union to access MAC addresses either byte- or wordwise */
typedef union mac_a {
uint8_t b[6];
uint16_t w[3];
} MAC_A;
/* Union to access IP addresses either byte- or wordwise */
typedef union ip_a {
uint8_t b[4];
uint16_t w[2];
uint32_t d;
} IP_A;
/*** Structures ***/
/* Structure for an Ethernet header */
typedef struct eth {
MAC_A destination; // 6 Byte destination address
MAC_A source; // 6 Byte source address
uint16_t protocol; // 2 Byte ethernet type
uint8_t data[1]; // data origin (pseudo-pointer)
} ETH_t;
/* Structure for an IP header */
typedef struct ip {
uint8_t version; // 1 Byte version (bit 0-3) and IHL (bit 4-7)
uint8_t service_type; // 1 Byte type of service
uint16_t length; // 2 Bytes total length
uint16_t identification; // 2 Bytes identification
uint16_t flags; // 2 Bytes flags (bit 0-2) and fragment offset (bit 3- 15)
uint8_t ttl; // 1 Byte Time-To-Live
uint8_t protocol; // 1 Byte protocol
uint16_t header_checksum; // 2 Bytes header checksum
IP_A source; // 4 Bytes source IP address
IP_A destination; // 4 Bytes destination IP address
uint8_t data[1]; // data origin (pseudo-pointer)
} IP_t;
/* Structure for a TCP header */
typedef struct tcp {
uint16_t source_port; // 2 Byte source port
uint16_t destination_port; // 2 Byte destination port
uint32_t sequence; // 4 Byte sequence number
uint32_t ack_number; // 4 Byte acknowledgement number
uint16_t data_flags; // 2 Byte data offset (bit 0-3) and flags (bit 7-15)
uint16_t window_size; // 2 Byte window size
uint16_t checksum; // 2 Byte checksum
uint16_t urgent; // 2 Byte urgent pointer
uint8_t data[1]; // data origin (pseudo-pointer)
} TCP_t;
/***** GLOBAL VARIABLES *******************************************************/
uint8_t sample[] = {0xFE,0xFF,0x20,0x00,0x01,0x00,0x00,0x00,0x01,0x00,\
0x00,0x00,0x08,0x00,0x45,0x00,0x00,0x28,0x0F,0x4E,\
0x40,0x00,0x80,0x06,0x91,0xE6,0x91,0xFE,0xA0,0xED,\
0x41,0xD0,0xE4,0xDF,0x0D,0x2C,0x00,0x50,0x38,0xAF,\
0xFF,0xF3,0x11,0x4C,0x81,0xE4,0x50,0x10,0x25,0xBC,\
0x57,0x2D,0x00,0x00};
/***** FUNCTION PROTOTYPES ****************************************************/
void print_binary (uint8_t data, uint8_t count);
void address_print_mac (MAC_A *mac);
void address_print_ip (IP_A *ip);
uint16_t eth_get_header_length (void);
uint16_t eth_get_total_length (ETH_t *frame);
void eth_print_protocol (uint16_t type);
void ip_print_protocol (uint8_t type);
void eth_print (ETH_t *frame);
void ip_print (IP_t *frame);
void tcp_print (TCP_t *frame);
/***** LOCAL FUNCTIONS ********************************************************/
/******************************************************************************
* print_binary *
* @brief Function to print a given 8-bit value in binary form. *
* *
* This function prints the given 8-bit value in binary form. *
* *
* @param data 8-bit value *
* @param count Number of bits to be printed *
******************************************************************************/
void print_binary (uint8_t data, uint8_t count) {
/* Iterate over all 8 bits */
for (int i=(count-1); i>=0; i--) {
/* Print current bit */
if (data & (1<<i)) {
/* Bit is 1 */
printf("1");
} else {
/* Bit is 0 */
printf("0");
}
/* If not the last (LSB) bit ... */
if (i>0) {
/* Print separator */
printf(" ");
}
}
/* A void function has nothing to return */
return;
}
/******************************************************************************
* address_print_mac *
* @brief Function to print a given MAC address in a formatted way. *
* *
* This function prints the given MAC in the form XX:XX:XX:XX:XX:XX. *
* *
* @param mac Pointer to the MAC address *
******************************************************************************/
void address_print_mac (MAC_A *mac) {
/* Iterate over all 6 bytes of the MAC address */
for (unsigned int i=0; i<sizeof(MAC_A); i++) {
/* Print current byte */
printf("%02X",mac->b[i]);
/* If not the last byte ... */
if (i < (sizeof(MAC_A)-1)) {
/* ... additionally print a '-' */
printf("-");
}
}
/* A void function has nothing to return */
return;
}
/******************************************************************************
* address_print_ip *
* @brief Function to print a given IP address in a formatted way. *
* *
* This function prints the given IP in the form x.x.x.x. *
* *
* @param ip Pointer to the IP address *
******************************************************************************/
void address_print_ip (IP_A *ip) {
/* Iterate over all 4 bytes of the IP address */
for (unsigned int i=0; i<sizeof(IP_A); i++) {
/* Print current byte */
printf("%u",ip->b[i]);
/* If not the last byte ... */
if (i < (sizeof(IP_A)-1)) {
/* ... additionally print a ':' */
printf(".");
}
}
/* A void function has nothing to return */
return;
}
/******************************************************************************
* eth_get_header_length *
* @brief Function to calculate the ETH header size in bytes. *
* *
* This function returns the size of the ETH header in bytes. *
* *
* @return Size of the ETH header in bytes *
******************************************************************************/
uint16_t eth_get_header_length (void) {
/* Return the length of the ETH header */
return (uint16_t)(2*sizeof(MAC_A) + sizeof(uint16_t));
}
/******************************************************************************
* eth_get_total_length *
* @brief Function to calculate the frame total size in bytes. *
* *
* This function calculates the total size of the frame according to the *
* derived (fixed) header sizes and the information from the IP frame. *
* *
* @param frame Pointer to the data frame *
* @return Size of the frame in bytes *
******************************************************************************/
uint16_t eth_get_total_length (ETH_t *frame) {
/* Temporary variable for the number of bytes */
uint16_t length = 0;
/* Temporary pointer to access the IP frame */
IP_t *ip_frame = (IP_t*)frame->data;
/* Add the length of the ETH header */
length += eth_get_header_length();
/* Add the total length of the IP frame */
length += LITTLE2BIG16(ip_frame->length);
/* Return the calculated length */
return length;
}
/******************************************************************************
* eth_print_protocol *
* @brief Function to print the ETH protocol type. *
* *
* This function prints the name of the given protocol (if known). *
* *
* @param type 16-bit protocol number *
******************************************************************************/
void eth_print_protocol (uint16_t type) {
/* Check if protocol is known */
switch(type) {
case ETHERTYPE_IP4:
printf("IPv4");
break;
case ETHERTYPE_ARP:
printf("ARP");
break;
case ETHERTYPE_IP6:
printf("IPv6");
break;
case ETHERTYPE_PTP:
printf("PTP");
break;
default:
printf("UNKNOWN");
break;
}
/* A void function has nothing to return */
return;
}
/******************************************************************************
* ip_print_protocol *
* @brief Function to print the IP protocol type. *
* *
* This function prints the name of the given protocol (if known). *
* *
* @param type 8-bit protocol number *
******************************************************************************/
void ip_print_protocol (uint8_t type) {
/* Check if protocol is known */
switch(type) {
case IPTYPE_ICMP:
printf("ICMP");
break;
case IPTYPE_IGMP:
printf("IGMP");
break;
case IPTYPE_TCP:
printf("TCP");
break;
case IPTYPE_UDP:
printf("UDP");
break;
default:
printf("UNKNOWN");
break;
}
/* A void function has nothing to return */
return;
}
/******************************************************************************
* eth_print *
* @brief Function to print information from ETH frame. *
* *
* This function prints the information contained in a given ETH frame. *
* *
* @param frame Pointer to the data frame *
******************************************************************************/
void eth_print (ETH_t *frame) {
/* Print output-header */
printf("Ethernet Header:\n");
/* Print the destination address */
printf(" |-Destination Address : ");
address_print_mac(&(*frame).destination);
printf("\n");
/* Print the source address */
printf(" |-Source Address : ");
address_print_mac(&(*frame).source);
printf("\n");
/* Print the ETH header length */
printf(" |-ETH Header Length : %u Bytes\n",eth_get_header_length());
/* Print the ETH total length */
printf(" |-ETH Total Length : %u Bytes\n",eth_get_total_length(frame));
/* Print the contained protocol */
printf(" |-Protocol : 0x%04X (",LITTLE2BIG16(frame->protocol));
eth_print_protocol(LITTLE2BIG16(frame->protocol));
printf(")\n");
/* A void function has nothing to return */
return;
}
/******************************************************************************
* ip_print *
* @brief Function to print information from IP frame. *
* *
* This function prints the information contained in a given IP frame. *
* *
* @param frame Pointer to the data frame *
******************************************************************************/
void ip_print (IP_t *frame) {
/* Print output-header */
printf("IP Header:\n");
/* Print the destination IP */
printf(" |-Destination IP : ");
address_print_ip(&(*frame).destination);
printf("\n");
/* Print the source address */
printf(" |-Source IP : ");
address_print_ip(&(*frame).source);
printf("\n");
/* Print the IP version */
printf(" |-IP Version : IPv%u\n",(frame->version&0xF0)>>4);
/* Print the IP header length */
printf(" |-IP Header Length : %u Bytes\n",(frame->version&0x0F)*4);
/* Print the IP total length */
printf(" |-IP Total Length : %u Bytes\n",LITTLE2BIG16(frame->length));
/* Print the time to live (TTL) */
printf(" |-TTL : %u\n",frame->ttl);
/* Print the contained protocol */
printf(" |-Protocol : 0x%02X (",frame->protocol);
ip_print_protocol(frame->protocol);
printf(")\n");
/* Print the transmitted checksum */
printf(" |-Checksum : 0x%04X\n",LITTLE2BIG16(frame->header_checksum));
/* A void function has nothing to return */
return;
}
/******************************************************************************
* tcp_print *
* @brief Function to print information from TCP frame. *
* *
* This function prints the information contained in a given TCP frame. *
* *
* @param frame Pointer to the data frame *
******************************************************************************/
void tcp_print (TCP_t *frame) {
/* Print output-header */
printf("TCP Header:\n");
/* Print the destination Port */
printf(" |-Destination Port : %u\n",LITTLE2BIG16(frame->destination_port));
/* Print the source Port */
printf(" |-Source Port : %u\n",LITTLE2BIG16(frame->source_port));
/* Print the TCP header length */
printf(" |-TCP Header Length : %u Bytes\n",((frame->data_flags&0xF000)>>12)*4+16);
/* Print the contained flags */
printf(" |-Flags : ");
print_binary(frame->data_flags&0x003F,6);
printf("\n");
printf(" |-Urgent Flag : %d\n",((frame->data_flags&TCP_MASK_URG)>>TCP_OSET_URG));
printf(" |-ACK Flag : %d\n",((frame->data_flags&TCP_MASK_ACK)>>TCP_OSET_ACK));
printf(" |-Push Flag : %d\n",((frame->data_flags&TCP_MASK_PSH)>>TCP_OSET_PSH));
printf(" |-Reset Flag : %d\n",((frame->data_flags&TCP_MASK_RST)>>TCP_OSET_RST));
printf(" |-Synchronise Flag : %d\n",((frame->data_flags&TCP_MASK_SYN)>>TCP_OSET_SYN));
printf(" |-Finish Flag : %d\n",((frame->data_flags&TCP_MASK_FIN)>>TCP_OSET_FIN));
/* Print the window size */
printf(" |-Window Size : %u\n",LITTLE2BIG16(frame->window_size));
/* Print the transmitted checksum */
printf(" |-Checksum : 0x%04X\n",LITTLE2BIG16(frame->checksum));
/* A void function has nothing to return */
return;
}
/***** MAIN ROUTINE ***********************************************************/
int main (void) {
/*** Local Variables ***/
ETH_t *eth_frame;
IP_t *ip_frame;
TCP_t *tcp_frame;
/* Typecast the sample record on the ETH frame */
eth_frame = (ETH_t*)sample;
/* Extract the IP part from the ETH frame */
ip_frame = (IP_t*)eth_frame->data;
/* Extract the TCP part from the IP frame */
tcp_frame = (TCP_t*)ip_frame->data;
/* Print the information of all three frames */
eth_print(eth_frame);
ip_print(ip_frame);
tcp_print(tcp_frame);
/* Notify the user about the termination of the program */
printf("\nThe program will now be terminated...\n");
return 0; /* Return with Success (0) */
}
/******************************************************************************/
# Get the current path(s) (relevant directory on last position)
TASKPATH := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
CHPATH := $(dir $(TASKPATH:%/=%))
# Variables for text substitution
empty:=
slash:= /
space:= $(empty) $(empty)
task:= task_
ch:= ch_
# Get TASK number
TASK := $(subst $(slash),$(space),$(TASKPATH))
TASK := $(lastword $(TASK))
TASK := $(subst $(task),$(empty),$(TASK))
# Get CH number
CH := $(subst $(slash),$(space),$(CHPATH))
CH := $(lastword $(CH))
CH := $(subst $(ch),$(empty),$(CH))
# Specify SRD directory
SRCDIR = .
# Call superior makefile
include ../../makefile
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment