Concatenate array with define and varaible - c language - c

I am looking for a solution to concatenate in a array with value from defines and variable. I have already try with memcpy like that but it not working :
#define ADDRESS {0x00, 0x00, 0x00, 0x00, 0x00, 0x45}
#define SIGNATURE {0xC6, 0x54, 0x2D}
uint8_t packetCounter = 0;
uint8_t RadioData[2]={'2','1'};
uint8_t Packet = sizeof(uint8_t);
memcpy(Packet, ADDRESS, sizeof(ADDRESS));
memcpy(Packet, SIGNATURE, sizeof(SIGNATURE));
memcpy(Packet, packetCounter, sizeof(packetCounter));
memcpy(Packet, data, sizeof(data));
The goal of this code is to have an array with those value : ADDRESS+SIGNATURE+packetCounter+data. And I would like also to add "_" between each variable after.
Do you have any solution?
Thanks

It's not entirely clear what it is you want, but maybe something like this?
#include <stdint.h>
#define ADDRESS 0x00, 0x00, 0x00, 0x00, 0x00, 0x45
#define SIGNATURE 0xC6, 0x54, 0x2D
void Some_Function(void) {
uint8_t packetCounter = 0;
uint8_t RadioData[2]={'2','1'};
uint8_t Packet[] = {ADDRESS, SIGNATURE, packetCounter, RadioData[0], RadioData[1]};
}

Your problem is that Packet is an integer variable. The memcpy needs a pointer, not an integer variable. Your trying to copy a lot of bytes to a single byte location.

The quick and easy way worked fine for me. I see the exact bytes in the packet, in my debugger.
#include <vector>
#define ADDRESS {0x00, 0x00, 0x00, 0x00, 0x00, 0x45}
#define SIGNATURE {0xC6, 0x54, 0x2D}
uint8_t address[] ADDRESS;
uint8_t signature[] SIGNATURE;
uint8_t packetCounter = 0;
uint8_t RadioData[2] = { '2','1' };
int main() {
std::vector<uint8_t> packet;
std::copy(std::begin(address), std::end(address), std::back_inserter(packet));
std::copy(std::begin(signature), std::end(signature), std::back_inserter(packet));
packet.push_back(packetCounter);
std::copy(std::begin(RadioData), std::end(RadioData), std::back_inserter(packet));
// packet now has the bytes expected
return 0;
}
This is c++, although the question had both tags. I can put them in a malloc'ed area just as easily if you need C. Also the #define is completely unnecessary. I'd rather just define static const arrays.
I probably would have used unsigned char or char, possibly with a static assert if they need to be 8 bit.

Related

How to add a uint8_t array into a char*

I have a char *data that is a Datagram to represent the packet I want to send in but I need to insert on that an uint8_t array.
// Datagram to represent the packet
char datagram[4096], source_ip[32], *data, *pseudogram;
// zero out the packet buffer
memset(datagram, 0, 4096);
// IP header
struct iphdr *iph = (struct iphdr *)datagram;
// UDP header
struct udphdr *udph = (struct udphdr *)(datagram + sizeof(struct ip));
// Data part
data = datagram + sizeof(struct iphdr) + sizeof(struct udphdr);
uint8_t packet_bytes[] = { 0xff, 0xff, 0x81, 0x01, 0x01 };
memcpy(data, packet_bytes, 5);
Doing this allows me to insert what I need and it works but the problem is that I have and uint8_t array with 0x00 in the middle making this harder than I thought because the 0x00 hex also means a termination of an array, how can I make it to work with this array instead ?
char packet_bytes[] = {
0xff, 0xff, 0x81, 0x00, 0x00, 0x00, 0x00, 0x30,
0x13, 0x43, 0x00, 0x01, 0x01, 0x01, 0x02, 0x00,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
0x06, 0x00, 0x00, 0x10, 0x01, 0x01, 0x00, 0x63,
0x02, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x05,
0x00, 0x00, 0x00, 0x0c, 0x00, 0x09, 0x04, 0x00,
0x0a, 0x00, 0x03, 0x01, 0x00, 0x11, 0x77, 0x25
};
the problem is that I have and uint8_t array with 0x00 in the middle making this harder than I thought because the 0x00 hex also means a termination of an array
There is no such thing as "termination of an array" in C. There is null termination of character arrays used as strings, but that isn't applicable here. So the memcpy part will work just fine.
You have some other problems however:
char datagram[4096], char packet_bytes[] etc
char is unsuitable, dangerous and non-portable for the purpose of holding raw binary data. Use uint8_t instead. See Is char signed or unsigned by default?
struct iphdr *iph = (struct iphdr *)datagram;
This will lead to undefined behavior because of alignment and strict aliasing. What is the strict aliasing rule? You cannot wildly type pun from a character array to another type by pointer casts (though the other way around from "any type" to character type is possible). Furthermore, your struct may contain padding, in which case it is extra non-portable and you don't want to be sending padding bytes around.
(struct udphdr *)(datagram + sizeof(struct ip)); Same problem as above.
The only reliable way to do this is either to disable struct padding and then memcpy in/out of the struct. Or alternatively write serialization/deserialization routines accessing one struct member at a time, moving it to/from the raw data.

