How to use structure with dynamically changing size of data? - c

Question for C only, C++ and vectors do not solve problem.
I have such structure:
typedef __packed struct Packet_s
{
U8 head;
U16 len;
U32 id;
U8 data;
U8 end;
U16 crc;
} Packet_t, *Packet_p;
(EDIT: U8 is uint8_t (unsigned char) and so on)
For example, I've received packet(hex):
24 0B 00 07 00 00 00 AA 0D 16 1C
where
head = 0x24
len = 0x0B 0x00
id = 0x07 0x00 0x00 0x00
data = 0xAA
end = 0x0D
crc = 0x16 0x1C
I can copy it from incoming buffer like this
U8 Buffer[SIZE]; // receives all bytes here
memcpy(&Packet, &Buffer, buffer_len);
and work futher with it.
Is it possible to use my structure if field "DATA" is longer than 1 byte?
How can I handle something like this?
24 0F 00 07 00 00 00 AA BB CC DD EE 0D BD 66
Length of packet will be always known (2 and 3 bytes have info about length).
EDIT: Under "handle" I mean that I want to do next:
if (isCRCmatch() )
{
if(Packet.id == SPECIAL_ID_1)
{
// do something
}
if(Packet.id == SPECIAL_ID_2)
{
// do other
}
if(Packet.data[0] == 0xAA)
{
// do one stuff
}
if(Packet.data[1] == 0xBB && Packet.id == SPECIAL_ID_3 )
{
// do another stuff
}
}
And also (if possible ofc) I would like to send "anwers" using same structure:
U8 rspData[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06};
SendResponce(Packet.id, rspData);
void SendResponce (U8 id_rsp, uint8_t* data_rsp)
{
Packet_t ResponceData;
uint16_t crc;
uint8_t *data;
ResponceData.head = 0x24;
ResponceData.len = sizeof(ResponceData); // HERE IS PROBLEM ONE
ResponceData.id = id_rsp;
ResponceData.data = *data_rsp; // HERE IS PROBLEM TWO
ResponceData.end = 0x0D; // symbol '\r'
data = (uint8_t*)&ResponceData;
crc = GetCrc(data, sizeof(ResponceData)-2); // last 2 bytes with crc
ResponceData.crc = crc;//(ack_crc >> 8 | ack_crc);
SendData((U8*)&ResponceData, sizeof(ResponceData)); // Send rsp packet
}
First problem - I cant get size of all structure automatically, since pointer will be always 4 bytes...
Second problem - I sure that I will lose rsp data since I don't know where is end of it.

You can't have dynamic buffer in middle of a struct.
Another way to solve the problem is divide the struct to two pieces.
For example (notice that data is here a flexible array member):
typedef __packed struct Packet_s
{
U8 head;
U16 len;
U32 id;
U8 data[];
} Packet_t, *Packet_p;
typedef __packed struct PacketEnd_s
{
U8 end;
U16 crc;
} PacketEnd_t, *PacketEnd_p;
Then use
Packet_t *pPacket = (Packet_t *)&Buffer;
PacketEnd_t *pPacketEnd = (PacketEnd_t *)( count pointer here by using pPacket->len );
Assuming that __packed allows to use unaligned access to members of __packed structs.

