LinuxQuestions.org
Visit Jeremy's Blog.
Go Back   LinuxQuestions.org > Forums > Linux Forums > Linux - Software > Linux - Kernel
User Name
Password
Linux - Kernel This forum is for all discussion relating to the Linux kernel.

Notices


Reply
  Search this Thread
Old 06-15-2018, 09:47 AM   #1
Poison Nuke
Member
 
Registered: Aug 2012
Location: Germany
Posts: 40

Rep: Reputation: Disabled
kernel-module: self created kthread does not stop


Hello,

Im getting blind, I cant see where there is an issue with my code. Im trying to implement my own UDP-Server inside the bcm5974 kernel module (which is essential for my project).

On rmmod the newly created thread wont stop.

The secondary issue is, that only the UDP-runs, the original driver implementation is dead after starting the thread (so no mousemovement). Is there anything blocking the parent-thread?

Maybe someone has an idea too, about the BAD-ADDRESS error (error -14) upon receiving a UDP packet ?



Here is the reduced code:
Code:
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/usb/input.h>
#include <linux/hid.h>
#include <linux/mutex.h>
#include <linux/input/mt.h>

#include <net/sock.h>
#include <linux/init.h>
#include <linux/kthread.h>
#include <linux/signal.h>
#include <linux/types.h>
#include <linux/netdevice.h>
#include <linux/ip.h>
#include <linux/in.h>
#include <linux/delay.h>

#define REMOTE_PORT 30567
#define RECEIVE_PORT 31337
struct socket *udp_socket;
unsigned char lineCounter = 0;
int lastUsedSlots[16];
unsigned int lastUsedSlotsX[16];
unsigned int lastUsedSlotsY[16];

struct kthread_t {
	struct task_struct *thread;
	struct socket *sock;
	struct sockaddr_in addr;
	struct socket *sock_send;
	struct sockaddr_in addr_send;
	int running;
};
struct kthread_t *kthread = NULL;