Defining array of bytes for use to call later in C program

Initializing a SI labs radio, the software develops a header file as well as a patch file. first part is, depending on the patch file it outputs different ways. here is a snippet of each patch:
Rev B patch:
#define SI446X_PATCH_CMDS \
{ 0x04,0x11,0xF7,0x76,0x00,0x00,0xA6,0x82 }, \
{ 0x05,0x61,0xE6,0x82,0x5E,0xB7,0xFB,0x93 }, \
{ 0x05,0x1E,0x12,0xBD,0x5A,0xC2,0x52,0x41 }, \
{ 0xE7,0xF4,0xDF,0x6A,0x24,0xD9,0xBA,0x31 }, \
OR
Rev C patch:
#define SI446X_PATCH_CMDS \
0x08,0x04,0x21,0x71,0x4B,0x00,0x00,0xDC,0x95, \
0x08,0x05,0xA6,0x22,0x21,0xF0,0x41,0x5B,0x26, \
0x08,0xE2,0x2F,0x1C,0xBB,0x0A,0xA8,0x94,0x28, \
0x08,0x05,0x87,0x67,0xE2,0x58,0x1A,0x07,0x5B, \
Now this will be hardcoded into the software and either one commented out. but it must have been done this way for a reason and i dont understand it. for initial testing i placed each line of 8 bytes (as it needs to be pushed over SPI this way) into an array and then created a pointer to the array since the length isnt necessary as they are all 8 bytes like i said. iss there a more intelligent way i should cade this based on the way it is presented?
uint8_t array_1[8] = { 0x04, 0x11, 0xF7, 0x76, 0x00, 0x00, 0xA6, 0x82 };
uint8_t array_2[8] = { 0x05, 0x61, 0xE6, 0x82, 0x5E, 0xB7, 0xFB, 0x93 };
uint8_t *theArrays[] = { array_1, array_2, array_3, array_4, array_5, array_6,
array_7, array_8, array_9, array_10, array_11, array_12, array_13,
I then program the SPI using this code and manually typed in the qty into a for loop as i cant get sizeof from the pointer array.
HAL_SPI_Transmit(&hspi1, theArrays[i], 8, 50);
These macros just make things a bit easier.
Assuming the number of (sub)arrays in both macros matches the number of arrays in your array of pointers, your code would look like this in full version:
uint8_t array_1[8] = { 0x04, 0x11, 0xF7, 0x76, 0x00, 0x00, 0xA6, 0x82 };
uint8_t array_2[8] = { 0x05, 0x61, 0xE6, 0x82, 0x5E, 0xB7, 0xFB, 0x93 };
uint8_t array_3[8] = ...
uint8_t array_4[8] = ...
uint8_t array_...
uint8_t array_12[8] = ...
uint8_t array_13[8] = ...
uint8_t *theArrays[] = { array_1, array_2, array_3, array_4, array_5, array_6,
array_7, array_8, array_9, array_10, array_11, array_12, array_13,
...
HAL_SPI_Transmit(&hspi1, theArrays[i], 8, 50);
With these macros (stored in some nice header) you can just do this:
Revision B:
#define SPI_MESSAGE_SIZE 8
const uint8_t theArray[][SPI_MESSAGE_SIZE] = {SI446X_PATCH_CMDS};
_Static_assert(sizeof theArray/sizeof *theArray == SOME_EXPECTED_SIZE, "SI446X_PATCH_CMDS corrupt");
...
HAL_SPI_Transmit(&hspi1, theArrays[i], SPI_MESSAGE_SIZE, 50);
or in case of Revision C
#define SPI_MESSAGE_SIZE 8
const uint8_t theArray[] = {SI446X_PATCH_CMDS};
_Static_assert(sizeof theArray/sizeof *theArray == SOME_EXPECTED_SIZE, "SI446X_PATCH_CMDS corrupt");
...
// For Rev C, the array contains a <length> byte before the SPI data.
// Adjust addressing accordingly
uint8_t len = theArrays[i*(SPI_MESSAGE_SIZE+1)];
HAL_SPI_Transmit(&hspi1, &theArrays[i*(SPI_MESSAGE_SIZE+1)+1], len, 50);
The static assert was suggested by Lundin. I am not aware of the correct value to compare but there should be some useful define somewhere in Silabs Radio's headers.

Powershell: how to intialize an array of bytes like in C?

In C you can do something like:
uint16_t datalen = 1024;
uint16_t crc = 0x1021;
uint8_t myHeader = {0x41, 0xBE, 0x21, 0x08, datlen/256, datalen%256, crc/256, crc%256};
Now, how can I accomplish an array initialization like this in Powershell?
I want to send the byte array later to serial port.
Not so different:
[uint16]$datalen = 1024
[uint16]$crc = 0x1021
[byte[]]$myHeader = 0x41, 0xBE, 0x21, 0x08, ($datalen/256), ($datalen%256), ($crc/256), ($crc%256)

Issues when using pcapsendpacket to send 80211 frames in C

I'm trying to send 802.11 frames using pcap_sendpacket with the following radiotap:
u_char RADIOTAP_HDR[] = {
0x00, // it_version
0x00, // padding
0x0a, 0x00, // length
0x00, 0x00, 0x80, 0x00, // IEEE80211_RADIOTAP_TX_FLAGS
0x00, 0x08, // no-ack required
};
I'm also using 802.11 header defined in include/linux/ieee80211.h:
struct ieee80211_hdr {
uint16_t /*__le16*/ frame_control;
uint16_t /*__le16*/ duration_id;
uint8_t addr1[6];
uint8_t addr2[6];
uint8_t addr3[6];
uint16_t /*__le16*/ seq_ctrl;
//uint8_t addr4[6];
} __attribute__ ((packed));
When capturing the frame with Wireshark, it looks like an Ethernet frame where the radiotap header is traduced as an Ehternet header.
Did I make a mistake somewhere ?
Regards

C - Writing structs to a file (.pcap)

I am trying to write a .pcap file, which is something that can be used in Wireshark.
In order to do that, I have a couple of structs with various data types I need to write to a file. (see code)
So, I create the struct instances, fill in the data, use FILE* fp = fopen("test.pcap","w"), and then I'm unsure how to properly write it to the file. I believe I should use memcpy but I'm not sure of the best way to do it. I have mostly resorted to C++ libraries in the past to do this. Any suggestions?
typedef struct pcap_hdr_s {
uint32_t magic_number; /* magic number */
uint16_t version_major; /* major version number */
uint16_t version_minor; /* minor version number */
int32_t thiszone; /* GMT to local correction */
uint32_t sigfigs; /* accuracy of timestamps */
uint32_t snaplen; /* max length of captured packets, in octets */
uint32_t network; /* data link type */
} pcap_hdr_t;
typedef struct pcaprec_hdr_s {
uint32_t ts_sec; /* timestamp seconds */
uint32_t ts_usec; /* timestamp microseconds */
uint32_t incl_len; /* number of octets of packet saved in file */
uint32_t orig_len; /* actual length of packet */
} pcaprec_hdr_t;
typedef struct ethernet_hdr_s {
uint8_t dst[6]; /* destination host address */
uint8_t src[6]; /* source host address */
uint16_t type; /* IP? ARP? RARP? etc */
} ethernet_hdr_t;
typedef struct ip_hdr_s {
uint8_t ip_hl:4, /* both fields are 4 bits */
ip_v:4;
uint8_t ip_tos;
uint16_t ip_len;
uint16_t ip_id;
uint16_t ip_off;
uint8_t ip_ttl;
uint8_t ip_p;
uint16_t ip_sum;
uint32_t ip_src;
uint32_t ip_dst;
}ip_hdr_t;
typedef struct udp_header
{
uint16_t src;
uint16_t dst;
uint16_t length;
uint16_t checksum;
} udp_header_t;
Use libpcap or WinPcap - pcap_open_dead() to get a "fake" pcap_t to use with pcap_dump_open() to specify the link-layer header type (for Ethernet, use DLT_EN10MB) and snapshot length (use 65535), pcap_dump_open() to open the file for writing, pcap_dump() to write out a packet, and pcap_dump_close() to close the file. MUCH easier than directly using fopen(), fwrite(), and fclose() (which are what libpcap/WinPcap use "under the hood").
And, yes, you have to get the byte order in the packets correct. The byte order depends on the protocol; for the type field in the Ethernet header, and for all multi-byte fields in IP, TCP, and UDP headers, they have to be in big-endian order. (The magic number in the pcap file is irrelevant to this - it only indicates the byte order of the fields in the file header and the per-packet record header, NOT the byte order of the fields in the packet, as well as, due to the way it's implemented in Linux, the meta-data at the beginning of packets in Linux USB captures. The packet data is supposed to look exactly as it would "on the wire".)
Use fwrite(). You need to check this info but I think .pcap files are written in binary mode.
Example:
pcaprec_hdr_t pcaprec_hdr;
// fill pcaprec_hdr with valid info
FILE* pFile = NULL;
pFile = fopen ("myfile.pcap" , "wb"); // open for writing in binary mode
fwrite (&pcaprec_hdr, 1, sizeof(pcaprec_hdr_t) , pFile);
fclose(pFile);
Here's my understanding of what Guy Harris is suggesting. So, as per Kyslik's request, we have:
#include <libpcap/pcap.h>
/* Ethernet/IP/SCTP INIT chunk */
static const unsigned char pkt1[82] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x45, 0x00, /* ......E. */
0x00, 0x44, 0x55, 0xb1, 0x00, 0x00, 0x40, 0x84, /* .DU...#. */
0x26, 0x83, 0x7f, 0x00, 0x00, 0x01, 0x7f, 0x00, /* &....... */
0x00, 0x01, 0x00, 0x01, 0x1f, 0x90, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x68, 0xe5, 0x88, 0x1b, 0x01, 0x00, /* ..h..... */
0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, /* .$...... */
0xa0, 0x00, 0x00, 0x04, 0xff, 0xff, 0x00, 0x00, /* ........ */
0x16, 0x2e, 0x80, 0x00, 0x00, 0x04, 0xc0, 0x00, /* ........ */
0x00, 0x04, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x05, /* ........ */
0x00, 0x00 /* .. */
};
int main(int argc, char *argv[]) {
pcap_t *handle = pcap_open_dead(DLT_EN10MB, 1 << 16);
pcap_dumper_t *dumper = pcap_dump_open(handle, "/tmp/pktcap/cap.pcap");
struct pcap_pkthdr pcap_hdr;
pcap_hdr.caplen = sizeof(pkt1);
pcap_hdr.len = pcap_hdr.caplen;
pcap_dump((u_char *)dumper, &pcap_hdr, pkt1);
pcap_dump_close(dumper);
return 0;
}

Resources