C structure alignment and network protocol headers - c

Solaris 10 SPARC
Sun Studio C compiler 12.3
On SPARC64 machines if you access a variable which isn't correctly aligned on the relevant 4 or 8 byte boundary, you will get a core dump. This requires the coder to jump through a few hoops to cope with this requirement, (but also makes you write portable code too).
If we have a C structure which models a network protocol header, (i.e. these 16 bits are a port, these 8 bits are the flags etc), if we then use alignment directives to suit a SPARC64 processor, will this still retain the byte mapping, or will everything break. Is there logic hiding the implementation of the byte storage from the layout of the struct.
typedef struct TCPHdr_
{
uint16_t th_sport; /**< source port */
uint16_t th_dport; /**< destination port */
uint32_t th_seq; /**< sequence number */
uint32_t th_ack; /**< acknowledgement number */
uint8_t th_offx2; /**< offset and reserved */
uint8_t th_flags; /**< pkt flags */
uint16_t th_win; /**< pkt window */
uint16_t th_sum; /**< checksum */
uint16_t th_urp; /**< urgent pointer */
} TCPHdr;
gets aligned like this:
typedef struct TCPHdr_
{
uint16_t th_sport __attribute__((aligned(8))); /**< source port */
uint16_t th_dport __attribute__((aligned(8))); /**< destination port */
uint32_t th_seq __attribute__((aligned(8))); /**< sequence number */
uint32_t th_ack __attribute__((aligned(8))); /**< acknowledgement number */
uint8_t th_offx2 __attribute__((aligned(8))); /**< offset and reserved */
uint8_t th_flags __attribute__((aligned(8))); /**< pkt flags */
uint16_t th_win __attribute__((aligned(8))); /**< pkt window */
uint16_t th_sum __attribute__((aligned(8))); /**< checksum */
uint16_t th_urp __attribute__((aligned(8))); /**< urgent pointer */
} TCPHdr;
Mostly it's a query about code like this:
SET_PKT_LEN(p, sizeof(IPV6Hdr) + sizeof(TCPHdr) + payload_len);
and
p1->tcph = (TCPHdr *)raw_tcp;
where the raw bytes are converted to the struct or a sizeof() tests the size of the struct. Will it still work or will the new struct not be able to map the network bytes?

You can cast an unaligned structure to its aligned version but data would be wrong. You need to put data to the right positions in memory manually. E.g. a function *unaligned_to_aligned* can copy data field by field. It can use unions to avoid core dumps.
When working with raw data from the network, take into account endianness. Network protocols and your platform can have different representation of numbers in memory and you may have to change the order of bytes in *int*s, *short*s etc.