#define dprintk(level, format, a...)\
	{ if (debug >= level) printk(KERN_DEBUG format, ##a); }

	
[...]
	
int ksocket_receive(struct socket* sock, struct sockaddr_in* addr, unsigned char* buf, int len) {
	struct msghdr msg;
	struct iovec iov;
	mm_segment_t oldfs;
	int size = 0;

	if (sock->sk == NULL) return 0;

	iov.iov_base = buf;
	iov.iov_len = len;


	msg.msg_flags = 0;
	msg.msg_name = addr;
	msg.msg_namelen = sizeof(struct sockaddr_in);
	msg.msg_control = NULL;
	msg.msg_controllen = 0;
	msg.msg_iter.iov = &iov;
	msg.msg_iter.count = len;
	msg.msg_iter.type = ITER_IOVEC;
	msg.msg_iter.nr_segs = 1;
	msg.msg_control = NULL;

	oldfs = get_fs();
	set_fs(KERNEL_DS);
	size = sock_recvmsg(sock, &msg, msg.msg_flags);
	set_fs(oldfs);

	return size;
}


//the actual kthread-function
static void ksocket_start(void) {
	int size, err;
	int bufsize = 10;
	unsigned char buf[bufsize + 1];
	int udp_ip;

	allow_signal(SIGKILL | SIGSTOP);

	/* kernel thread initialization */
	kthread->running = 1;
	current->flags |= PF_NOFREEZE;

	/* create a socket */
	if ((err = sock_create(AF_INET, SOCK_DGRAM, IPPROTO_UDP, &kthread->sock)) < 0) {
		dprintk(1, "bcm5974: Could not create a datagram socket, error = %d\n", -ENXIO);
		goto out;
	}

	memset(&kthread->addr, 0, sizeof(struct sockaddr));
	memset(&kthread->addr_send, 0, sizeof(struct sockaddr));
	kthread->addr.sin_family = AF_INET;
	udp_ip = (160 << 24) | (48 << 16) | (199 << 8) | (98);
	kthread->addr.sin_addr.s_addr = htonl(udp_ip);
	kthread->addr.sin_port = htons(RECEIVE_PORT);

	if ((err = kthread->sock->ops->bind(kthread->sock, (struct sockaddr *)&kthread->addr, sizeof(struct sockaddr))) < 0) {
		dprintk(1, "bcm5974: Could not bind or connect to socket, error = %d\n", -err);
		goto close_and_out;
	}

	dprintk(1, "bcm5974: listening on port %d\n", RECEIVE_PORT);

	/* main loop */
	while (!kthread_should_stop()) {
		memset(&buf, 0, bufsize + 1);
		size = ksocket_receive(kthread->sock, &kthread->addr, buf, bufsize);

		if (size < 0) {
			dprintk(1, "bcm5974: error getting datagram, sock_recvmsg error = %d\n", size);
		} else {
			dprintk(1, "bcm5974: received %d bytes\n", size);
			/* data processing */
		}
	}
	do_exit(0);
	

close_and_out:
	sock_release(kthread->sock);
	sock_release(kthread->sock_send);
	kthread->sock = NULL;
	kthread->sock_send = NULL;

out:
	do_exit(0);
}



//simple udp-sender, has nothing to do with ksocket, should run on its own
int send_udp_msg(struct socket *sock, struct sockaddr_in *cl, char *buf, int len) {
	struct msghdr msg;
	struct kvec iov;
	int size;
	
	
	iov.iov_base = buf;
	iov.iov_len = len;
	
	msg.msg_control = NULL;
	msg.msg_controllen = 0;
	msg.msg_flags = 0;
	msg.msg_name = cl;
	msg.msg_namelen = sizeof(struct sockaddr_in);
	
	dprintk(1, "preparing to send udp");

	size = kernel_sendmsg(sock, &msg, &iov, 1, len);


	return size;
}


/* report trackpad data as logical trackpad state */
static int report_tp_state(struct bcm5974 *dev, int size) {
....
	int udp_error, udp_ip;
	struct sockaddr_in sin;
	int udp_len = 112;
	char udp_msg[];
	udp_ip = (192 << 24) | (168 << 16) | (107 << 8) | (119);
	sin.sin_addr.s_addr = htonl(udp_ip);
	sin.sin_family = AF_INET;
	sin.sin_port = htons(REMOTE_PORT);


	udp_error = sock_create_kern(&init_net, AF_INET, SOCK_DGRAM, IPPROTO_UDP, &udp_socket);
	if (udp_error >= 0) {
		send_udp_msg(udp_socket, &sin, udp_msg, udp_len);
		sock_release(udp_socket);
	}
	else {
		dprintk(1, "cannot create UDP socket\n");
	}
}

//initially called upon modprobe, the kthread is created here
static int bcm5974_probe(struct usb_interface *iface, const struct usb_device_id *id) {
	int error = -ENOMEM;
	kthread = kmalloc(sizeof(struct kthread_t), GFP_KERNEL);
	memset(kthread, 0, sizeof(struct kthread_t));

	/* start kernel thread */
	kthread->thread = kthread_run((void *)ksocket_start, NULL, "ksocket");
	if (IS_ERR(kthread->thread)) {
		dprintk(1, "bcm5974 ksocket, unable to start kernel thread");
		kfree(kthread);
		kthread = NULL;
		return error;
	}

	...
}

//called on rmmod, should stop the kthread
static void bcm5974_disconnect(struct usb_interface *iface) {
	struct bcm5974 *dev = usb_get_intfdata(iface);
	int err;

	kthread->running = 0;
	if (kthread->thread == NULL) {
		dprintk(1, "bcm5974: no kernel thread to kill\n");
	} else {
		err = kthread_stop(kthread->thread);

		/* wait for kernel thread to die */
		if (err < 0) {
			dprintk(1, "bcm5974: unknown error %d while trying to terminate kernel thread\n", -err);
		} else {
			while (kthread->running == 1) msleep(10);
			dprintk(1, "bcm5974: succesfully killed kernel thread!\n");
		}
	}

	/* free allocated resources before exit */
	if (kthread->sock != NULL) {
		sock_release(kthread->sock);
		kthread->sock = NULL;
	}

	kfree(kthread);
	kthread = NULL;
}

static struct usb_driver bcm5974_driver = {
	.name			= "bcm5974",
	.probe			= bcm5974_probe,
	.disconnect		= bcm5974_disconnect,
	.suspend		= bcm5974_suspend,
	.resume			= bcm5974_resume,
	.id_table		= bcm5974_table,
	.supports_autosuspend	= 1,
};

module_usb_driver(bcm5974_driver);

Last edited by Poison Nuke; 06-15-2018 at 09:50 AM.
 
Old 06-17-2018, 09:36 AM   #2
AwesomeMachine
LQ Guru
 
Registered: Jan 2005
Location: USA and Italy
Distribution: Debian testing/sid; OpenSuSE; Fedora; Mint
Posts: 5,482

Rep: Reputation: 997Reputation: 997Reputation: 997Reputation: 997Reputation: 997Reputation: 997Reputation: 997Reputation: 997
Does your kernel allow forced module unloading? Maybe you could run the module through a debugger and pinpoint your problem area. https://people.freedesktop.org/~narm...debugging.html
 
Old 06-17-2018, 11:56 AM   #3
Poison Nuke
Member
 
Registered: Aug 2012
Location: Germany
Posts: 40

Original Poster
Rep: Reputation: Disabled
is there any way to run only the module through a debugger without needing a virtual machine?

But maybe it is just a simple beginners error Ive made here? It is nothing more than simply starting a thread and opening a port. But in lack of a new tutorial I was using a tutorial from kernel 2.6 and tried to correct the errors.
 
Old 06-25-2018, 04:32 PM   #4
X-LFS-2010
Member
 
Registered: Apr 2016
Posts: 382

Rep: Reputation: Disabled
i suggest reversing what your doing and starting over at least until you know ALLOT more about cpu

#1 does rmmod for that module work before your hack is added? make sure it does.

#2 i assume your not doing a userland hack, if so that's a whole different story and model.

#3 add your hacks in the original kernel module in a flowing manner (that does something and returns with the normal program flow - don't change the flow). don't try to create a new process until "there is nothing left to do but decide how kernel.org should offer it as an optional feature".

yes it's possible if your in a kernel driver and call "some function somewhere" that you'll be in a different segment that process security will flag (or perhaps hasn't flagged for interrupts, or something), and that will be a problem

if your creating a new "sub driver", well linux supports it but that's a whole different story than "creating a driver". you have to use all the linux kernel ins and outs of two drivers (for that, you'd look at driver packs that have multiple parts).

you could create a new separate driver, but that again requires hacking the kernel tree, and it sounds like you don't need that.

you should be using GIT(1) and developer access so if your hack is successful, you aren't doing it all again in a different way so that your changes can be submitted to linux in a future version. you might even dead-end your project if you begin relying on changes that linux deveoper world cannot accept or branch.
 
Old 06-25-2018, 05:14 PM   #5
Poison Nuke
Member
 
Registered: Aug 2012
Location: Germany
Posts: 40

Original Poster
Rep: Reputation: Disabled
I found out this day, that there was no error. The only problem is the blocking sock_recvmsg function. As long as no UDP packet arrives, nothing can interrupt that call.

So the solution is using the "MSG_DONTWAIT" flag or just send an random UDP packet on the open port from the terminating function. Im not shure about the MSG_DONTWAIT flag, as it makes a latency inducing sleep neccessary (otherwise one cpu core would be fully utilized with polling the socket).


and btw: I alread know ALLOT about threading and cpus. Your assumption is based on nothing, so dont judge one without knowing anything about him! Simple errors can happen to you, too.

Last edited by Poison Nuke; 06-25-2018 at 05:19 PM.
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
How do I wakeup a kthread that's sleeping with msleep_interruptible() so I can stop it? rszimm Programming 3 09-28-2016 12:00 AM
How to STOP a kernel module from loading? webvandals Linux - General 19 01-31-2011 03:20 PM
[SOLVED] Blacklist kernel module (stop autoloading) ? Vilius Debian 4 08-30-2010 01:31 AM
AUDIO DRIVER INSTALL, ERROR: The NVIDIA kernel module was not created. linuxshrikant Linux - Software 1 05-29-2010 01:45 PM
How do i stop a kernel module loading? The_JinJ Linux - Newbie 1 03-13-2005 04:33 PM

LinuxQuestions.org > Forums > Linux Forums > Linux - Software > Linux - Kernel

All times are GMT -5. The time now is 11:46 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration