Using bitfields for parsing network packets - c

I have the thankless job of writing an IPv6 header parser.
I'm wondering if the version, traffic class and flow control labels could be parsed out using bitfields.
I wrote some test code. Executing on an x86 system I get unexpected results.
#include <stdint.h>
#include <stdio.h>
typedef struct __attribute__ ((__packed__)) {
uint32_t flow_label:20;
uint32_t traffic_class:8;
uint32_t ip_version:4;
} test_t;
int main(int argc, char **argv)
{
uint8_t data[] = { 0x60, 0x00, 0x00, 0x00 };
test_t *ipv6 = (void *)data;
printf("Size is %zu, version %u, traffic class %u, flow label %u\n", sizeof(test_t), ipv6->ip_version, ipv6->traffic_class, ipv6->flow_label);
}
I'd expect the first nibble to be available in ip_version, but it doesn't seem to be, instead I get:
Size is 4, version 0, traffic class 0, flow label 96
or with the field order inverted
Size is 4, version 0, traffic class 6, flow label 0
Can anyone explain why this happens?

With bitfields, it's implementation dependent how they are laid out. You're better off declaring a 32 bit field for the start of the packet and using bit shifting to extract the relevant fields.
uint8_t ipver = data[0] >> 4;
uint8_t tclass = ((data[0] & 0xf) << 4) | (data[1] >> 4);
uint32_t flowlbl = (((uint32_t)data[1] & 0xf) << 16) | ((uint32_t)data[2] << 8) | data[3];
Indeed, even the Linux netinet/ip6.h header doesn't use a bit field for the ipv6 header:
struct ip6_hdr
{
union
{
struct ip6_hdrctl
{
uint32_t ip6_un1_flow; /* 4 bits version, 8 bits TC,
20 bits flow-ID */
uint16_t ip6_un1_plen; /* payload length */
uint8_t ip6_un1_nxt; /* next header */
uint8_t ip6_un1_hlim; /* hop limit */
} ip6_un1;
uint8_t ip6_un2_vfc; /* 4 bits version, top 4 bits tclass */
} ip6_ctlun;
struct in6_addr ip6_src; /* source address */
struct in6_addr ip6_dst; /* destination address */
};

Related

Big endian byte array to small endian struct elements in C, arm