For the record, here's the structs I'm using:
typedef struct TCPHdr_raw_ {
union {
uint16_t th_sport; /**< source port */
uint8_t th_sport8[2]; /**< source port */
} sport;
union {
uint16_t th_dport; /**< destination port */
uint8_t th_dport8[2]; /**< destination port */
} dport;
union {
uint32_t th_seq; /**< sequence number */
uint8_t th_seq8[4]; /**< sequence number */
} seq;
union {
uint32_t th_ack; /**< acknowledgement number */
uint8_t th_ack8[4]; /**< acknowledgement number */
} ack;
uint8_t th_offx2; /**< offset and reserved */
uint8_t th_flags; /**< pkt flags */
union {
uint16_t th_win; /**< pkt window */
uint8_t th_win8[2]; /**< pkt window */
} win;
union {
uint16_t th_sum; /**< checksum */
uint8_t th_sum8[2]; /**< checksum */
} sum;
union {
uint16_t th_urp; /**< urgent pointer */
uint8_t th_urp8[2]; /**< urgent pointer */
} urp;
} TCPHdr_raw;
typedef struct TCPHdr_
{
uint16_t th_sport __attribute__((aligned(8))); /**< source port */
uint16_t th_dport __attribute__((aligned(8))); /**< destination port */
uint32_t th_seq __attribute__((aligned(8))); /**< sequence number */
uint32_t th_ack __attribute__((aligned(8))); /**< acknowledgement number */
uint8_t th_offx2 __attribute__((aligned(8))); /**< offset and reserved */
uint8_t th_flags __attribute__((aligned(8))); /**< pkt flags */
uint16_t th_win __attribute__((aligned(8))); /**< pkt window */
uint16_t th_sum __attribute__((aligned(8))); /**< checksum */
uint16_t th_urp __attribute__((aligned(8))); /**< urgent pointer */
} TCPHdr;
and routines like this:
copy_raw_tcp_header(&(p->tcph), &tcph);
void copy_raw_tcp_header(TCPHdr *tcph, uint8_t *pktdata) {
TCPHdr_raw *raw_tcp_hdr = (TCPHdr_raw *)pktdata;
memcpy(&tcph->sport, &raw_tcp_hdr->sport.th_sport8, sizeof(uint16_t));
memcpy(&tcph->dport, &raw_tcp_hdr->dport.th_dport8, sizeof(uint16_t));
memcpy(&tcph->seq, &raw_tcp_hdr->seq.th_seq8, sizeof(uint32_t));
memcpy(&tcph->ack, &raw_tcp_hdr->ack.th_ack8, sizeof(uint32_t));
tcph->th_offx2 = raw_tcp_hdr->th_offx2;
tcph->th_flags = raw_tcp_hdr->th_flags;
memcpy(&tcph->th_win, &raw_tcp_hdr->win.th_win8, sizeof(uint16_t));
memcpy(&tcph->th_sum, &raw_tcp_hdr->sum.th_sum8, sizeof(uint16_t));
memcpy(&tcph->th_urp, &raw_tcp_hdr->urp.th_urp8, sizeof(uint16_t));
}
replace previous code like this:
p->tcph = &tcph;

Related

if I have populated all fields of iphdr then how to calculate the tcphdr->doff and iphdr->ihl | tcp data offset and length of ip header

