STM32F1 write/read flash memory, cortex M3 - c++

I need to write/read flash memory in my blue pill board (stm32f103c8t6) and I followed this tutorial https://www.youtube.com/watch?v=BKgh896Bj8Q&t=32s but I used Keil uVision 5 IDE and I had this error
" #error 167: argument of type "uint32_t" is incompatible with parameter of type "const char *" "
Here is the .c library I used
static uint32_t GetPage(uint32_t Address)
{
for (int indx=0; indx<128; indx++)
{
if((Address < (0x08000000 + (1024 *(indx+1))) ) && (Address >= (0x08000000 + 1024*indx)))
{
return (0x08000000 + 1024*indx);
}
}
return -1;
}
uint32_t Flash_Write_Data (uint32_t StartPageAddress, uint32_t * DATA_32)
{
static FLASH_EraseInitTypeDef EraseInitStruct;
uint32_t PAGEError;
int sofar=0;
int numberofwords = (strlen(DATA_32)/4) + ((strlen(DATA_32) % 4) != 0);
/* Unlock the Flash to enable the flash control register access *************/
HAL_FLASH_Unlock();
/* Erase the user Flash area*/
uint32_t StartPage = GetPage(StartPageAddress);
uint32_t EndPageAdress = StartPageAddress + numberofwords*4;
uint32_t EndPage = GetPage(EndPageAdress);
/* Fill EraseInit structure*/
EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;
EraseInitStruct.PageAddress = StartPage;
EraseInitStruct.NbPages = ((EndPage - StartPage)/FLASH_PAGE_SIZE) +1;
if (HAL_FLASHEx_Erase(&EraseInitStruct, &PAGEError) != HAL_OK)
{
/*Error occurred while page erase.*/
return HAL_FLASH_GetError ();
}
/* Program the user Flash area word by word*/
while (sofar<numberofwords)
{
if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, StartPageAddress, DATA_32[sofar]) == HAL_OK)
{
StartPageAddress += 4; // use StartPageAddress += 2 for half word and 8 for double word
sofar++;
}
else
{
/* Error occurred while writing data in Flash memory*/
return HAL_FLASH_GetError ();
}
}
/* Lock the Flash to disable the flash control register access (recommended
to protect the FLASH memory against possible unwanted operation) *********/
HAL_FLASH_Lock();
return 0;
}
void Flash_Read_Data (uint32_t StartPageAddress, __IO uint32_t * DATA_32)
{
while (1)
{
*DATA_32 = *(__IO uint32_t *)StartPageAddress;
if (*DATA_32 == 0xffffffff)
{
*DATA_32 = '\0';
break;
}
StartPageAddress += 4;
DATA_32++;
}
}
void Convert_To_Str (uint32_t *data, char *str)
{
int numberofbytes = ((strlen(data)/4) + ((strlen(data) % 4) != 0)) *4;
for (int i=0; i<numberofbytes; i++)
{
str[i] = data[i/4]>>(8*(i%4));
}
}
And in the main.c I just used Flash_Write_Data(0x0801FC00,data);
It's all commands from the .c and .h files, and I also used CubeMX with Keil IDE (don't know if it makes any diference)
I don't know if it's a keils configuration problem, the .c and .h libraries used in the tutorial don't see to be so much complex.
I searched on the internet and it's a very common error but didn't find a solution. I didn't even found much about Flash memory in cortex M3 with PAGE MEMORY TYPE. If someone could help with this error or write/read flash memory in cortex M3 I would appreciate it.

Related

Accessing /dev/mem from GNU Radio on ZedBoard