You should split your processing function into two distinct functions:
One which will discard everything until it finds the head byte. This byte usually is a constant byte, marking the start of a packet. This is done this way, in order to avoid start to read in the middle of a previously sent packet (think i.e. the startup order of the sender and the listener devices).
Once it finds the start of the packet, it can read the header, len and id and receive all the data storing it into your Buffer variable, until it reads the end byte or there is a buffer overflow, in which case it would just discard the data and start again.
NOTE that into the Buffer variable only should be written the actual data. All the other fields (len, id and so) can be stored in different variables, or in a struct containing only the Packet information, but no data. This way, you spit the application data from the transmission information.
Note also that this function does not interpret the idfield, nor the datafield. It just sends this information to the other funciton, which will do the processing or discard if the id or the dataare not correct / known.
Once the end byte is found, you can pass the information to the actual processing function. Its header would be something like:
void processPacket(U8 *data, U32 id, U16 len);
and the call to it would be:
void receiveFrame() {
//Receive head
//Receive id
//Receive len
//Fill in Buffer with the actual data
//Call the processPacket function
processPacket(&Buffer[0], id, len);
}
A more complete example could be:
//It is not packet, since you fill it reading from the buffer and assigning
//to it, not casting the buffer into it.
//It has no data field. The data is in a different variable.
typedef struct Packet_s
{
U8 head;
U16 len;
U32 id;
U8 end;
U16 crc;
} PacketInfo_t;
U8 Buffer[MAX_BUFFER_SIZE];
PacketInfo_t info;
void receiveFrame() {
info.head=//Receive head
info.len=//Receive len
info.id=//Receive id
//Fill the buffer variable
processPacket(&Buffer[0], &info);
}
void processPacket(U8 *data, PacketInfo_t *info);
For sending, just use the same format:
void sendPacket(U8 *data, PacketInfo_t *info);
This function sould prepare the Packet header from info and read the data from data.
And finally, a word of caution: casting (or memcpy) a received packet directly into a struct is almost never a good idea. You have to take into account not only the zero holes (using the __packet attribute), but also the endianness and the data format representation of the sender and receiver systems, since if they are different, you would end up with the wrong values.

Is it possible to use my structure if field "DATA" is longer than 1 byte?
No, since it has only room for 1 data byte. But you can use a slightly modified version of your structure.
typedef __packed struct Packet_s
{
U8 head;
U16 len;
U32 id;
U8 data[DATALENMAX]; // define appropriately
U8 end;
U16 crc;
} Packet_t, *Packet_p;
Of course, you'd have to adapt the copying accordingly:
memcpy(&Packet, &Buffer, buffer_len), memmove(&Packet.end, &Packet.data[buffer_len-7-3], 3);
Regarding the added problems, it's necessary to pass the data length to SendResponce():
SendResponce(rspData, sizeof rspData);
void SendResponce(uint8_t* data_rsp, int datalen)
{
Packet_t ResponceData;
uint16_t crc;
uint8_t *data;
ResponceData.head = 0x24;
ResponceData.len = 7+datalen+3; // HERE WAS PROBLEM ONE
ResponceData.id = SPECIAL_ID_X;
memcpy(ResponceData.data, data_rsp, datalen); // HERE WAS PROBLEM TWO
ResponceData.data[datalen] = 0x0D; // symbol '\r'
data = (uint8_t*)&ResponceData;
crc = GetCrc(data, 7+datalen+1); // last 2 bytes with crc
ResponceData.crc = crc;//(ack_crc >> 8 | ack_crc);
memmove(ResponceData.data+datalen+1, &ResponceData.crc, 2);
SendData((U8*)&ResponceData, ResponceData.len); // Send rsp packet
}

Related

GPS UART data written multiple times to Buffer

I am receiving/reading data from a GPS module sent via USART3 to the STM32F091.
The data gets there just fine which I confirm by sending it to my PC COM3 port and feeding it to 'u-center' (GPS evaulation software).
My problem is that I want to evaluate the data myself in my C program, and for that purpose I feed it into a Ring Buffer, however, every character of the GPS signal is written multiple times to the buffer, instead of one by one.
For example
GGGGGGGPPPPPPPPSSSSSSSS instead of GPS
I am unsure what I'm doing wrong, maybe it's something really obvious I'm overlooking after staring at this code so long.
Here's the relevant code.
stm32f0xx_it.c
#include <main.h>
void USART3_8_IRQHandler(void)
{
if (USART_FLAG_RXNE != RESET)
{
uint16_t byte = 0;
/* Data reception */
/* Clear Overrun Error Flag, necessary when RXNE is used */
USART_GetITStatus(USART3, USART_IT_ORE);
/* Read from Receive Data Register and put into byte */
byte = USART_ReceiveData(USART3);
(*pRXD3).wr = ((*pRXD3).wr + 1) % (*pRXD3).max;
(*pRXD3).Buffer[(*pRXD3).wr] = byte;
/* Send Data to PC, and reset Transmission Complete Flag */
USART_GetITStatus(USART1, USART_IT_TC);
USART_SendData(USART1, byte);
return;
}
return;
}
uartGPS.h
....
struct GPSuart
{
BYTE Buffer[255];
WORD max;
WORD re;
WORD wr;
};
....
main.h
....
extern volatile BYTE B_ser_txd_3[255];
extern volatile BYTE B_ser_rxd_3[255];
extern volatile struct GPSuart TXD_uart_3;
extern volatile struct GPSuart RXD_uart_3;
extern volatile struct GPSuart *pRXD3;
extern volatile struct GPSuart *pTXD3;
....
Let me know if I should provide additional information.
This:
if (USART_FLAG_RXNE != RESET)
does not test a flag, that code is inspecting the flag constant itself, which is not what you meant.
You need more code, to access the UART's status register and check the flag:
if (USART_GetFlagStatus(USARTx, USART_FLAG_RXNE) != RESET)

