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);
Related
So I have a binary file that I want to read that is structured such that there are 256 segments of the following structure:
First Byte: integer representing the length of the bits of the field following it that you need to read. It doesn't necessarily end at a byte boundary
Variable number of bits: The field you want to read. It doesn't necessarily end at a byte boundary
The file ends with 0's padded out so that it ends at a byte boundary.
I'm struggling to figure out an ideal method that involves reading as few individual bits as possible. I'm thinking of maybe reading the length first, dividing this value by 8 and reading that number of bytes next, and then using remainder of the previous operation (if any) to read the rest of the field bit by bit. I'm not sure if this is an ideal method however. Any suggestions?
Edit: Attached is a link to the files. The readable file is the format I would like to print out the binary file as.
To take an example from the desired output:
length for 9c: 4
code for 9c: 1101
4 would be the first byte read from the binary file, and 1101 would be the variable number of bits
https://ln2.sync.com/dl/e85dc8b40/3f5wbhaq-kxz3ijv8-wuts3t32-442gbsh2
The naive method works excellently (for small files)
The input is actually completely unaligned, just a series of bits, without any padding.
[I'll delete this answer in 1 minute, because I dont want do do someone's homework]
#include <stdio.h>
#include <stdlib.h>
#define the_path "/home/Download/binary_file.dict"
struct bitfile {
FILE *fp;
unsigned char byte;
unsigned char left;
};
struct bitfile * bfopen(char *path)
{
struct bitfile *bp;
bp = malloc(sizeof *bp);
bp->fp = fopen(path, "rb" );
bp->byte = 0;
bp->left = 0;
return bp;
}
int bfclose(struct bitfile * bp)
{
int rc;
rc = fclose(bp->fp);
free(bp);
return rc;
}
int bfgetb(struct bitfile * bp)
{
int ch;
if (!bp->left) {
ch = fgetc(bp->fp);
if (ch < 0) return EOF;
bp->byte = ch;
bp->left = 8;
}
bp->left -= 1;
ch = bp->byte & (1u << bp->left) ? 1 : 0;
// bp->byte >>= 1;
return ch;
}
void bfflush(struct bitfile * bp)
{
bp->left =0;
}
unsigned bp_get_n( struct bitfile *bp, unsigned bitcount)
{
unsigned val=0;
while(bitcount--) {
int ch;
ch = bfgetb(bp);
if (ch < 0) return EOF;
val <<=1;
val |= ch;
}
return val;
}
int main(void)
{
struct bitfile *bp;
int ch;
unsigned iseg, ibit, nbit;
bp = bfopen( the_path);
for (iseg =0; iseg <16*16; iseg++) {
// bfflush(bp);
nbit = bp_get_n(bp, 8);
fprintf(stdout, "Seg%u: %u bits\n", iseg, nbit);
fprintf(stdout, "payload:");
for (ibit=0; ibit < nbit; ibit++) {
ch = bfgetb(bp);
if (ch < 0) break;
fputc( '0'+ ch, stdout);
}
fprintf(stdout, ".\n");
}
bfclose(bp);
return 0;
}
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
I'm a complete newbie in C and have an assignment that states I have to implement CRC-16 into a given UDP File Transfer solution. Given code is as follows:
#pragma comment(lib, "ws2_32.lib")
#include "stdafx.h"
#include <winsock2.h>
#include "ws2tcpip.h"
#include <stdio.h>
#define TARGET_IP "10.4.115.122"
//#define TARGET_IP "127.0.0.1"
#define BUFFERS_LEN 1024
#define SIZE_PACKET 10 // we can send up to 9 999 999 999 packets
#define HEADER_LEN (SIZE_PACKET + 5)
#define DATA_LEN (BUFFERS_LEN - HEADER_LEN)
//#define SENDER
#define END {getchar();return 0;}
#define RECEIVER
typedef struct Data
{
int size;
char *data;
}Data;
#ifdef SENDER
#define TARGET_PORT 5005
#define LOCAL_PORT 8888
#endif // SENDER
#ifdef RECEIVER
#define TARGET_PORT 8888
#define LOCAL_PORT 5005
#endif // RECEIVER
void InitWinsock()
{
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
}
void print(char *data, int size)
{
for (int i = 0; i < size; i++)
{
if (data[i] == '\0')
{
printf("\\0");
}
else
{
printf("%c", data[i]);
}
}
printf("\n");
}
void clearBuffer(char *buffer, int size)
{
/* Put NULL character on the array */
for (int i = 0; i < size; i++)
{
buffer[i] = '\0';
}
}
void createHeaderBuffers(char *buffer, int info, int size)
{
// create the array containing the number of the packet and the data length
char temp[HEADER_LEN];
clearBuffer(temp, HEADER_LEN);
sprintf(temp, "%d", info);
int size_temp = strlen(temp);
int begin = size - size_temp;
for (int i = 0; i < size; i++)
{
if (i < begin) // fill the begining of the array with zero
{
buffer[i] = '0';
}
else // add the usefull info at the end e.g : 0000052
{
buffer[i] = temp[i - begin];
}
}
}
int createBuffer( char *buffer, char *data,int numPacket,int dataLength)
{
/* Create the buffer we will send*/
char numPacket_c[SIZE_PACKET+1];
char dataLength_c[5];
clearBuffer(buffer, BUFFERS_LEN);
clearBuffer(numPacket_c, 4);
clearBuffer(dataLength_c, 5);
createHeaderBuffers(numPacket_c, numPacket, SIZE_PACKET); // create the array containing the number of the packet
createHeaderBuffers(dataLength_c, dataLength, 4); // create the array containing the length of the data
for (int i = 0; i < BUFFERS_LEN; i++)
{
char ch;
if (i < SIZE_PACKET) // start by adding the number of the packet byte by byte
{
buffer[i] = numPacket_c[i];
}
else if (i < SIZE_PACKET+4) // then we add the length of the data
{
buffer[i] = dataLength_c[i- SIZE_PACKET];
}
else if (i < HEADER_LEN) // the the flag to say if it(s the end of the file
{
if(dataLength < DATA_LEN -1)
buffer[i] = '1';
else
buffer[i] = '0';
}
else if (i < HEADER_LEN + dataLength) // the the data
{
buffer[i] = data[i - HEADER_LEN];
}
else // fill the rest of the buffer with NULL character
{
buffer[i] = '\0';
}
}
return 0;
}
void copy(char *dest, char *source, int size)
{
/* Copy a buffer in another one byte by byte */
//printf("%s\n", source);
for (int i = 0; i < size; i++)
{
dest[i] = source[i];
//printf("%c\n", source[i]);
}
}
void readFile(char *buffer, int size, char *data, int *numPacket, int *dataLength, int *isEnd)
{
//print(buffer, size);
char isEnd_c[2];
char numPacket_c[SIZE_PACKET + 1];
char dataLength_c[5];
clearBuffer(isEnd_c, 2);
clearBuffer(numPacket_c, SIZE_PACKET + 1);
clearBuffer(dataLength_c, 5);
clearBuffer(data, DATA_LEN + 1);
for (int i = 0; i < size; i++)
{
if (i < SIZE_PACKET) // read the number of the packet
{
numPacket_c[i] = buffer[i];
printf("%c", buffer[i]);
}
else if (i < SIZE_PACKET + 4) // read the length of the data
{
dataLength_c[i - SIZE_PACKET] = buffer[i];
}
else if (i < HEADER_LEN) // read the isEnd FLAG
{
printf("\n%c\n", buffer[i]);
isEnd_c[0] = buffer[i];
}
else // read the data
{
data[i - HEADER_LEN] = buffer[i];
}
}
*numPacket = atoi(numPacket_c);
*isEnd = atoi(isEnd_c);
*dataLength = atoi(dataLength_c);
printf("%d ; %d ; %d\n", *numPacket, *dataLength, *isEnd);
}
unsigned short crc16(const unsigned char* numPacket, unsigned char length) {
unsigned char x;
unsigned short crc = 0xFFFF;
while (length--) {
x = crc >> 8 ^ *numPacket++;
x ^= x >> 4;
crc = (crc << 8) ^ ((unsigned short)(x << 12)) ^ ((unsigned short)(x << 5)) ^ ((unsigned short)x);
}
return crc;
}
//**********************************************************************
int main()
{
SOCKET socketS;
InitWinsock();
struct sockaddr_in local;
struct sockaddr_in from;
int fromlen = sizeof(from);
local.sin_family = AF_INET;
local.sin_port = htons(LOCAL_PORT);
local.sin_addr.s_addr = INADDR_ANY;
socketS = socket(AF_INET, SOCK_DGRAM, 0);
if (bind(socketS, (sockaddr*)&local, sizeof(local)) != 0) {
printf("Binding error!\n");
getchar(); //wait for press Enter
return 1;
}
//**********************************************************************
#ifdef SENDER
FILE *fp, *fp1;
char buffer_tx[BUFFERS_LEN];
int numPacket = 0;
char numberPacket[BUFFERS_LEN];
int isEnd = 0;
char test[100];
char header[HEADER_LEN];
char data[DATA_LEN];
char dataContent[DATA_LEN];
int len;
int num;
char *token;
sockaddr_in addrDest;
addrDest.sin_family = AF_INET;
addrDest.sin_port = htons(TARGET_PORT);
InetPton(AF_INET, _T(TARGET_IP), &addrDest.sin_addr.s_addr);
char *name = "test.jpg";
fp = fopen(name, "rb");
if (fp == NULL)
{
printf("error opening file\n");
}
fseek(fp, 0L, SEEK_END);
int sz = ftell(fp);
rewind(fp);
sz = (int)(sz / DATA_LEN) + 1;
strncpy(buffer_tx, name, BUFFERS_LEN); //put the nam of the file in the buffer
sendto(socketS, buffer_tx, BUFFERS_LEN, 0, (sockaddr*)&addrDest, sizeof(addrDest)); // send the name of the file
recvfrom(socketS, buffer_tx, BUFFERS_LEN, 0, (sockaddr*)&from, &fromlen); // wait aknowledgment
clearBuffer(buffer_tx, BUFFERS_LEN);
sprintf(buffer_tx, "%d", sz);
sendto(socketS, buffer_tx, BUFFERS_LEN, 0, (sockaddr*)&addrDest, sizeof(addrDest)); // send size of file
recvfrom(socketS, buffer_tx, BUFFERS_LEN, 0, (sockaddr*)&from, &fromlen); // wait aknowledgment
// This is to be sure that the receiver receive the name and the size correctly in the right order
clearBuffer(buffer_tx, BUFFERS_LEN);
clearBuffer(dataContent, DATA_LEN);
int n = 1;
int dataLength = 0;
while ((n = fread(dataContent, 1, DATA_LEN - 1,fp)) > 0) // read data of the file
{
clearBuffer(buffer_tx, BUFFERS_LEN); // clear the buffer for further utilisation
createBuffer(buffer_tx, dataContent, numPacket++, n); // add the header to the data |numPacket|dataLength|isEnd|data|
sendto(socketS, buffer_tx, BUFFERS_LEN, 0, (sockaddr*)&addrDest, sizeof(addrDest)); // send the packet
}
fclose(fp);
#endif // SENDER
#ifdef RECEIVER
FILE *fp;
char buffer_rx[BUFFERS_LEN];
Data *data;
int n = 0;
int k;
int how_many = 310;
//strncpy(buffer_rx, "12:1|salut", BUFFERS_LEN);
printf("Waiting for datagram ...\n");
int numPacket = 0;
int isEnd = 0;
int size = 0;
char size_file_c[BUFFERS_LEN];
int size_file = 0;
char header[HEADER_LEN];
char d[DATA_LEN + 1];
char name[BUFFERS_LEN];
char output[30];
char salut[DATA_LEN + 1];
sockaddr_in addrDest;
addrDest.sin_family = AF_INET;
addrDest.sin_port = htons(TARGET_PORT);
InetPton(AF_INET, _T(TARGET_IP), &addrDest.sin_addr.s_addr);
recvfrom(socketS, name, BUFFERS_LEN, 0, (sockaddr*)&from, &fromlen); // receiving name of file
sendto(socketS, name, BUFFERS_LEN, 0, (sockaddr*)&addrDest, sizeof(addrDest)); // send aknowledgment
recvfrom(socketS, size_file_c, BUFFERS_LEN, 0, (sockaddr*)&from, &fromlen); // receiving size of file
sendto(socketS, size_file_c, BUFFERS_LEN, 0, (sockaddr*)&addrDest, sizeof(addrDest)); // send aknowledgment
size_file = atoi(size_file_c);
// This is to be sure that the receiver receive the name and the size correctly in the right order
data = (Data *)calloc(size_file, sizeof(Data)); // allocate memory for the data
//closesocket(socketS);
//END;
//analyseBuffer(buffer_rx,d, &numPacket, &isEnd);
for (int i = 0; i < size_file; i++)
{
printf("waiting packet\n");
if ((k = recvfrom(socketS, buffer_rx, BUFFERS_LEN, 0, (sockaddr*)&from, &fromlen)) == SOCKET_ERROR) // receive a packet
{
printf("error during reception");
getchar();
return -1;
}
else
{
readFile(buffer_rx, BUFFERS_LEN, d, &numPacket, &size, &isEnd); // analyse the pacet to extract the data, the number of the packet, the data lenght and if it's the end
data[numPacket].data = (char*) calloc(size, 1); // allocate only the necessary memory
data[numPacket].size = size;
//print(d, DATA_LEN);
copy(data[numPacket].data, d, data[numPacket].size); // copy only the usefull info (without '\0')
printf("%d ; %d\n", i, size_file);
if (isEnd)
break;
clearBuffer(buffer_rx, BUFFERS_LEN); // clear the buffer for further utilisation
}
}
printf("file name : %s\n", name);
printf("enter the name of new file to be saved\n");
scanf("%s", output); // ask the user to set a file name
fp = fopen(output, "wb");
for (int i = 0; i <size_file; i++)
{
fwrite(data[i].data, data[i].size, 1, fp); // write the data to the file in the right order
}
fclose(fp); // close the file
closesocket(socketS);
#endif // RECEIVER
//**********************************************************************
getchar(); //wait for press Enter
return 0;
}
Notice the CRC-16 function , which is:
unsigned short crc16(const unsigned char* numPacket, unsigned char length) {
unsigned char x;
unsigned short crc = 0xFFFF;
while (length--) {
x = crc >> 8 ^ *numPacket++;
x ^= x >> 4;
crc = (crc << 8) ^ ((unsigned short)(x << 12)) ^ ((unsigned short)(x << 5)) ^ ((unsigned short)x);
}
return crc;
}
My question is : What is the best/easiest way to implement the CRC-16 function I have here? Do I pass a unsigned short crc parameter variable to the createBuffer() function, call the crc16() function inside the createBuffer() function and take the value it returns and assign it to the parameter value and then append it to the buffer?
Or is there a much simpler way to do it that I'm currently not thinking about?
Regarding What is the best/easiest way to implement the CRC-16 function I have here?
First, it appears your CRC-16 function is already implemented. How to use it is illustrated below.
CRC functions are typically used to take a file or buffer of any size as input, and produce a unique value for the purpose of verifying the contents of the file.
Here is a simple example of how I would use this function to read two types of input... (note, bufIn, and buf can be arrays of much larger sizes)
int main(void)
{
unsigned char bufIn[] = {1,45,76,23,245,9,54,55,210,90,23,54,78,14,27,86,34};
char buf[] = {"lkjahsloiwuyhfajsldnaouiyhrqkuhsldajnfdlakdsfa;jsidurfaliu;adjklflkja;sdlkjasdklfauiea;e"};
unsigned short crcOut1, crcOut2;
crcOut1 = crc16(bufIn, sizeof(bufIn)); //for bufIn returns 0x7782
crcOut2 = crc16(buf, sizeof(buf)); //for buf returns 0x98FB
return 0;
}
EDIT to address question in comment...
In your code, one possible way to use this is to call the crc16() function inside your fread while loop:
unsigned short packetCrc;
while ((n = fread(dataContent, 1, DATA_LEN - 1,fp)) > 0) // read data of the file
{
packetCrc = crc16(dataContent, n);
// verify packetCrc value against some expected value perhaps?
clearBuffer(buffer_tx, BUFFERS_LEN); // clear the buffer for further utilisation
createBuffer(buffer_tx, dataContent, numPacket++, n); // add the header to the data |numPacket|dataLength|isEnd|data|
sendto(socketS, buffer_tx, BUFFERS_LEN, 0, (sockaddr*)&addrDest, sizeof(addrDest)); // send the packet
}
The code:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <Windows.h>
HANDLE creatFile(void);
long WriteBuffer(HANDLE);
char * GetBuffer(void);
void main(void)
{
HANDLE hFile;
printf("CreateFile: ");
hFile = creatFile();
if(hFile != NULL)
{
WriteBuffer(hFile);
FlushFileBuffers(hFile);
}
CloseHandle(hFile);
printf("\n\rDone");
getchar();
}
HANDLE creatFile(void)
{
HANDLE hFile;
LPCWSTR sFileName = L"\\\\.\\E:";
DWORD dwDesiredAccess = GENERIC_WRITE;
DWORD fShareMode = FILE_SHARE_WRITE | FILE_SHARE_WRITE;
DWORD fCreationDisposition = OPEN_EXISTING;
DWORD fFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
hFile = CreateFile(sFileName, dwDesiredAccess,fShareMode,
NULL, fCreationDisposition, fFlagsAndAttributes,
NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
hFile = NULL;
printf("INVALID_HANDLE_VALUE: ");
switch (GetLastError())
{
case 5:
printf("\n\r Administrative Account required to run this program\n\r");
break;
case 87:
printf("\n\r Invalid Parameter in CreateFile Call \n\r");
break;
default:
printf("Error %d\n",GetLastError());
break;
}
return NULL;
}
else
{
printf("Attached -> %d\n\r",hFile);
return hFile;
}
}
long WriteBuffer(HANDLE hFile)
{
char *str = GetBuffer(); // x 64 will give us 512 (sector sized buffer) ;
DWORD bytesWritten;
long totalBytesWritten = 0;
long idx = 0;
int len = strlen(str);
for(idx = 0; idx < 100000; idx ++)
{
if(WriteFile(hFile, str, 512 * sizeof(char), &bytesWritten, NULL))
{
totalBytesWritten += bytesWritten;
printf("Sectors Written : %d\r",idx+1);
}
else
{
int le = GetLastError();
printf("Last Error : %d\r",GetLastError());
break;
}
}
printf("\n\r");
printf("Bytes Written: %d\n\r", totalBytesWritten);
printf("Handle -> %d\n\r",hFile);
return totalBytesWritten;
}
char * GetBuffer(void)
{
int i = 0, idx = 0;
const char * cstr_init = "ERASED1 ";
char *buffer = (char*)malloc(512);
char word2[512];
for (idx = 0; idx < 512; idx+=8) {
for (i = 0; i < 8; i++) {
buffer[idx+i] = cstr_init[i];
if(strlen(buffer) == 512)
break;
}
}
return buffer;
}
The problems:
char * GetBuffer has extraneous data of 16 bytes in it. I modified WriteFile so that it only write 512 (instead of the 528) chars that the buffer actually holds.
After 16 sectors of writing - WriteFile fails with GetLastError = 5 (Access Denied)
The Questions:
How do I fix WriteFile so that it does NOT fail after 16 sectors and...
How do I fix GetBuffer so it actually produces a 512 buffer and not 528?
Notes
The application is ANSI C and the program is being run as admin.
I can't speak to the error with WriteFile(), however, you've got issues with your string operations.
C strings are null terminated, that is, the string literal "abc" is actually an array of characters like: {'a','b','c','\0'} All str...() operations rely on this fact. There is no information stored anywhere on the length of the string, only the fact that it is expected to end with a '\0'.
Your GetBuffer() function improved:
char * GetBuffer(void)
{
int i = 0, idx = 0;
const char * cstr_init = "ERASED1 ";
char *buffer = malloc(513); // Space for a '\0'
for (idx = 0; idx < 512; idx+=8) {
for (i = 0; i < 8; i++) {
buffer[idx+i] = cstr_init[i];
}
}
}
You were getting weird results for strlen() because it looks for a '\0' and was only finding one at 528 bytes, reading outside of the 512 bytes malloced is invoking undefined behavior, you could have found a '\0' at 513 bytes, or never found one.
Other comments, after calling GetBuffer() you never free() the char * returned, that is a memory leak since it was malloced and lost outside of that context. Also, a better implementation of GetBuffer() would be:
char * GetBuffer(void)
{
const char * cstr_init = "ERASED1 ";
const int cstr_init_len = strlen(cstr_init);
char * buffer = calloc(1,513); // Guaranteed zeroed
int i;
for (i = 0; i < 512; i+=8) {
memcpy(buffer+i, cstr_init, cstr_init_len);
// Or strcpy(buffer+1, cstr_init);
// Or strcat(buffer, cstr_init); // Inefficient because each call runs from buffer[0] to find a '\0' for where to start appending
}
return buffer;
}
the INT type could only be a 2 byte number from 0 - 65536 unsigned. replace all INT types with LONG (long) to start with...Not sure what compiler environment you are in though - as this change may not apply
I was unable to fix question 2 - the way I would have liked. However, by Telling WriteFile to write 512 bytes out of the buffer of 528 bytes - I got the desired results. As for Question 1.
Because The Disk drive has a Filesystem on it - Windows OS recognises that fact and prevents writing to the full drive. All I needed to do was in fact Lock the drive and that would give me exclusive access to the drive.
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <Windows.h>
#include <winioctl.h>
HANDLE creatFile(void);
long WriteBuffer(HANDLE);
char * GetBuffer(void);
void main(void)
{
HANDLE hFile;
printf("CreateFile: ");
hFile = creatFile();
if(hFile != NULL)
{
WriteBuffer(hFile);
FlushFileBuffers(hFile);
}
CloseHandle(hFile);
printf("\n\rDone");
getchar();
}
HANDLE creatFile(void)
{
HANDLE hFile;
LPCWSTR sFileName = L"\\\\.\\E:";
DWORD dwDesiredAccess = GENERIC_WRITE;
DWORD fShareMode = FILE_SHARE_WRITE | FILE_SHARE_WRITE;
DWORD fCreationDisposition = OPEN_EXISTING;
DWORD fFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
BOOL bResult = FALSE; // results flag
LPDWORD lpBytesReturned = 0;
hFile = CreateFile(sFileName, dwDesiredAccess,fShareMode,
NULL, fCreationDisposition, fFlagsAndAttributes,
NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
hFile = NULL;
printf("INVALID_HANDLE_VALUE: ");
switch (GetLastError())
{
case 5:
printf("\n\r Administrative Account required to run this program\n\r");
break;
case 87:
printf("\n\r Invalid Parameter in CreateFile Call \n\r");
break;
default:
printf("Error %d\n",GetLastError());
break;
}
return NULL;
}
else
{
printf("Attached -> %d\n\r",hFile);
// HERE I JUST ADD THE FSCTL_LOCK_VOLUME command to stop Windows preventing me from writing to the drive
bResult = DeviceIoControl(hFile, // device to be queried
FSCTL_LOCK_VOLUME, // dwIoControlCode
NULL, 0, // no input buffer
NULL, 0, // output buffer
lpBytesReturned, // # bytes returned
(LPOVERLAPPED) NULL); // synchronous I/O
return hFile;
}
}
long WriteBuffer(HANDLE hFile)
{
char *str = GetBuffer(); // x 64 will give us 512 (sector sized buffer) ;
DWORD bytesWritten;
long totalBytesWritten = 0;
long idx = 0;
int len = strlen(str);
for(idx = 0; idx < 100000; idx ++)
{
if(WriteFile(hFile, str, 512 * sizeof(char), &bytesWritten, NULL))
{
totalBytesWritten += bytesWritten;
printf("Sectors Written : %d\r",idx+1);
}
else
{
int le = GetLastError();
printf("\n\rLast Error : %d\r",GetLastError());
break;
}
}
printf("\n\r");
printf("Bytes Written: %d\n\r", totalBytesWritten);
printf("Handle -> %d\n\r",hFile);
return totalBytesWritten;
}
char * GetBuffer(void)
{
const char * cstr_init = "ERASED2 ";
const int cstr_init_len = strlen(cstr_init);
char *buffer = (char*)malloc(513);
int i;
for (i = 0; i < 512; i+=8) {
memcpy(buffer+i, cstr_init, cstr_init_len);
// Or strcpy(buffer+1, cstr_init);
// Or strcat(buffer, cstr_init); // Inefficient because each call runs from buffer[0] to find a '\0' for where to start appending
}
return buffer;
}
So for future reference, if you wish to write directly to the drive it is important to LOCK the volume first. I know that there are memory leaks within the above code - but as a learning exercise for the Writing of data to a drive I am not bothered. The code will be tidied up and made into a .dll
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?
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);