📄 ksock_single.c
字号:
static int errno;#define __KERNEL_SYSCALLS__#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/signal.h>#include <linux/init.h>#include <linux/wait.h>#include <linux/smp_lock.h>#include <linux/net.h>#include <net/sock.h>#include <asm/unistd.h>#include <asm/uaccess.h>#include <net/bluetooth/bluetooth.h>#include <net/bluetooth/l2cap.h>#define VERSION "0.1"#define LISTENER 0#define DATACONN 1struct session { struct list_head list; struct socket *sock; wait_queue_t wait; unsigned int type; unsigned long state; atomic_t killed;};static LIST_HEAD(session_list);static DECLARE_WAIT_QUEUE_HEAD(worker_wait);static atomic_t terminate, running;static struct session *ksock_add_session(struct socket *sock, int type){ struct session *s = kmalloc(sizeof(*s), GFP_KERNEL); if (!s) return NULL; memset(s, 0, sizeof(*s)); init_waitqueue_entry(&s->wait, current); add_wait_queue(sock->sk->sleep, &s->wait); s->sock = sock; s->type = type; s->state = 0; list_add(&s->list, &session_list); /* Do not increment module usage count for listeting sessions. * Otherwise we won't be able to unload the module. */ if (type != LISTENER) MOD_INC_USE_COUNT; return s;}static inline int ksock_del_session(struct session *s){ struct socket *sock = s->sock; int type = s->type; list_del(&s->list); remove_wait_queue(sock->sk->sleep, &s->wait); sock_release(sock); kfree(s); if (type != LISTENER) MOD_DEC_USE_COUNT; return 0;}static void ksock_kill_sessions(void){ struct list_head *p, *n; list_for_each_safe(p, n, &session_list) ksock_del_session(list_entry(p, struct session, list));}static inline void ksock_process_data(struct session *s){ struct socket *sock = s->sock; struct sock *sk = sock->sk; struct sk_buff *skb; struct msghdr msg; memset(&msg, 0, sizeof(msg)); msg.msg_iovlen = 1; /* Get data directly from socket receive queue without copying it. * And echo it back. */ while ((skb = skb_dequeue(&sk->receive_queue))) { struct iovec iv = { skb->data, skb->len }; BT_INFO("Session %p received %d bytes", s, skb->len); msg.msg_iov = &iv; sock->ops->sendmsg(sock, &msg, skb->len, NULL); kfree_skb(skb); } if (sk->state != BT_CONNECTED) ksock_del_session(s);}static inline void ksock_accept_connection(struct session *s){ struct socket *sock = s->sock, *nsock; int err; /* Fast check for a new connection. * Avoids unnesesary socket allocations. */ if (list_empty(&bluez_pi(sock->sk)->accept_q)) return; nsock = sock_alloc(); if (!nsock) return; nsock->type = sock->type; nsock->ops = sock->ops; err = sock->ops->accept(sock, nsock, O_NONBLOCK); if (err < 0) { sock_release(nsock); return; } ksock_add_session(nsock, DATACONN);}static inline void ksock_process_sessions(void){ struct list_head *p, *n; list_for_each_safe(p, n, &session_list) { struct session *s; s = list_entry(p, struct session, list); if (atomic_read(&s->killed)) ksock_del_session(s); if (s->type == LISTENER) ksock_accept_connection(s); else ksock_process_data(s); }}static void ksock_worker(void){ BT_INFO(""); daemonize(); reparent_to_init(); set_fs(KERNEL_DS); while (!atomic_read(&terminate)) { set_current_state(TASK_INTERRUPTIBLE); /* Process stuff */ ksock_process_sessions(); /* Done. Let's sleep. * Incomming connections and data will wake us up. */ schedule(); } set_current_state(TASK_RUNNING); return;}static int ksock_add_listener(bdaddr_t *ba, int psm){ struct sockaddr_l2 addr; struct l2cap_options opts; struct socket *sock; int size, err = 0; BT_INFO("psm %d", psm); /* Create socket */ err = sock_create(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP, &sock); if (err < 0) { BT_ERR("Create socket failed %d", err); return err; } /* Bind socket */ bacpy(&addr.l2_bdaddr, ba); addr.l2_family = AF_BLUETOOTH; addr.l2_psm = htobs(psm); err = sock->ops->bind(sock, (struct sockaddr *) &addr, sizeof(addr)); if (err < 0) { BT_ERR("Bind failed %d", err); goto failed; } /* Set L2CAP options */ size = sizeof(opts); sock->ops->getsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, (void *)&opts, &size); opts.imtu = 1024; sock->ops->setsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, (void *)&opts, size); /* Start listening on the socket */ err = sock->ops->listen(sock, 10); if (err) { BT_ERR("Listen failed %d", err); goto failed; } /* Add listening session */ if (!ksock_add_session(sock, LISTENER)) goto failed; return 0;failed: sock_release(sock); return err;}static int ksock_run(void *unused){ DECLARE_WAITQUEUE(wait, current); atomic_inc(&running); daemonize(); sigfillset(¤t->blocked); set_fs(KERNEL_DS); sprintf(current->comm, "ksock"); BT_INFO(""); /* Listen on PSM 11 and 12 */ ksock_add_listener(BDADDR_ANY, 11); ksock_add_listener(BDADDR_ANY, 12); add_wait_queue(&worker_wait, &wait); ksock_worker(); remove_wait_queue(&worker_wait, &wait); ksock_kill_sessions(); atomic_dec(&running); return 0;}int __init ksock_init(void){ kernel_thread(ksock_run, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND); return 0;}void ksock_cleanup(void){ /* Terminate working thread. * ie. Set terminate flag and wake it up */ atomic_inc(&terminate); wake_up_interruptible(&worker_wait); /* Wait until worker is running */ while (atomic_read(&running)) schedule(); return;}module_init(ksock_init);module_exit(ksock_cleanup);MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");MODULE_DESCRIPTION("L2CAP kernel sockets example ver " VERSION);MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -