Keyboard interrupt handler causing system to freeze - linux-kernel

This is my first stack overflow post (long time lurker), so sorry in advance if this question isn't well worded.
I'm trying to make a kernel module to emulate keypresses when a user presses a button, and using http://www.staerk.de/thorsten/My_Tutorials/Writing_Linux_kernel_modules as an example.
It does simulate a keypress when the module is initialized, but when I send an interrupt and try to run the same code the entire virtual machine freezes.
Here's snippits of my code:
static void got_char(struct work_struct *taskp)
{
struct myprivate *myp = container_of(taskp, struct myprivate, task);
if ((myp->scancode == 0x01) || (myp->scancode == 0x81))
{
printk ("You pressed Esc !\n");
println ("Pressed ESC ! \n");
ch=65;
tty_insert_flip_char(tty, ch, 0);
con_schedule_flip(tty);
}
else if (myp->scancode == 0x1D) {
printk ("You pressed Ctrl!\n");
}
else {
printk("Scancode = %d", myp->scancode);
}
}
irq_handler_t irq_handler(int irq, void *dev_id, struct pt_regs *regs)
{
static int initialised = 0;
/*
* Read keyboard status
*/
myp->scancode = inb(0x60);
if (initialised == 0) {
INIT_WORK(&myp->task, got_char);
initialised = 1;
}
else {
PREPARE_WORK(&myp->task, got_char);
}
schedule_work(&myp->task);
return (irq_handler_t) IRQ_HANDLED;
}
/* Helper method to print stuff to the terminal */
static void println(char *string)
{
tty = current->signal->tty;
(tty->driver->ops)->write (tty, string, strlen(string));
((tty->driver->ops)->write) (tty, "\015\012", 2);
}
/* Initialize the module and Register the IRQ handler */
static int __init keybrd_int_register(void)
{
myp = kmalloc(sizeof (*myp), GFP_KERNEL);
int result;
/* Request IRQ 1, the keyboard IRQ */
result = request_irq (1, (irq_handler_t) irq_handler, IRQF_SHARED, "keyboard_stats_irq", (void *)(irq_handler));
/* Test simulating keypress */
println ("inserting A ! \n");
ch=65;
tty_insert_flip_char(tty, ch, 0);
con_schedule_flip(tty);
if (result)
printk(KERN_INFO "can't get shared interrupt for keyboard\n");
return result;
}
Everything works as expected, except for when ESC is pressed, then my entire system just freezes and I have to restart my VM.
I've looked through many posts and forums online and can't find an answer.
Any suggestions would be appreciated, thanks in advance.

Related

Sending a string to UART gives garbage with printf