In my application microcontroller stm32f103 is receiving by USART fixed lenght messages, they contains gps velocity which is big endian data. But elements in structure are small endian. Is there any way without doing it manually to write it in correct way?
typedef struct {
uint32_t test1;
uint16_t test2;
}Mst;
uint8_t myArray[6] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 };
void main()
{
Mst * myStruct_p = (Mst)myArray;
}
But after that myStruct_p->test1 equals 0x030201, but should be 0x010203, and myStruct_p->test2 equals 0x0605, but should be 0x0506.
As it is ARM-Cortex M3 we can use special processor instructions. ARM CMSIS have a very handy intrinsic functions __REV & __REV16 which actually compile to the single machine code instruction.
typedef union
{
struct
{
uint32_t test1;
uint16_t test2;
};
uint8_t bytes[6];
}Mst;
Mst mst = {.bytes = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 }};
void main()
{
mst.test1 = __REV(mst.test1);
mst.test2 = __REV16(mst.test2);
}
Casting in that way won't work.
You can do a "deserialize" operation.
Although this might be slower than some other methods, it allows you to control the protocol better (e.g. the struct member order doesn't have to follow the protocol) And, there might be padding in the struct, which would show up if we added (e.g.) uint32_t test3; to the end of the struct.
Here's the code:
#include <stdio.h>
#include <stdint.h>
typedef struct {
uint32_t test1;
uint16_t test2;
} Mst;
uint8_t myArray[6] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 };
uint32_t
get32(uint8_t **base)
{
uint8_t *ptr;
uint32_t val = 0;
ptr = *base;
for (int len = sizeof(uint32_t); len > 0; --len) {
val <<= 8;
val |= *ptr++;
}
*base = ptr;
return val;
}
uint16_t
get16(uint8_t **base)
{
uint8_t *ptr;
uint16_t val = 0;
ptr = *base;
for (int len = sizeof(uint16_t); len > 0; --len) {
val <<= 8;
val |= *ptr++;
}
*base = ptr;
return val;
}
int
main(void)
{
Mst myS;
uint8_t *arr = myArray;
myS.test1 = get32(&arr);
myS.test2 = get16(&arr);
printf("test1=%8.8X test2=%4.4X\n",myS.test1,myS.test2);
return 0;
}
UPDATE:
Yes guys that will work but, i would like to use the processor as little as possible. This is rather manualy putting bytes in to correct order. Also Procedure Mst * struct_p = (Mst*)myArray works safe, because while defining struct i use __attribute__((packed)), just forgoten to write this
I was going to mention/suggest packed as a possibility.
In either case you can use [under GNU]: byteswap.h to get bswap_*. Endian swapping is quite common, so these are [highly] optimized for the given arch. They can even invoke compiler intrinsics (e.g. __builtin_bswap32) which utilize any special instructions the arch has (e.g. x86 has the bswap instruction, and arm has rev16).
So, you can do [i.e. replace the for loop with] (e.g.) bswap_*:
#include <stdio.h>
#include <stdint.h>
#include <byteswap.h>
typedef struct {
uint32_t test1;
uint16_t test2;
uint32_t test3;
} __attribute__((__packed__)) Mst;
uint8_t myArray[] = {
0x01, 0x02, 0x03, 0x04,
0x05, 0x06,
0x07, 0x08, 0x09, 0x0A
};
void
getall(Mst *myS)
{
myS->test1 = bswap_32(myS->test1);
myS->test2 = bswap_16(myS->test2);
myS->test3 = bswap_32(myS->test3);
}
int
main(void)
{
Mst *myS = (Mst *) myArray;
getall(myS);
printf("test1=%8.8X test2=%4.4X test3=%8.8X\n",
myS->test1,myS->test2,myS->test3);
return 0;
}
Overlaying a struct pointer onto a byte array may not necessarily work due to alignment issues and structure padding.
The proper way would be to first use memcpy to copy over the elements:
Mst myStruct;
memcpy(&myStruct.test1, myArray, sizeof(myStruct.test1);
memcpy(&myStruct.test2, myArray + 4, sizeof(myStruct.test2);
Then use ntohs and ntohl which converts 16 and 32 bit values respectively from big endian format to the host's endianness.
myStruct.test1 = ntohl(myStruct.test1);
myStruct.test2 = ntohs(myStruct.test2);
If you just need to convert 8bit data into big endian let say data format will be in order (A B C D) and in little endian data format will be (D C B A) if final result will be stored in 32bit variable and if 16 bit variable then format will (A B) and (B A) .
So this can be done with little bit shifting technique if you know your UART data comming in which format.
Let us first assume that your UART data comes in Little endian and you want it in big endian then you can do like this.
//no structure required
uint32_t myValue;
uint16_t value;
uint8_t myArray[4] = { 0x04, 0x03, 0x02, 0x01 };
// little endian data for 32 bit
uint8_t A[2] = {0x02 ,0x01}; // little endian data for 16 bit
void main()
{
myValue = myArray[3]<<24 | myArray[2]<<16 | myArray[1]<<8 | myArray[0]; // result in big endian 32 bit value
value = A[1]<<8 | A[0]; // result in big endian 16bit value
}

How to create bitfield out of existing variables in C

I am working on a Motorola HCS08 µCU in CodeWarrior V10.6, I am trying to create an extern bitfield which has bits from existing registers. The way the bitfields are created in the µCU header is like
typedef unsigned char byte;
typedef union {
byte Byte;
struct {
byte PTAD0 :1;
byte PTAD1 :1;
byte PTAD2 :1;
byte PTAD3 :1;
byte PTAD4 :1;
byte PTAD5 :1;
byte PTAD6 :1;
byte PTAD7 :1;
} Bits;
} PTADSTR;
extern volatile PTADSTR _PTAD #0x00000000;
#define PTAD _PTAD.Byte
#define PTAD_PTAD0 _PTAD.Bits.PTAD0
#define PTAD_PTAD1 _PTAD.Bits.PTAD1
#define PTAD_PTAD2 _PTAD.Bits.PTAD2
#define PTAD_PTAD3 _PTAD.Bits.PTAD3
#define PTAD_PTAD4 _PTAD.Bits.PTAD4
#define PTAD_PTAD5 _PTAD.Bits.PTAD5
#define PTAD_PTAD6 _PTAD.Bits.PTAD6
#define PTAD_PTAD7 _PTAD.Bits.PTAD7
Which will let the register value be changed either by PTAD = 0x01, or PTAD_PTAD0 = 1, for example. This definition is basically the same for PTAD, PTBD, PTCD, ... PTGD, the only thing changing is the address.
My attemp to create a custom bitfield out of the previous existing variables is
typedef union {
byte Byte;
struct {
byte *DB0;
byte *DB1;
byte *DB2;
byte *DB3;
byte *DB4;
byte *DB5;
byte *DB6;
byte *DB7;
} Bits;
} LCDDSTR;
I would create and initialize the bitfield as LCDDSTR lcd = {{&PTGD_PTGD6, &PTBD_PTBD5, ...}}, because by some reason, the initialization like LCDSTR lcd = {*.Bits.DB0 = &PTGD_PTGD6, *.Bits.DB1 = &PTBD_PTBD5, ...} (treating it as a struct, please correct me again) advice in How to initialize a struct in accordance with C programming language standards does not work with this compiler (it does work on an online compiler).
However, as you may see I am sort of grouping the bits, and (if it would work) I would be able to change the values of the actual register by doing *lcd.Bits.DB0 = 1, or something like that, but if I do lcd.Byte = 0x00, I would be changing the last (I think) byte of the memory address contained in lcd.Bits.DB0, you know, because the struct doesn't actually contains the data, but the pointers instead.
How would I go on achieving a struct that is able to contain and modify bits from several registers? (I guess the problem here is that in memory the bits are not one next to the other, which I guess would make it easier). Is it even possible? I hope it is.
How would I go on achieving a struct that is able to contain and modify bits from several registers? (I guess the problem here is that in memory the bits are not one next to the other..
I don't think you can do it with a struct. That is because bitfields by definition have to occupy the same or contiguous addresses.
However macros may be useful here
#define DB0 PTGD_PTGD6
#define DB1 PTBD_PTBD5
....
And to clear the bits to all 0's or set to all 1's you can use a multiline macro
#define SET_DB(x) do { \
PTGD_PTGD6 = x; \
PTBD_PTBD5 = x; \
...... \
} while(0)
How would I go on achieving a struct that is able to contain and modify bits from several registers?
You can't.
A structure must represent a single, continuous block of memory -- otherwise, operations like taking the sizeof the structure, or performing operations on a pointer to one would make no sense.
If you want to permute the bits of a value, you will need to find some way of doing so explicitly. If the order of your bits is relatively simple, this may be possible with a few bitwise operations; if it's weirder, you may need to use a lookup table.
Beyond that: bitfields in C are pretty limited. The language does not make a lot of guarantees about how a structure containing bitfields will end up laid out in memory; they are generally best avoided for portable code. (Which doesn't apply here, as you're writing code for a specific compiler/microcontroller combination, but it's worth keeping in mind in general.)
Your union does unfortunately not make any sense, because it forms a union of one byte and 8 byte*. Since a pointer is 16 bit on HCS08, this ends up as 8*2 = 16 bytes of data, which can't be used in any meaningful way.
Please note that the C structure called bit-fields is very poorly specified by the standard and therefore should be avoided in any program. See this.
Please note that the Codewarrior register maps aren't remotely close to following the C standard (nor MISRA-C).
Please note that structs in general are problematic for hardware register mapping, since structs can contain padding. You don't have that problem on HCS08 specifically, since it doesn't require alignment of data. But most MCUs do require that.
It is therefore better to roll out your own register map in standard C if you have that option. The port A data register could simply be defined like this:
#define PTAD (*(volatile uint8_t*)0x0000U)
#define PTAD7 (1U << 7)
#define PTAD6 (1U << 6)
#define PTAD5 (1U << 5)
#define PTAD4 (1U << 4)
#define PTAD3 (1U << 3)
#define PTAD2 (1U << 2)
#define PTAD1 (1U << 1)
#define PTAD0 (1U << 0)
As we can tell, defining the bit masks is mostly superfluous anyway, as PTAD |= 1 << 7; is equally readable to PTAD |= PTAD7;. This is because this was a pure I/O port. Defining textual bit masks for status and control registers on the other hand, increases the readability of the code significantly.
If you want to modify bits from several registers, you'd do something like the following:
Assume we have a RGB (red-green-blue) LED, common cathode, with 3 colors connected to 3 different pins on 3 different ports. Instead of beating up the PCB designer, you could do this:
#define RGB_RED_PTD PTAD
#define RGB_RED_PTDD PTADD
...
#define RGB_BLUE_PTD PTBD
#define RGB_BLUE_PTDD PTBDD
...
#define RGB_GREEN_PTD PTDD
#define RGB_GREEN PTDD PTDDD
#define RGB_RED_PIN 1
#define RGB_BLUE_PIN 5
#define RGB_GREEN_PIN 3
You can now set these independently of where they happen to be located on the hardware:
void rgb_init (void)
{
RGB_RED_PTDD |= (1 << RGB_RED_PIN);
RGB_BLUE_PTDD |= (1 << RGB_BLUE_PIN);
RGB_GREEN_PTDD |= (1 << RGB_GREEN_PIN);
}
void rgb_yellow (void)
{
RGB_RED_PTD |= (1 << RGB_RED_PIN);
RGB_BLUE_PTD &= ~(1 << RGB_BLUE_PIN);
RGB_GREEN_PTD |= (1 << RGB_GREEN_PIN);
}
And so on. Examples were for HCS08 but the same can of course be used universally on any MCU with direct port I/O.
It sounds like an approach such as the following is along the lines of where you would like to go with a solution.
I have not tested this as I do not have the hardware however this should provide an alternative to look at.
This assumes that you want to turn on particular pins or turn off particular pins but there will not be a case where you will want to turn on some pins and turn off other pins for a particular device in a single operation. If that should be the case I would consider making the type of RegPinNo be an unsigned short to include an op code for each register/pin number combination.
This also assumes that timing of operations is not a critical constraint and that the hardware has sufficient horsepower such that small loops are not much of a burden on throughput and hogging CPU time needed for other things. So this code may need changes to improve optimization if that is a consideration.
I assume that you want some kind of a easily readable way of expressing a command that will turn on and off a series of bits scattered across several areas of memory.
The first thing is to come up with a representation of what such a command would look like and it seems to me that borrowing from a char array to represent a string would suffice.
typedef byte RegPinNo; // upper nibble indicates register number 0 - 7, lower nibble indicates pin number 0 - 7
const byte REGPINNOEOS = 0xff; // the end of string for a RegPinNo array.
And these would be used to define an array of register/pin numbers as in the following.
RegPinNo myLed[] = { 0x01, 0x12, REGPINNOEOS }; // LED is addressed through Register 0, Pin 0 and Register 1, Pin 1 (zero based)
So at this point we have a way to describe that a particular device, an LED in this case, is addressed through a series of register/pin number items.
Next lets create a small library of functions that will use this representation to actually modify the specific pins in specific registers by traversing this array of register/pin numbers and performing an operation on it such as setting the bit in the register or clearing the bit in the register.
typedef unsigned char byte;
typedef union {
byte Byte;
struct {
byte PTAD0 : 1;
byte PTAD1 : 1;
byte PTAD2 : 1;
byte PTAD3 : 1;
byte PTAD4 : 1;
byte PTAD5 : 1;
byte PTAD6 : 1;
byte PTAD7 : 1;
} Bits;
} PTADSTR;
// Define a pointer to the beginning of the register area. This area is composed of
// 8 different registers each of which is one byte in size.
// We will address these registers as Register 0, Register 1, ... Register 7 which just happens
// to be how C does its zero based indexing.
// The bits representing pins on the PCB we will address as Pin 0, Pin 1, ... Pin 7.
extern volatile PTADSTR (* const _PTAD) = 0x00000000;
void SetRegPins(RegPinNo *x)
{
byte pins[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
int i;
for (i = 0; x[i] != REGPINNOEOS; i++) {
byte bRegNo = (x[i] >> 4) & 0x07; // get the register number, 0 - 7
byte bPinNo = x[i] & 0x07; // get the pin number, 0 - 7
_PTAD[bRegNo].Byte |= pins[bPinNo];
}
}
void ClearRegPins(RegPinNo *x)
{
byte pins[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
int i;
for (i = 0; x[i] != REGPINNOEOS; i++) {
byte bRegNo = (x[i] >> 4) & 0x07; // get the register number, 0 - 7
byte bPinNo = x[i] & 0x07; // get the pin number, 0 - 7
_PTAD[bRegNo].Byte &= ~pins[bPinNo];
}
}
void ToggleRegPins(RegPinNo *x)
{
byte pins[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
int i;
for (i = 0; x[i] != REGPINNOEOS; i++) {
byte bRegNo = (x[i] >> 4) & 0x07; // get the register number, 0 - 7
byte bPinNo = x[i] & 0x07; // get the pin number, 0 - 7
_PTAD[bRegNo].Byte ^= pins[bPinNo];
}
}
You would use the above something like the following. Not sure what a time delay function would look like in your environment so I am using a function Sleep() which takes an argument as to the number of milliseconds to delay or sleep.
void LightLed (int nMilliSeconds)
{
RegPinNo myLed[] = { 0x01, 0x12, REGPINNOEOS }; // LED is addressed through Register 0, Pin 0 and Register 1, Pin 1 (zero based)
SetRegPins(myLed); // turn on the LED
Sleep(nMilliSeconds); // delay for a time with the LED lit
ClearRegPins(myLed); // turn the LED back off
}
Edit - A Refinement
A more efficient implementation that would allow multiple pins to be set in a particular register at the same time would be to define the use of RegPinNo as being an unsigned short` with the upper byte being the register number and the lower byte being the pins to manipulate as a bit mask for the byte.
With this approach you would have a SetRegPins() function that would look like the following. A similar change would be needed for the other functions.
void SetRegPins(RegPinNo *x)
{
int i;
for (i = 0; x[i] != REGPINNOEOS; i++) {
byte bRegNo = (x[i] >> 8) & 0x07; // get the register number, 0 - 7
byte bPinNo = x[i] & 0xFF; // get the pin mask
_PTAD[bRegNo].Byte |= bPinNo;
}
}
And the typedefs would look like:
typedef unsigned short RegPinNo; // upper byte indicates register number 0 - 7, lower byte provides pin mask
const byte REGPINNOEOS = 0xffff; // the end of string for a RegPinNo array.
And these elements would be used like:
void LightLed (int nMilliSeconds)
{
RegPinNo myLed[] = { 0x0002, 0x0103, REGPINNOEOS }; // LED is addressed through Register 0, Pin 1 and Register 1, Pin 0 and Pin 1 (zero based)
SetRegPins(myLed); // turn on the LED
Sleep(nMilliSeconds); // delay for a time with the LED lit
ClearRegPins(myLed); // turn the LED back off
}

arm cortex m0 nf51822 c programing hard fault, really puzzled

I was trying to transform a char type buffer into a struct defined by me in order to analyze the buffer by TLV. But i jumped into hard fault again and again.
codes are these: a little bit long.
#define BigtoLittle32(A) ((( (uint32_t)(A) & 0xff000000) >> 24) | \
(( (uint32_t)(A) & 0x00ff0000) >> 8) | \
(( (uint32_t)(A) & 0x0000ff00) << 8) | \
(( (uint32_t)(A) & 0x000000ff) << 24))
enum {
DISH = 0
} CB_DISH_TLV_TYPES;
typedef struct cb_tlv_node_s
{
uint32_t type;
uint32_t length;
char value[0];
} cb_tlv_node_t;
typedef struct cb_ble_buffer_s {
uint16_t total_length;
uint16_t current_length;
int8_t current_data_id;
int8_t expect_package_id;
char buffer[500];
} cb_ble_buffer_t;
static cb_ble_buffer_t current_buffer;
cb_tlv_node_t *
cb_tlv_read(char *buffer)
{
uint32_t a,b,c,d;
cb_tlv_node_t * tlv_p;
tlv_p = (cb_tlv_node_t *)buffer;
/* tlv_p->length = BigtoLittle32(tlv_p->length);*/ //this code also cause hard fault
/* tlv_p->type = BigtoLittle32(tlv_p->type);*/ //didn't test this one ,but high risk causing hard fault
return tlv_p;
}
//ble packages are reorgnized and call this function. it excutes in the ble recieve interupt
int
cb_dish_data_processer(char * data, int length)
{
assert(data != NULL);
assert(length > 0);
cb_tlv_node_t *tlv_p = cb_tlv_read(data);
//test
int a = sizeof(CB_DISH_TLV_TYPES);
//if ((char)tlv_p->type != DISH) { //this code is fine and steady
if (tlv_p->type != DISH) { //this leads to hard fault
return CB_PC_CODE_UNRECOGNIZE;
}
cb_dish_tlv_read(tlv_p->value, tlv_p->length);
return CB_PC_CODE_PROCESSED;
}
Fist I am sure that pointers are not lost ,so there should not be any kind if illegal address been used;
Second I assume my process is too long to be in an interrupt so I moved my codes out side and excite in the main loop, but still useless;
So I am stucked here, I can't find any reason causing this.
if you need more info ,leave a message, I will be waiting online.
ps:the hardware board is Nordic nf51822 with 8kB RAM, 256kB flash ROM
BTW:Is it true that calloc and other alloc functions are forbidden in this kind of boards?
because when I try to alloc a new space dynamically, the board goes wrong and reset it self.
Thanks a lot
One thing that looks suspicious is that you convert char* buffer to (cb_tlv_node_t *) and try to use it. ARM requires that 32-bit integers are correctly aligned to 4-byte boundaries when accesing them. It is likely that buffer pointed by char *buffer is aligned to 1-byte boundaries. by user694733
so i changed this
typedef struct cb_ble_buffer_s {
uint16_t total_length;
uint16_t current_length;
int8_t current_data_id;
int8_t expect_package_id;
char buffer[500];
} cb_ble_buffer_t;
into this
typedef struct cb_ble_buffer_s {
uint16_t total_length;
uint16_t current_length;
int16_t current_data_id;
int16_t expect_package_id;
char buffer[500];
} cb_ble_buffer_t;
and it just works fine and steady
many thanks to #user694733

MSP430 - Mixing Ports Registers inside an struct

I am now doing a program for a MSP430 in C and I am using Port 1.6, 1.7, 2.0, 2.1, and 2.2 to drive some LEDs. Now, in order to turn ON all LEDs I simply have to write:
P1OUT |= 0xC0;
P2OUT |= 0x07;
However, I would like to know if is possible to create an C structure (with the name LED_ACTIVATION) that points to bits 0, 1, and 2 of the P2OUT Register (0x0029) and to bits 6 and 7 from P1OUT Register (0x0021), that will allow me to write something like this:
LED_ACTIVATION = 0x2F;
where port 2.2 is the most significant bit (bit 5) and port 1.6 is the lowest significant bit(bit 0).
In the MSP we can do this assignment for each register like this:
__no_init volatile union
{
unsigned char P1OUT; /* Port 1 Output */
struct
{
unsigned char P0 : 1; /* */
unsigned char P1 : 1; /* */
unsigned char P2 : 1; /* */
unsigned char P3 : 1; /* */
unsigned char P4 : 1; /* */
unsigned char P5 : 1; /* */
unsigned char P6 : 1; /* */
unsigned char P7 : 1; /* */
}P1OUT_bit;
} #0x0021;
or like this:
#define P1OUT_ (0x0021u) /* Port 1 Output */
DEFC( P1OUT , P1OUT_)
But is it possible to mix both register address?
Thanks.
The MSP430 is not bit/pin addressable. So, no, you can't create a structure that contains individual pins from multiple ports.
In order to make:
LED_ACTIVATION = 0x2F;
You would need to use a function or a macro.
See also: Accessing individual I/O pin on MSP430

Error in packet parsing

i trying to parse a packet. till the ip header everything is fine(i'm able to retrieve all the values correctly). but for the udp header( checked if the protocol is 17) , the values are coming out to be wrong( all the 4 fields).
I'm trying to do this:
struct udp_header{
uint16_t sport;
uint16_t dport;
uint16_t len;
uint16_t chksum;
};
struct udp_header* udp= (struct udp_header*)(packet + 14 + ip_hdr->ip_hl*4);
Packet is the pointer pointing to the beginning of the packet. 14 is for ethernet header.The header length ip when checked is giving out the correct value. But after performing this operation i'm getting all the fields wrongly. when tried with uint8_t as data type( i know its wrong! ) the destintion port somehow is coming out correct.
You have run into endianness. IP packets have all fields in network byte order (aka "big-endian"), and your host system probably runs little-endian. Look into ntohs() and friends for one approach.
The proper approach is to not copy the structure as-is from the network data, but instead extract each field manually and byte-swap it if necessary. This also works around any issues with padding and alignment, there's no guarantee that your struct is mapped into your computer's memory in exactly the same way as the packet is serialized.
So you would do e.g.:
udp_header.sport = ntohs(*(unsigned short*) (packet + 14 + 4 * ip_hdr->ip_hl));
This is also a bit iffy, since it assumes the resulting address can validly be cast into a pointer to unsigned short. On x86 that will work, but it's not epic.
Even better, in my opinion, is to drop the use of pointers and instead write a function called e.g. unsigned short read_u16(void *packet, size_t offset) that extracts the value byte-by-byte and returns it. Then you'd just do:
udp_header.sport = read_u16(packet, 14 + 4 * ip_hdr->ip_hl);
I always use this struct for IP header:
struct sniff_ip {
u_char ip_vhl; /* version << 4 | header length >> 2 */
u_char ip_tos; /* type of service */
u_short ip_len; /* total length */
u_short ip_id; /* identification */
u_short ip_off; /* fragment offset field */
#define IP_RF 0x8000 /* reserved fragment flag */
#define IP_DF 0x4000 /* dont fragment flag */
#define IP_MF 0x2000 /* more fragments flag */
#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
u_char ip_ttl; /* time to live */
u_char ip_p; /* protocol */
u_short ip_sum; /* checksum */
struct in_addr ip_src,ip_dst; /* source and dest address */
};
#define IP_HL(ip) (((ip)->ip_vhl) & 0x0f)
#define IP_V(ip) (((ip)->ip_vhl) >> 4)
And to get the UDP struct pointer:
udp = (struct sniff_udp*)(packet + SIZE_ETHERNET + (IP_HL(ip)*4));
As another answer remarked, you have to deal with endianness of your data.
The other thing you need to deal with is byte alignment. For speed, when you define a structure in C like this:
struct udp_header{
uint16_t sport;
uint16_t dport;
uint16_t len;
uint16_t chksum;
};
The C compiler may leave padding bytes between these fields so that member accesses can be done with faster single-instruction memory access assembly instructions. You can check if your c compiler is doing this by printf("struct size is: %u\n", sizeof(struct udp_header));
Assuming you are using GCC, you must disable padding bytes by adding #pragma pack(1) before the structure definition. To re-enable padding for speed you should then use #pragma pack().

Resources