memcpy structure failed - c

I tried to memcpy measure_msg (struct test) to a buffer. However, the code below doesn't seems to copy the data. The value return
**** ptr:0xb781c238
**** ptr:0xb781c23c
**** ptr:0xb781c244
buff[0]=5 - buff[1]=0 - buff[2]=0 - buff[3]=0 - buff[4]=W - buff[5]= - buff[6]= - buff[7]= - buff[8]= - buff[9]= - buff[10]= - buff[11]= -
What has gone wrong in this chunk of code?
struct test{
int mode;
int id;
};
int func()
{
int i, size;
struct test measure_msg;
char buff[20];
char* ptr;
memset(&measure_msg, 0x00, sizeof(struct test));
ptr = buff;
fprintf(stderr, "**** ptr:%p\n", ptr);
sprintf(ptr, "%02d%02d", 50, 0);
ptr += 4;
size = 4;
size += sizeof(struct test);
fprintf(stderr, "**** ptr:%p\n", ptr);
measure_msg.id = 9999;
measure_msg.mode = 1111;
memcpy(ptr, &measure_msg, sizeof(struct test));
ptr += sizeof(struct test);
fprintf(stderr, "**** ptr:%p\n", ptr);
for (i=0; i<size; i++){
fprintf(stderr, "buff[%d]=%c - ", i, buff[i]);
}
return 0;
}