On my system in /usr/include/netinet/iphdr this is the struct iphdr looks like
struct iphdr
{
#if __BYTE_ORDER == __LITTLE_ENDIAN
unsigned int ihl:4;
unsigned int version:4;
#elif __BYTE_ORDER == __BIG_ENDIAN
unsigned int version:4;
unsigned int ihl:4;
#else
# error "Please fix <bits/endian.h>"
#endif
uint8_t tos;
uint16_t tot_len;
uint16_t id;
uint16_t frag_off;
uint8_t ttl;
uint8_t protocol;
uint16_t check;
uint32_t saddr;
uint32_t daddr;
/*The options start here. */
};
Assume I have crafted all the ip header fields with values. Now I want to calculate ip header length which is iphdr->ihl field on my system. I am assuming this is ip header length, so the length of my made ip header can't be sizeof(struct iphdr) then what that might be.
Also the struct tcphdr looks like this
struct tcphdr
{
__extension__ union
{
struct
{
uint16_t th_sport; /* source port */
uint16_t th_dport; /* destination port */
tcp_seq th_seq; /* sequence number */
tcp_seq th_ack; /* acknowledgement number */
# if __BYTE_ORDER == __LITTLE_ENDIAN
uint8_t th_x2:4; /* (unused) */
uint8_t th_off:4; /* data offset */
# endif
# if __BYTE_ORDER == __BIG_ENDIAN
uint8_t th_off:4; /* data offset */
uint8_t th_x2:4; /* (unused) */
# endif
uint8_t th_flags;
# define TH_FIN 0x01
# define TH_SYN 0x02
# define TH_RST 0x04
# define TH_PUSH 0x08
# define TH_ACK 0x10
# define TH_URG 0x20
uint16_t th_win; /* window */
uint16_t th_sum; /* checksum */
uint16_t th_urp; /* urgent pointer */
};
struct
{
uint16_t source;
uint16_t dest;
uint32_t seq;
uint32_t ack_seq;
# if __BYTE_ORDER == __LITTLE_ENDIAN
uint16_t res1:4;
uint16_t doff:4;
uint16_t fin:1;
uint16_t syn:1;
uint16_t rst:1;
uint16_t psh:1;
uint16_t ack:1;
uint16_t urg:1;
uint16_t res2:2;
# elif __BYTE_ORDER == __BIG_ENDIAN
uint16_t doff:4;
uint16_t res1:4;
uint16_t res2:2;
uint16_t urg:1;
uint16_t ack:1;
uint16_t psh:1;
uint16_t rst:1;
uint16_t syn:1;
uint16_t fin:1;
# else
# error "Adjust your <bits/endian.h> defines"
# endif
uint16_t window;
uint16_t check;
uint16_t urg_ptr;
};
};
};
so assume again that I have populated all the field of tcphdr with values now I want doff(data offset). how to calculate it
struct iphdr *iph=buffer;
// populate the fields of iph
//but what is iph->ihl? to calculate how?
int iphdrlen = iph->ihl*4;
struct tcphdr *tcph=(struct tcphdr *)(buffer + iphdrlen);
//populate all the fields of tcph
//but also how to calculate tcph->doff
should it be like for iphdr->ihl
//after populating all the fields of iph then just do following to get iph->ihl
iph->ihl=sizeof(iph);
and should it be like for tcph->doff
//after populating all the fields of tcph just do following
tcph->doff = (unsigned int)(sizeof(iph))+sizeof(tcph)));
and that will work, so will it?
IP header has two "parts" - a mandatory fixed sized part, which is represented by struct iphdr and the latter is represented by options that optionally can be present (see the comment /*The options start here. */). The header length is the whole header length with options. So, unless you have actually added some options it is only the length of the header, which you can either calculate or read in the standard:
IHL: 4 bits
Internet Header Length is the length of the internet header in 32
bit words, and thus points to the beginning of the data. Note that
the minimum value for a correct header is 5.
Now, one byte is 4 bits, and 32 bits are 4 words. Thus it is either sizeof(struct iphdr)/4 or you can set it to 5.
TCP data offset is basically the same, but for TCP. Since TCP header can also contain options, the same logic applies. According to the standard (scroll to next page):
Data Offset: 4 bits
The number of 32 bit words in the TCP Header. This indicates where
the data begins. The TCP header (even one including options) is an
integral number of 32 bits long.
So, basically it is calculated the same way. It is not a pointer, it is a number which indicates length of the header. According to wikipedia if your header has no options, the value of this field is also 5.

Accessing a nested structure

