xref: /openbmc/linux/net/bluetooth/cmtp/capi.c (revision 94cdda6b)
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/export.h>
24 #include <linux/proc_fs.h>
25 #include <linux/seq_file.h>
26 #include <linux/types.h>
27 #include <linux/errno.h>
28 #include <linux/kernel.h>
29 #include <linux/sched.h>
30 #include <linux/slab.h>
31 #include <linux/poll.h>
32 #include <linux/fcntl.h>
33 #include <linux/skbuff.h>
34 #include <linux/socket.h>
35 #include <linux/ioctl.h>
36 #include <linux/file.h>
37 #include <linux/wait.h>
38 #include <linux/kthread.h>
39 #include <net/sock.h>
40 
41 #include <linux/isdn/capilli.h>
42 #include <linux/isdn/capicmd.h>
43 #include <linux/isdn/capiutil.h>
44 
45 #include "cmtp.h"
46 
47 #define CAPI_INTEROPERABILITY		0x20
48 
49 #define CAPI_INTEROPERABILITY_REQ	CAPICMD(CAPI_INTEROPERABILITY, CAPI_REQ)
50 #define CAPI_INTEROPERABILITY_CONF	CAPICMD(CAPI_INTEROPERABILITY, CAPI_CONF)
51 #define CAPI_INTEROPERABILITY_IND	CAPICMD(CAPI_INTEROPERABILITY, CAPI_IND)
52 #define CAPI_INTEROPERABILITY_RESP	CAPICMD(CAPI_INTEROPERABILITY, CAPI_RESP)
53 
54 #define CAPI_INTEROPERABILITY_REQ_LEN	(CAPI_MSG_BASELEN + 2)
55 #define CAPI_INTEROPERABILITY_CONF_LEN	(CAPI_MSG_BASELEN + 4)
56 #define CAPI_INTEROPERABILITY_IND_LEN	(CAPI_MSG_BASELEN + 2)
57 #define CAPI_INTEROPERABILITY_RESP_LEN	(CAPI_MSG_BASELEN + 2)
58 
59 #define CAPI_FUNCTION_REGISTER		0
60 #define CAPI_FUNCTION_RELEASE		1
61 #define CAPI_FUNCTION_GET_PROFILE	2
62 #define CAPI_FUNCTION_GET_MANUFACTURER	3
63 #define CAPI_FUNCTION_GET_VERSION	4
64 #define CAPI_FUNCTION_GET_SERIAL_NUMBER	5
65 #define CAPI_FUNCTION_MANUFACTURER	6
66 #define CAPI_FUNCTION_LOOPBACK		7
67 
68 
69 #define CMTP_MSGNUM	1
70 #define CMTP_APPLID	2
71 #define CMTP_MAPPING	3
72 
73 static struct cmtp_application *cmtp_application_add(struct cmtp_session *session, __u16 appl)
74 {
75 	struct cmtp_application *app = kzalloc(sizeof(*app), GFP_KERNEL);
76 
77 	BT_DBG("session %p application %p appl %d", session, app, appl);
78 
79 	if (!app)
80 		return NULL;
81 
82 	app->state = BT_OPEN;
83 	app->appl = appl;
84 
85 	list_add_tail(&app->list, &session->applications);
86 
87 	return app;
88 }
89 
90 static void cmtp_application_del(struct cmtp_session *session, struct cmtp_application *app)
91 {
92 	BT_DBG("session %p application %p", session, app);
93 
94 	if (app) {
95 		list_del(&app->list);
96 		kfree(app);
97 	}
98 }
99 
100 static struct cmtp_application *cmtp_application_get(struct cmtp_session *session, int pattern, __u16 value)
101 {
102 	struct cmtp_application *app;
103 	struct list_head *p, *n;
104 
105 	list_for_each_safe(p, n, &session->applications) {
106 		app = list_entry(p, struct cmtp_application, list);
107 		switch (pattern) {
108 		case CMTP_MSGNUM:
109 			if (app->msgnum == value)
110 				return app;
111 			break;
112 		case CMTP_APPLID:
113 			if (app->appl == value)
114 				return app;
115 			break;
116 		case CMTP_MAPPING:
117 			if (app->mapping == value)
118 				return app;
119 			break;
120 		}
121 	}
122 
123 	return NULL;
124 }
125 
126 static int cmtp_msgnum_get(struct cmtp_session *session)
127 {
128 	session->msgnum++;
129 
130 	if ((session->msgnum & 0xff) > 200)
131 		session->msgnum = CMTP_INITIAL_MSGNUM + 1;
132 
133 	return session->msgnum;
134 }
135 
136 static void cmtp_send_capimsg(struct cmtp_session *session, struct sk_buff *skb)
137 {
138 	struct cmtp_scb *scb = (void *) skb->cb;
139 
140 	BT_DBG("session %p skb %p len %d", session, skb, skb->len);
141 
142 	scb->id = -1;
143 	scb->data = (CAPIMSG_COMMAND(skb->data) == CAPI_DATA_B3);
144 
145 	skb_queue_tail(&session->transmit, skb);
146 
147 	wake_up_interruptible(sk_sleep(session->sock->sk));
148 }
149 
150 static void cmtp_send_interopmsg(struct cmtp_session *session,
151 					__u8 subcmd, __u16 appl, __u16 msgnum,
152 					__u16 function, unsigned char *buf, int len)
153 {
154 	struct sk_buff *skb;
155 	unsigned char *s;
156 
157 	BT_DBG("session %p subcmd 0x%02x appl %d msgnum %d", session, subcmd, appl, msgnum);
158 
159 	skb = alloc_skb(CAPI_MSG_BASELEN + 6 + len, GFP_ATOMIC);
160 	if (!skb) {
161 		BT_ERR("Can't allocate memory for interoperability packet");
162 		return;
163 	}
164 
165 	s = skb_put(skb, CAPI_MSG_BASELEN + 6 + len);
166 
167 	capimsg_setu16(s, 0, CAPI_MSG_BASELEN + 6 + len);
168 	capimsg_setu16(s, 2, appl);
169 	capimsg_setu8 (s, 4, CAPI_INTEROPERABILITY);
170 	capimsg_setu8 (s, 5, subcmd);
171 	capimsg_setu16(s, 6, msgnum);
172 
173 	/* Interoperability selector (Bluetooth Device Management) */
174 	capimsg_setu16(s, 8, 0x0001);
175 
176 	capimsg_setu8 (s, 10, 3 + len);
177 	capimsg_setu16(s, 11, function);
178 	capimsg_setu8 (s, 13, len);
179 
180 	if (len > 0)
181 		memcpy(s + 14, buf, len);
182 
183 	cmtp_send_capimsg(session, skb);
184 }
185 
186 static void cmtp_recv_interopmsg(struct cmtp_session *session, struct sk_buff *skb)
187 {
188 	struct capi_ctr *ctrl = &session->ctrl;
189 	struct cmtp_application *application;
190 	__u16 appl, msgnum, func, info;
191 	__u32 controller;
192 
193 	BT_DBG("session %p skb %p len %d", session, skb, skb->len);
194 
195 	switch (CAPIMSG_SUBCOMMAND(skb->data)) {
196 	case CAPI_CONF:
197 		if (skb->len < CAPI_MSG_BASELEN + 10)
198 			break;
199 
200 		func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 5);
201 		info = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 8);
202 
203 		switch (func) {
204 		case CAPI_FUNCTION_REGISTER:
205 			msgnum = CAPIMSG_MSGID(skb->data);
206 
207 			application = cmtp_application_get(session, CMTP_MSGNUM, msgnum);
208 			if (application) {
209 				application->state = BT_CONNECTED;
210 				application->msgnum = 0;
211 				application->mapping = CAPIMSG_APPID(skb->data);
212 				wake_up_interruptible(&session->wait);
213 			}
214 
215 			break;
216 
217 		case CAPI_FUNCTION_RELEASE:
218 			appl = CAPIMSG_APPID(skb->data);
219 
220 			application = cmtp_application_get(session, CMTP_MAPPING, appl);
221 			if (application) {
222 				application->state = BT_CLOSED;
223 				application->msgnum = 0;
224 				wake_up_interruptible(&session->wait);
225 			}
226 
227 			break;
228 
229 		case CAPI_FUNCTION_GET_PROFILE:
230 			if (skb->len < CAPI_MSG_BASELEN + 11 + sizeof(capi_profile))
231 				break;
232 
233 			controller = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 11);
234 			msgnum = CAPIMSG_MSGID(skb->data);
235 
236 			if (!info && (msgnum == CMTP_INITIAL_MSGNUM)) {
237 				session->ncontroller = controller;
238 				wake_up_interruptible(&session->wait);
239 				break;
240 			}
241 
242 			if (!info && ctrl) {
243 				memcpy(&ctrl->profile,
244 					skb->data + CAPI_MSG_BASELEN + 11,
245 					sizeof(capi_profile));
246 				session->state = BT_CONNECTED;
247 				capi_ctr_ready(ctrl);
248 			}
249 
250 			break;
251 
252 		case CAPI_FUNCTION_GET_MANUFACTURER:
253 			if (skb->len < CAPI_MSG_BASELEN + 15)
254 				break;
255 
256 			if (!info && ctrl) {
257 				int len = min_t(uint, CAPI_MANUFACTURER_LEN,
258 						skb->data[CAPI_MSG_BASELEN + 14]);
259 
260 				memset(ctrl->manu, 0, CAPI_MANUFACTURER_LEN);
261 				strncpy(ctrl->manu,
262 					skb->data + CAPI_MSG_BASELEN + 15, len);
263 			}
264 
265 			break;
266 
267 		case CAPI_FUNCTION_GET_VERSION:
268 			if (skb->len < CAPI_MSG_BASELEN + 32)
269 				break;
270 
271 			if (!info && ctrl) {
272 				ctrl->version.majorversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 16);
273 				ctrl->version.minorversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 20);
274 				ctrl->version.majormanuversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 24);
275 				ctrl->version.minormanuversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 28);
276 			}
277 
278 			break;
279 
280 		case CAPI_FUNCTION_GET_SERIAL_NUMBER:
281 			if (skb->len < CAPI_MSG_BASELEN + 17)
282 				break;
283 
284 			if (!info && ctrl) {
285 				int len = min_t(uint, CAPI_SERIAL_LEN,
286 						skb->data[CAPI_MSG_BASELEN + 16]);
287 
288 				memset(ctrl->serial, 0, CAPI_SERIAL_LEN);
289 				strncpy(ctrl->serial,
290 					skb->data + CAPI_MSG_BASELEN + 17, len);
291 			}
292 
293 			break;
294 		}
295 
296 		break;
297 
298 	case CAPI_IND:
299 		if (skb->len < CAPI_MSG_BASELEN + 6)
300 			break;
301 
302 		func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 3);
303 
304 		if (func == CAPI_FUNCTION_LOOPBACK) {
305 			int len = min_t(uint, skb->len - CAPI_MSG_BASELEN - 6,
306 						skb->data[CAPI_MSG_BASELEN + 5]);
307 			appl = CAPIMSG_APPID(skb->data);
308 			msgnum = CAPIMSG_MSGID(skb->data);
309 			cmtp_send_interopmsg(session, CAPI_RESP, appl, msgnum, func,
310 						skb->data + CAPI_MSG_BASELEN + 6, len);
311 		}
312 
313 		break;
314 	}
315 
316 	kfree_skb(skb);
317 }
318 
319 void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb)
320 {
321 	struct capi_ctr *ctrl = &session->ctrl;
322 	struct cmtp_application *application;
323 	__u16 appl;
324 	__u32 contr;
325 
326 	BT_DBG("session %p skb %p len %d", session, skb, skb->len);
327 
328 	if (skb->len < CAPI_MSG_BASELEN)
329 		return;
330 
331 	if (CAPIMSG_COMMAND(skb->data) == CAPI_INTEROPERABILITY) {
332 		cmtp_recv_interopmsg(session, skb);
333 		return;
334 	}
335 
336 	if (session->flags & BIT(CMTP_LOOPBACK)) {
337 		kfree_skb(skb);
338 		return;
339 	}
340 
341 	appl = CAPIMSG_APPID(skb->data);
342 	contr = CAPIMSG_CONTROL(skb->data);
343 
344 	application = cmtp_application_get(session, CMTP_MAPPING, appl);
345 	if (application) {
346 		appl = application->appl;
347 		CAPIMSG_SETAPPID(skb->data, appl);
348 	} else {
349 		BT_ERR("Can't find application with id %d", appl);
350 		kfree_skb(skb);
351 		return;
352 	}
353 
354 	if ((contr & 0x7f) == 0x01) {
355 		contr = (contr & 0xffffff80) | session->num;
356 		CAPIMSG_SETCONTROL(skb->data, contr);
357 	}
358 
359 	capi_ctr_handle_message(ctrl, appl, skb);
360 }
361 
362 static int cmtp_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
363 {
364 	BT_DBG("ctrl %p data %p", ctrl, data);
365 
366 	return 0;
367 }
368 
369 static void cmtp_reset_ctr(struct capi_ctr *ctrl)
370 {
371 	struct cmtp_session *session = ctrl->driverdata;
372 
373 	BT_DBG("ctrl %p", ctrl);
374 
375 	capi_ctr_down(ctrl);
376 
377 	atomic_inc(&session->terminate);
378 	wake_up_process(session->task);
379 }
380 
381 static void cmtp_register_appl(struct capi_ctr *ctrl, __u16 appl, capi_register_params *rp)
382 {
383 	DECLARE_WAITQUEUE(wait, current);
384 	struct cmtp_session *session = ctrl->driverdata;
385 	struct cmtp_application *application;
386 	unsigned long timeo = CMTP_INTEROP_TIMEOUT;
387 	unsigned char buf[8];
388 	int err = 0, nconn, want = rp->level3cnt;
389 
390 	BT_DBG("ctrl %p appl %d level3cnt %d datablkcnt %d datablklen %d",
391 		ctrl, appl, rp->level3cnt, rp->datablkcnt, rp->datablklen);
392 
393 	application = cmtp_application_add(session, appl);
394 	if (!application) {
395 		BT_ERR("Can't allocate memory for new application");
396 		return;
397 	}
398 
399 	if (want < 0)
400 		nconn = ctrl->profile.nbchannel * -want;
401 	else
402 		nconn = want;
403 
404 	if (nconn == 0)
405 		nconn = ctrl->profile.nbchannel;
406 
407 	capimsg_setu16(buf, 0, nconn);
408 	capimsg_setu16(buf, 2, rp->datablkcnt);
409 	capimsg_setu16(buf, 4, rp->datablklen);
410 
411 	application->state = BT_CONFIG;
412 	application->msgnum = cmtp_msgnum_get(session);
413 
414 	cmtp_send_interopmsg(session, CAPI_REQ, 0x0000, application->msgnum,
415 				CAPI_FUNCTION_REGISTER, buf, 6);
416 
417 	add_wait_queue(&session->wait, &wait);
418 	while (1) {
419 		set_current_state(TASK_INTERRUPTIBLE);
420 
421 		if (!timeo) {
422 			err = -EAGAIN;
423 			break;
424 		}
425 
426 		if (application->state == BT_CLOSED) {
427 			err = -application->err;
428 			break;
429 		}
430 
431 		if (application->state == BT_CONNECTED)
432 			break;
433 
434 		if (signal_pending(current)) {
435 			err = -EINTR;
436 			break;
437 		}
438 
439 		timeo = schedule_timeout(timeo);
440 	}
441 	set_current_state(TASK_RUNNING);
442 	remove_wait_queue(&session->wait, &wait);
443 
444 	if (err) {
445 		cmtp_application_del(session, application);
446 		return;
447 	}
448 }
449 
450 static void cmtp_release_appl(struct capi_ctr *ctrl, __u16 appl)
451 {
452 	struct cmtp_session *session = ctrl->driverdata;
453 	struct cmtp_application *application;
454 
455 	BT_DBG("ctrl %p appl %d", ctrl, appl);
456 
457 	application = cmtp_application_get(session, CMTP_APPLID, appl);
458 	if (!application) {
459 		BT_ERR("Can't find application");
460 		return;
461 	}
462 
463 	application->msgnum = cmtp_msgnum_get(session);
464 
465 	cmtp_send_interopmsg(session, CAPI_REQ, application->mapping, application->msgnum,
466 				CAPI_FUNCTION_RELEASE, NULL, 0);
467 
468 	wait_event_interruptible_timeout(session->wait,
469 			(application->state == BT_CLOSED), CMTP_INTEROP_TIMEOUT);
470 
471 	cmtp_application_del(session, application);
472 }
473 
474 static u16 cmtp_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
475 {
476 	struct cmtp_session *session = ctrl->driverdata;
477 	struct cmtp_application *application;
478 	__u16 appl;
479 	__u32 contr;
480 
481 	BT_DBG("ctrl %p skb %p", ctrl, skb);
482 
483 	appl = CAPIMSG_APPID(skb->data);
484 	contr = CAPIMSG_CONTROL(skb->data);
485 
486 	application = cmtp_application_get(session, CMTP_APPLID, appl);
487 	if ((!application) || (application->state != BT_CONNECTED)) {
488 		BT_ERR("Can't find application with id %d", appl);
489 		return CAPI_ILLAPPNR;
490 	}
491 
492 	CAPIMSG_SETAPPID(skb->data, application->mapping);
493 
494 	if ((contr & 0x7f) == session->num) {
495 		contr = (contr & 0xffffff80) | 0x01;
496 		CAPIMSG_SETCONTROL(skb->data, contr);
497 	}
498 
499 	cmtp_send_capimsg(session, skb);
500 
501 	return CAPI_NOERROR;
502 }
503 
504 static char *cmtp_procinfo(struct capi_ctr *ctrl)
505 {
506 	return "CAPI Message Transport Protocol";
507 }
508 
509 static int cmtp_proc_show(struct seq_file *m, void *v)
510 {
511 	struct capi_ctr *ctrl = m->private;
512 	struct cmtp_session *session = ctrl->driverdata;
513 	struct cmtp_application *app;
514 	struct list_head *p, *n;
515 
516 	seq_printf(m, "%s\n\n", cmtp_procinfo(ctrl));
517 	seq_printf(m, "addr %s\n", session->name);
518 	seq_printf(m, "ctrl %d\n", session->num);
519 
520 	list_for_each_safe(p, n, &session->applications) {
521 		app = list_entry(p, struct cmtp_application, list);
522 		seq_printf(m, "appl %d -> %d\n", app->appl, app->mapping);
523 	}
524 
525 	return 0;
526 }
527 
528 static int cmtp_proc_open(struct inode *inode, struct file *file)
529 {
530 	return single_open(file, cmtp_proc_show, PDE_DATA(inode));
531 }
532 
533 static const struct file_operations cmtp_proc_fops = {
534 	.owner		= THIS_MODULE,
535 	.open		= cmtp_proc_open,
536 	.read		= seq_read,
537 	.llseek		= seq_lseek,
538 	.release	= single_release,
539 };
540 
541 int cmtp_attach_device(struct cmtp_session *session)
542 {
543 	unsigned char buf[4];
544 	long ret;
545 
546 	BT_DBG("session %p", session);
547 
548 	capimsg_setu32(buf, 0, 0);
549 
550 	cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, CMTP_INITIAL_MSGNUM,
551 				CAPI_FUNCTION_GET_PROFILE, buf, 4);
552 
553 	ret = wait_event_interruptible_timeout(session->wait,
554 			session->ncontroller, CMTP_INTEROP_TIMEOUT);
555 
556 	BT_INFO("Found %d CAPI controller(s) on device %s", session->ncontroller, session->name);
557 
558 	if (!ret)
559 		return -ETIMEDOUT;
560 
561 	if (!session->ncontroller)
562 		return -ENODEV;
563 
564 	if (session->ncontroller > 1)
565 		BT_INFO("Setting up only CAPI controller 1");
566 
567 	session->ctrl.owner      = THIS_MODULE;
568 	session->ctrl.driverdata = session;
569 	strcpy(session->ctrl.name, session->name);
570 
571 	session->ctrl.driver_name   = "cmtp";
572 	session->ctrl.load_firmware = cmtp_load_firmware;
573 	session->ctrl.reset_ctr     = cmtp_reset_ctr;
574 	session->ctrl.register_appl = cmtp_register_appl;
575 	session->ctrl.release_appl  = cmtp_release_appl;
576 	session->ctrl.send_message  = cmtp_send_message;
577 
578 	session->ctrl.procinfo      = cmtp_procinfo;
579 	session->ctrl.proc_fops = &cmtp_proc_fops;
580 
581 	if (attach_capi_ctr(&session->ctrl) < 0) {
582 		BT_ERR("Can't attach new controller");
583 		return -EBUSY;
584 	}
585 
586 	session->num = session->ctrl.cnr;
587 
588 	BT_DBG("session %p num %d", session, session->num);
589 
590 	capimsg_setu32(buf, 0, 1);
591 
592 	cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
593 				CAPI_FUNCTION_GET_MANUFACTURER, buf, 4);
594 
595 	cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
596 				CAPI_FUNCTION_GET_VERSION, buf, 4);
597 
598 	cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
599 				CAPI_FUNCTION_GET_SERIAL_NUMBER, buf, 4);
600 
601 	cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
602 				CAPI_FUNCTION_GET_PROFILE, buf, 4);
603 
604 	return 0;
605 }
606 
607 void cmtp_detach_device(struct cmtp_session *session)
608 {
609 	BT_DBG("session %p", session);
610 
611 	detach_capi_ctr(&session->ctrl);
612 }
613