Unable to read from status port in ATAPIO mode - io

I recently got interested in developing my own operating system for fun. While creating the OS and the drivers, I encountered several issues while making the ATA driver. One of the major issues is that if I try to request ATAPIO to read an address (in CHS) and try to get the results from the data port (0x1F0), it returns the same number each time I poll the port. Any suggestions welcome!
Link to repo (code looks better)
ata.hpp
#ifndef DRIVERS_ATA_HPP
#define DRIVERS_ATA_HPP
#include <stdint.h>
#include <stddef.h>
namespace os {
namespace drivers {
namespace commands {
constexpr uint16_t identity = 0xEC;
constexpr uint8_t read_sec = 0x20;
constexpr uint8_t write_sec = 0x30;
}
namespace ports {
constexpr uint8_t io_base = (uint8_t) 0x1F0;
constexpr uint16_t data = io_base + (uint16_t) 0;
constexpr uint16_t err = io_base + (uint16_t) 1;
constexpr uint16_t sec_count = io_base + (uint16_t) 2;
constexpr uint16_t sec_num = io_base + (uint16_t) 3;
constexpr uint16_t cylin_low = io_base + (uint16_t) 4;
constexpr uint16_t cylin_high = io_base + (uint16_t) 4;
constexpr uint8_t drive_head_select = io_base + (uint8_t) 6; // 8 bit output
constexpr uint8_t command = io_base + (uint8_t) 7; // 8 bit output
constexpr uint8_t status = io_base + (uint8_t) 7; // 8 bit output
}
namespace drive_type {
enum {
master_drive = 0xA0,
slave_drive = 0xB0
};
}
// Got info from https://wiki.osdev.org/PCI_IDE_Controller#Read.2FWrite_From_ATA_Drive
namespace drive_bit {
enum {
master_bit = 0,
slave_bit = 1
};
}
// for ata::write() function
struct CHS {
uint16_t cylinder;
uint16_t head;
uint16_t sector;
};
struct data_packet {
data_packet(uint16_t *dat, size_t siz) : data(dat), size(siz) {}
uint16_t *data;
size_t size;
operator bool() { return data && size; }
};
class ata {
public:
ata(unsigned poll_lim = 1000);
~ata();
operator bool() { return ata_init_success; }
data_packet read(int drive_bit, CHS addr, uint16_t num_sectors);
bool write(int drive_bit, CHS addr, data_packet dat);
private:
void identity_cmd();
bool ata_init_success;
unsigned polling_limit;
};
}
}
#endif /* DRIVERS_ATA_HPP */
ata.cpp
#include <drivers/ata.hpp>
#include <drivers/instr.hpp>
#include <lib/zmem.hpp>
#include <lib/zio.hpp>
#include <lib/zassert.hpp>
namespace os {
namespace drivers {
ata::ata(unsigned poll_lim) : ata_init_success(false), polling_limit(poll_lim) {
identity_cmd();
}
ata::~ata() {
}
// TODO: fix memory leak resulting from data_packet... maybe add a destructor?
data_packet ata::read(int drive_bit, CHS addr, uint16_t num_sectors) {
uint16_t num_read = num_sectors * 256;
data_packet packet = { new uint16_t[num_read](), num_read };
instr::outw(ports::drive_head_select, drive_type::master_drive | (drive_bit << 4) | addr.head);
instr::outw(ports::sec_count, num_read * sizeof(uint16_t));
instr::outw(ports::sec_num, addr.sector);
instr::outw(ports::cylin_low, addr.cylinder & 0xFF); // zero out 0000 0000 1111 1111
instr::outw(ports::cylin_high, addr.cylinder & 0xFF00);
// Changed from outb to outw
instr::outw(ports::command, commands::read_sec);
for (size_t i = 0; i < packet.size; i++)
packet.data[i] = instr::inw(ports::data);
return packet;
}
bool ata::write(int drive_bit, CHS addr, data_packet dat) {
if (!dat) return false;
instr::outw(ports::sec_count, dat.size / 512);
instr::outw(ports::sec_num, addr.sector);
instr::outw(ports::cylin_low, addr.cylinder & 0xFF); // zero out 0000 0000 1111 1111
instr::outw(ports::cylin_high, addr.cylinder & 0xFF00);
instr::outw(ports::drive_head_select, drive_type::master_drive | (drive_bit << 4) | addr.head);
// changed from outb to outw
instr::outw(ports::command, commands::write_sec);
for (size_t i = 0; i < dat.size; i++)
instr::outw(ports::data, dat.data[i]);
return true;
}
void ata::identity_cmd() {
instr::outw(ports::drive_head_select, drive_type::master_drive);
// Zero out the IO ports
for (uint16_t port = 0x1F2; port <= 0x1F5; port++)
instr::outw(port, NULL);
instr::outw(ports::command, commands::identity);
// Polling for the status
unsigned polling_index = 0;
uint16_t status;
while (polling_index++ < polling_limit) {
status = instr::inw(ports::status);
if ((status & 128) == 0) break;
}
if (status == 0) {
ata_init_success = false;
return;
}
// Read 256 16 bit values from the data (0x1F0) port
uint16_t identity_data[256]{};
for (uint16_t i = 0; i < 256; i++)
identity_data[i] = instr::inw(ports::data);
#ifdef DEBUG
zl::cout << "Ata Driver Testing" << zl::endl;
zl::cout << "Polling status is " << status << zl::endl;
for (int i = 0; i < 256; i++)
zl::cout << "[" << i << "]: " << identity_data[i] << ",";
zl::cout << zl::endl;
zl::cout << "End of Ata Driver Testing" << zl::endl;
#endif
}
}
}
kernel_entry.cpp
extern "C" void main() {
config_os();
os::drivers::ata driv;
char hello_world[20] = "hello world!";
//driv.write(os::drivers::drive_bit::master_bit, {0, 0, 50}, {hello_world, sizeof(hello_world)});
auto res = driv.read(os::drivers::drive_bit::master_bit, {0, 0, 50}, 1);
zl::cout << "Data from ata driver: " << res.data[0] << zl::endl;
}