I have a nested structure like below:
struct stm32fxxx_state {
struct stm32fxxx_gpio_state {
union {
uint32_t regs[10];
struct {
uint32_t MODER;
uint32_t OTYPER;
uint32_t OSPEEDR;
uint32_t PUPDR;
uint32_t IDR;
uint32_t ODR;
uint32_t BSRR;
uint32_t LCKR;
uint32_t AFRL;
uint32_t AFRH;
};
};
} GPIO[STM32FXXX_NUM_GPIOS];
struct stm32fxxx_spi_regs {
union {
uint16_t regs[9];
struct {
uint16_t CR1;
uint16_t CR2;
uint16_t SR;
uint16_t DR;
uint16_t CRCPR;
uint16_t RXCRCR;
uint16_t TXCRCR;
uint16_t I2SCFGR;
uint16_t I2SPR;
};
};
} SPI[STM32FXXX_NUM_SPIS];
uint32_t PWR_CR;
uint32_t PWR_CSR;
};
This structure has been instantiated in the main function in a structure as below:
struct stm32fxxx_gpio {
SysBusDevice parent;
MemoryRegion mmio;
qemu_irq irq;
uint8_t port_id, _port_id;
struct stm32fxxx_state *state;
struct stm32fxxx_gpio_state *gregs;
};
Somewhere further in the code, the structure is accessed as follows:
uint32_t valx = val ^ self->state->GPIO[self->port_id].MODER;
and
uint32_t valx = val ^ self->gregs->OTYPER;
Where self is declared as struct stm32fxxx_gpio *self
My question is: how is self->state different from self->gregs? How are these two access to the structure is different.
The code is compiled and runs fine. I want to know how these two access return different data? Or what is the use of such nested structures?
I understand state contains the gpio_state attributes as well. But state structure does not have attributes different from gpio_state structure, then why do we need structures in this case?
self->state and self->regs are 2 different pointers. The code probably initializes these fields to point to parts of the same structure.
You try to reinvent the wheel and you did it wrong.
you have defined structures with the hardware registers.
Your declarations are not "generic" as many families have different registers. For example F3xx has additional BRR register.
Order of the registers is wrong.
Some peripherals have unused space between the registers. For example
typedef struct
{
__IO uint32_t ACR; /*!< FLASH access control register, Address offset: 0x00 */
__IO uint32_t KEYR; /*!< FLASH key register, Address offset: 0x04 */
__IO uint32_t OPTKEYR; /*!< FLASH option key register, Address offset: 0x08 */
__IO uint32_t SR; /*!< FLASH status register, Address offset: 0x0C */
__IO uint32_t CR; /*!< FLASH control register, Address offset: 0x10 */
__IO uint32_t AR; /*!< FLASH address register, Address offset: 0x14 */
uint32_t RESERVED; /*!< Reserved, 0x18 */
__IO uint32_t OBR; /*!< FLASH Option byte register, Address offset: 0x1C */
__IO uint32_t WRPR; /*!< FLASH Write register, Address offset: 0x20 */
} FLASH_TypeDef;
If your idea is to save registers in the RAM it is enough to
GPIO_TypeDef savedGPIOs[NUMBER_OF_GPIOS];
and
savedGPIOs[0] = *GPIOA;
but I do not see too much sense in it.

cast multiple structs to a char string

this is my first time posting on stack overflow so be gentle. I am writing a networking program in c to run on linux machines. The goal of my program is to be able to capture packets sent to it, change the source ip and hw address, rebuild the packet with the new info and send it back out onto the wire. My question relates to the rebuilding process. I have some structs that I am using to hold information about various headers in my programs. Detailed here
struct my_ip
{
u_int8_t ip_vhl; /* header length, version */
#define IP_V(ip) (((ip)->ip_vhl & 0xf0) >> 4)
#define IP_HL(ip) ((ip)->ip_vhl & 0x0f)
u_int8_t ip_tos; /* type of service */
u_int16_t ip_len; /* total length */
u_int16_t ip_id; /* identification */
u_int16_t ip_off; /* fragment offset field */
#define IP_DF 0x4000 /* dont fragment flag */
#define IP_MF 0x2000 /* more fragments flag */
#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
u_int8_t ip_ttl; /* time to live */
u_int8_t ip_p; /* protocol */
u_int16_t ip_sum; /* checksum */
struct in_addr ip_src,ip_dst; /* source and dest address */
};
/* UDP header */
struct sniff_udp
{
u_short uh_sport; /* source port */
u_short uh_dport; /* destination port */
u_short uh_ulen; /* udp length */
u_short uh_sum; /* udp checksum */
};
#define SIZE_UDP 8 /* length of UDP header */
#define SIZE_ETHERNET 14
As well as a few other structs from the pcap library(like ether_header). I cast the u_char* to these structs like so
struct my_ip* ip = (struct my_ip*)(packet + sizeof(struct ether_header));
struct ether_header* eptr = (struct ether_header *) packet;
Where packet is a u_char holding the entirety of the packet
My question is, once I have modified data within these structures how do I cast all of my stucts back into a single u_char string? I am trying to cast each struct to fill a different segment of string in the same way a packet is structured
This is the code I have so far.
void buildPacket(sniff_udp *udp, ether_header *ethh, my_ip *ip, u_char *payload, u_char *buffer)
{
memset(buffer,0, (sizeof(udp)+sizeof(ethh)+sizeof(ip)+sizeof(payload)));
buffer=(u_char *)(ethh); // adds layer 2 header
(buffer+SIZE_ETHERNET)= (u_char *)ip; // adds layer 3 header
(buffer+SIZE_ETHERNET+sizeof(ip))=(u_char *) udp; // adds protocol header
(buffer+SIZE_ETHERNET+sizeof(ip)+SIZE_UDP)=(u_char *)payload; // adds payload
}
This isn't the correct way to do it from what I've gathered. How can I cast multiple structs to the same string?
Something like
(buffer+SIZE_ETHERNET)= (u_char *)ip; // adds layer 3 header
isn't valid because the lefthand operator of = won't be a (modifable) lvalue.
You can use memcpy() to copy contents of memory. The correct code should be like this:
void buildPacket(sniff_udp *udp, ether_header *ethh, my_ip *ip, u_char *payload, u_char *buffer)
{
memset(buffer,0, (sizeof(udp)+sizeof(ethh)+sizeof(ip)+sizeof(payload)));
memcpy(buffer, ethh, SIZE_ETHERNET); // adds layer 2 header
memcpy(buffer+SIZE_ETHERNET, ip, sizeof(ip)); // adds layer 3 header
memcpy(buffer+SIZE_ETHERNET+sizeof(ip), udp, SIZE_UDP); // adds protocol header
memcpy(buffer+SIZE_ETHERNET+sizeof(ip)+SIZE_UDP, payload, sizeof(payload)); // adds payload
}
This code doesn't seem correct because sizeof(udp), sizeof(ethh), sizeof(ip) and sizeof(payload) will return the size of pointers, not what is pointed, and I don't think it is what you want. Use correct size instead of them.

