core.c revision 831441862956fffa17b9801db37e6ea1650b0f69
1/*
2   CMTP implementation for Linux Bluetooth stack (BlueZ).
3   Copyright (C) 2002-2003 Marcel Holtmann <marcel@holtmann.org>
4
5   This program is free software; you can redistribute it and/or modify
6   it under the terms of the GNU General Public License version 2 as
7   published by the Free Software Foundation;
8
9   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
10   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
11   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
12   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
13   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
14   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
18   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
19   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
20   SOFTWARE IS DISCLAIMED.
21*/
22
23#include <linux/module.h>
24
25#include <linux/types.h>
26#include <linux/errno.h>
27#include <linux/kernel.h>
28#include <linux/sched.h>
29#include <linux/slab.h>
30#include <linux/poll.h>
31#include <linux/fcntl.h>
32#include <linux/freezer.h>
33#include <linux/skbuff.h>
34#include <linux/socket.h>
35#include <linux/ioctl.h>
36#include <linux/file.h>
37#include <linux/init.h>
38#include <net/sock.h>
39
40#include <linux/isdn/capilli.h>
41
42#include <net/bluetooth/bluetooth.h>
43#include <net/bluetooth/l2cap.h>
44
45#include "cmtp.h"
46
47#ifndef CONFIG_BT_CMTP_DEBUG
48#undef  BT_DBG
49#define BT_DBG(D...)
50#endif
51
52#define VERSION "1.0"
53
54static DECLARE_RWSEM(cmtp_session_sem);
55static LIST_HEAD(cmtp_session_list);
56
57static struct cmtp_session *__cmtp_get_session(bdaddr_t *bdaddr)
58{
59	struct cmtp_session *session;
60	struct list_head *p;
61
62	BT_DBG("");
63
64	list_for_each(p, &cmtp_session_list) {
65		session = list_entry(p, struct cmtp_session, list);
66		if (!bacmp(bdaddr, &session->bdaddr))
67			return session;
68	}
69	return NULL;
70}
71
72static void __cmtp_link_session(struct cmtp_session *session)
73{
74	__module_get(THIS_MODULE);
75	list_add(&session->list, &cmtp_session_list);
76}
77
78static void __cmtp_unlink_session(struct cmtp_session *session)
79{
80	list_del(&session->list);
81	module_put(THIS_MODULE);
82}
83
84static void __cmtp_copy_session(struct cmtp_session *session, struct cmtp_conninfo *ci)
85{
86	bacpy(&ci->bdaddr, &session->bdaddr);
87
88	ci->flags = session->flags;
89	ci->state = session->state;
90
91	ci->num = session->num;
92}
93
94
95static inline int cmtp_alloc_block_id(struct cmtp_session *session)
96{
97	int i, id = -1;
98
99	for (i = 0; i < 16; i++)
100		if (!test_and_set_bit(i, &session->blockids)) {
101			id = i;
102			break;
103		}
104
105	return id;
106}
107
108static inline void cmtp_free_block_id(struct cmtp_session *session, int id)
109{
110	clear_bit(id, &session->blockids);
111}
112
113static inline void cmtp_add_msgpart(struct cmtp_session *session, int id, const unsigned char *buf, int count)
114{
115	struct sk_buff *skb = session->reassembly[id], *nskb;
116	int size;
117
118	BT_DBG("session %p buf %p count %d", session, buf, count);
119
120	size = (skb) ? skb->len + count : count;
121
122	if (!(nskb = alloc_skb(size, GFP_ATOMIC))) {
123		BT_ERR("Can't allocate memory for CAPI message");
124		return;
125	}
126
127	if (skb && (skb->len > 0))
128		skb_copy_from_linear_data(skb, skb_put(nskb, skb->len), skb->len);
129
130	memcpy(skb_put(nskb, count), buf, count);
131
132	session->reassembly[id] = nskb;
133
134	if (skb)
135		kfree_skb(skb);
136}
137
138static inline int cmtp_recv_frame(struct cmtp_session *session, struct sk_buff *skb)
139{
140	__u8 hdr, hdrlen, id;
141	__u16 len;
142
143	BT_DBG("session %p skb %p len %d", session, skb, skb->len);
144
145	while (skb->len > 0) {
146		hdr = skb->data[0];
147
148		switch (hdr & 0xc0) {
149		case 0x40:
150			hdrlen = 2;
151			len = skb->data[1];
152			break;
153		case 0x80:
154			hdrlen = 3;
155			len = skb->data[1] | (skb->data[2] << 8);
156			break;
157		default:
158			hdrlen = 1;
159			len = 0;
160			break;
161		}
162
163		id = (hdr & 0x3c) >> 2;
164
165		BT_DBG("hdr 0x%02x hdrlen %d len %d id %d", hdr, hdrlen, len, id);
166
167		if (hdrlen + len > skb->len) {
168			BT_ERR("Wrong size or header information in CMTP frame");
169			break;
170		}
171
172		if (len == 0) {
173			skb_pull(skb, hdrlen);
174			continue;
175		}
176
177		switch (hdr & 0x03) {
178		case 0x00:
179			cmtp_add_msgpart(session, id, skb->data + hdrlen, len);
180			cmtp_recv_capimsg(session, session->reassembly[id]);
181			session->reassembly[id] = NULL;
182			break;
183		case 0x01:
184			cmtp_add_msgpart(session, id, skb->data + hdrlen, len);
185			break;
186		default:
187			if (session->reassembly[id] != NULL)
188				kfree_skb(session->reassembly[id]);
189			session->reassembly[id] = NULL;
190			break;
191		}
192
193		skb_pull(skb, hdrlen + len);
194	}
195
196	kfree_skb(skb);
197	return 0;
198}
199
200static int cmtp_send_frame(struct cmtp_session *session, unsigned char *data, int len)
201{
202	struct socket *sock = session->sock;
203	struct kvec iv = { data, len };
204	struct msghdr msg;
205
206	BT_DBG("session %p data %p len %d", session, data, len);
207
208	if (!len)
209		return 0;
210
211	memset(&msg, 0, sizeof(msg));
212
213	return kernel_sendmsg(sock, &msg, &iv, 1, len);
214}
215
216static void cmtp_process_transmit(struct cmtp_session *session)
217{
218	struct sk_buff *skb, *nskb;
219	unsigned char *hdr;
220	unsigned int size, tail;
221
222	BT_DBG("session %p", session);
223
224	if (!(nskb = alloc_skb(session->mtu, GFP_ATOMIC))) {
225		BT_ERR("Can't allocate memory for new frame");
226		return;
227	}
228
229	while ((skb = skb_dequeue(&session->transmit))) {
230		struct cmtp_scb *scb = (void *) skb->cb;
231
232		if ((tail = (session->mtu - nskb->len)) < 5) {
233			cmtp_send_frame(session, nskb->data, nskb->len);
234			skb_trim(nskb, 0);
235			tail = session->mtu;
236		}
237
238		size = min_t(uint, ((tail < 258) ? (tail - 2) : (tail - 3)), skb->len);
239
240		if ((scb->id < 0) && ((scb->id = cmtp_alloc_block_id(session)) < 0)) {
241			skb_queue_head(&session->transmit, skb);
242			break;
243		}
244
245		if (size < 256) {
246			hdr = skb_put(nskb, 2);
247			hdr[0] = 0x40
248				| ((scb->id << 2) & 0x3c)
249				| ((skb->len == size) ? 0x00 : 0x01);
250			hdr[1] = size;
251		} else {
252			hdr = skb_put(nskb, 3);
253			hdr[0] = 0x80
254				| ((scb->id << 2) & 0x3c)
255				| ((skb->len == size) ? 0x00 : 0x01);
256			hdr[1] = size & 0xff;
257			hdr[2] = size >> 8;
258		}
259
260		skb_copy_from_linear_data(skb, skb_put(nskb, size), size);
261		skb_pull(skb, size);
262
263		if (skb->len > 0) {
264			skb_queue_head(&session->transmit, skb);
265		} else {
266			cmtp_free_block_id(session, scb->id);
267			if (scb->data) {
268				cmtp_send_frame(session, nskb->data, nskb->len);
269				skb_trim(nskb, 0);
270			}
271			kfree_skb(skb);
272		}
273	}
274
275	cmtp_send_frame(session, nskb->data, nskb->len);
276
277	kfree_skb(nskb);
278}
279
280static int cmtp_session(void *arg)
281{
282	struct cmtp_session *session = arg;
283	struct sock *sk = session->sock->sk;
284	struct sk_buff *skb;
285	wait_queue_t wait;
286
287	BT_DBG("session %p", session);
288
289	daemonize("kcmtpd_ctr_%d", session->num);
290	set_user_nice(current, -15);
291
292	init_waitqueue_entry(&wait, current);
293	add_wait_queue(sk->sk_sleep, &wait);
294	while (!atomic_read(&session->terminate)) {
295		set_current_state(TASK_INTERRUPTIBLE);
296
297		if (sk->sk_state != BT_CONNECTED)
298			break;
299
300		while ((skb = skb_dequeue(&sk->sk_receive_queue))) {
301			skb_orphan(skb);
302			cmtp_recv_frame(session, skb);
303		}
304
305		cmtp_process_transmit(session);
306
307		schedule();
308	}
309	set_current_state(TASK_RUNNING);
310	remove_wait_queue(sk->sk_sleep, &wait);
311
312	down_write(&cmtp_session_sem);
313
314	if (!(session->flags & (1 << CMTP_LOOPBACK)))
315		cmtp_detach_device(session);
316
317	fput(session->sock->file);
318
319	__cmtp_unlink_session(session);
320
321	up_write(&cmtp_session_sem);
322
323	kfree(session);
324	return 0;
325}
326
327int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock)
328{
329	struct cmtp_session *session, *s;
330	bdaddr_t src, dst;
331	int i, err;
332
333	BT_DBG("");
334
335	baswap(&src, &bt_sk(sock->sk)->src);
336	baswap(&dst, &bt_sk(sock->sk)->dst);
337
338	session = kzalloc(sizeof(struct cmtp_session), GFP_KERNEL);
339	if (!session)
340		return -ENOMEM;
341
342	down_write(&cmtp_session_sem);
343
344	s = __cmtp_get_session(&bt_sk(sock->sk)->dst);
345	if (s && s->state == BT_CONNECTED) {
346		err = -EEXIST;
347		goto failed;
348	}
349
350	bacpy(&session->bdaddr, &bt_sk(sock->sk)->dst);
351
352	session->mtu = min_t(uint, l2cap_pi(sock->sk)->omtu, l2cap_pi(sock->sk)->imtu);
353
354	BT_DBG("mtu %d", session->mtu);
355
356	sprintf(session->name, "%s", batostr(&dst));
357
358	session->sock  = sock;
359	session->state = BT_CONFIG;
360
361	init_waitqueue_head(&session->wait);
362
363	session->msgnum = CMTP_INITIAL_MSGNUM;
364
365	INIT_LIST_HEAD(&session->applications);
366
367	skb_queue_head_init(&session->transmit);
368
369	for (i = 0; i < 16; i++)
370		session->reassembly[i] = NULL;
371
372	session->flags = req->flags;
373
374	__cmtp_link_session(session);
375
376	err = kernel_thread(cmtp_session, session, CLONE_KERNEL);
377	if (err < 0)
378		goto unlink;
379
380	if (!(session->flags & (1 << CMTP_LOOPBACK))) {
381		err = cmtp_attach_device(session);
382		if (err < 0)
383			goto detach;
384	}
385
386	up_write(&cmtp_session_sem);
387	return 0;
388
389detach:
390	cmtp_detach_device(session);
391
392unlink:
393	__cmtp_unlink_session(session);
394
395failed:
396	up_write(&cmtp_session_sem);
397	kfree(session);
398	return err;
399}
400
401int cmtp_del_connection(struct cmtp_conndel_req *req)
402{
403	struct cmtp_session *session;
404	int err = 0;
405
406	BT_DBG("");
407
408	down_read(&cmtp_session_sem);
409
410	session = __cmtp_get_session(&req->bdaddr);
411	if (session) {
412		/* Flush the transmit queue */
413		skb_queue_purge(&session->transmit);
414
415		/* Kill session thread */
416		atomic_inc(&session->terminate);
417		cmtp_schedule(session);
418	} else
419		err = -ENOENT;
420
421	up_read(&cmtp_session_sem);
422	return err;
423}
424
425int cmtp_get_connlist(struct cmtp_connlist_req *req)
426{
427	struct list_head *p;
428	int err = 0, n = 0;
429
430	BT_DBG("");
431
432	down_read(&cmtp_session_sem);
433
434	list_for_each(p, &cmtp_session_list) {
435		struct cmtp_session *session;
436		struct cmtp_conninfo ci;
437
438		session = list_entry(p, struct cmtp_session, list);
439
440		__cmtp_copy_session(session, &ci);
441
442		if (copy_to_user(req->ci, &ci, sizeof(ci))) {
443			err = -EFAULT;
444			break;
445		}
446
447		if (++n >= req->cnum)
448			break;
449
450		req->ci++;
451	}
452	req->cnum = n;
453
454	up_read(&cmtp_session_sem);
455	return err;
456}
457
458int cmtp_get_conninfo(struct cmtp_conninfo *ci)
459{
460	struct cmtp_session *session;
461	int err = 0;
462
463	down_read(&cmtp_session_sem);
464
465	session = __cmtp_get_session(&ci->bdaddr);
466	if (session)
467		__cmtp_copy_session(session, ci);
468	else
469		err = -ENOENT;
470
471	up_read(&cmtp_session_sem);
472	return err;
473}
474
475
476static int __init cmtp_init(void)
477{
478	l2cap_load();
479
480	BT_INFO("CMTP (CAPI Emulation) ver %s", VERSION);
481
482	cmtp_init_sockets();
483
484	return 0;
485}
486
487static void __exit cmtp_exit(void)
488{
489	cmtp_cleanup_sockets();
490}
491
492module_init(cmtp_init);
493module_exit(cmtp_exit);
494
495MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
496MODULE_DESCRIPTION("Bluetooth CMTP ver " VERSION);
497MODULE_VERSION(VERSION);
498MODULE_LICENSE("GPL");
499MODULE_ALIAS("bt-proto-5");
500