You're doing something strange but, look this:
sprintf(ptr, "%02d%02d", 50, 0);
You'll write a string to your buffer. Now buf will contains "5000". Please note that it won't contain the values 50 and 0 but their string representation!
Now when you copy the buffer to your struct you'll set its fields to these four bytes but they're not what you see when printing the string but its ASCII codes. Note that on this line:
fprintf(stderr, "buff[%d]=%c - ", i, buff[i]);
You print the content of the buffer as characters, '5' is stored as 0x35 (53 in decimal) then it'll be the content of the first byte of your structure (and so on).
If this is really what you want to do your code is exact (but you're playing too much with pointers, is it just a test?) but it's really really strange otherwise you're walking in the wrong direction to do what you need.

When you memcpy your measure_msg to the buff you are copying int type values. After that, you are printing char type values. An int type value is composed by 4 bytes which may have no printing representation: i.e 33752069 int value, 0x02030405 in hex format, has 4 bytes that, once been printed like chars you get 0x02, 0x03, 0x04 and 0x05 char values.
Change your print masc to use int values and cast each buff[i] to int and your values will be printed.
fprintf(stderr, "buff[%d]=%d - ", i, (int)buff[i])

The memcpy () call is working all right on my system (GCC/MinGW, Windows). You aren't getting the proper output because some of the "characters" getting copied into buff are non-printable.
Try
fprintf (stderr, "buff[%d]=%x - ", i, buff[i]);
instead.
The data will be stored as
buff [0] = 0x35 /* ASCII for '5' */
buff [1] = 0x30 /* ASCII for '0' */
buff [2] = 0x30
buff [3] = 0x30
buff [4] = 0x57 /* as 1111 is 0x00000457 in hex */
buff [5] = 0x04 /* stored in little endian convention */
buff [6] = 0x00 /* and here size of int = 4 */
buff [7] = 0x00
buff [8] = 0x0F /* as 9999 is 0x0000270F in hex */
buff [9] = 0x27
buff [10] = 0x00
buff [11] = 0x00
But what are you trying to do anyway, by copying a struct to an array of chars?

Related

How can I push buffer into the stack provided the buffer contains a function value stored to it as per the following code?

struct dev *address - It reads the addresses from a structure of registers.
unsigned int bytes- number of bytes of data being read from the register address.
For example - (0x2, 1). 0x2 - register address and 1 - number of bytes.
i2c_read(struct dev *address, unsigned int bytes)
{
char buff[256];
char *p1 = buff; // Contains a pointer to a buffer of 256 bytes
p1 = func(address, bytes); //values to be stored to the "pointer of a buffer of 256 bytes".
}
The buffer contains values to be stored from func(address, bytes).
int push() //to push the buffer into the stack.
{
//push the buffer to stack here?.
}
I tried doing something like this -
void push(unsigned int *result_buffer)
{
unsigned int *tos, *p1, arr_stack[MAX_SIZE];
//MAX_SIZE is the size of the stack.
tos = arr_stack; /* tos points to the top of stack */
p1 = arr_stack; /* initialize p1 */
printf("\n Simple Stack Example - Pointers");
if (p1 == (tos + MAX_SIZE)) {
printf("\nStatus : Stack Overflow.\n");
} else {
*p1 = *result_buffer;
printf("\nPush Value : %d ", *(p1));
p1++;
}
}
Your error is in the definition of func(). You need to define your function. Let's say you have an i2c port. A function to comunicate with it should need the following to do its tasks:
An address for the i2c device.
The number of bytes to expect in the response.
An address to a buffer to store the response.
It would also be wise to return a code indicating the status of the operation, did it succeed? Why did it fail?
the signatre of the function should then be, assuming the error code is expressed as an integer:
int i2c_read(struct dev *address, int result_length, unsigned char* result_buffer);
At the call site, you must create a buffer that's large enough to store the result.
As in:
// Example: You've just sent read serial command... to read 4 bytes serial #...
unsigned char buffer[4];
if (i2c_read(address, 4, buffer) < 0) // buffer decays to a pointer when
// passed to the function.
{
printf("error! failed to read serial # !!!\n");
}
else
{
printf("serial # is: %02x%02x-%02x%02x\n", buffer[0], buffer[1], buffer[2], buffer[3]);
}
Your question was not very clear....
Usally I2c requires a command to be sent and a response to be received. In most i2c API I've seen, the signature of the send/receive function is:
int i2c_sendCcommand(WORD addr, int nbytesCommand, const unsigned char* command, int nBytesResponse, unsigned char* response);
// usage:
unsigned char cmdBuffer[] = { 0x43, 0x01 };
unsigned char respBuffer[4];
if (i2c_sendCcommand(0x1234, 2, cmdBuffer, 4, respBuffer) < 0)
{
printf("error! failed to read serial # !!!\n");
}
else
{
printf("serial # is: %02x%02x-%02x%02x\n", respBuffer[0],
respBuffer[1], respBuffer[2], respBuffer[3]);
}

Converting hexadecimal to ASCII in c

I'm working on an Android rom for a mobile phone and I want to make the kernel load the wifi MAC address from the device's NV partition. My code looks like this:
#include <linux/kernel.h>
#include <linux/random.h>
#include <linux/syscalls.h>
#define ETHER_ADDR_LEN 6
#define FILE_WIFI_MACADDR "/dev/block/mmcblk0p7"
static int bcm_wifi_get_mac_addr(unsigned char *buf)
{
int ret = 0;
mm_segment_t oldfs;
int i;
int fp;
int macbyte;
int readlen = 0;
uint rand_mac;
static unsigned char mymac[ETHER_ADDR_LEN] = {0,};
const unsigned char nullmac[ETHER_ADDR_LEN] = {0,};
const unsigned char bcastmac[] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
if (buf == NULL)
return -EAGAIN;
memset(buf, 0x00, ETHER_ADDR_LEN);
oldfs = get_fs();
set_fs(get_ds());
fp = sys_open(FILE_WIFI_MACADDR, O_RDONLY, 0);
if (fp < 0) {
pr_err("%s: Failed to read error %d for %s\n",
__FUNCTION__, fp, FILE_WIFI_MACADDR);
goto random_mac;
}
for (i = 0; i<12; i++) {
macbyte=0;
sys_lseek( fp,i+7680,SEEK_SET);
readlen = sys_read(fp,&macbyte,1);
if (i)
sprintf(macaddr,"%s%c",macaddr,macbyte);
else
sprintf(macaddr,"%c",macbyte);
}
if (readlen > 0) {
unsigned char* macbin;
macbin = (unsigned char*)macaddr;
pr_info("%s: READ MAC ADDRESS %02X:%02X:%02X:%02X:%02X:%02X\n",
__FUNCTION__,
macbin[0], macbin[1], macbin[2],
macbin[3], macbin[4], macbin[5]);
if (memcmp(macbin, nullmac, ETHER_ADDR_LEN) == 0 ||
memcmp(macbin, bcastmac, ETHER_ADDR_LEN) == 0) {
sys_close(fp);
goto random_mac;
}
memcpy(buf, macbin, ETHER_ADDR_LEN);
} else {
sys_close(fp);
goto random_mac;
}
sys_close(fp);
return ret;
random_mac:
set_fs(oldfs);
pr_debug("%s: %p\n", __func__, buf);
if (memcmp( mymac, nullmac, ETHER_ADDR_LEN) != 0) {
/* Mac displayed from UI is never updated..
So, mac obtained on initial time is used */
memcpy(buf, mymac, ETHER_ADDR_LEN);
return 0;
}
srandom32((uint)jiffies);
rand_mac = random32();
buf[0] = 0x00;
buf[1] = 0x90;
buf[2] = 0x4c;
buf[3] = (unsigned char)rand_mac;
buf[4] = (unsigned char)(rand_mac >> 8);
buf[5] = (unsigned char)(rand_mac >> 16);
memcpy(mymac, buf, 6);
pr_info("[%s] Exiting. MAC %02X:%02X:%02X:%02X:%02X:%02X\n",
__FUNCTION__,
buf[0], buf[1], buf[2], buf[3], buf[4], buf[5] );
return 0;
}
The idea is to load the nv parition, located at /dev/block/mmcblk0p7, then read the mac address, which is located at offset 7680 on the nv. The problem is that the MAC address is written in hex, so I'm trying to print it to an ASCII string using sprintf().
for (i = 0; i<12; i++) {
macbyte=0;
sys_lseek( fp,i+7680,SEEK_SET);
readlen = sys_read(fp,&macbyte,1);
if (i)
sprintf(macaddr,"%s%c",macaddr,macbyte);
else
sprintf(macaddr,"%c",macbyte);
}
In the nv the MAC looks something like this: 34 30 42 30 46 41 36 35 39 33 34 39, which in ASCII is 40B0FA659349. But instead the resulting MAC is 34:30:42:30:46:41, which tells me that the hex values are not getting converted at all.
What would be the proper way to export the hex values into an ASCII string? I'm new to programming and i was hoping someone could give me some tips.
Thanks in advance.
In your loop you are reading single bytes and converting them to hex strings, while what you actually need to do is read the hex string and convert it byte values. Unless you actually want a hex string, in which case no conversion is necessary.
You have 12 hex characters representing 6 bytes so:
#define MAC_LEN 6
uint8_t macbytes[MAC_LEN] ;
for( i = 0; i < MAC_LEN; i++ )
{
char hex_str[3] ;
unsigned byte_val ;
sys_lseek( fp, (i*2) + 7680, SEEK_SET ) ;
readlen = sys_read( fp, hex_str, 2 ) ;
sscanf( hex_str, "%2X", &byte_val ) ;
macbytes[i] = (uint8_t)byte_val ) ;
}
The data in NV is already ASCII coded hexadecimal; for example 0x34 is the ASCII code for the hex digit '4', and 0x30 that for '0', together the ASCII character pair "40" represent the single 8 bit integer value 0x40. So the conversion you need is ASCII to byte array, not "hex to ASCII" (which makes no semantic sense).
I think this is OP's stubbing block: forming a string version of the MAC address.
I'll make this wiki for anyone to modify, borrow or steal.
sys_lseek( fp,i+7680,SEEK_SET);
char macaddr[100];
char *p = macaddr;
const char *sep = "";
for (i = 0; i < 12; i++) {
unsigned char macbyte;
int readlen = sys_read(fp, &macbyte, 1);
if (readlen != 1) Handle_Error();
p += sprintf(p, "%s%02X", sep, macbyte);
sep = ":";
}
puts(macaddr);

