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