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