As it turns out, all the ATA commands need to be in 8 bit (or 1 byte) input/output. This means that all the inw() and outw() function calls should be converted into inb() and outb() function calls instead. When I made the switch, the problems disappeared!

Related

My thread-safe queue code appears to work, any possible race conditions, deadlocks, or other design problems?

I am new to using condition_variables and unique_locks in C++. I am working on creating an event loop that polls two custom event-queues and a "boolean" (see integer acting as boolean), which can be acted upon by multiple sources.
I have a demo (below) that appears to work, which I would greatly appreciate if you can review and confirm if it follows the best practices for using unique_lock and condition_variables and any problems you foresee happening (race conditions, thread blocking, etc).
In ThreadSafeQueue::enqueue(...): are we unlocking twice by calling notify and having the unique_lock go out of scope?
In the method TheadSafeQueue::dequeueAll(): We assume it is being called by a method that has been notified (cond.notify), and therefore has been locked. Is there a better way to encapsulate this to keep the caller cleaner?
Do we need to make our class members volatile similar to this?
Is there a better way to mockup our situation that allows us to test if we've correctly implemented the locks? Perhaps without the sleep statements and automating the checking process?
ThreadSafeQueue.h:
#include <condition_variable>
#include <cstdint>
#include <iostream>
#include <mutex>
#include <vector>
template <class T>
class ThreadSafeQueue {
public:
ThreadSafeQueue(std::condition_variable* cond, std::mutex* unvrsl_m)
: ThreadSafeQueue(cond, unvrsl_m, 1) {}
ThreadSafeQueue(std::condition_variable* cond, std::mutex* unvrsl_m,
uint32_t capacity)
: cond(cond),
m(unvrsl_m),
head(0),
tail(0),
capacity(capacity),
buffer((T*)malloc(get_size() * sizeof(T))),
scratch_space((T*)malloc(get_size() * sizeof(T))) {}
std::condition_variable* cond;
~ThreadSafeQueue() {
free(scratch_space);
free(buffer);
}
void resize(uint32_t new_cap) {
std::unique_lock<std::mutex> lock(*m);
check_params_resize(new_cap);
free(scratch_space);
scratch_space = buffer;
buffer = (T*)malloc(sizeof(T) * new_cap);
copy_cyclical_queue();
free(scratch_space);
scratch_space = (T*)malloc(new_cap * sizeof(T));
tail = get_size();
head = 0;
capacity = new_cap;
}
void enqueue(const T& value) {
std::unique_lock<std::mutex> lock(*m);
resize();
buffer[tail++] = value;
if (tail == get_capacity()) {
tail = 0;
} else if (tail > get_capacity())
throw("Something went horribly wrong TSQ: 75");
cond->notify_one();
}
// Assuming m has already been locked by the caller...
void dequeueAll(std::vector<T>* vOut) {
if (get_size() == 0) return;
scratch_space = buffer;
copy_cyclical_queue();
vOut->insert(vOut->end(), buffer, buffer + get_size());
head = tail = 0;
}
// Const functions because they shouldn't be modifying the internal variables
// of the object
bool is_empty() const { return get_size() == 0; }
uint32_t get_size() const {
if (head == tail)
return 0;
else if (head < tail) {
// 1 2 3
// 0 1 2
// 1
// 0
return tail - head;
} else {
// 3 _ 1 2
// 0 1 2 3
// capacity-head + tail+1 = 4-2+0+1 = 2 + 1
return get_capacity() - head + tail + 1;
}
}
uint32_t get_capacity() const { return capacity; }
//---------------------------------------------------------------------------
private:
std::mutex* m;
uint32_t head;
uint32_t tail;
uint32_t capacity;
T* buffer;
T* scratch_space;
uint32_t get_next_empty_spot();
void copy_cyclical_queue() {
uint32_t size = get_size();
uint32_t cap = get_capacity();
if (size == 0) {
return; // because we have nothing to copy
}
if (head + size <= cap) {
// _ 1 2 3 ... index = 1, size = 3, 1+3 = 4 = capacity... only need 1 copy
memcpy(buffer, scratch_space + head, sizeof(T) * size);
} else {
// 5 1 2 3 4 ... index = 1, size = 5, 1+5 = 6 = capacity... need to copy
// 1-4 then 0-1
// copy number of bytes: front = 1, to (5-1 = 4 elements)
memcpy(buffer, scratch_space + head, sizeof(T) * (cap - head));
// just copy the bytes from the front up to the first element in the old
// array
memcpy(buffer + (cap - head), scratch_space, sizeof(T) * tail);
}
}
void check_params_resize(uint32_t new_cap) {
if (new_cap < get_size()) {
std::cerr << "ThreadSafeQueue: check_params_resize: size(" << get_size()
<< ") > new_cap(" << new_cap
<< ")... data "
"loss will occur if this happens. Prevented."
<< std::endl;
}
}
void resize() {
uint32_t new_cap;
uint32_t size = get_size();
uint32_t cap = get_capacity();
if (size + 1 >= cap - 1) {
std::cout << "RESIZE CALLED --- BAD" << std::endl;
new_cap = 2 * cap;
check_params_resize(new_cap);
free(scratch_space); // free existing (too small) scratch space
scratch_space = buffer; // transfer pointer over
buffer = (T*)malloc(sizeof(T) * new_cap); // allocate a bigger buffer
copy_cyclical_queue();
// move over everything with memcpy from scratch_space to buffer
free(scratch_space); // free what used to be the too-small buffer
scratch_space =
(T*)malloc(sizeof(T) * new_cap); // recreate scratch space
tail = size;
head = 0;
// since we're done with the old array... delete for memory management->
capacity = new_cap;
}
}
};
// Event Types
// keyboard/mouse
// network
// dirty flag
Main.cpp:
#include <unistd.h>
#include <cstdint>
#include <iostream>
#include <mutex>
#include <queue>
#include <sstream>
#include <thread>
#include "ThreadSafeQueue.h"
using namespace std;
void write_to_threadsafe_queue(ThreadSafeQueue<uint32_t> *q,
uint32_t startVal) {
uint32_t count = startVal;
while (true) {
q->enqueue(count);
cout << "Successfully enqueued: " << count << endl;
count += 2;
sleep(count);
}
}
void sleep_and_set_redraw(int *redraw, condition_variable *cond) {
while (true) {
sleep(3);
__sync_fetch_and_or(redraw, 1);
cond->notify_one();
}
}
void process_events(vector<uint32_t> *qOut, condition_variable *cond,
ThreadSafeQueue<uint32_t> *q1,
ThreadSafeQueue<uint32_t> *q2, int *redraw, mutex *m) {
while (true) {
unique_lock<mutex> lck(*m);
cond->wait(lck);
q1->dequeueAll(qOut);
q2->dequeueAll(qOut);
if (__sync_fetch_and_and(redraw, 0)) {
cout << "FLAG SET" << endl;
qOut->push_back(0);
}
for (auto a : *qOut) cout << a << "\t";
cout << endl;
cout << "PROCESSING: " << qOut->size() << endl;
qOut->clear();
}
}
void test_2_queues_and_bool() {
try {
condition_variable cond;
mutex m;
ThreadSafeQueue<uint32_t> q1(&cond, &m, 1024);
ThreadSafeQueue<uint32_t> q2(&cond, &m, 1024);
int redraw = 0;
vector<uint32_t> qOut;
thread t1(write_to_threadsafe_queue, &q1, 2);
thread t2(write_to_threadsafe_queue, &q2, 1);
thread t3(sleep_and_set_redraw, &redraw, &cond);
thread t4(process_events, &qOut, &cond, &q1, &q2, &redraw, &m);
t1.join();
t2.join();
t3.join();
t4.join();
} catch (system_error &e) {
cout << "MAIN TEST CRASHED" << e.what();
}
}
int main() { test_2_queues_and_bool(); }