Peripheral definition

Could someone please explain the following construction to a beginner:
typedef struct
{
__IO uint32_t CTRL; /**< Control Register */
__IO uint32_t CNT; /**< Counter Value Register */
__IO uint32_t COMP0; /**< Compare Value Register 0 */
__IO uint32_t COMP1; /**< Compare Value Register 1 */
__I uint32_t IF; /**< Interrupt Flag Register */
__IO uint32_t IFS; /**< Interrupt Flag Set Register */
__IO uint32_t IFC; /**< Interrupt Flag Clear Register */
__IO uint32_t IEN; /**< Interrupt Enable Register */
__IO uint32_t FREEZE; /**< Freeze Register */
__I uint32_t SYNCBUSY; /**< Synchronization Busy Register */
} RTC_TypeDef;
#define RTC_BASE (0x40080000UL)
#define RTC ((RTC_TypeDef *) RTC_BASE)
especially the last line
Why are the brackets so unusual? What does the * mean? Pointer or multiply operator ?
Thanks
Why are the brackets so unusual? What does the * mean? Pointer or
multiply operator ?
* here is a pointer not multiplication operator.
There is nothing unusual here about the macro. It is just type casting the address to be of type struct RTC_TypeDef
Whenever you will encounter a single or multiple * after a datatype (even a user defined datatype), its a pointer.
What you are calling a constructions:
typedef struct
{
__IO uint32_t CTRL; /**< Control Register */
__IO uint32_t CNT; /**< Counter Value Register */
__IO uint32_t COMP0; /**< Compare Value Register 0 */
__IO uint32_t COMP1; /**< Compare Value Register 1 */
__I uint32_t IF; /**< Interrupt Flag Register */
__IO uint32_t IFS; /**< Interrupt Flag Set Register */
__IO uint32_t IFC; /**< Interrupt Flag Clear Register */
__IO uint32_t IEN; /**< Interrupt Enable Register */
__IO uint32_t FREEZE; /**< Freeze Register */
__I uint32_t SYNCBUSY; /**< Synchronization Busy Register */
} RTC_TypeDef;
is a structure and programmatically called a struct, a user-defined datatype. struct is keyword in C. And so is typedef. To keep it simple as of now, I'll say, typedef here is specifically used to have the convenience to write RTC_TypeDef; instead of having the need to write struct stRTC for example.
RTC_BASE is a macro. So, before compilation pre-processor will replace RTC_BASE with the value (0x40080000UL), again, it is for convenience and readability.
This last line:
#define RTC ((RTC_TypeDef *) RTC_BASE)
also is a macro defined. Which is nothing but a pointer of the RTC_Typedef type, pointing to whatever is located at the address (0x40080000UL)
So, before the compilation the pre-processor will replace all instances of RTC with ((RTC_TypeDef *)0x40080000UL).
If you increment RTC pointer, it will increment by sizeof(RTC_Typedef).
The structure definition is pretty straight forward, variables are encapsulated in a structure. That structure can then be referenced as RTC_TypeDef because you use typedef.
typedef struct
{
__IO uint32_t CTRL; /**< Control Register */
__IO uint32_t CNT; /**< Counter Value Register */
__IO uint32_t COMP0; /**< Compare Value Register 0 */
__IO uint32_t COMP1; /**< Compare Value Register 1 */
__I uint32_t IF; /**< Interrupt Flag Register */
__IO uint32_t IFS; /**< Interrupt Flag Set Register */
__IO uint32_t IFC; /**< Interrupt Flag Clear Register */
__IO uint32_t IEN; /**< Interrupt Enable Register */
__IO uint32_t FREEZE; /**< Freeze Register */
__I uint32_t SYNCBUSY; /**< Synchronization Busy Register */
} RTC_TypeDef; /** #} */
The following line means every time you write RTC_BASE, the compiler will replace that line with (0x40080000UL)
#define RTC_BASE (0x40080000UL)
And finally, the following line can be broken into two parts:
(RTB_TypeDef *)RTC_BASE
Which means (RTB_TypeDef *)(0x40080000UL) - basically tells the compiler to treat memory address 0x40080000UL as a pointer to RTB_TypeDef
and the extra parenthesis are there to denote a single variable as a compund expression RTC.
From that point on, whenever the compiler sees RTC, it will replace it with (RTB_TypeDef *)(0x40080000UL), basically a convenient way to mark the beginning of this structure in memory

