diff options
Diffstat (limited to 'net/bluetooth/cmtp/core.c')
| -rw-r--r-- | net/bluetooth/cmtp/core.c | 83 | 
1 files changed, 47 insertions, 36 deletions
diff --git a/net/bluetooth/cmtp/core.c b/net/bluetooth/cmtp/core.c index ec0a1347f93..67fe5e84e68 100644 --- a/net/bluetooth/cmtp/core.c +++ b/net/bluetooth/cmtp/core.c @@ -35,6 +35,7 @@  #include <linux/ioctl.h>  #include <linux/file.h>  #include <linux/init.h> +#include <linux/kthread.h>  #include <net/sock.h>  #include <linux/isdn/capilli.h> @@ -52,32 +53,29 @@ static LIST_HEAD(cmtp_session_list);  static struct cmtp_session *__cmtp_get_session(bdaddr_t *bdaddr)  {  	struct cmtp_session *session; -	struct list_head *p;  	BT_DBG(""); -	list_for_each(p, &cmtp_session_list) { -		session = list_entry(p, struct cmtp_session, list); +	list_for_each_entry(session, &cmtp_session_list, list)  		if (!bacmp(bdaddr, &session->bdaddr))  			return session; -	} +  	return NULL;  }  static void __cmtp_link_session(struct cmtp_session *session)  { -	__module_get(THIS_MODULE);  	list_add(&session->list, &cmtp_session_list);  }  static void __cmtp_unlink_session(struct cmtp_session *session)  {  	list_del(&session->list); -	module_put(THIS_MODULE);  }  static void __cmtp_copy_session(struct cmtp_session *session, struct cmtp_conninfo *ci)  { +	memset(ci, 0, sizeof(*ci));  	bacpy(&ci->bdaddr, &session->bdaddr);  	ci->flags = session->flags; @@ -114,7 +112,8 @@ static inline void cmtp_add_msgpart(struct cmtp_session *session, int id, const  	size = (skb) ? skb->len + count : count; -	if (!(nskb = alloc_skb(size, GFP_ATOMIC))) { +	nskb = alloc_skb(size, GFP_ATOMIC); +	if (!nskb) {  		BT_ERR("Can't allocate memory for CAPI message");  		return;  	} @@ -215,7 +214,8 @@ static void cmtp_process_transmit(struct cmtp_session *session)  	BT_DBG("session %p", session); -	if (!(nskb = alloc_skb(session->mtu, GFP_ATOMIC))) { +	nskb = alloc_skb(session->mtu, GFP_ATOMIC); +	if (!nskb) {  		BT_ERR("Can't allocate memory for new frame");  		return;  	} @@ -223,7 +223,8 @@ static void cmtp_process_transmit(struct cmtp_session *session)  	while ((skb = skb_dequeue(&session->transmit))) {  		struct cmtp_scb *scb = (void *) skb->cb; -		if ((tail = (session->mtu - nskb->len)) < 5) { +		tail = session->mtu - nskb->len; +		if (tail < 5) {  			cmtp_send_frame(session, nskb->data, nskb->len);  			skb_trim(nskb, 0);  			tail = session->mtu; @@ -231,9 +232,12 @@ static void cmtp_process_transmit(struct cmtp_session *session)  		size = min_t(uint, ((tail < 258) ? (tail - 2) : (tail - 3)), skb->len); -		if ((scb->id < 0) && ((scb->id = cmtp_alloc_block_id(session)) < 0)) { -			skb_queue_head(&session->transmit, skb); -			break; +		if (scb->id < 0) { +			scb->id = cmtp_alloc_block_id(session); +			if (scb->id < 0) { +				skb_queue_head(&session->transmit, skb); +				break; +			}  		}  		if (size < 256) { @@ -280,27 +284,31 @@ static int cmtp_session(void *arg)  	BT_DBG("session %p", session); -	daemonize("kcmtpd_ctr_%d", session->num);  	set_user_nice(current, -15);  	init_waitqueue_entry(&wait, current);  	add_wait_queue(sk_sleep(sk), &wait); -	while (!atomic_read(&session->terminate)) { +	while (1) {  		set_current_state(TASK_INTERRUPTIBLE); +		if (atomic_read(&session->terminate)) +			break;  		if (sk->sk_state != BT_CONNECTED)  			break;  		while ((skb = skb_dequeue(&sk->sk_receive_queue))) {  			skb_orphan(skb); -			cmtp_recv_frame(session, skb); +			if (!skb_linearize(skb)) +				cmtp_recv_frame(session, skb); +			else +				kfree_skb(skb);  		}  		cmtp_process_transmit(session);  		schedule();  	} -	set_current_state(TASK_RUNNING); +	__set_current_state(TASK_RUNNING);  	remove_wait_queue(sk_sleep(sk), &wait);  	down_write(&cmtp_session_sem); @@ -315,6 +323,7 @@ static int cmtp_session(void *arg)  	up_write(&cmtp_session_sem);  	kfree(session); +	module_put_and_exit(0);  	return 0;  } @@ -331,19 +340,20 @@ int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock)  	down_write(&cmtp_session_sem); -	s = __cmtp_get_session(&bt_sk(sock->sk)->dst); +	s = __cmtp_get_session(&l2cap_pi(sock->sk)->chan->dst);  	if (s && s->state == BT_CONNECTED) {  		err = -EEXIST;  		goto failed;  	} -	bacpy(&session->bdaddr, &bt_sk(sock->sk)->dst); +	bacpy(&session->bdaddr, &l2cap_pi(sock->sk)->chan->dst); -	session->mtu = min_t(uint, l2cap_pi(sock->sk)->omtu, l2cap_pi(sock->sk)->imtu); +	session->mtu = min_t(uint, l2cap_pi(sock->sk)->chan->omtu, +					l2cap_pi(sock->sk)->chan->imtu);  	BT_DBG("mtu %d", session->mtu); -	sprintf(session->name, "%s", batostr(&bt_sk(sock->sk)->dst)); +	sprintf(session->name, "%pMR", &session->bdaddr);  	session->sock  = sock;  	session->state = BT_CONFIG; @@ -363,22 +373,28 @@ int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock)  	__cmtp_link_session(session); -	err = kernel_thread(cmtp_session, session, CLONE_KERNEL); -	if (err < 0) +	__module_get(THIS_MODULE); +	session->task = kthread_run(cmtp_session, session, "kcmtpd_ctr_%d", +								session->num); +	if (IS_ERR(session->task)) { +		module_put(THIS_MODULE); +		err = PTR_ERR(session->task);  		goto unlink; +	}  	if (!(session->flags & (1 << CMTP_LOOPBACK))) {  		err = cmtp_attach_device(session); -		if (err < 0) -			goto detach; +		if (err < 0) { +			atomic_inc(&session->terminate); +			wake_up_process(session->task); +			up_write(&cmtp_session_sem); +			return err; +		}  	}  	up_write(&cmtp_session_sem);  	return 0; -detach: -	cmtp_detach_device(session); -  unlink:  	__cmtp_unlink_session(session); @@ -402,9 +418,9 @@ int cmtp_del_connection(struct cmtp_conndel_req *req)  		/* Flush the transmit queue */  		skb_queue_purge(&session->transmit); -		/* Kill session thread */ +		/* Stop session thread */  		atomic_inc(&session->terminate); -		cmtp_schedule(session); +		wake_up_process(session->task);  	} else  		err = -ENOENT; @@ -414,19 +430,16 @@ int cmtp_del_connection(struct cmtp_conndel_req *req)  int cmtp_get_connlist(struct cmtp_connlist_req *req)  { -	struct list_head *p; +	struct cmtp_session *session;  	int err = 0, n = 0;  	BT_DBG("");  	down_read(&cmtp_session_sem); -	list_for_each(p, &cmtp_session_list) { -		struct cmtp_session *session; +	list_for_each_entry(session, &cmtp_session_list, list) {  		struct cmtp_conninfo ci; -		session = list_entry(p, struct cmtp_session, list); -  		__cmtp_copy_session(session, &ci);  		if (copy_to_user(req->ci, &ci, sizeof(ci))) { @@ -465,8 +478,6 @@ int cmtp_get_conninfo(struct cmtp_conninfo *ci)  static int __init cmtp_init(void)  { -	l2cap_load(); -  	BT_INFO("CMTP (CAPI Emulation) ver %s", VERSION);  	cmtp_init_sockets();  | 
