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