I'm trying to format data sent over a USB UART with printf and it's giving me garbage. I can send a simple string and that works but anything I try to format gives junk. Looking through the code I think it has to do with my string not being in program space but I'm not sure.
Here is my main:
void main(void) {
CPU_PRESCALE(CPU_16MHz);
init_uart();
int degree = 0;
char buffer[50];
while(1) {
degree = (degree + 1) % 360;
send_str(PSTR("\n\nHello!!!\n\n"));
memset(buffer, 0, 50);
sprintf_P(buffer, PSTR("%d degrees\n"), degree);
send_str(buffer);
_delay_ms(20);
}
}
The output looks like this:
Hello!!!
����/�������(/����#Q��������
Hello!!!
����/�������(/����#Q��������
The USB UART code I found in a tutorial. The relevant parts look like this:
void send_str(const char *s)
{
char c;
while (1) {
c = pgm_read_byte(s++);
if (!c) break;
usb_serial_putchar(c);
}
}
int8_t usb_serial_putchar(uint8_t c)
{
uint8_t timeout, intr_state;
// if we're not online (enumerated and configured), error
if (!usb_configuration) return -1;
// interrupts are disabled so these functions can be
// used from the main program or interrupt context,
// even both in the same program!
intr_state = SREG;
cli();
UENUM = CDC_TX_ENDPOINT;
// if we gave up due to timeout before, don't wait again
if (transmit_previous_timeout) {
if (!(UEINTX & (1<<RWAL))) {
SREG = intr_state;
return -1;
}
transmit_previous_timeout = 0;
}
// wait for the FIFO to be ready to accept data
timeout = UDFNUML + TRANSMIT_TIMEOUT;
while (1) {
// are we ready to transmit?
if (UEINTX & (1<<RWAL)) break;
SREG = intr_state;
// have we waited too long? This happens if the user
// is not running an application that is listening
if (UDFNUML == timeout) {
transmit_previous_timeout = 1;
return -1;
}
// has the USB gone offline?
if (!usb_configuration) return -1;
// get ready to try checking again
intr_state = SREG;
cli();
UENUM = CDC_TX_ENDPOINT;
}
// actually write the byte into the FIFO
UEDATX = c;
// if this completed a packet, transmit it now!
if (!(UEINTX & (1<<RWAL))) UEINTX = 0x3A;
transmit_flush_timer = TRANSMIT_FLUSH_TIMEOUT;
SREG = intr_state;
return 0;
}

How to use IcmpSendEcho2() with APC callbacks in main thread?

First, the documentation for IcmpSendEcho2() contradicts itself:
It says:
The IcmpSendEcho2 function is called synchronously if the ApcRoutine or Event parameters are NULL
Then it says:
The IcmpSendEcho2 function is called asynchronously when either the ApcRoutine or Event parameters are specified
I presume the first one should be "if the ApcRoutine AND Event paramters are NULL"?
Also, it says under the return value:
When called asynchronously, the IcmpSendEcho2 function returns ERROR_IO_PENDING to indicate the operation is in progress
But I don't see that, I see it return 0 and GetLastError() returns ERROR_IO_PENDING. So, can both cases exist, or is the documentation completely wrong?
Now on to the next issue. I wanted to use IcmpSendEcho2() asynchronously using the ACP callback without events. This way, I didn't have to worry about resources should the number of hosts to process be extremely large. However, it doesn't work because no callback occurs. I found this in the documentation under the AcpRoutine parameter:
The routine that is called when the calling thread is in an alertable thread and an ICMPv4 reply arrives.
So I believe my problem is the main thread is not in an alterable state. Since I don't have an event to wait on, and I don't want to wait beyond the time it takes to complete everything, how do I put the main thread in an alterable state without having to guess using something like SleepEx()? Also, if I did use something like SleepEx(10,TRUE), would all the callbacks occur, or do you have to sit in a loop?
My callback context structure includes a shared global OutstandingCount type variable so I'd know when all requests were completed.
Also the ReplyBuffer is in the context structure. Another little nugget hidden in the documentation regarding the ReplyBuffer when using it asynchronously is:
The application must parse the data pointed to by ReplyBuffer parameter using the IcmpParseReplies function
So, the main question here: How are you supposed to properly use the IcmpSendEcho2() function with a AcpRoutine and no Event in a main thread?
-- Update --
Not sure if I should ask an entirely new question but now a problem where it doesn't call the ApcRoutine for every IcmpSendEcho2Ex() sent. The following code works for my normal network adapters (which are 255.255.255.0) but hangs for a 255.255.0.0 network because the outstandingcount never gets to zero.
The adapter it hangs on is:
VirtualBox Host-Only Ethernet Adapter
DHCP Enable: Yes
Autoconfiguration Enabled: Yes
Autoconfiguration IPv4Address: 169.254.21.120
Subnet Mask: 255.255.0.0
Also wonder how long it would take on networks like 10. with a subnet of 255.0.0.0.
Here's the code that starts with the IPV4Scan() built as x64 on Win10 x64:
#define PIO_APC_ROUTINE_DEFINED
#include <winternl.h>
#include <iphlpapi.h>
#include <IcmpAPI.h>
//--------------
// types
//--------------
typedef DWORD (WINAPI *LPFN_IcmpSendEcho2)(HANDLE, HANDLE , PIO_APC_ROUTINE, PVOID, IPAddr, LPVOID, WORD, PIP_OPTION_INFORMATION, LPVOID, DWORD, DWORD);
typedef DWORD (WINAPI *LPFN_IcmpSendEcho2Ex)(HANDLE, HANDLE , PIO_APC_ROUTINE, PVOID, IPAddr, IPAddr, LPVOID, WORD, PIP_OPTION_INFORMATION, LPVOID, DWORD, DWORD);
typedef HANDLE (WINAPI *LPFN_IcmpCreateFile)();
typedef BOOL (WINAPI *LPFN_IcmpCloseHandle)(HANDLE);
typedef DWORD (WINAPI *LPFN_IcmpParseReplies)(LPVOID, DWORD);
BYTE PingSignature[]={ 'X', 'Y', 'Z', '1', '2', '3', '4', '5', '6', '7', '8' };
typedef struct _sPingContext
{
ULONG *OutstandingCount; // shared number of pings outstanding
CMutex *Mutex; // mutex for ipsfound
CNumericBuffer<uint32_t> *IPsFound; // list of ips found (MSBF format)
LPFN_IcmpParseReplies fnIcmpParseReplies; // function pointer
BYTE ReplyBuffer[sizeof(ICMP_ECHO_REPLY) + sizeof(PingSignature) + sizeof(IO_STATUS_BLOCK) + 8]; // reply buffer (see API docs)
_sPingContext(ULONG *outstandingcount, CMutex *mutex, CNumericBuffer<uint32_t> *ipsfound, LPFN_IcmpParseReplies fnicmpparsereplies)
{
OutstandingCount=outstandingcount;
Mutex=mutex;
IPsFound=ipsfound;
fnIcmpParseReplies=fnicmpparsereplies;
memset(ReplyBuffer, 0, sizeof(ReplyBuffer));
};
} sPingContext, *psPingContext;
//-------------------------------------------------------------------------
// Purpose: Callback for async ping
//
// Input: ioresult - [i] io result of async operation
// pingccontext - [i] context passed on ping
// replysize - [i] reply size of ReplyBuffer
//
// Output: na
//
// Notes:
//
VOID PingCallbackCommon(DWORD ioresult, sPingContext* pingcontext, DWORD replysize)
{
// parse response buffer
if (pingcontext) {
if (ioresult==IP_SUCCESS) {
if (pingcontext->fnIcmpParseReplies(pingcontext->ReplyBuffer, replysize)) {
// point to reply buffer
PICMP_ECHO_REPLY pechoreply=reinterpret_cast<PICMP_ECHO_REPLY>(pingcontext->ReplyBuffer);
if (pechoreply->Status==IP_SUCCESS) {
// check response
if (pechoreply->DataSize==sizeof(PingSignature)) {
if (memcmp(pechoreply->Data, PingSignature, pechoreply->DataSize)==0) {
// successful ping
pingcontext->Mutex->Lock();
pingcontext->IPsFound->AddItem(pechoreply->Address);
pingcontext->Mutex->Unlock();
}
}
}
}
}
// reduce count
InterlockedDecrement(pingcontext->OutstandingCount);
// clean up
delete pingcontext;
}
}
//-------------------------------------------------------------------------
// Purpose: Callback for async ping
//
// Input: apccontext - [i] context passed on ping
//
// Output: na
//
// Notes:
//
VOID PingCallbackOld(PVOID apcontext)
{
sPingContext *pingcontext=reinterpret_cast<sPingContext*>(apcontext);
PingCallbackCommon(IP_SUCCESS, pingcontext, sizeof(pingcontext->ReplyBuffer));
}
//-------------------------------------------------------------------------
// Purpose: Callback for async ping
//
// Input: apccontext - [i] context passed on ping
// iostatusblock - [i] status of request
//
// Output: na
//
// Notes:
//
VOID PingCallback(PVOID apcontext, PIO_STATUS_BLOCK iostatusblock, ULONG reserved)
{
PingCallbackCommon(iostatusblock->Status, reinterpret_cast<sPingContext*>(apcontext), iostatusblock->Information);
}
//-------------------------------------------------------------------------
// Purpose: build list of network hosts using IPv4 Ping
//
// Input: subnet - [i] subnet being scanned (LSB format)
// hoststart - [i] host starting number for scan
// hostend - [i] host ending number for scan
// ips - [io] numeric buffer to update with found addresses
//
// Output: na
//
// Notes:
//
void IPV4Ping(IPAddr sourceip, uint32_t subnet, uint32_t hoststart, uint32_t hostend, CNumericBuffer<uint32_t> &ips)
{
// skip 127. network
if ((sourceip & 0xFF)==127)
return;
bool oldlib=false;
LPFN_IcmpSendEcho2Ex fnIcmpSendEcho2Ex=NULL;
LPFN_IcmpCreateFile fnIcmpCreateFile=NULL;
LPFN_IcmpCloseHandle fnIcmpCloseHandle=NULL;
LPFN_IcmpParseReplies fnIcmpParseReplies=NULL;
// first thing is first - check which set of functions to use
HMODULE hlib=LoadLibrary(_T("iphlpapi.dll"));
if (hlib) {
// load functions
fnIcmpCreateFile=(LPFN_IcmpCreateFile) GetProcAddress(hlib, "IcmpCreateFile");
fnIcmpSendEcho2Ex=(LPFN_IcmpSendEcho2Ex) GetProcAddress(hlib, "IcmpSendEcho2Ex");
fnIcmpCloseHandle=(LPFN_IcmpCloseHandle) GetProcAddress(hlib, "IcmpCloseHandle");
fnIcmpParseReplies=(LPFN_IcmpParseReplies) GetProcAddress(hlib, "IcmpParseReplies");
}
// check if have everything
if (!hlib || fnIcmpCreateFile==NULL || fnIcmpSendEcho2Ex==NULL || fnIcmpCloseHandle==NULL || fnIcmpParseReplies==NULL) {
// no, try old version
oldlib=true;
// clean up
if (hlib) {
FreeLibrary(hlib);
}
// load old lib
hlib=LoadLibrary(_T("icmp.dll"));
// check if loaded
if (hlib) {
// load functions
fnIcmpCreateFile=(LPFN_IcmpCreateFile) GetProcAddress(hlib, "IcmpCreateFile");
fnIcmpSendEcho2Ex=(LPFN_IcmpSendEcho2Ex) GetProcAddress(hlib, "IcmpSendEcho2Ex");
fnIcmpCloseHandle=(LPFN_IcmpCloseHandle) GetProcAddress(hlib, "IcmpCloseHandle");
fnIcmpParseReplies=(LPFN_IcmpParseReplies) GetProcAddress(hlib, "IcmpParseReplies");
}
}
// check if have everything
if (hlib) {
if (fnIcmpCreateFile!=NULL && fnIcmpSendEcho2Ex!=NULL && fnIcmpCloseHandle!=NULL && fnIcmpParseReplies!=NULL) {
// open icmp
HANDLE hicmp=fnIcmpCreateFile();
if (hicmp!=INVALID_HANDLE_VALUE) {
// variables for callback handling
ULONG outstandingcount=0;
CMutex mutex;
// process pings
for (uint32_t host=hoststart; host<=hostend; host++) {
// build full ip
IPAddr ip=subnet | host;
ip=GETMSBFDWORD(&ip);
// create context
sPingContext *pcontext;
if ((pcontext=new sPingContext(&outstandingcount, &mutex, &ips, fnIcmpParseReplies))!=NULL) {
// count request
InterlockedIncrement(&outstandingcount);
// now issue ping
DWORD result=fnIcmpSendEcho2Ex(hicmp,
NULL,
oldlib ? (PIO_APC_ROUTINE) PingCallbackOld : PingCallback,
pcontext,
sourceip,
ip,
PingSignature,
sizeof(PingSignature),
NULL,
pcontext->ReplyBuffer,
sizeof(pcontext->ReplyBuffer),
50);
// check if failed
if (result==0) {
// check if because pending
if (GetLastError()!=ERROR_IO_PENDING) {
// no - use callback to clean up
CDebugPrint::DebugPrint(_T("IcmpSendEcho Error %u\n"), GetLastError());
PingCallbackOld(pcontext);
}
else {
// fire off pending APC callbacks ready
SleepEx(0, TRUE);
}
}
else {
// completed sync - use callback to clean up
PingCallbackOld(pcontext);
}
}
}
// wait for completion
while (outstandingcount) {
// handle callbacks
SleepEx(10, TRUE);
}
// clean up
fnIcmpCloseHandle(hicmp);
}
}
// clean up
FreeLibrary(hlib);
}
}
//-------------------------------------------------------------------------
// Purpose: build list of network hosts by way of IP scan for V4
//
// Input: ipadapteraddress - [i] adapter ip address to build for
//
// Output: na
//
// Notes: ip addresses are MSBF
//
void IPV4Scan(IP_ADAPTER_UNICAST_ADDRESS *ipadapteraddress)
{
// build the subnet mask to use
if (ipadapteraddress->OnLinkPrefixLength<=32 && ipadapteraddress->OnLinkPrefixLength!=0) {
in_addr ia=reinterpret_cast<sockaddr_in*>(ipadapteraddress->Address.lpSockaddr)->sin_addr;
// valid mask length - build mask
uint32_t rangemask=((1U<<(32-ipadapteraddress->OnLinkPrefixLength))-1);
uint32_t mask=~rangemask;
uint32_t subnet=GETMSBFDWORD(&ia.s_addr) & mask;
CDebugPrint::DebugPrint(_T("Subnet %u.%u.%u.%u/%u\n"), (subnet>>24) & 0xFF, (subnet>>16) & 0xFF, (subnet>>8) & 0xFF, (subnet>>0) & 0xFF, ipadapteraddress->OnLinkPrefixLength);
CDebugPrint::DebugPrint(_T("Scanning %u hosts\n"), (UINT32_MAX & rangemask)-1);
CNumericBuffer<uint32_t> ipsfound;
IPV4Ping(ia.s_addr, subnet, 1, (UINT32_MAX & rangemask)-1, ipsfound);
for (UINT i=0; i<(UINT)ipsfound.GetCount(); i++) {
uint32_t ip=ipsfound[i];
CDebugPrint::DebugPrint(_T("Ping found %u.%u.%u.%u\n"), ip & 0xFF, (ip>>8) & 0xFF, (ip>>16) & 0xFF, (ip>>24) & 0xFF);
}
}
else CDebugPrint::DebugPrint(_T("Invalid subnet length %u\n"), ipadapteraddress->OnLinkPrefixLength);
}
I presume the first one should be "if the ApcRoutine AND Event
paramters are NULL"?
yes, you correct.
But I don't see that, I see it return 0 and GetLastError() returns
ERROR_IO_PENDING. So, can both cases exist, or is the documentation
completely wrong?
documentation completely wrong. by fact IcmpSendEcho2[Ex] return BOOL and error code via SetLastError ( more exactly by RtlNtStatusToDosError)
so on asynchronous call it return FALSE (0) and GetLastError() will be ERROR_IO_PENDING if all ok - this mean apc callback will be called, or another error if fail - apc callback will be not called (better call it by self in this case, for common error handling)
how do I put the main thread in an alterable state
this already depend from what your thread doing. in some case possible write event loop with MsgWaitForMultipleObjectsEx function - at once wait on windows events and be alertable. also possible wait on some objects too. if you can not rewrite self message loop with MsgWaitForMultipleObjectsEx - you can do call from worked thread, or periodically call SleepEx(0, TRUE) or undocumented NtTestAlert. without know what your main thread doing - hard say exactly what is better.
demo code can look like:
#include <iphlpapi.h>
#include <IPExport.h>
#include <icmpapi.h>
class EchoRequestContext
{
HANDLE _hFile = 0;
PVOID _ReplyBuffer = 0;
LONG _dwRefCount = 1;
ULONG _dwThreadId = GetCurrentThreadId();
static void WINAPI sOnApc(PVOID This, PIO_STATUS_BLOCK piosb, ULONG )
{
reinterpret_cast<EchoRequestContext*>(This)->OnApc(
RtlNtStatusToDosError(piosb->Status),
(ULONG)piosb->Information);
}
void OnApc(ULONG dwError, ULONG ReplySize)
{
OnReply(dwError, (PICMP_ECHO_REPLY)_ReplyBuffer, ReplySize);
if (_ReplyBuffer) delete [] _ReplyBuffer;
Release();
}
void OnReply(ULONG dwError, PICMP_ECHO_REPLY ReplyBuffer, ULONG ReplySize)
{
if (dwError)
{
DbgPrint("dwError=%u\n", dwError);
return ;
}
if (IcmpParseReplies(ReplyBuffer, ReplySize))
{
__nop();
}
}
~EchoRequestContext()
{
if (_hFile) IcmpCloseHandle(_hFile);
PostThreadMessageW(_dwThreadId, WM_QUIT, 0, 0);
}
public:
void AddRef()
{
InterlockedIncrementNoFence(&_dwRefCount);
}
void Release()
{
if (!InterlockedDecrement(&_dwRefCount))
{
delete this;
}
}
ULONG Create()
{
HANDLE hFile = IcmpCreateFile();
if (hFile == INVALID_HANDLE_VALUE)
{
return GetLastError();
}
_hFile = hFile;
return NOERROR;
}
void SendEcho(
IPAddr DestinationAddress,
const void* RequestData,
WORD RequestSize,
ULONG ReplySize,
ULONG Timeout,
UCHAR Flags,
UCHAR Ttl)
{
if (PVOID ReplyBuffer = new UCHAR[ReplySize])
{
_ReplyBuffer = ReplyBuffer;
IP_OPTION_INFORMATION opt = { Ttl, 0, Flags };
AddRef();
ULONG dwError = IcmpSendEcho2Ex(_hFile, 0, sOnApc, this,
0, DestinationAddress,
const_cast<void*>(RequestData), RequestSize,
&opt, ReplyBuffer, ReplySize, Timeout) ? NOERROR : GetLastError();
switch (dwError)
{
case NOERROR:
case ERROR_IO_PENDING:
break;
default:
OnApc(dwError, 0 );
}
return ;
}
OnApc(ERROR_OUTOFMEMORY, 0);
}
};
#define IP(a, b, c, d) ((ULONG)(a + (b << 8) + (c << 16) + (d << 24)))
void EchoTest()
{
WSADATA wd;
if (NOERROR == WSAStartup(WINSOCK_VERSION, &wd))
{
if (EchoRequestContext* p = new EchoRequestContext)
{
if (p->Create() == NOERROR)
{
p->SendEcho(IP(8,8,8,8), "1234567890ABCDEF", 16, 0x100, 4000, IP_FLAG_DF, 255);
}
p->Release();
}
MSG msg;
__loop:
switch (MsgWaitForMultipleObjectsEx(0, 0, INFINITE,
QS_ALLINPUT, MWMO_ALERTABLE|MWMO_WAITALL))
{
default:
__debugbreak();
break;
case WAIT_FAILED:
break;
case WAIT_OBJECT_0:
while (PeekMessageW(&msg, 0, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
{
goto __exit;
}
}
case STATUS_USER_APC: // == WAIT_IO_COMPLETION
goto __loop;
}
__exit:
WSACleanup();
}
}

Problem stopping a child loop using sigaction and intercepting Ctrl*C

I'm trying to write a program that intercepts Ctrl^C using sigaction, and then terminates the child of a fork.
Code:
static void usrHandler(int sig, siginfo_t * si, void * ignore) {
printf("Interrupt Worked");
}
int main(int argc, char * argv[]) {
struct sigaction sa;
sa.sa_flags = SA_SIGINFO;
sigemptyset( & sa.sa_mask);
sa.sa_sigaction = usrHandler;
sigaction(SIGINT, & sa, NULL);
int currentFile = 1;
int fd;
int forkChild;
forkChild = fork();
if (forkChild == 0) {
sleep(100);
} else if (forkChild > 0) {
sa.sa_sigaction = SIG_IGN;
sigaction(SIGUSR1, & sa, NULL);
}
}
I tried to remove all non necessary code for my example. For some reason I can not get the interrupt to work when I press Ctrl^C. Eventually I would like to be able to close the child and continue in the parent. Am I doing something wrong here?
For some reason I can not get the interrupt to work when I press Ctrl^C.
Because your data in IO buffer, so change printf("Interrupt Worked"); to printf("Interrupt Worked\n"); (add \n), you will get data.
For IO buffer, see https://stackoverflow.com/a/53083985/7671328

User space netlink socket receives empty messages from kernel space

Disclaimer - I have to admit that it's the 1'st time I'm using this kernel interface (socket).
I'm currently working on a design of a kernel module that is based on a netlink socket .
I'm using Ubuntu14.04 and linux kernel 4.
As a starter, I wanted to make sure that I can use the netlink socket in both directions.
I've written an application that does the following:
1) User send a message to kernel via the netlink socket.
2) Kernel, upon receiving the message – sends "ABCD" string message to a workqueue.
3) When the "ABCD" message is received by the workqueue, it calls a function (named - my_wq_function) which send it back to the user space via netlink socket.
4) In the user space I'm using a recvmsg function (blocking until a message is received) and displays the "ABCD" message.
My problem is that the return value from the recvmsg function is 20 (instead of 4), and the data itself (i.e. NLMSG_DATA) is empty.
During the debug I tried to change the message to "ABCD1234" and got a return value of 24 bytes, however the data is still empty.
I also verified that my entire path until the point of sending the "ABCD" from kernel to the socket is OK.
Not sure what I'm doing wrong here & will highly appreciate your help.
Thanks in advance, MotiC.
my code example can be found below:
User space code:
printf("netlink receiver thread started...\n");
nlh_rcv = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD));
while(true) //endless loop on netlink socket
{
memset(nlh_rcv, 0, NLMSG_SPACE(MAX_PAYLOAD));
iov_rcv.iov_base = (void *)nlh_rcv;
iov_rcv.iov_len = nlh_rcv->nlmsg_len;
msg_rcv.msg_name = (void *)&dest_addr;
msg_rcv.msg_namelen = sizeof(dest_addr);
msg_rcv.msg_iov = &iov;
msg_rcv.msg_iovlen = 1;
ret=recvmsg(sock_fd, &msg_rcv, 0);
printf("errno=%i bytes=%i message from kernel: %s\n",errno, ret, (char*)NLMSG_DATA(nlh_rcv));
uint8_t mymsg[100];
memcpy(mymsg, NLMSG_DATA(nlh_rcv), 100);
printf("message from kernel: %s\n",mymsg);
}
Kernel space code:
#include <linux/module.h> /* Needed by all modules */
#include <linux/kernel.h> /* Needed for KERN_INFO */
#include <linux/init.h> /* Needed for the macros */
#include <net/sock.h>
#include <linux/socket.h>
#include <linux/net.h>
#include <asm/types.h>
#include <linux/netlink.h>
#include <linux/skbuff.h>
#include <linux/workqueue.h>
MODULE_LICENSE("GPL");
#include "rf_Kdriver_main.h"
//------ definitions ------------------------------------------------------------------------------------------------------------
#define NETLINK_USER 31
#define MAX_PAYLOAD 1024 /* maximum payload size*/
struct sock *nl_sk = NULL;
struct nlmsghdr *nlh;
struct nlmsghdr *nlh_out;
struct sk_buff *skb_out;
char buf_to_user[100];
int pid;
//------------------------------------------------------------------------------------------------------------------------------
struct workqueue_struct *my_wq;
typedef struct {
struct work_struct my_work;
uint8_t msg_to_pc[128];
uint8_t msg_len;
} my_work_t;
my_work_t *work, *work2;
//-----------------------------------------------------------------------------------------------------------------------------
static void my_wq_function( struct work_struct *work)
{
int res;
my_work_t *my_work = (my_work_t *)work;
skb_out = nlmsg_new(my_work->msg_len,0);
if (!skb_out)
{
printk("Failed to allocate new skb\n");
return;
}
nlh_out = nlmsg_put(skb_out, 0, 0, NLMSG_DONE,my_work->msg_len, 0);
NETLINK_CB(skb_out).dst_group = 0;
memcpy((char*)NLMSG_DATA(nlh_out), my_work->msg_to_pc , my_work->msg_len);
printk( "dequeue message to pc=%s len=%i\n", (char*)NLMSG_DATA(nlh_out), (int)strlen((char*)NLMSG_DATA(nlh_out)));
res = nlmsg_unicast(nl_sk, skb_out, pid);
if (res<0)
printk("Failed to send message from kernel to user\n");
kfree( (void *)work );
return;
}
//-----------------------------------------------------------------------------------------------------------------------------
int send_up_msg_to_workque(uint8_t msg_to_pc[], uint8_t msg_len)
{
int ret=0;
work = (my_work_t *)kmalloc(sizeof(my_work_t), GFP_KERNEL);
if (work) {
INIT_WORK( (struct work_struct *)work, my_wq_function );
memcpy(work->msg_to_pc, msg_to_pc, msg_len);
work->msg_len = msg_len;
ret = queue_work( my_wq, /*(struct work_struct *)RR*/work );
printk("kuku ret=%i msg=%s\n",ret,work->msg_to_pc);
}
return ret;
}
//------------------------------------------------------------------------------------------------------------------------------
static void netlink_recv_msg(struct sk_buff *skb)
{
char *msg = "ABCD1234";
printk(KERN_INFO "Entering: %s\n", __FUNCTION__);
nlh=(struct nlmsghdr*)skb->data;
printk(KERN_INFO "Netlink at kernel received msg payload: %s\n",(char*)NLMSG_DATA(nlh));
//rr
pid = nlh->nlmsg_pid;
send_up_msg_to_workque((uint8_t*) msg, strlen(msg));
}
//-------------------------------------------------------------------------------------------------------------------------------------
struct netlink_kernel_cfg cfg = {
.input = netlink_recv_msg,
};
static int __init rf_driver_start(void)
{
printk(KERN_INFO "Loading RF Driver module1...\n");
my_wq = create_workqueue("my_queue");
if (!my_wq)
{
printk("Failed to create work queue\n");
}
printk("Entering: %s\n",__FUNCTION__);
nl_sk = netlink_kernel_create(&init_net, NETLINK_USER, &cfg);
if(!nl_sk)
{
printk(KERN_ALERT "Error creating socket.\n");
return -10;
}
return 0;
}
//--------------------------------------------------------------------------------------------------------------
static void __exit rf_driver_end(void)
{
netlink_kernel_release(nl_sk);
flush_workqueue(my_wq);
destroy_workqueue(my_wq);
printk(KERN_INFO "RF Driver exit...\n");
}
module_init(rf_driver_start);
module_exit(rf_driver_end);
Update,
I changed my user space function to:
char buf[100];
ret=recv(sock_fd, buf, 100, 0);
instead of:
ret=recvmsg(sock_fd, &msg_rcv, 0);
and it works...
does anyone have an idea regarding this strange behavior ?
Thanks.
Can you please paste complete userspace code.
I guess 'len' int this code is the issue:
memset(nlh_rcv, 0, NLMSG_SPACE(MAX_PAYLOAD));
iov_rcv.iov_len = nlh_rcv->nlmsg_len; << check to what value is it getting initialized.