C - Problems extracting data from buffer. Possibly endianess-related

I'm having some difficulties extracting data from a buffer using memcpy.
First, I memcpy some variables into a buffer:
int l1_connect(const char* hostname, int port) {
// Variables to be stored in the buffer
char *msg = "Hi, I'm a message"; // strlen(msg) == 17
uint16_t sender_id = htons(1); // sizeof(sender_id) == 2
uint16_t packet_size = htons(sizeof(packet_size)+sizeof(sender_id)+strlen(msg)); // sizeof(packet_size) == 2
// Checking values
printf("l1_connect():\nsender_id: %d, packet_size: %d\n\n", ntohs(sender_id), ntohs(packet_size));
// sender_id == 1, packet_size == 21
// The buffer
char buf[100];
// Copying everything
memcpy(&buf, &sender_id, sizeof(sender_id));
memcpy(&buf+sizeof(sender_id), &packet_size, sizeof(packet_size));
memcpy(&buf+sizeof(sender_id)+sizeof(packet_size), &msg, strlen(msg));
// Passing buf to another function
int bytes_sent = l1_send(1, buf, sizeof(buf));
}
I then try to extract that data (checking, before sending over UDP socket):
int l1_send( int device, const char* buf, int length ) {
// Variables in which to store extracted data
uint16_t id = 0;
uint16_t size = 0;
char msg[50];
memcpy(&id, &buf, sizeof(id));
memcpy(&size, &buf+sizeof(id), sizeof(size));
int remaining = ntohs(size) - (sizeof(id) + sizeof(size));
printf("l1_send():\nremaining: %d\n", remaining); // -37041
// memcpy-ing with correct(?) offset
memcpy(&msg, &buf+sizeof(id)+sizeof(size), 50);
msg[49] = '\0';
printf("id: %d\n", ntohs(id)); // 8372
printf("size: %d\n", ntohs(size)); // 37045
printf("msg: %s\n", msg); // ��$_�
return 0; // For now
}
As you can see, the values aren't quite what I'm expecting. Can anyone tell me what I'm doing wrong?
Your pointer math is incorrect. You're using &buf where you should just be using buf. If this doesn't explain what is wrong, nothing else I can say will:
#include <stdio.h>
int main(int argc, char **argv)
{
char buff[100];
printf("buff : %p\nbuff+10 : %p\n&buff+10 : %p\n", buff, buff+10, &buff+10);
return 0;
}
Output (varies by platform, obviously)
buff : 0xbf87a8bc
buff+10 : 0xbf87a8c6
&buff+10 : 0xbf87aca4
See it live. The math you're doing is incrementing by type, which for &buf is a pointer to array of 100 chars; not a simple char address. Therefore, &buff + 10 (in my sample) says "give me the 10th array of 100 chars from where I am now.". The subsequent write is invoking undefined behavior as a consequence.
Valgrind is your buddy here, btw. It would have caught this in a heartbeat.
Update
May as well fill in the entire gambit while I'm here. This is also wrong in l1_send:
memcpy(&id, &buf, sizeof(id));
// this------^
and the subsequent other areas you're using it in that function. You're taking the address of a parameter pointer, not the value within it. I'm confident you need buf there as well.
Try this:
memcpy(buf, &sender_id, sizeof(sender_id));
memcpy(buf + sizeof(sender_id), &packet_size, sizeof(packet_size));
memcpy(buf + sizeof(sender_id) + sizeof(packet_size), msg, strlen(msg));
To help you understand what is wrong with your code, you can read this.
Related: Pointer math vs. Array index