How to write to multiple files on different disks simultaneously in one thread with DMA?

I use aio to write multiple files on different disk in one thread. When I use buffered writing, IO processing is concurrent. But cpu loads is very high. When I open files with DIRECT flag, IO processing isn't concurrent.
How to write to multiple files on different disks simultaneously in one thread with DMA?
#include <malloc.h>
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <sstream>
#include <inttypes.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/syscall.h>
#include <linux/aio_abi.h>
using namespace std;
long double timeDiff(timespec start, timespec end) {
const long double s = start.tv_sec + start.tv_nsec * 1.0e-9;
const long double e = end.tv_sec + end.tv_nsec * 1.0e-9;
return e - s;
}
// nr: maximum number of requests that can simultaneously reside in the context.
inline int io_setup(unsigned nr, aio_context_t *ctxp) {
return syscall(__NR_io_setup, nr, ctxp);
}
inline int io_destroy(aio_context_t ctx) {
return syscall(__NR_io_destroy, ctx);
}
// Every I/O request that is submitted to
inline int io_submit(aio_context_t ctx, long nr, struct iocb **iocbpp) {
return syscall(__NR_io_submit, ctx, nr, iocbpp);
}
// For every completed I/O request kernel creates an io_event structure.
// minimal number of events one wants to get.
// maximum number of events one wants to get.
inline int io_getevents(aio_context_t ctx, long min_nr, long max_nr,
struct io_event *events, struct timespec *timeout) {
return syscall(__NR_io_getevents, ctx, min_nr, max_nr, events, timeout);
}
int main(int argc, char *argv[]) {
// prepare data
const unsigned int kAlignment = 4096;
const long data_size = 1600 * 1024 * 12 / 8;
//const long data_size = 2448 * 1344 * 12 / 8;
void * data = memalign(kAlignment, data_size);
memset(data, 0, data_size);
//for (int i = 0; i < data_size; ++i)
// data[i] = 'A';
// prepare fd
//const int file_num = 3;
const int file_num = 2;
int fd_arr[file_num];
for (int i = 0; i < file_num; ++i) {
ostringstream filename;
if (i == 0) {
//filename << "/data/test";
filename << "/test";
} else {
filename << "/data" << i << "/test";
}
//filename << "/data/test" << i;
int fd = open(filename.str().c_str(), O_WRONLY | O_NONBLOCK | O_CREAT | O_DIRECT | O_APPEND, 0644);
//int fd = open(filename.str().c_str(), O_WRONLY | O_NONBLOCK | O_CREAT | O_DIRECT, 0644);
//int fd = open(filename.str().c_str(), O_WRONLY | O_NONBLOCK | O_CREAT, 0644);
if (fd < 0) {
perror("open");
return -1;
}
fd_arr[i] = fd;
}
aio_context_t ctx;
struct io_event events[file_num];
int ret;
ctx = 0;
ret = io_setup(1000, &ctx);
if (ret < 0) {
perror("io_setup");
return -1;
}
struct iocb cbs[file_num];
for (int i = 0; i < file_num; ++i) {
memset(&cbs[i], 0, sizeof(cbs[i]));
}
struct iocb * cbs_pointer[file_num];
for (int i = 0; i < file_num; ++i) {
/* setup I/O control block */
cbs_pointer[i] = &cbs[i];
cbs[i].aio_fildes = fd_arr[i];
cbs[i].aio_lio_opcode = IOCB_CMD_PWRITE; // IOCV_CMD
cbs[i].aio_nbytes = data_size;
}
timespec tStart, tCurr;
clock_gettime(CLOCK_REALTIME, &tStart);
const int frame_num = 10000;
for (int k = 0; k < frame_num; ++k) {
for (int i = 0; i < file_num; ++i) {
/* setup I/O control block */
cbs[i].aio_buf = (uint64_t)data;
//cbs[i].aio_offset = k * data_size;
}
ret = io_submit(ctx, file_num, cbs_pointer);
if (ret < 0) {
perror("io_submit");
return -1;
}
/* get reply */
ret = io_getevents(ctx, file_num, file_num, events, NULL);
//printf("events: %d, k: %d\n", ret, k);
}
clock_gettime(CLOCK_REALTIME, &tCurr);
cout << "frame: " << frame_num << " time: " << timeDiff(tStart, tCurr) << endl;
ret = io_destroy(ctx);
if (ret < 0) {
perror("io_destroy");
return -1;
}
// close fd
for (int i = 0; i < file_num; ++i) {
fsync(fd_arr[i]);
close(fd_arr[i]);
}
return 0;
}
Linux can make writes actually async if and only if the physical extents being written are allocated on the disc already. Otherwise it has to take a mutex and do the allocation first, thus everything becomes synchronous.
Note that truncating the file to a new length usually doesn't actually allocate the underlying extents. You need to prewrite the contents first. Thereafter, rewriting the same extents will now be done async and thus become concurrent.
As you might be gathering, async file i/o on Linux is not great, though it keeps on getting better over time. Windows or FreeBSD have far superior implementations. Even OS X is not terrible. Use any of those instead.