interacting user space during system call

I'm trying to write block device driver that implements read/write operations.
The tricky thing is that the information is not in the hardware, but in a user space process. Therefore, during the read/write system call I would like to interact the user space (i.e. sendign signal to the user space).
However, my user space process catching the signal only after the read/write system call returned. adding wait in the system call implementation seems to be ignored somehow.
I used this code at the read system call:
ssize_t sleepy_read(struct file *filp, char *buf, size_t count, loff_t *f_pos)
{
struct siginfo info;
struct task_struct *t;
int ret;
#define SIG_TEST 44
memset(&info, 0, sizeof(struct siginfo));
info.si_signo = SIG_TEST;
info.si_code = SI_QUEUE;
info.si_int = 1234;
rcu_read_lock();
t = pid_task(find_pid_ns(current->pid, &init_pid_ns), PIDTYPE_PID);
if(t == NULL){
printk(KERN_ERR "no such pid\n");
rcu_read_unlock();
return -ENODEV;
}
rcu_read_unlock();
ret = send_sig_info(SIG_TEST, &info, t); //send the signal
if (ret < 0) {
printk("error sending signal\n");
return ret;
}
wait_event_interruptible(wq, flag != 0);
msleep(10000);
return (0);
}
and this code at user space:
#define SIG_TEST 44
int g_devFile = -1;
void receiveData(int n, siginfo_t *info, void *unused)
{
printf("received value %i\n", info->si_int);
}
int main(void)
{
struct sigaction sig;
sig.sa_sigaction = receiveData;
sig.sa_flags = SA_SIGINFO;
sigaction(SIG_TEST, &sig, NULL);
g_devFile = open(devname, O_RDWR);
if ( g_devFile < 0 ) {
fprintf(stderr,"Error opening device[%s] file err[%s]\n",devname,strerror(errno));
return -1;
} else {
fprintf (stderr, "device opened. ptr=%p\n", (void*)g_devFile);
}
i = read(g_devFile, &buff, 11);
}
Currently I'm catching my signal (in user space) only after the 10 seconds sleep expieres (the wait seems to be ignored).
Any idea will be appriceated. Thanks.

Resources