Typedef an externel structure in file using cross-compiler (arm-none-eabi-gcc)

I'm trying to compile a project which consist of severel source fies & header files & includes some structure definiton. But when I compile an error comes
"error: expected specifier-qualifier-list before 'typedef'" in file "uip.h"
I have a structure in file named as "httpd.h"
struct httpd_state {
unsigned char timer;
struct psock sin, sout;
struct pt outputpt, scriptpt;
char inputbuf[50];
char filename[20];
char state;
struct httpd_fsdata_file_noconst *file;
int len;
char *scriptptr;
int scriptlen;
unsigned short count;
};
I want to typedef this structure in another file named as "uip.h"
struct uip_conn {
uip_ipaddr_t ripaddr; /**< The IP address of the remote host. */
u16_t lport; /**< The local TCP port, in network byte order. */
u16_t rport; /**< The local remote TCP port, in network order. */
u8_t rcv_nxt[4]; /**< The sequence number that we expect toreceive next. */
u8_t snd_nxt[4]; /**< The sequence number that was last sent by us. */
u16_t len; /**< Length of the data that was previously sent. */
u16_t mss; /**< Current maximum segment size for the connection. */
u16_t initialmss; /**< Initial maximum segment size for the connection. */
u8_t sa; /**< Retransmission time-out calculation state variable. */
u8_t sv; /**< Retransmission time-out calculation state variable. */
u8_t rto; /**< Retransmission time-out. */
u8_t tcpstateflags; /**< TCP state and flags. */
u8_t timer; /**< The retransmission timer. */
u8_t nrtx; /**< The number of retransmissions for the last segment sent*/
/** The application state. */
**typedef struct httpd_state uip_tcp_appstate_t;
uip_tcp_appstate_t appstate;**
} __attribute__((packed));
Can anyone please help??
You can't have a typedef statement inside a struct definition. Either hoist it outside of the struct, or don't use the typedef at all:
// Option #1: Hoisting
typedef struct httpd_state uip_tcp_appstate_t;
struct uip_conn {
...
uip_tcp_appstate_t appstate;
};
// Option #2: No typedef
struct uip_conn {
...
struct httpd_state appstate;
};

Resources