I'm trying to access a custom IP block from GNU Radio [ZedBoard] using /dev/mem. I tested the code routine writing and doing iterative reading from /dev/mem from a local c file. The code running directly from the console correctly sets the registers and reads the correct values back.
I made a custom GNU Radio block using this code but when executing the grc flow python script I receive the error that /dev/mem was not accessible.
I know that this is NOT a safe way to interact with the device and am working on a driver to replace this. Currently I need this to work for testing and development. I went so far as to change permissions to /dev/mem to 777, I added my local user (Linaro) to the kmem group as well. I execute the python file for the flowgraph using sudo as well.
What am I overlooking? Thank you.
edit: Adding the output error is : "Permission Denied" if run from sudo after chmod 777 /dev/mem the error is : "Operation not permitted"
/* -*- c++ -*- */
/*
* Copyright 1970 <+YOU OR YOUR COMPANY+>.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gnuradio/io_signature.h>
#include "qpskModulator_impl.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
#include <fcntl.h>
#define READ 0
#define WRITE 1
#define SAMPLES 64
#define INPUT_WIDTH 32
int memmap_fpga(int direction, char * address, float value);
namespace gr {
namespace fpga_accelerators {
qpskModulator::sptr
qpskModulator::make()
{
return gnuradio::get_initial_sptr
(new qpskModulator_impl());
}
/*
* The private constructor
*/
qpskModulator_impl::qpskModulator_impl()
: gr::block("qpskModulator",
gr::io_signature::make(1, 1, sizeof(float)),
gr::io_signature::make(2, 2, sizeof(short)))
{}
/*
* Our virtual destructor.
*/
qpskModulator_impl::~qpskModulator_impl()
{
}
void
qpskModulator_impl::forecast (int noutput_items, gr_vector_int &ninput_items_required)
{
ninput_items_required[0] = noutput_items;
ninput_items_required[1] = noutput_items;
}
int
qpskModulator_impl::general_work (int noutput_items,
gr_vector_int &ninput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items)
{
const float *in = (const float *) input_items[0];
short *out0 = (short *) output_items[0]; // I CHANNEL
short *out1 = (short *) output_items[1]; // Q CHANNEL
short data_valid;
const float BLANK = 0;
float GO = 1;
//int hwI_mod[SAMPLES*INPUT_WIDTH/2];
//int hwQ_mod[SAMPLES*INPUT_WIDTH/2];
int i;
char * DATA_IN_ADDR = "0x43c00004";
char * GO_ADDR = "0x43c00000";
char * DATA_OUT_ADDR = "0x43c00008";
char * DATA_VALID_ADDR = "0x43c0000C";
// transfer input array and size to FPGA
memmap_fpga(WRITE, DATA_IN_ADDR, *in);
memmap_fpga(WRITE, GO_ADDR, GO); // assert go
GO = 0;
memmap_fpga(WRITE, GO_ADDR, GO); // reset go value
data_valid = 0;
while (data_valid == 0) {
data_valid = memmap_fpga(READ, DATA_VALID_ADDR, BLANK);
}
// read the outputs back from the FPGA
unsigned temp_dataout;
unsigned y;
for (i=0; i < SAMPLES*INPUT_WIDTH/2 - 8; i++)
{
temp_dataout = memmap_fpga(READ, DATA_OUT_ADDR, BLANK);
out0[i] = temp_dataout & 0xfff; // I channel
y = out0[i] >> 11;
if (y == 1)
out0[i] = out0[i] - 4096;
out1[i] = (temp_dataout >> 12) & 0xfff;
y = out1[i] >> 11;
if (y == 1)
out1[i] = out1[i] - 4096;
//printf("%d: HW: I_mod = %d and Q_mod = %d\n", i, hwI_mod[i], hwQ_mod[i]);
}
// Do <+signal processing+>
// Tell runtime system how many input items we consumed on
// each input stream.
consume_each (noutput_items);
// Tell runtime system how many output items we produced.
return noutput_items;
}
} /* namespace fpga_accelerators */
} /* namespace gr */
int memmap_fpga(int direction, char * address, float value){
unsigned gpio_addr = strtoul(address, NULL, 0);
/* DEBUG INFO
printf("address: %08x\n",gpio_addr);
if (direction == IN)
printf("direction: IN\n");
else
printf("direction: OUT\n");
printf("value: %d\n",value);
*/
int fd;
unsigned page_addr, page_offset;
void *ptr;
unsigned page_size=sysconf(_SC_PAGESIZE);
short temp_value;
if (gpio_addr == 0) {
printf("GPIO physical address is required.\n");
return -1;
}
/* Open /dev/mem file */
fd = open ("/dev/mem", O_RDWR);
if (fd < 1) {
printf("Couldn't open /dev/mem\n");
return -1;
}
/* mmap the device into memory */
page_addr = (gpio_addr & (~(page_size-1)));
page_offset = gpio_addr - page_addr;
ptr = mmap(NULL, page_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, page_addr);
if (direction == READ) {
/* Read value from the device register */
temp_value = *((unsigned *)(ptr + page_offset));
//printf("gpio dev-mem test: input: %08x\n",temp_value);
munmap(ptr, page_size);
return(temp_value);
} else {
/* Write value to the device register */
*((unsigned *)(ptr + page_offset)) = value;
munmap(ptr, page_size);
//printf("Wrote to register\n");
}
munmap(ptr, page_size);
return 0;
}
Two things:
You open and memmap the same file for Read/Write access multiple times, without closing it in between – that's a recipe for disaster. Maybe you're just running out of file descriptors (there's a limit on that). Actually reading the errno (you should be doing that!!) would tell you the reason.
Then: Even opening and closing the file repeatedly is a bad idea, performance wise– just open and mmap it once in the constructor. There's no advantage reopening it constantly.

Why thrift TBinaryProtocol read recv data more complex than just size + content

Thrift version is 0.8. I'm implementing my own thrift transport layer in client with C++, protocol use Binary, my server is use frame transport and binary protocol, and is no problem for sure. And I get "No more data to read" exception in TTransport.h readAll function. I traced the call link, find in TBinaryProtocol.tcc
template <class Transport_>
uint32_t TBinaryProtocolT<Transport_>::readMessageBegin(std::string& name,
TMessageType& messageType,
int32_t& seqid) {
uint32_t result = 0;
int32_t sz;
result += readI32(sz); **//sz should be the whole return buf len without the first 4 bytes?**
if (sz < 0) {
// Check for correct version number
int32_t version = sz & VERSION_MASK;
if (version != VERSION_1) {
throw TProtocolException(TProtocolException::BAD_VERSION, "Bad version identifier");
}
messageType = (TMessageType)(sz & 0x000000ff);
result += readString(name);
result += readI32(seqid);
} else {
if (this->strict_read_) {
throw TProtocolException(TProtocolException::BAD_VERSION, "No version identifier... old protocol client in strict mode?");
} else {
// Handle pre-versioned input
int8_t type;
result += readStringBody(name, sz);
result += readByte(type); **//No more data to read in buf, so exception here**
messageType = (TMessageType)type;
result += readI32(seqid);
}
}
return result;
}
So my quesiton is: in frame transport, the data struct, should ONLY be size + content(result, seqid, function name....), that's exactly what my server pack. Then my client read the first 4 bytes lenth, and use it to fetch the whole content, is there any other left to read now?
Here is my client code, I believe quite simple.the most import part I have emphasize that.
class CthriftCli
{
......
TMemoryBuffer write_buf_;
TMemoryBuffer read_buf_;
enum CthriftConn::State state_;
uint32_t frameSize_;
};
void CthriftCli::OnConn4SgAgent(const TcpConnectionPtr& conn)
{
if(conn->connected() ){
conn->setTcpNoDelay(true);
wp_tcp_conn_ = boost::weak_ptr<muduo::net::TcpConnection>(conn);
if(unlikely(!(sp_countdown_latch_4_conn_.get()))) {
return 0;
}
sp_countdown_latch_4_conn_->countDown();
}
}
void CthriftCli::OnMsg4SgAgent(const muduo::net::TcpConnectionPtr& conn,
muduo::net::Buffer* buffer,
muduo::Timestamp receiveTime)
{
bool more = true;
while (more)
{
if (state_ == CthriftConn::kExpectFrameSize)
{
if (buffer->readableBytes() >= 4)
{
frameSize_ = static_cast<uint32_t>(buffer->peekInt32());
state_ = CthriftConn::kExpectFrame;
}
else
{
more = false;
}
}
else if (state_ == CthriftConn::kExpectFrame)
{
if (buffer->readableBytes() >= frameSize_)
{
uint8_t* buf = reinterpret_cast<uint8_t*>((const_cast<char*>(buffer->peek())));
read_buf_.resetBuffer(buf, sizeof(int32_t) + frameSize_, TMemoryBuffer::COPY); **// all the return buf, include first size bytes**
if(unlikely(!(sp_countdown_latch_.get()))){
return;
}
sp_countdown_latch_->countDown();
buffer->retrieve(sizeof(int32_t) + frameSize_);
state_ = CthriftConn::kExpectFrameSize;
}
else
{
more = false;
}
}
}
}
uint32_t CthriftCli::read(uint8_t* buf, uint32_t len) {
if (read_buf_.available_read() == 0) {
if(unlikely(!(sp_countdown_latch_.get()))){
return 0;
}
sp_countdown_latch_->wait();
}
return read_buf_.read(buf, len);
}
void CthriftCli::readEnd(void) {
read_buf_.resetBuffer();
}
void CthriftCli::write(const uint8_t* buf, uint32_t len) {
return write_buf_.write(buf, len);
}
uint32_t CthriftCli::writeEnd(void)
{
uint8_t* buf;
uint32_t size;
write_buf_.getBuffer(&buf, &size);
if(unlikely(!(sp_countdown_latch_4_conn_.get()))) {
return 0;
}
sp_countdown_latch_4_conn_->wait();
TcpConnectionPtr sp_tcp_conn(wp_tcp_conn_.lock());
if (sp_tcp_conn && sp_tcp_conn->connected()) {
muduo::net::Buffer send_buf;
send_buf.appendInt32(size);
send_buf.append(buf, size);
sp_tcp_conn->send(&send_buf);
write_buf_.resetBuffer(true);
} else {
#ifdef MUDUO_LOG
MUDUO_LOG_ERROR << "conn error, NOT send";
#endif
}
return size;
}
So please give me some hints about this?
You seem to have mixed concepts of 'transport' and 'protocol'.
Binary Protocol describes how data should be encoded (protocol layer).
Framed Transport describes how encoded data should be delivered (forwarded by message length) - transport layer.
Important part - Binary Protocol is not (and should not) be aware of any transport issues. So if you add frame size while encoding on transport level, you should also interpret incoming size before passing read bytes to Binary Protocol for decoding. You can (for example) use it to read all required bytes at once etc.
After quick looking trough you code: try reading 4 bytes of frame size instead of peeking it. Those bytes should not be visible outside transport layer.

Have a very long buffer but only use the last 1GB bytes of data.

Need to write an application in C/C++ on Linux that receives a stream of bytes from a socket and process them. The total bytes could be close to 1TB. If I have unlimited amount memory, I will just put it all in the memory, so my application can easily process data. It's much easy to do many things on flat memory space, such as memmem(), memcmp() ... On a circular buffer, the application has to be extra smart to be aware of the circular buffer.
I have about 8G of memory, but luckily due to locality, my application never needs to go back by more than 1GB from the latest data it received. Is there a way to have a 1TB buffer, with only the latest 1GB data mapped to physical memory? If so, how to do it?
Any ideas? Thanks.
Here's an example. It sets up a full terabyte mapping, but initially inaccessible (PROT_NONE). You, the programmer, maintain a window that can only extend and move upwards in memory. The example program uses a one and a half gigabyte window, advancing it in steps of 1,023,739,137 bytes (the mapping_use() makes sure the available pages cover at least the desired region), and does actually modify every page in every window, just to be sure.
#define _GNU_SOURCE
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
typedef struct mapping mapping;
struct mapping {
unsigned char *head; /* Start of currently accessible region */
unsigned char *tail; /* End of currently accessible region */
unsigned char *ends; /* End of region */
size_t page; /* Page size of this mapping */
};
/* Discard mapping.
*/
void mapping_free(mapping *const m)
{
if (m && m->ends > m->head) {
munmap(m->head, (size_t)(m->ends - m->head));
m->head = NULL;
m->tail = NULL;
m->ends = NULL;
m->page = 0;
}
}
/* Move the accessible part up in memory, to [from..to).
*/
int mapping_use(mapping *const m, void *const from, void *const to)
{
if (m && m->ends > m->head) {
unsigned char *const head = ((unsigned char *)from <= m->head) ? m->head :
((unsigned char *)from >= m->ends) ? m->ends :
m->head + m->page * (size_t)(((size_t)((unsigned char *)from - m->head)) / m->page);
unsigned char *const tail = ((unsigned char *)to <= head) ? head :
((unsigned char *)to >= m->ends) ? m->ends :
m->head + m->page * (size_t)(((size_t)((unsigned char *)to - m->head) + m->page - 1) / m->page);
if (head > m->head) {
munmap(m->head, (size_t)(head - m->head));
m->head = head;
}
if (tail > m->tail) {
#ifdef USE_MPROTECT
mprotect(m->tail, (size_t)(tail - m->tail), PROT_READ | PROT_WRITE);
#else
void *result;
do {
result = mmap(m->tail, (size_t)(tail - m->tail), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_FIXED | MAP_PRIVATE | MAP_NORESERVE, -1, (off_t)0);
} while (result == MAP_FAILED && errno == EINTR);
if (result == MAP_FAILED)
return errno = ENOMEM;
#endif
m->tail = tail;
}
return 0;
}
return errno = EINVAL;
}
/* Initialize a mapping.
*/
int mapping_create(mapping *const m, const size_t size)
{
void *base;
size_t page, truesize;
if (!m || size < (size_t)1)
return errno = EINVAL;
m->head = NULL;
m->tail = NULL;
m->ends = NULL;
m->page = 0;
/* Obtain default page size. */
{
long value = sysconf(_SC_PAGESIZE);
page = (size_t)value;
if (value < 1L || (long)page != value)
return errno = ENOTSUP;
}
/* Round size up to next multiple of page. */
if (size % page)
truesize = size + page - (size % page);
else
truesize = size;
/* Create mapping. */
do {
errno = ENOTSUP;
base = mmap(NULL, truesize, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE, -1, (off_t)0);
} while (base == MAP_FAILED && errno == EINTR);
if (base == MAP_FAILED)
return errno;
/* Success. */
m->head = base;
m->tail = base;
m->ends = (unsigned char *)base + truesize;
m->page = page;
errno = 0;
return 0;
}
static void memtouch(void *const ptr, const size_t size)
{
if (ptr && size > 0) {
unsigned char *mem = (unsigned char *)ptr;
const size_t step = 2048;
size_t n = size / (size_t)step - 1;
mem[0]++;
mem[size-1]++;
while (n-->0) {
mem += step;
mem[0]++;
}
}
}
int main(void)
{
const size_t size = (size_t)1024 * (size_t)1024 * (size_t)1024 * (size_t)1024;
const size_t need = (size_t)1500000000UL;
const size_t step = (size_t)1023739137UL;
unsigned char *base;
mapping map;
size_t i;
if (mapping_create(&map, size)) {
fprintf(stderr, "Cannot create a %zu-byte mapping: %m.\n", size);
return EXIT_FAILURE;
}
printf("Have a %zu-byte mapping at %p to %p.\n", size, (void *)map.head, (void *)map.ends);
fflush(stdout);
base = map.head;
for (i = 0; i <= size - need; i += step) {
printf("Requesting %p to %p .. ", (void *)(base + i), (void *)(base + i + need));
fflush(stdout);
if (mapping_use(&map, base + i, base + i + need)) {
printf("Failed (%m).\n");
fflush(stdout);
return EXIT_FAILURE;
}
printf("received %p to %p.\n", (void *)map.head, (void *)map.tail);
fflush(stdout);
memtouch(base + i, need);
}
mapping_free(&map);
return EXIT_SUCCESS;
}
The approach is twofold. First, an inaccessible (PROT_NONE) mapping is created to reserve the necessary virtual contiguous address space. If we omit this step, it would make it possible for a malloc() call or similar to acquire pages within this range, which would defeat the entire purpose; a single terabyte-long mapping.
Second, when the accessible window extends into the region, either mprotect() (if USE_MPROTECT is defined), or mmap() is used to make the required pages accessible. Pages no longer needed are completely unmapped.
Compile and run using
gcc -Wall -Wextra -std=c99 example.c -o example
time ./example
or, to use mmap() only once and mprotect() to move the window,
gcc -DUSE_MPROTECT=1 -Wall -Wextra -std=c99 example.c -o example
time ./example
Note that you probably don't want to run the test if you don't have at least 4GB of physical RAM.
On this particular machine (i5-4200U laptop with 4GB of RAM, 3.13.0-62-generic kernel on Ubuntu x86_64), quick testing didn't show any kind of performance difference between mprotect() and mmap(), in execution speed or resident set size.
If anyone bothers to compile and run the above, and finds that one of them has a repeatable benefit/drawback (resident set size or time used), I'd very much like to know about it. Please also define your kernel and CPU used.
I'm not sure which details I should expand on, since this is pretty straightforward, really, and the Linux man pages project man 2 mmap and man 2 mprotect pages are quite descriptive. If you have any questions on this approach or program, I'd be happy to try and elaborate.

Detect USB hardware keylogger

I need to determine is there hardware keylogger that was plugged to PC with USB keyboard. It needs to be done via software method, from user-land. However wiki says that it is impossible to detect HKL using soft, there are several methods exists. The best and I think only one overiew that present in net relating that theme is "Detecting Hardware Keyloggers, by Fabian Mihailowitsch - youtube".
Using this overview I am developing a tool to detect USB hardware keyloggers. The sources for detecting PS/2 keyloggers was already shared by author and available here. So my task is to make it worked for USB only.
As suggested I am using libusb library to interfere with USB devices in system.
So, there are methods I had choosen in order to detect HKL:
Find USB keyboard that bugged by HKL. Note that HKL is usually
invisible from device list in system or returned by libusb.
Detect Keyghost HKL by: Interrupt read from USB HID device, send usb reset (libusb_reset_device), read interrupt again. If data returned on last read is not nulls then keylogger detected. It is described on page 45 of Mihailowitsch's presentation
Time measurement. The idea is measure time of send/receive packets using control transfer for original keyboard for thousands times. In case HKL has been plugged, program will measure time again and then compare the time with the original value. For HKL it have to be much(or not so much) greater.
Algorithm is:
Send an output report to Keyboard(as Control transfer) (HID_REPORT_TYPE_OUTPUT 0x02 )
Wait for ACKed packet
Repeat Loop (10.000 times)
Measure time
Below is my code according to steps of detection.
1. Find USB keyboard
libusb_device * UsbKeyboard::GetSpecifiedDevice(PredicateType pred)
{
if (_usbDevices == nullptr) return nullptr;
int i = 0;
libusb_device *dev = nullptr;
while ((dev = _usbDevices[i++]) != NULL)
{
struct libusb_device_descriptor desc;
int r = libusb_get_device_descriptor(dev, &desc);
if (r >= 0)
{
if (pred(desc))
return dev;
}
}
return nullptr;
}
libusb_device * UsbKeyboard::FindKeyboard()
{
return GetSpecifiedDevice([&](libusb_device_descriptor &desc) {
bool isKeyboard = false;
auto dev_handle = libusb_open_device_with_vid_pid(_context, desc.idVendor, desc.idProduct);
if (dev_handle != nullptr)
{
unsigned char buf[255] = "";
// product description contains 'Keyboard', usually string is 'USB Keyboard'
if (libusb_get_string_descriptor_ascii(dev_handle, desc.iProduct, buf, sizeof(buf)) >= 0)
isKeyboard = strstr((char*)buf, "Keyboard") != nullptr;
libusb_close(dev_handle);
}
return isKeyboard;
});
}
Here we're iterating through all USB devices in system and checks their Product string. In my system this string for keyboard is 'USB keyboard' (obviously).
Is it stable way to detect keyboard through Product string? Is there other ways?
2. Detect Keyghost HKL using Interrupt read
int UsbKeyboard::DetectKeyghost(libusb_device *kbdev)
{
int r, i;
int transferred;
unsigned char answer[PACKET_INT_LEN];
unsigned char question[PACKET_INT_LEN];
for (i = 0; i < PACKET_INT_LEN; i++) question[i] = 0x40 + i;
libusb_device_handle *devh = nullptr;
if ((r = libusb_open(kbdev, &devh)) < 0)
{
ShowError("Error open device", r);
return r;
}
r = libusb_set_configuration(devh, 1);
if (r < 0)
{
ShowError("libusb_set_configuration error ", r);
goto out;
}
printf("Successfully set usb configuration 1\n");
r = libusb_claim_interface(devh, 0);
if (r < 0)
{
ShowError("libusb_claim_interface error ", r);
goto out;
}
r = libusb_interrupt_transfer(devh, 0x81 , answer, PACKET_INT_LEN,
&transferred, TIMEOUT);
if (r < 0)
{
ShowError("Interrupt read error ", r);
goto out;
}
if (transferred < PACKET_INT_LEN)
{
ShowError("Interrupt transfer short read %", r);
goto out;
}
for (i = 0; i < PACKET_INT_LEN; i++) {
if (i % 8 == 0)
printf("\n");
printf("%02x, %02x; ", question[i], answer[i]);
}
printf("\n");
out:
libusb_close(devh);
return 0;
}
I've got such error on libusb_interrupt_transfer:
libusb: error [hid_submit_bulk_transfer] HID transfer failed: [5] Access denied
Interrupt read error - Input/Output Error (LIBUSB_ERROR_IO) (GetLastError() - 1168)
No clue why 'access denied', then IO error, and GetLastError() returns 1168, which means - Element not found (What element?). Looking for help here.
Time measurement. Send output report and wait for ACK packet.
int UsbKeyboard::SendOutputReport(libusb_device *kbdev)
{
const int PACKET_INT_LEN = 1;
int r, i;
unsigned char answer[PACKET_INT_LEN];
unsigned char question[PACKET_INT_LEN];
for (i = 0; i < PACKET_INT_LEN; i++) question[i] = 0x30 + i;
for (i = 1; i < PACKET_INT_LEN; i++) answer[i] = 0;
libusb_device_handle *devh = nullptr;
if ((r = libusb_open(kbdev, &devh)) < 0)
{
ShowError("Error open device", r);
return r;
}
r = libusb_set_configuration(devh, 1);
if (r < 0)
{
ShowError("libusb_set_configuration error ", r);
goto out;
}
printf("Successfully set usb configuration 1\n");
r = libusb_claim_interface(devh, 0);
if (r < 0)
{
ShowError("libusb_claim_interface error ", r);
goto out;
}
printf("Successfully claim interface\n");
r = libusb_control_transfer(devh, CTRL_OUT, HID_SET_REPORT, (HID_REPORT_TYPE_OUTPUT << 8) | 0x00, 0, question, PACKET_INT_LEN, TIMEOUT);
if (r < 0) {
ShowError("Control Out error ", r);
goto out;
}
r = libusb_control_transfer(devh, CTRL_IN, HID_GET_REPORT, (HID_REPORT_TYPE_INPUT << 8) | 0x00, 0, answer, PACKET_INT_LEN, TIMEOUT);
if (r < 0) {
ShowError("Control In error ", r);
goto out;
}
out:
libusb_close(devh);
return 0;
}
Error the same as for read interrupt:
Control Out error - Input/Output Error (LIBUSB_ERROR_IO) (GetLastError() - 1168
)
How to fix please? Also how to wait for ACK packet?
Thank you.
UPDATE:
I've spent a day on searching and debbuging. So currently my problem is only to
send Output report via libusb_control_transfer. The 2nd method with interrupt read is unnecessary to implement because of Windows denies access to read from USB device using ReadFile.
It is only libusb stuff left, here is the code I wanted to make work (from 3rd example):
// sending Output report (LED)
// ...
unsigned char buf[65];
buf[0] = 1; // First byte is report number
buf[1] = 0x80;
r = libusb_control_transfer(devh, CTRL_OUT,
HID_SET_REPORT/*0x9*/, (HID_REPORT_TYPE_OUTPUT/*0x2*/ << 8) | 0x00,
0, buf, (uint16_t)2, 1000);
...
The error I've got:
[ 0.309018] [00001c0c] libusb: debug [_hid_set_report] Failed to Write HID Output Report: [1] Incorrect function
Control Out error - Input/Output Error (LIBUSB_ERROR_IO) (GetLastError() - 1168)
This error occures right after DeviceIoControl call in libusb internals.
What means "Incorrect function" there?

Winpcap saving raw packets not from an adapter

I am trying to build an application that converts my old custom Ethernet logs (bin files) to standard winpcap style logs.
The problem is that I can't seem to find an example of how to opening a pcap_t* without using an adapter (network card). The temp.pkt has not been created.
I have looked thou the examples provided with Winpcap and all of them use a live adapter when dumping packets. This example is the closest \WpdPack\Examples-pcap\savedump\savedump.c is the closest, see example below slightly modified.
#ifdef _MSC_VER
/*
* we do not want the warnings about the old deprecated and unsecure CRT functions
* since these examples can be compiled under *nix as well
*/
#define _CRT_SECURE_NO_WARNINGS
#endif
#include "pcap.h"
int main(int argc, char **argv)
{
pcap_if_t *alldevs;
pcap_if_t *d;
int inum;
int i=0;
pcap_t *adhandle;
char errbuf[PCAP_ERRBUF_SIZE];
pcap_dumper_t *dumpfile;
/* Open the adapter */
if ((adhandle= pcap_open(??????, // name of the device
65536, // portion of the packet to capture.
// 65536 grants that the whole packet will be captured on all the MACs.
1, // promiscuous mode (nonzero means promiscuous)
1000, // read timeout
errbuf // error buffer
)) == NULL)
{
fprintf(stderr,"\nUnable to open the adapter. %s is not supported by WinPcap\n", d->name);
/* Free the device list */
pcap_freealldevs(alldevs);
return -1;
}
/* Open the dump file */
dumpfile = pcap_dump_open(adhandle, argv[1]);
if(dumpfile==NULL) {
fprintf(stderr,"\nError opening output file\n");
return -1;
}
// ---------------------------
struct pcap_pkthdr header;
header.ts.tv_sec = 1 ; /* seconds */
header.ts.tv_usec = 1; /* and microseconds */
header.caplen = 100; /* length of portion present */
header.len = 100 ; /* length this packet (off wire) */
u_char pkt_data[100];
for( int i = 0 ; i < 100 ; i++ ) {
pkt_data[i] = i ;
}
pcap_dump( (u_char *) dumpfile, &header, (u_char *) &pkt_data);
// ---------------------------
/* start the capture */
// pcap_loop(adhandle, 0, packet_handler, (unsigned char *)dumpfile);
pcap_close(adhandle);
return 0;
}
I suggest doing that using pcap_t since using WinPcap is better than writing it yourself.
The following steps is how to do it:
Use pcap_open_dead() function to create a pcap_t. Read the function description here. The linktype for Ethernet is 1.
Use pcap_dump_open() function to create a pcap_dumper_t.
Use pcap_dump() function to write the packet to the dump file.
I hope this would help you.
If all you're doing is converting your own file format to .pcap, you don't need a pcap_t*, you can just use something like:
FILE* create_pcap_file(const char *filename, int linktype)
{
struct pcap_file_header fh;
fh.magic = TCPDUMP_MAGIC;
fh.sigfigs = 0;
fh.version_major = 2;
fh.version_minor = 4;
fh.snaplen = 2<<15;
fh.thiszone = 0;
fh.linktype = linktype;
FILE *file = fopen(filename, "wb");
if(file != NULL) {
if(fwrite(&fh, sizeof(fh), 1, file) != 1) {
fclose(file);
file = NULL;
}
}
return file;
}
int write_pcap_packet(FILE* file,size_t length,const unsigned char *data,const struct timeval *tval)
{
struct pcap_pkthdr pkhdr;
pkhdr.caplen = length;
pkhdr.len = length;
pkhdr.ts = *tval;
if(fwrite(&pkhdr, sizeof(pkhdr), 1, file) != 1) {
return 1;
}
if(fwrite(data, 1, length, file) != length) {
return 2;
}
return 0;
}