Chibios and the SIM900 Shiled

i have this problem,
i have STM32 Nucleo L152RE and a Shield SIM 900,
now if i write this easy thread all work well,
'static THD_WORKING_AREA(waRead, 128);
static THD_FUNCTION(Thread,arg) {
(void)arg;
chRegSetThreadName("th_callback");
while (TRUE){
/* This will wait for a character to be received */
uint8_t c = sdGet(&SD1); //questo prende il carattere
sdPut(&SD2, c); // questo lo spara alla terminale
}
}
'
when i sand a AT commnad i see the ok answer.
Now i create this buffer
'static uint8_t bufferMsg[128];'
and i use this thread for store the answer
' static THD_WORKING_AREA(waRead5, 128);
static THD_FUNCTION(Thread5,arg) {
chRegSetThreadName("th_Riempio_Buffer");
msg_t charbuf;
int count=0;
uint8_t c;
event_listener_t Uart1Data;
eventmask_t flags;
chEvtRegisterMask((event_source_t *)chnGetEventSource(&SD1), &Uart1Data, EVENT_MASK(1));
while (TRUE) {
chEvtWaitOneTimeout(EVENT_MASK(1), MS2ST(10));
chSysLock();
flags =chEvtGetAndClearFlags(&Uart1Data);
chSysUnlock();
if (flags & CHN_INPUT_AVAILABLE)
{
do
{
charbuf = chnGetTimeout(&SD1,TIME_IMMEDIATE);
if (charbuf != Q_TIMEOUT)
{
while((charbuf != '\n') && (count < 128)) {
sdWrite(&SD2, (uint8_t *)B3,4); // va bene
bufferMsg[count]= charbuf;
count++;
}
}
}
while (charbuf != Q_TIMEOUT);
}
}
}
'
this threads don't work and don't store the answer, can you help me?
best regards
A.
fot me i use,
Define
#define buffer_size 128
char buffer[buffer_size + 1];
int nbytes = 0;
Function
void SIM_callback(){ /* GSM900 Serial */
char x = SIM.getc();
buffer[nbytes] = x;
nbytes++; if (nbytes > buffer_size) nbytes = buffer_size;
buffer[nbytes] = '\0';
}
Main
main (){
// Clear Buffer
buffer[nbytes] = '\0';
...
while(1);
...
}

