xref: /linux/net/bluetooth/cmtp/core.c (revision cb299ba8b5ef2239429484072fea394cd7581bd7)
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 #define VERSION "1.0"
48 
49 static DECLARE_RWSEM(cmtp_session_sem);
50 static LIST_HEAD(cmtp_session_list);
51 
52 static struct cmtp_session *__cmtp_get_session(bdaddr_t *bdaddr)
53 {
54 	struct cmtp_session *session;
55 	struct list_head *p;
56 
57 	BT_DBG("");
58 
59 	list_for_each(p, &cmtp_session_list) {
60 		session = list_entry(p, struct cmtp_session, list);
61 		if (!bacmp(bdaddr, &session->bdaddr))
62 			return session;
63 	}
64 	return NULL;
65 }
66 
67 static void __cmtp_link_session(struct cmtp_session *session)
68 {
69 	__module_get(THIS_MODULE);
70 	list_add(&session->list, &cmtp_session_list);
71 }
72 
73 static void __cmtp_unlink_session(struct cmtp_session *session)
74 {
75 	list_del(&session->list);
76 	module_put(THIS_MODULE);
77 }
78 
79 static void __cmtp_copy_session(struct cmtp_session *session, struct cmtp_conninfo *ci)
80 {
81 	bacpy(&ci->bdaddr, &session->bdaddr);
82 
83 	ci->flags = session->flags;
84 	ci->state = session->state;
85 
86 	ci->num = session->num;
87 }
88 
89 
90 static inline int cmtp_alloc_block_id(struct cmtp_session *session)
91 {
92 	int i, id = -1;
93 
94 	for (i = 0; i < 16; i++)
95 		if (!test_and_set_bit(i, &session->blockids)) {
96 			id = i;
97 			break;
98 		}
99 
100 	return id;
101 }
102 
103 static inline void cmtp_free_block_id(struct cmtp_session *session, int id)
104 {
105 	clear_bit(id, &session->blockids);
106 }
107 
108 static inline void cmtp_add_msgpart(struct cmtp_session *session, int id, const unsigned char *buf, int count)
109 {
110 	struct sk_buff *skb = session->reassembly[id], *nskb;
111 	int size;
112 
113 	BT_DBG("session %p buf %p count %d", session, buf, count);
114 
115 	size = (skb) ? skb->len + count : count;
116 
117 	if (!(nskb = alloc_skb(size, GFP_ATOMIC))) {
118 		BT_ERR("Can't allocate memory for CAPI message");
119 		return;
120 	}
121 
122 	if (skb && (skb->len > 0))
123 		skb_copy_from_linear_data(skb, skb_put(nskb, skb->len), skb->len);
124 
125 	memcpy(skb_put(nskb, count), buf, count);
126 
127 	session->reassembly[id] = nskb;
128 
129 	kfree_skb(skb);
130 }
131 
132 static inline int cmtp_recv_frame(struct cmtp_session *session, struct sk_buff *skb)
133 {
134 	__u8 hdr, hdrlen, id;
135 	__u16 len;
136 
137 	BT_DBG("session %p skb %p len %d", session, skb, skb->len);
138 
139 	while (skb->len > 0) {
140 		hdr = skb->data[0];
141 
142 		switch (hdr & 0xc0) {
143 		case 0x40:
144 			hdrlen = 2;
145 			len = skb->data[1];
146 			break;
147 		case 0x80:
148 			hdrlen = 3;
149 			len = skb->data[1] | (skb->data[2] << 8);
150 			break;
151 		default:
152 			hdrlen = 1;
153 			len = 0;
154 			break;
155 		}
156 
157 		id = (hdr & 0x3c) >> 2;
158 
159 		BT_DBG("hdr 0x%02x hdrlen %d len %d id %d", hdr, hdrlen, len, id);
160 
161 		if (hdrlen + len > skb->len) {
162 			BT_ERR("Wrong size or header information in CMTP frame");
163 			break;
164 		}
165 
166 		if (len == 0) {
167 			skb_pull(skb, hdrlen);
168 			continue;
169 		}
170 
171 		switch (hdr & 0x03) {
172 		case 0x00:
173 			cmtp_add_msgpart(session, id, skb->data + hdrlen, len);
174 			cmtp_recv_capimsg(session, session->reassembly[id]);
175 			session->reassembly[id] = NULL;
176 			break;
177 		case 0x01:
178 			cmtp_add_msgpart(session, id, skb->data + hdrlen, len);
179 			break;
180 		default:
181 			if (session->reassembly[id] != NULL)
182 				kfree_skb(session->reassembly[id]);
183 			session->reassembly[id] = NULL;
184 			break;
185 		}
186 
187 		skb_pull(skb, hdrlen + len);
188 	}
189 
190 	kfree_skb(skb);
191 	return 0;
192 }
193 
194 static int cmtp_send_frame(struct cmtp_session *session, unsigned char *data, int len)
195 {
196 	struct socket *sock = session->sock;
197 	struct kvec iv = { data, len };
198 	struct msghdr msg;
199 
200 	BT_DBG("session %p data %p len %d", session, data, len);
201 
202 	if (!len)
203 		return 0;
204 
205 	memset(&msg, 0, sizeof(msg));
206 
207 	return kernel_sendmsg(sock, &msg, &iv, 1, len);
208 }
209 
210 static void cmtp_process_transmit(struct cmtp_session *session)
211 {
212 	struct sk_buff *skb, *nskb;
213 	unsigned char *hdr;
214 	unsigned int size, tail;
215 
216 	BT_DBG("session %p", session);
217 
218 	if (!(nskb = alloc_skb(session->mtu, GFP_ATOMIC))) {
219 		BT_ERR("Can't allocate memory for new frame");
220 		return;
221 	}
222 
223 	while ((skb = skb_dequeue(&session->transmit))) {
224 		struct cmtp_scb *scb = (void *) skb->cb;
225 
226 		if ((tail = (session->mtu - nskb->len)) < 5) {
227 			cmtp_send_frame(session, nskb->data, nskb->len);
228 			skb_trim(nskb, 0);
229 			tail = session->mtu;
230 		}
231 
232 		size = min_t(uint, ((tail < 258) ? (tail - 2) : (tail - 3)), skb->len);
233 
234 		if ((scb->id < 0) && ((scb->id = cmtp_alloc_block_id(session)) < 0)) {
235 			skb_queue_head(&session->transmit, skb);
236 			break;
237 		}
238 
239 		if (size < 256) {
240 			hdr = skb_put(nskb, 2);
241 			hdr[0] = 0x40
242 				| ((scb->id << 2) & 0x3c)
243 				| ((skb->len == size) ? 0x00 : 0x01);
244 			hdr[1] = size;
245 		} else {
246 			hdr = skb_put(nskb, 3);
247 			hdr[0] = 0x80
248 				| ((scb->id << 2) & 0x3c)
249 				| ((skb->len == size) ? 0x00 : 0x01);
250 			hdr[1] = size & 0xff;
251 			hdr[2] = size >> 8;
252 		}
253 
254 		skb_copy_from_linear_data(skb, skb_put(nskb, size), size);
255 		skb_pull(skb, size);
256 
257 		if (skb->len > 0) {
258 			skb_queue_head(&session->transmit, skb);
259 		} else {
260 			cmtp_free_block_id(session, scb->id);
261 			if (scb->data) {
262 				cmtp_send_frame(session, nskb->data, nskb->len);
263 				skb_trim(nskb, 0);
264 			}
265 			kfree_skb(skb);
266 		}
267 	}
268 
269 	cmtp_send_frame(session, nskb->data, nskb->len);
270 
271 	kfree_skb(nskb);
272 }
273 
274 static int cmtp_session(void *arg)
275 {
276 	struct cmtp_session *session = arg;
277 	struct sock *sk = session->sock->sk;
278 	struct sk_buff *skb;
279 	wait_queue_t wait;
280 
281 	BT_DBG("session %p", session);
282 
283 	daemonize("kcmtpd_ctr_%d", session->num);
284 	set_user_nice(current, -15);
285 
286 	init_waitqueue_entry(&wait, current);
287 	add_wait_queue(sk_sleep(sk), &wait);
288 	while (!atomic_read(&session->terminate)) {
289 		set_current_state(TASK_INTERRUPTIBLE);
290 
291 		if (sk->sk_state != BT_CONNECTED)
292 			break;
293 
294 		while ((skb = skb_dequeue(&sk->sk_receive_queue))) {
295 			skb_orphan(skb);
296 			cmtp_recv_frame(session, skb);
297 		}
298 
299 		cmtp_process_transmit(session);
300 
301 		schedule();
302 	}
303 	set_current_state(TASK_RUNNING);
304 	remove_wait_queue(sk_sleep(sk), &wait);
305 
306 	down_write(&cmtp_session_sem);
307 
308 	if (!(session->flags & (1 << CMTP_LOOPBACK)))
309 		cmtp_detach_device(session);
310 
311 	fput(session->sock->file);
312 
313 	__cmtp_unlink_session(session);
314 
315 	up_write(&cmtp_session_sem);
316 
317 	kfree(session);
318 	return 0;
319 }
320 
321 int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock)
322 {
323 	struct cmtp_session *session, *s;
324 	int i, err;
325 
326 	BT_DBG("");
327 
328 	session = kzalloc(sizeof(struct cmtp_session), GFP_KERNEL);
329 	if (!session)
330 		return -ENOMEM;
331 
332 	down_write(&cmtp_session_sem);
333 
334 	s = __cmtp_get_session(&bt_sk(sock->sk)->dst);
335 	if (s && s->state == BT_CONNECTED) {
336 		err = -EEXIST;
337 		goto failed;
338 	}
339 
340 	bacpy(&session->bdaddr, &bt_sk(sock->sk)->dst);
341 
342 	session->mtu = min_t(uint, l2cap_pi(sock->sk)->omtu, l2cap_pi(sock->sk)->imtu);
343 
344 	BT_DBG("mtu %d", session->mtu);
345 
346 	sprintf(session->name, "%s", batostr(&bt_sk(sock->sk)->dst));
347 
348 	session->sock  = sock;
349 	session->state = BT_CONFIG;
350 
351 	init_waitqueue_head(&session->wait);
352 
353 	session->msgnum = CMTP_INITIAL_MSGNUM;
354 
355 	INIT_LIST_HEAD(&session->applications);
356 
357 	skb_queue_head_init(&session->transmit);
358 
359 	for (i = 0; i < 16; i++)
360 		session->reassembly[i] = NULL;
361 
362 	session->flags = req->flags;
363 
364 	__cmtp_link_session(session);
365 
366 	err = kernel_thread(cmtp_session, session, CLONE_KERNEL);
367 	if (err < 0)
368 		goto unlink;
369 
370 	if (!(session->flags & (1 << CMTP_LOOPBACK))) {
371 		err = cmtp_attach_device(session);
372 		if (err < 0)
373 			goto detach;
374 	}
375 
376 	up_write(&cmtp_session_sem);
377 	return 0;
378 
379 detach:
380 	cmtp_detach_device(session);
381 
382 unlink:
383 	__cmtp_unlink_session(session);
384 
385 failed:
386 	up_write(&cmtp_session_sem);
387 	kfree(session);
388 	return err;
389 }
390 
391 int cmtp_del_connection(struct cmtp_conndel_req *req)
392 {
393 	struct cmtp_session *session;
394 	int err = 0;
395 
396 	BT_DBG("");
397 
398 	down_read(&cmtp_session_sem);
399 
400 	session = __cmtp_get_session(&req->bdaddr);
401 	if (session) {
402 		/* Flush the transmit queue */
403 		skb_queue_purge(&session->transmit);
404 
405 		/* Kill session thread */
406 		atomic_inc(&session->terminate);
407 		cmtp_schedule(session);
408 	} else
409 		err = -ENOENT;
410 
411 	up_read(&cmtp_session_sem);
412 	return err;
413 }
414 
415 int cmtp_get_connlist(struct cmtp_connlist_req *req)
416 {
417 	struct list_head *p;
418 	int err = 0, n = 0;
419 
420 	BT_DBG("");
421 
422 	down_read(&cmtp_session_sem);
423 
424 	list_for_each(p, &cmtp_session_list) {
425 		struct cmtp_session *session;
426 		struct cmtp_conninfo ci;
427 
428 		session = list_entry(p, struct cmtp_session, list);
429 
430 		__cmtp_copy_session(session, &ci);
431 
432 		if (copy_to_user(req->ci, &ci, sizeof(ci))) {
433 			err = -EFAULT;
434 			break;
435 		}
436 
437 		if (++n >= req->cnum)
438 			break;
439 
440 		req->ci++;
441 	}
442 	req->cnum = n;
443 
444 	up_read(&cmtp_session_sem);
445 	return err;
446 }
447 
448 int cmtp_get_conninfo(struct cmtp_conninfo *ci)
449 {
450 	struct cmtp_session *session;
451 	int err = 0;
452 
453 	down_read(&cmtp_session_sem);
454 
455 	session = __cmtp_get_session(&ci->bdaddr);
456 	if (session)
457 		__cmtp_copy_session(session, ci);
458 	else
459 		err = -ENOENT;
460 
461 	up_read(&cmtp_session_sem);
462 	return err;
463 }
464 
465 
466 static int __init cmtp_init(void)
467 {
468 	l2cap_load();
469 
470 	BT_INFO("CMTP (CAPI Emulation) ver %s", VERSION);
471 
472 	cmtp_init_sockets();
473 
474 	return 0;
475 }
476 
477 static void __exit cmtp_exit(void)
478 {
479 	cmtp_cleanup_sockets();
480 }
481 
482 module_init(cmtp_init);
483 module_exit(cmtp_exit);
484 
485 MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
486 MODULE_DESCRIPTION("Bluetooth CMTP ver " VERSION);
487 MODULE_VERSION(VERSION);
488 MODULE_LICENSE("GPL");
489 MODULE_ALIAS("bt-proto-5");
490