Malformed packet in dns client implementation

Hi there for fun i'm developing a tiny dns client on a unix system.
I've read the documentation about dns protocol i wrote a tiny function
int makeQuestion(char* dns_addr,char *name){
int s = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
register int len_name = strlen(name);
if(s<0)
return errno;
struct sockaddr_in address;
bzero(&address,sizeof(address));
address.sin_port = htons(53);
address.sin_addr.s_addr = inet_addr(dns_addr);
dns_header header;
memset(&header,0,sizeof(dns_header));
header.id = htons(getpid());
header.q_count = htons(1);
dns_question quest = {
.qclass = htons(IN),
.qtype = htons(A)
};
register int pack_size = sizeof(dns_header)+len_name+2+sizeof(dns_question);
char *packet = malloc(pack_size);
memcpy(packet,&header,sizeof(dns_header));
for(int i = 0;i<len_name;i++)
*(packet +i +sizeof(dns_header)) = name[i];
packet[len_name+sizeof(dns_header)] = '.';
packet[len_name+sizeof(dns_header)+1] = '\0';
memcpy(packet+sizeof(dns_header)+len_name+2,&quest,sizeof(dns_question));
sendto(s,packet,pack_size,NULL,&address,sizeof(address));
return OK;
}
The structure for the dns header and dns query are declared like:
//DNS header structures
typedef struct dns_header
{
uint16_t id; // identification number
uint8_t rd :1; // recursion desired
uint8_t tc :1; // truncated message
uint8_t aa :1; // authoritive answer
uint8_t opcode :4; // purpose of message
uint8_t qr :1; // query/response flag
uint8_t rcode :4; // response code
uint8_t cd :1; // checking disabled
uint8_t ad :1; // authenticated data
uint8_t z :1; // its z! reserved
uint8_t ra :1; // recursion available
uint16_t q_count; // number of question entries
uint16_t ans_count; // number of answer entries
uint16_t auth_count; // number of authority entries
uint16_t add_count; // number of resource entries
}dns_header;
typedef struct dns_question
{
uint16_t qtype;
uint16_t qclass;
}dns_question;
Now i executed the code while wireshark was running and i saw the packet that seemed to be correct but in the query section wireshark said
Name: <Unknown extended label>
So the question is there is a way i have to use to store the dns name of the queried host in the packet or there is something wrong in the implementation. Sorry for the loosing of time and sorry for my English. Thanks indeed
I solved finally. Studing better the protocoll ( the domain name system) where the reference is at this link a the wrong part was in the section called qname ( the name of the host that in my case the protocoll wasn't able to determinate the size)
So as the document said qname is:
a domain name represented as a sequence of labels, where
each label consists of a length octet followed by that
number of octets. The domain name terminates with the
zero length octet for the null label of the root. Note
that this field may be an odd number of octets; no
padding is used.
So i changed my code to transform www.example.com in 3www7example3com
and everything works

Using bitfields for parsing network packets

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 */
};

Memory alignment issue in received network packets