Create a string from uint32/16_t and then parse back the original numbers

I need to put into a char* some uint32_t and uint16_t numbers. Then I need to get them back from the buffer.
I have read some questions and I've tried to use sprintf to put them into the char* and sscanf get the original numbers again. However, I'm not able to get them correctly.
Here's an example of my code with only 2 numbers. But I need more than 2, that's why I use realloc. Also, I don't know how to use sprintf and sscanf properly with uint16_t
uint32_t gid = 1100;
uint32_t uid = 1000;
char* buffer = NULL;
uint32_t offset = 0;
buffer = realloc(buffer, sizeof(uint32_t));
sprintf(buffer, "%d", gid);
offset += sizeof(uint32_t);
buffer = realloc(buffer, sizeof(uint32_t) + sizeof(buffer));
sprintf(buffer+sizeof(uint32_t), "%d", uid);
uint32_t valorGID;
uint32_t valorUID;
sscanf(buffer, "%d", &valorGID);
buffer += sizeof(uint32_t);
sscanf(buffer, "%d", &valorUID);
printf("ValorGID %d ValorUID %d \n", valorGID, valorUID);
And what I get is
ValorGID 11001000 ValorUID 1000
What I need to get is
ValorGID 1100 ValorUID 1000
I am new in C, so any help would be appreciated.
buffer = realloc(buffer, sizeof(uint32_t));
sprintf(buffer, "%d", gid);
offset += sizeof(uint32_t);
buffer = realloc(buffer, sizeof(uint32_t) + sizeof(buffer));
sprintf(buffer+sizeof(uint32_t), "%d", uid);
This doesn't really make sense, and will not work as intended except in lucky circumstances.
Let us assume that the usual CHAR_BIT == 8 holds, so sizeof(uint32_t) == 4. Further, let us assume that int is a signed 32-bit integer in two's complement representation without padding bits.
sprintf(buffer, "%d", gid) prints the decimal string representation of the bit-pattern of gid interpreted as an int to buffer. Under the above assumptions, gid is interpreted as a number between -2147483648 and 2147483647 inclusive. Thus the decimal string representation may contain a '-', contains 1 to 10 digits and the 0-terminator, altogether it uses two to twelve bytes. But you have allocated only four bytes, so whenever 999 < gid < 2^32-99 (the signed two's complement interpretation is > 999 or < -99), sprintf writes past the allocated buffer size.
That is undefined behaviour.
It's likely to not crash immediately because allocating four bytes usually gives you a larger chunk of memory effectively (if e.g. malloc always returns 16-byte aligned blocks, the twelve bytes directly behind the allocated four cannot be used by other parts of the programme, but belong to the programme's address space, and writing to them will probably go undetected). But it can easily crash later when the end of the allocated chunk lies on a page boundary.
Also, since you advance the write offset by four bytes for subsequent sprintfs, part of the previous number gets overwritten if the string representation (excluding the 0-termnator) used more than four bytes (while the programme didn't yet crash due to writing to non-allocated memory).
The line
buffer = realloc(buffer, sizeof(uint32_t) + sizeof(buffer));
contains further errors.
buffer = realloc(buffer, new_size); loses the reference to the allocated memory and causes a leak if realloc fails. Use a temporary and check for success
char *temp = realloc(buffer, new_size);
if (temp == NULL) {
/* reallocation failed, recover or cleanup */
free(buffer);
exit(EXIT_FAILURE);
}
/* it worked */
buffer = temp;
/* temp = NULL; or let temp go out of scope */
The new size sizeof(uint32_t) + sizeof(buffer) of the new allocation is always the same, sizeof(uint32_t) + sizeof(char*). That's typically eight or twelve bytes, so it doesn't take many numbers to write outside the allocated area and cause a crash or memory corruption (which may cause a crash much later).
You must keep track of the number of bytes allocated to buffer and use that to calculate the new size. There is no (portable¹) way to determine the size of the allocated memory block from the pointer to its start.
Now the question is whether you want to store the string representations or the bit patterns in the buffer.
Storing the string representations has the problem that the length of the string representation varies with the value. So you need to include separators between the representations of the numbers, or ensure that all representations have the same length by padding (with spaces or leading zeros) if necessary. That would for example work like
#include <stdint.h>
#include <inttypes.h>
#define MAKESTR(x) # x
#define STR(x) MAKESTR(x)
/* A uint32_t can use 10 decimal digits, so let each field be 10 chars wide */
#define FIELD_WIDTH 10
uint32_t gid = 1100;
uint32_t uid = 1000;
size_t buf_size = 0, offset = 0;
char *buffer = NULL, *temp = NULL;
buffer = realloc(buffer, FIELD_WIDTH + 1); /* one for the '\0' */
if (buffer == NULL) {
exit(EXIT_FAILURE);
}
buf_size = FIELD_WIDTH + 1;
sprintf(buffer, "%0" STR(FIELD_WIDTH) PRIu32, gid);
offset += FIELD_WIDTH;
temp = realloc(buffer, buf_size + FIELD_WIDTH);
if (temp == NULL) {
free(buffer);
exit(EXIT_FAILURE);
}
buffer = temp;
temp = NULL;
buf_size += FIELD_WIDTH;
sprintf(buffer + offset, "%0" STR(FIELD_WIDTH) PRIu32, uid);
offset += FIELD_WIDTH;
/* more */
uint32_t valorGID;
uint32_t valorUID;
/* rewind for scanning */
offset = 0;
sscanf(buffer + offset, "%" STR(FIELD_WIDTH) SCNu32, &valorGID);
offset += FIELD_WIDTH;
sscanf(buffer + offset, "%" STR(FIELD_WIDTH) SCNu32, &valorUID);
printf("ValorGID %u ValorUID %u \n", valorGID, valorUID);
with zero-padded fixed-width fields. If you'd rather use separators than a fixed width, the calculation of the required length and the offsets becomes more complicated, but unless the numbers are large, it would use less space.
If you'd rather store the bit-patterns, which would be the most compact way of storing, you'd use something like
size_t buf_size = 0, offset = 0;
unsigned char *buffer = NULL, temp = NULL;
buffer = realloc(buffer, sizeof(uint32_t));
if (buffer == NULL) {
exit(EXIT_FAILURE);
}
buf_size = sizeof(uint32_t);
for(size_t b = 0; b < sizeof(uint32_t); ++b) {
buffer[offset + b] = (gid >> b*8) & 0xFF;
}
offset += sizeof(uint32_t);
temp = realloc(buffer, buf_size + sizeof(uint32_t));
if (temp == NULL) {
free(buffer);
exit(EXIT_FAILURE);
}
buffer = temp;
temp = NULL;
buf_size += sizeof(uint32_t);
for(size_t b = 0; b < sizeof(uint32_t); ++b) {
buffer[offset + b] = (uid >> b*8) & 0xFF;
}
offset += sizeof(uint32_t);
/* And for reading the values */
uint32_t valorGID, valorUID;
/* rewind */
offset = 0;
valorGID = 0;
for(size_t b = 0; b < sizeof(uint32_t); ++b) {
valorGID |= buffer[offset + b] << b*8;
}
offset += sizeof(uint32_t);
valorUID = 0;
for(size_t b = 0; b < sizeof(uint32_t); ++b) {
valorUID |= buffer[offset + b] << b*8;
}
offset += sizeof(uint32_t);
¹ If you know how malloc etc. work in your implementation, it may be possible to find the size from malloc's bookkeeping data.
The format specifier '%d' is for int and thus is wrong for uint32_t. First uint32_t is an unsigned type, so you should at least use '%u', but then it might also have a different width than int or unsigned. There are macros foreseen in the standard: PRIu32 for printf and SCNu32 for scanf. As an example:
sprintf(buffer, "%" PRIu32, gid);
The representation returned by sprintf is a char*. If you are trying to store an array of integers as their string representatins then your fundamental data type is a char**. This is a ragged matrix of char if we are storing only the string data itself, but since the longest string a uint32_t can yield is 10 chars, plus one for the terminating null, it makes sense to preallocate this many bytes to hold each string.
So to store n uint32_t's from array a in array s as strings:
const size_t kMaxIntLen=11;
uint32_t *a,b;
// fill a somehow
...
size_t n,i;
char **s.*d;
if((d=(char*)malloc(n*kMaxIntLen))==NULL)
// error!
if((s=(char**)malloc(n*sizeof(char*)))==NULL)
// error!
for(i=0;i<n;i++)
{
s[i]=d+i; // this is incremented by sizeof(char*) each iteration
snprintf(s[i],kMaxIntLen,"%u",a[i]); // snprintf to be safe
}
Now the ith number is at s[i] so to print it is just printf("%s",s[i]);, and to retrieve it as an integer into b is sscanf(s[i],"%u",&b);.
Subsequent memory management is a bit trickier. Rather than constantly using using realloc() to grow the buffer, it is better to preallocate a chunk of memory and only alter it when exhausted. If realloc() fails it returns NULL, so store a pointer to your main buffer before calling it and that way you won't lose a reference to your data. Reallocate the d buffer first - again allocate enough room for several more strings - then if it succeeds see if d has changed. If so, destroy (free()) the s buffer, malloc() it again and rebuild the indices (you have to do this since if d has changed all your indices are stale). If not, realloc() s and fix up the new indices. I would suggest wrapping this whole thing in a structure and having a set of routines to operate on it, e.g.:
typedef struct StringArray
{
char **strArray;
char *data;
size_t nStrings;
} StringArray;
This is a lot of work. Do you have to use C? This is vastly easier as a C++ STL vector<string> or list<string> with the istringstream classes and the push_back() container method.
uint32_t gid = 1100;
uint32_t uid = 1000;
char* buffer = NULL;
uint32_t offset = 0;
buffer = realloc(buffer, sizeof(uint32_t));
sprintf(buffer, "%d", gid);
offset += sizeof(uint32_t);
buffer = realloc(buffer, sizeof(uint32_t) + sizeof(buffer));
sprintf(buffer+sizeof(uint32_t), "%d", uid);
uint32_t valorGID;
uint32_t valorUID;
sscanf(buffer, "%4d", &valorGID);
buffer += sizeof(uint32_t);
sscanf(buffer, "%d", &valorUID);
printf("ValorGID %d ValorUID %d \n", valorGID, valorUID);
`
I think this may resolve the issue !

linux kernel convert char * to uint8_t[6] (read string to mac)

I need to convert a string "00:11:22:33:44:55" to an uint8_t[6] representing a mac.
I tried on my own, read somewhere char can be casted to uint8_t, but I'm kinda exhausted to try on my own. :(
Maybe there is a function in the kernel which does what I want.
If not, here is my code, what do I do wrong?
char * cleaned_mac =NULL;
char * extractMac(unsigned char * shared_user_buffer, size_t offset) {
char * buffer = kmalloc(17, GFP_KERNEL);
cleaned_mac = kmalloc(13, GFP_KERNEL);
int i = 0;
strncpy(buffer, shared_user_buffer + offset, 17);
printk("BUFFER [%s]\n", buffer);
while (*buffer && i < 12) {
if (isxdigit(*buffer)) {
printk("BUFFER [%c]\n", *buffer);
cleaned_mac[i] = *buffer;
printk("CLEANED BUFFER [%c]\n", *cleaned_mac);
i++;
}
++buffer;
}
cleaned_mac[12]=0x00;
printk("CLEANED BUFFER [%s]\n", cleaned_mac);
return cleaned_mac;
}
calling it like:
uint8_t * mac;
mac = extractMac(shared_user_buffer, strlen(tmq_server_prefix));
printk(KERN_DEBUG "MAC[%s]\n", mac);
printk(KERN_DEBUG "MAC[%02x:%02x:%02x:%02x:%02x:%02x]\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
so when I give "08:00:27:19:1f:02" in the function the result is:
Oct 13 17:41:28 client2 kernel: [ 1953.179271] CLEANED BUFFER [080027191f02]
Oct 13 17:41:28 client2 kernel: [ 1953.179273] MAC[080027191f02]
Oct 13 17:41:28 client2 kernel: [ 1953.179276] MAC[30:38:30:30:32:37]
So 08 became 30 and 38 ? Why is that?
Solution inspired from Dave (thank you):
uint8_t * cleaned_mac = NULL;
uint8_t * extractMac(unsigned char * shared_user_buffer, size_t offset) {
char *c;
char * buffer = kmalloc(17, GFP_KERNEL);
int p = 0;
const char * sep = ":";
cleaned_mac = kmalloc(ETH_ALEN * sizeof(uint8_t), GFP_KERNEL);
strncpy(buffer, shared_user_buffer + offset, 17);
while ((c = strsep(&buffer, sep))) {
cleaned_mac[p++] = simple_strtol(c, NULL, 16);
}
return cleaned_mac;
}
Usage then:
uint8_t * mac;
mac = extractMac(shared_user_buffer, strlen(tmq_server_prefix));
printk(KERN_DEBUG "---------------MAC [%02x:%02x:%02x:%02x:%02x:%02x]\n",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
I can't decipher how your code is supposed to work, so I'll just write how I would do it:
char* macIn = "08:00:27:19:1f:02";
uint8_t macOut[6] = {0};
sscanf(macIn, "%2x:%2x:%2x:%2x:%2x:%2x", macOut, macOut+1, macOut+2, macOut+3, macOut+4, macOut+5);
printf("MAC IN: [%s]\n", macIn);
printf("MAC OUT (hex): [%02x:%02x:%02x:%02x:%02x:%02x]\n",
macOut[0], macOut[1], macOut[2], macOut[3], macOut[4], macOut[5]);
printf("MAC OUT (decimal): [%02d:%02d:%02d:%02d:%02d:%02d]\n",
macOut[0], macOut[1], macOut[2], macOut[3], macOut[4], macOut[5]);
Tokenize the string, and call strtol on each result
char *c;
int p = 0;
for(c=strtok(buffer, ",");c;c=strtok(NULL, ","))
mac[p++] = strtol(c, NULL, 16);
The %02x printf format interprets mac[0] as an integer, and prints it out as a string by converting it to two-digit hex.
Since mac[0] holds the ASCII character 0, whose ASCII code is 0x30, it's perfectly normal that you get the output you have.
You have to take every pair of characters, verify that the are really in the range '0'..'9', 'A'..'F' or 'a'..'f'. Then you take the first, map it to its "meaning" (0..15), multiply it with 16 and add the second one, mapped as well.
I've encoutered the same problem, finally solved with this simple code, it is in linux kernel.
char *mac_local = "e4:95:6e:4e:ee:6c";
for(i=0;i<6;i++)
buffAssco[i+START_POS] = simple_strtol(mac_local+3*i,NULL,16)&0xff;
The 11-year-old answer from Chriszuma is actually wrong.
Reading "%2x" to an uint8_t will result in some unintentional memory modification.
The right specifier to read hex value for uint8_t is "%hhx"
So the sscanf should be like this:
sscanf(macIn, "%2hhx:%2hhx:%2hhx:%2hhx:%2hhx:%2hhx", macOut, macOut+1, macOut+2, macOut+3, macOut+4, macOut+5);

Resources