Netlink socket, libnl - - nl_recvmsgs_default returning -22

I have similar problem as here:
Netlink sockets and libnl - nl_recvmsgs_default returning -16 (EBUSY)
But nl_recvmsgs_defaul() return this error value -22 (NLE_MSGTYPE_NOSUPPORT).
Does anyone have an idea why I get this error?
Here is example program:
Kernel:
enum {
DOC_EXMPL_A_UNSPEC,
DOC_EXMPL_A_MSG,
__DOC_EXMPL_A_MAX,
};
#define DOC_EXMPL_A_MAX (__DOC_EXMPL_A_MAX - 1)
#define VERSION_NR 1
static struct genl_family doc_exmpl_gnl_family = {
.id = GENL_ID_GENERATE,
.hdrsize = 0,
.name = "CONTROL_EXMPL",
.version = VERSION_NR,
};
enum {
DOC_EXMPL_C_UNSPEC,
DOC_EXMPL_C_ECHO,
__DOC_EXMPL_C_MAX,
};
#define DOC_EXMPL_C_MAX (__DOC_EXMPL_C_MAX - 1)
int doc_exmpl_echo(struct sk_buff *skb_2, struct genl_info *info)
{
struct sk_buff *skb;
struct nlattr *na, *pos;
int len, rem, type, rc;
char * mydata;
void *msg_head;
if (info == NULL)
goto out;
len = nlmsg_attrlen(info->nlhdr, GENL_HDRLEN);
na = nlmsg_attrdata(info->nlhdr, GENL_HDRLEN);
printk(KERN_DEBUG "len1: %d, sizeof: %d ,len: %d", nlmsg_len(info->nlhdr),
GENL_HDRLEN, len);
nla_for_each_attr(pos, na, len, rem) {
type = nla_type(pos);
mydata = (char *) nla_data(pos);
printk(KERN_DEBUG "Type: %d", type);
if (mydata != NULL)
printk(KERN_DEBUG "Data: %s", mydata);
}
skb = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
if (skb == NULL)
goto out;
msg_head = genlmsg_put(skb, 0, info->snd_seq+1, &doc_exmpl_gnl_family, 0, DOC_EXMPL_C_ECHO);
if (msg_head == NULL) {
rc = -ENOMEM;
goto out;
}
rc = nla_put_u8(skb, DOC_EXMPL_A_MSG, 8);
if (rc != 0)
goto out;
/* finalize the message */
genlmsg_end(skb, msg_head);
//rc = genlmsg_unicast(skb,info->snd_pid );
rc = genlmsg_unicast(genl_info_net(info), skb,info->snd_pid);
if (rc != 0)
goto out;
printk(KERN_DEBUG "End");
return 0;
out:
printk("an error occured in doc_exmpl_echo:\n");
return 0;
}
struct genl_ops doc_exmpl_gnl_ops_echo = {
.cmd = DOC_EXMPL_C_ECHO,
.flags = 0,
.policy = NULL,
.doit = doc_exmpl_echo,
.dumpit = NULL,
};
Userspace code
#include <stdio.h>
#include <stdlib.h>
#include <netlink/netlink.h>
#include <netlink/genl/genl.h>
#include <netlink/genl/ctrl.h>
#include <netlink/socket.h>
#include <netlink/msg.h>
#include <net/if.h>
static int expectedId;
static int nlCallback(struct nl_msg* msg, void* arg)
{
struct nlmsghdr* ret_hdr = nlmsg_hdr(msg);
struct nlattr *tb_msg[2 + 1];
char *str;
if (ret_hdr->nlmsg_type != expectedId)
{
// what is this??
return NL_STOP;
}
struct genlmsghdr *gnlh = (struct genlmsghdr*) nlmsg_data(ret_hdr);
nla_parse(tb_msg, 2, genlmsg_attrdata(gnlh, 0),
genlmsg_attrlen(gnlh, 0), NULL);
if (tb_msg[1]) {
str = nla_get_string(tb_msg[1]);
printf("str: %s", str);
}
return 0;
}
int main(int argc, char **argv) {
int cmd, rc;
struct nl_handle *sk;
struct nl_msg *msg;
//allocate socket
sk = nl_handle_alloc();
//connect to generic netlink
genl_connect(sk);
//find the nl80211 driver ID
expectedId = genl_ctrl_resolve(sk, "CONTROL_EXMPL");
//allocate a message
msg = nlmsg_alloc();
cmd = 1;
int flags = 0;
// setup the message
genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, expectedId, 0, NLM_F_REQUEST, cmd, 1);
NLA_PUT_STRING(msg, 3, "Hello test");
nl_send_auto_complete(sk, msg);
nl_socket_modify_cb(sk, NL_CB_VALID, NL_CB_CUSTOM,
nlCallback, NULL);
rc = nl_recvmsgs_default(sk);
printf("rc = %d \n", rc);
nlmsg_free(msg);
return 0;
nla_put_failure:
nlmsg_free(msg);
return 1;
}
OK I found the problem.
I have bad sequencer number in kernel code, it should be:
genlmsg_put(skb, 0, info->snd_seq, &doc_exmpl_gnl_family, 0, DOC_EXMPL_C_ECHO);
It's the same problem as here: Netlink sockets and libnl - nl_recvmsgs_default returning -16 (EBUSY) but I got other error.