I'm writing a custom protocol in the linux kernel. I'm using the following structures
struct syn {
__be32 id;
__be64 cookie;
};
struct ack {
__be32 id; // Right now, setting it to 14 (Just a random choice)
__be32 sequence;
};
struct hdr {
............
__be32 type; //last element
};
When I send and receive packets, I map the structures syn and ack (for different packets) to the address of hdr->type.
This should ideally mean that the id (in syn and ack structures) should be mapped to the hdr->type and whatever follows the struct hdr should be mapped to either syn->cookie or ack->sequence, depending on which struct I'm mapping on to the hdr->type.
But on printing out the memory addresses for these variables, I get the following
//For struct syn
hdr->type at ffff880059f55444
syn->id at ffff880059f55444
syn->cookie at ffff880059f5544c //See the last two bits
//For struct ack_frame
hdr->type at ffff880059f55044
ack->id at ffff880059f55044
ack->sequence at ffff880059f55048 //See the last two bits
So why do syn->cookie and ack->sequence start at different offsets relative to hdr->type when ack->id and syn->id have the same size?
EDIT 1: I map these structures using
char *ptr = (char *)&hdr->type;
//For syn
struct syn *syn1 = (struct syn *)ptr
//For ack
struct ack *ack1 = (struct ack *)ptr
since you work in 64 bits the compiler fills struct the following:
struct syn {
uint32_t id
uint32_t hole -- the compiler must add here cause it mist align
uint64_t seq
}
I guess the data doesn't have holes, so to fix it you will need to set seq to uint32_t and cast it later.
https://gcc.gnu.org/onlinedocs/gcc/Common-Type-Attributes.html#Common-Type-Attributes
Look at packed. For whatever reason, GCC doesn't let me link directly to that section.
You should define your structure as following. Attribute packed means allignment should be as 1 byte.
Following structure will be 12 bytes longs. If you dont use "attribyte" key word, your structure would be 16 bytes long.
struct yours{
__be32 id;
__be64 cookie;
}__attribute__((__packed__));

issue with C pwrite(); extra bytes got written to file

I am having a weird issue when i do a pwrite a struct to a file. It adds a single byte with next to a char entry in the struct. When i tried to write the char alone to a file it correctly wrote a single byte. Could some one tell me why the single byte got added??
int main(){
typedef struct pcap_hdr_s {
guint32 magic_number; /* magic number */
guint16 version_major; /* major version number */
guint16 version_minor; /* minor version number */
gint32 thiszone; /* GMT to local correction */
guint32 sigfigs; /* accuracy of timestamps */
guint32 snaplen; /* max length of captured packets, in octets */
guint32 network; /* data link type */
guint32 ts_sec; /* timestamp seconds */
guint32 ts_usec; /* timestamp microseconds */
guint32 incl_len; /* number of octets of packet saved in file */
guint32 orig_len; /* actual length of packet */
guint16 fcf;
char seqno;
guint16 dpan;
guint16 daddr;
guint16 saddr;
gint16 payload_data;
} pcaprec_hdr_t;
pcaprec_hdr_t packet_header;
packet_header.magic_number = PCAP_MAGIC;
packet_header.version_major = 2;
packet_header.version_minor = 4;
packet_header.thiszone = 0;
packet_header.sigfigs = 0;
packet_header.snaplen = 65535;
packet_header.network = 195;
struct timeval tv;
gettimeofday(&tv, NULL);
packet_header.ts_sec = tv.tv_sec;
packet_header.ts_usec = tv.tv_usec;
packet_header.incl_len = 11;
packet_header.orig_len = 13;
packet_header.seqno = 255;
packet_header.dpan = 65535;
packet_header.daddr = 65535;
packet_header.saddr = 65535;
packet_header.payload_data = 8;
int fd = open("sample.cap", O_CREAT | O_WRONLY);
printf("Bytes written: %d \n",pwrite(fd, &packet_header, sizeof(packet_header),0));
}
The struct has a char var "seq" and next to the seq no value a single byte of random value gets added in the file.
Your structure contains a char data member and you probably have word-alignment on. See if you can find a "pack" option in the compiler.
You can probably use a #pragma pack(1) or similar pragma (pragma's are implementation specific) to change the alignment for a particular set of classes.
Be careful though, the compiler word-aligns for performance reasons. The memory bus typically works on word boundaries, so you could end up requiring two fetchs for each word that straddles the word boundary thereby slowing memory access down a bit.
You might want to stream the structure members out individually if you're concerned about the added bytes in the file.

Resources