Situation: My code is mostly hacked into the Linux kernel driver. I want to notify the application in user space of noteworthy unprocessed events before they are launched into the main system.
Steps to solve: I found a good example for sending UDP packets from kernel space: http://kernelnewbies.org/Simple_UDP_Server They use INADDR_LOOPBACK as the destination address, which is exactly what I want.
Since this is an interrupt context, I decided to use a work queue to send packets (I got BUG: Scheduling while atomic without it). Thus, my send code is based on the kernelwew kernel code, which is completed in the work queue structure launched with INIT_WORK and sched_work in the main process. I do not announce my own work queue.
I do not use the Netpoll API as this question , which does not allow sending data from and to localhost. "You cannot send yourself"
Problem: Data sent from the kernel and received from my UDP receiver rarely matches. I have no idea why this is happening.
Code for dummy data for testing, including defining the structure for the work queue:
static struct socket *sock_send; static struct sockaddr_in addr_send; static struct ksocket_workmessage { unsigned char *buf; int len; struct work_struct workmessage; } workmsg; unsigned char testmsg[] = {'T', 'e', 's', 't', 'i', 'n', 'g', 'm', 's', 'g', '\0'}; workmsg.buf = testmsg; workmsg.len = 11; INIT_WORK(&workmsg.workmessage, handle_workmessage); schedule_work(&workmsg.workmessage);
Passing the actual package is similar to "int ksocket_send" from the kernelnewbies example. The only difference is that my send_socket is static and I need to get buf and len with container_of from the work queue. I work in a completely static context. My handle_workmessage method is also static:
static void handle_workmessage(struct work_struct *work) { struct msghdr msg; struct iovec iov; mm_segment_t oldfs; int size = 0; struct ksocket_workmessage *workmsg = container_of(work, struct ksocket_workmessage, workmessage); if (sock_send->sk==NULL) return; iov.iov_base = workmsg->buf; iov.iov_len = workmsg->len; msg.msg_flags = 0; msg.msg_name = &addr_send; msg.msg_namelen = sizeof(struct sockaddr_in); msg.msg_control = NULL; msg.msg_controllen = 0; msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = NULL; oldfs = get_fs(); set_fs(KERNEL_DS); size = sock_sendmsg(sock_send,&msg,workmsg->len); set_fs(oldfs); }
The end result is as follows:
int main(int argc, char**argv) { int sockfd,n; struct sockaddr_in servaddr; socklen_t len; unsigned char mesg[1000]; sockfd=socket(AF_INET,SOCK_DGRAM,0); bzero(&servaddr,sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr=htonl(INADDR_ANY); servaddr.sin_port=htons(REC_PORT); bind(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr)); for (;;) { n = recv(sockfd,mesg,1000,0); printf("-------------------------------------------------------\n"); mesg[n] = 0; printf("Received the following: %d bytes\n", n); printf("%s",mesg); printf("%c",mesg[0]); printf(",%c",mesg[1]); printf(",%c",mesg[2]); printf(",%c",mesg[3]); printf(",%c",mesg[4]); printf(",%c",mesg[5]); printf(",%c",mesg[6]); printf(",%c",mesg[7]); printf(",%c",mesg[8]); printf(",%c\n",mesg[9]); //printf("%c\n",mesg[0]); printf("-------------------------------------------------------\n"); memset(mesg, 0, sizeof(mesg)); } }
The result looks distorted, although I always send the same message for testing purposes:
What could be the reason for this? Since this sometimes works with the expected output of TestingmsgT, e, s, t, i, n, g, m, s, g, this should not be a technical limitation. Packet fragmentation should not happen either, since I only send 11 bytes. Also there is no packet loss. Every time I send a package, it is also accepted.
UPDATE: THIS WORKS .. but I donβt know why firstly, thanks for the comment from alk that I forgot the obvious. To register immediately before sending data. I recorded before calling schedule_work. Now I register directly in my send method workmsg-> buf before it is stored in the void * pointer from iov. This data has already been processed.
Struct ksocket_workmessage had char *, my data was char [] and assigned to the structure pointer.
Now I have changed the data type in my ksocket_workmessage structure:
struct ksocket_workmessage { unsigned char buf[11]; int len; struct work_struct workmessage; } workmsg;
Since I no longer have a pointer, I could not create my unsigned char testmsg [], so I went for the buf assignment directly:
workmsg.buf[0] = 'T'; workmsg.buf[1] = 'e'; workmsg.buf[2] = 's'; workmsg.buf[3] = 't'; workmsg.buf[4] = 'i'; workmsg.buf[5] = 'n'; workmsg.buf[6] = 'g'; workmsg.buf[7] = 'm'; workmsg.buf[8] = 's'; workmsg.buf[9] = 'g'; workmsg.buf[10] = '\0';
If someone tells me where my initial approach failed, I gladly accept it as the correct answer.