Parse dns header in C

I would like to have a dns-parser. I have found this code:
https://github.com/uvic-sdo/DNS-Packet-Parser
Which is quite useful and understandable. It prints DNS answer (Resource Records) using RR structure:
typedef struct {
uint16_t type;
uint16_t clas;
uint32_t ttl;
uint16_t rdlength;
} static_RR;
The answer is than derived from packet:
static_RR* RRd = (static_RR*) ((void*) pd->data + sizeofUrl(pd->data));
I have two questions:
1) How to get a name of the dns answer?
2) How can I derive a dns query. By creating a separate structure, perhaps?
rfc1035: 4.1.3. Resource record format
code example rfc1035: DNS client
typedef __declare_packed_struct s_dns_rr
{
uint16_t name;
uint16_t type;
uint16_t class;
int32_t ttl;
uint16_t rdlength;
} s_dns_rr;
int
parse_rr(uint8_t *res, uint8_t **offset)
{
s_dns_rr *rr;
uint16_t rdlength = 0;
size_t qname_len = 0;
uint8_t qname[DNS_QNAME_MAX_LEN] = {0};
rr = (s_dns_rr *) *offset;
if (DNS_PTR_NAME == dns_ptr_type(rr->name))
{
parse_label(res, res + dns_ptr_offset(rr->name), qname, &qname_len);
}
rdlength = ntohs(rr->rdlength);
*offset += sizeof(*rr);
fprintf(stdout, " -> %s %s %s %u %u", qname,
tr_dns_str(dns_type_str, rr->type, uint16_t, ntohs),
tr_dns_str(dns_class_str, rr->class, uint16_t, ntohs),
ntohl(rr->ttl), rdlength);
if (0 == rdlength)
{
fprintf(stdout, "\n");
return 0;
}
fprintf(stdout, " ");
switch (ntohs(rr->type))
{
case DNS_TYPE_CNAME:
qname_len = 0;
qname[0] = 0;
parse_label(res, (uint8_t *) &rr->name, qname, &qname_len);
if (qname_len == 0)
{
qname[0] = 0;
}
fprintf(stdout, "%s", (const char *) qname);
break;
case DNS_TYPE_A:
fprintf(stdout, "%u.%u.%u.%u", (*offset)[0], (*offset)[1], (*offset)[2],
(*offset)[3]);
break;
default:
break;
}
fprintf(stdout, "\n");
*offset += rdlength;
return (int) rdlength;
}

Resources