Linux Audio

Check our new training course

Loading...
v6.8
  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/signal.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
 73static 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 %u", 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
 90static 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
100static struct cmtp_application *cmtp_application_get(struct cmtp_session *session, int pattern, __u16 value)
101{
102	struct cmtp_application *app;
 
103
104	list_for_each_entry(app, &session->applications, list) {
 
105		switch (pattern) {
106		case CMTP_MSGNUM:
107			if (app->msgnum == value)
108				return app;
109			break;
110		case CMTP_APPLID:
111			if (app->appl == value)
112				return app;
113			break;
114		case CMTP_MAPPING:
115			if (app->mapping == value)
116				return app;
117			break;
118		}
119	}
120
121	return NULL;
122}
123
124static int cmtp_msgnum_get(struct cmtp_session *session)
125{
126	session->msgnum++;
127
128	if ((session->msgnum & 0xff) > 200)
129		session->msgnum = CMTP_INITIAL_MSGNUM + 1;
130
131	return session->msgnum;
132}
133
134static void cmtp_send_capimsg(struct cmtp_session *session, struct sk_buff *skb)
135{
136	struct cmtp_scb *scb = (void *) skb->cb;
137
138	BT_DBG("session %p skb %p len %u", session, skb, skb->len);
139
140	scb->id = -1;
141	scb->data = (CAPIMSG_COMMAND(skb->data) == CAPI_DATA_B3);
142
143	skb_queue_tail(&session->transmit, skb);
144
145	wake_up_interruptible(sk_sleep(session->sock->sk));
146}
147
148static void cmtp_send_interopmsg(struct cmtp_session *session,
149					__u8 subcmd, __u16 appl, __u16 msgnum,
150					__u16 function, unsigned char *buf, int len)
151{
152	struct sk_buff *skb;
153	unsigned char *s;
154
155	BT_DBG("session %p subcmd 0x%02x appl %u msgnum %u", session, subcmd, appl, msgnum);
156
157	skb = alloc_skb(CAPI_MSG_BASELEN + 6 + len, GFP_ATOMIC);
158	if (!skb) {
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 %u", 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			if (!info && ctrl) {
255				int len = min_t(uint, CAPI_MANUFACTURER_LEN,
256						skb->data[CAPI_MSG_BASELEN + 14]);
257
258				memset(ctrl->manu, 0, CAPI_MANUFACTURER_LEN);
259				strncpy(ctrl->manu,
260					skb->data + CAPI_MSG_BASELEN + 15, len);
261			}
262
263			break;
264
265		case CAPI_FUNCTION_GET_VERSION:
266			if (skb->len < CAPI_MSG_BASELEN + 32)
267				break;
268
 
 
269			if (!info && ctrl) {
270				ctrl->version.majorversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 16);
271				ctrl->version.minorversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 20);
272				ctrl->version.majormanuversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 24);
273				ctrl->version.minormanuversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 28);
274			}
275
276			break;
277
278		case CAPI_FUNCTION_GET_SERIAL_NUMBER:
279			if (skb->len < CAPI_MSG_BASELEN + 17)
280				break;
281
 
 
282			if (!info && ctrl) {
283				int len = min_t(uint, CAPI_SERIAL_LEN,
284						skb->data[CAPI_MSG_BASELEN + 16]);
285
286				memset(ctrl->serial, 0, CAPI_SERIAL_LEN);
287				strncpy(ctrl->serial,
288					skb->data + CAPI_MSG_BASELEN + 17, len);
289			}
290
291			break;
292		}
293
294		break;
295
296	case CAPI_IND:
297		if (skb->len < CAPI_MSG_BASELEN + 6)
298			break;
299
300		func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 3);
301
302		if (func == CAPI_FUNCTION_LOOPBACK) {
303			int len = min_t(uint, skb->len - CAPI_MSG_BASELEN - 6,
304						skb->data[CAPI_MSG_BASELEN + 5]);
305			appl = CAPIMSG_APPID(skb->data);
306			msgnum = CAPIMSG_MSGID(skb->data);
307			cmtp_send_interopmsg(session, CAPI_RESP, appl, msgnum, func,
308						skb->data + CAPI_MSG_BASELEN + 6, len);
309		}
310
311		break;
312	}
313
314	kfree_skb(skb);
315}
316
317void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb)
318{
319	struct capi_ctr *ctrl = &session->ctrl;
320	struct cmtp_application *application;
321	__u16 appl;
322	__u32 contr;
323
324	BT_DBG("session %p skb %p len %u", session, skb, skb->len);
325
326	if (skb->len < CAPI_MSG_BASELEN)
327		return;
328
329	if (CAPIMSG_COMMAND(skb->data) == CAPI_INTEROPERABILITY) {
330		cmtp_recv_interopmsg(session, skb);
331		return;
332	}
333
334	if (session->flags & BIT(CMTP_LOOPBACK)) {
335		kfree_skb(skb);
336		return;
337	}
338
339	appl = CAPIMSG_APPID(skb->data);
340	contr = CAPIMSG_CONTROL(skb->data);
341
342	application = cmtp_application_get(session, CMTP_MAPPING, appl);
343	if (application) {
344		appl = application->appl;
345		CAPIMSG_SETAPPID(skb->data, appl);
346	} else {
347		BT_ERR("Can't find application with id %u", appl);
348		kfree_skb(skb);
349		return;
350	}
351
352	if ((contr & 0x7f) == 0x01) {
353		contr = (contr & 0xffffff80) | session->num;
354		CAPIMSG_SETCONTROL(skb->data, contr);
355	}
356
 
 
 
 
 
 
357	capi_ctr_handle_message(ctrl, appl, skb);
358}
359
360static int cmtp_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
361{
362	BT_DBG("ctrl %p data %p", ctrl, data);
363
364	return 0;
365}
366
367static void cmtp_reset_ctr(struct capi_ctr *ctrl)
368{
369	struct cmtp_session *session = ctrl->driverdata;
370
371	BT_DBG("ctrl %p", ctrl);
372
373	capi_ctr_down(ctrl);
374
375	atomic_inc(&session->terminate);
376	wake_up_process(session->task);
377}
378
379static void cmtp_register_appl(struct capi_ctr *ctrl, __u16 appl, capi_register_params *rp)
380{
381	DECLARE_WAITQUEUE(wait, current);
382	struct cmtp_session *session = ctrl->driverdata;
383	struct cmtp_application *application;
384	unsigned long timeo = CMTP_INTEROP_TIMEOUT;
385	unsigned char buf[8];
386	int err = 0, nconn, want = rp->level3cnt;
387
388	BT_DBG("ctrl %p appl %u level3cnt %u datablkcnt %u datablklen %u",
389	       ctrl, appl, rp->level3cnt, rp->datablkcnt, rp->datablklen);
390
391	application = cmtp_application_add(session, appl);
392	if (!application) {
393		BT_ERR("Can't allocate memory for new application");
394		return;
395	}
396
397	if (want < 0)
398		nconn = ctrl->profile.nbchannel * -want;
399	else
400		nconn = want;
401
402	if (nconn == 0)
403		nconn = ctrl->profile.nbchannel;
404
405	capimsg_setu16(buf, 0, nconn);
406	capimsg_setu16(buf, 2, rp->datablkcnt);
407	capimsg_setu16(buf, 4, rp->datablklen);
408
409	application->state = BT_CONFIG;
410	application->msgnum = cmtp_msgnum_get(session);
411
412	cmtp_send_interopmsg(session, CAPI_REQ, 0x0000, application->msgnum,
413				CAPI_FUNCTION_REGISTER, buf, 6);
414
415	add_wait_queue(&session->wait, &wait);
416	while (1) {
417		set_current_state(TASK_INTERRUPTIBLE);
418
419		if (!timeo) {
420			err = -EAGAIN;
421			break;
422		}
423
424		if (application->state == BT_CLOSED) {
425			err = -application->err;
426			break;
427		}
428
429		if (application->state == BT_CONNECTED)
430			break;
431
432		if (signal_pending(current)) {
433			err = -EINTR;
434			break;
435		}
436
437		timeo = schedule_timeout(timeo);
438	}
439	set_current_state(TASK_RUNNING);
440	remove_wait_queue(&session->wait, &wait);
441
442	if (err) {
443		cmtp_application_del(session, application);
444		return;
445	}
446}
447
448static void cmtp_release_appl(struct capi_ctr *ctrl, __u16 appl)
449{
450	struct cmtp_session *session = ctrl->driverdata;
451	struct cmtp_application *application;
452
453	BT_DBG("ctrl %p appl %u", ctrl, appl);
454
455	application = cmtp_application_get(session, CMTP_APPLID, appl);
456	if (!application) {
457		BT_ERR("Can't find application");
458		return;
459	}
460
461	application->msgnum = cmtp_msgnum_get(session);
462
463	cmtp_send_interopmsg(session, CAPI_REQ, application->mapping, application->msgnum,
464				CAPI_FUNCTION_RELEASE, NULL, 0);
465
466	wait_event_interruptible_timeout(session->wait,
467			(application->state == BT_CLOSED), CMTP_INTEROP_TIMEOUT);
468
469	cmtp_application_del(session, application);
470}
471
472static u16 cmtp_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
473{
474	struct cmtp_session *session = ctrl->driverdata;
475	struct cmtp_application *application;
476	__u16 appl;
477	__u32 contr;
478
479	BT_DBG("ctrl %p skb %p", ctrl, skb);
480
481	appl = CAPIMSG_APPID(skb->data);
482	contr = CAPIMSG_CONTROL(skb->data);
483
484	application = cmtp_application_get(session, CMTP_APPLID, appl);
485	if ((!application) || (application->state != BT_CONNECTED)) {
486		BT_ERR("Can't find application with id %u", appl);
487		return CAPI_ILLAPPNR;
488	}
489
490	CAPIMSG_SETAPPID(skb->data, application->mapping);
491
492	if ((contr & 0x7f) == session->num) {
493		contr = (contr & 0xffffff80) | 0x01;
494		CAPIMSG_SETCONTROL(skb->data, contr);
495	}
496
497	cmtp_send_capimsg(session, skb);
498
499	return CAPI_NOERROR;
500}
501
502static char *cmtp_procinfo(struct capi_ctr *ctrl)
503{
504	return "CAPI Message Transport Protocol";
505}
506
507static int cmtp_proc_show(struct seq_file *m, void *v)
508{
509	struct capi_ctr *ctrl = m->private;
510	struct cmtp_session *session = ctrl->driverdata;
511	struct cmtp_application *app;
 
512
513	seq_printf(m, "%s\n\n", cmtp_procinfo(ctrl));
514	seq_printf(m, "addr %s\n", session->name);
515	seq_printf(m, "ctrl %d\n", session->num);
516
517	list_for_each_entry(app, &session->applications, list) {
518		seq_printf(m, "appl %u -> %u\n", app->appl, app->mapping);
 
519	}
520
521	return 0;
522}
523
 
 
 
 
 
 
 
 
 
 
 
 
 
524int cmtp_attach_device(struct cmtp_session *session)
525{
526	unsigned char buf[4];
527	long ret;
528
529	BT_DBG("session %p", session);
530
531	capimsg_setu32(buf, 0, 0);
532
533	cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, CMTP_INITIAL_MSGNUM,
534				CAPI_FUNCTION_GET_PROFILE, buf, 4);
535
536	ret = wait_event_interruptible_timeout(session->wait,
537			session->ncontroller, CMTP_INTEROP_TIMEOUT);
538
539	BT_INFO("Found %d CAPI controller(s) on device %s", session->ncontroller, session->name);
540
541	if (!ret)
542		return -ETIMEDOUT;
543
544	if (!session->ncontroller)
545		return -ENODEV;
546
547	if (session->ncontroller > 1)
548		BT_INFO("Setting up only CAPI controller 1");
549
550	session->ctrl.owner      = THIS_MODULE;
551	session->ctrl.driverdata = session;
552	strcpy(session->ctrl.name, session->name);
553
554	session->ctrl.driver_name   = "cmtp";
555	session->ctrl.load_firmware = cmtp_load_firmware;
556	session->ctrl.reset_ctr     = cmtp_reset_ctr;
557	session->ctrl.register_appl = cmtp_register_appl;
558	session->ctrl.release_appl  = cmtp_release_appl;
559	session->ctrl.send_message  = cmtp_send_message;
560
561	session->ctrl.procinfo      = cmtp_procinfo;
562	session->ctrl.proc_show     = cmtp_proc_show;
563
564	if (attach_capi_ctr(&session->ctrl) < 0) {
565		BT_ERR("Can't attach new controller");
566		return -EBUSY;
567	}
568
569	session->num = session->ctrl.cnr;
570
571	BT_DBG("session %p num %d", session, session->num);
572
573	capimsg_setu32(buf, 0, 1);
574
575	cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
576				CAPI_FUNCTION_GET_MANUFACTURER, buf, 4);
577
578	cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
579				CAPI_FUNCTION_GET_VERSION, buf, 4);
580
581	cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
582				CAPI_FUNCTION_GET_SERIAL_NUMBER, buf, 4);
583
584	cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
585				CAPI_FUNCTION_GET_PROFILE, buf, 4);
586
587	return 0;
588}
589
590void cmtp_detach_device(struct cmtp_session *session)
591{
592	BT_DBG("session %p", session);
593
594	detach_capi_ctr(&session->ctrl);
595}
v3.1
  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 <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
 73static 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
 90static 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
100static 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
126static 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
136static 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
150static 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
186static 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			controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 10);
257
258			if (!info && ctrl) {
259				int len = min_t(uint, CAPI_MANUFACTURER_LEN,
260						skb->data[CAPI_MSG_BASELEN + 14]);
261
262				memset(ctrl->manu, 0, CAPI_MANUFACTURER_LEN);
263				strncpy(ctrl->manu,
264					skb->data + CAPI_MSG_BASELEN + 15, len);
265			}
266
267			break;
268
269		case CAPI_FUNCTION_GET_VERSION:
270			if (skb->len < CAPI_MSG_BASELEN + 32)
271				break;
272
273			controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 12);
274
275			if (!info && ctrl) {
276				ctrl->version.majorversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 16);
277				ctrl->version.minorversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 20);
278				ctrl->version.majormanuversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 24);
279				ctrl->version.minormanuversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 28);
280			}
281
282			break;
283
284		case CAPI_FUNCTION_GET_SERIAL_NUMBER:
285			if (skb->len < CAPI_MSG_BASELEN + 17)
286				break;
287
288			controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 12);
289
290			if (!info && ctrl) {
291				int len = min_t(uint, CAPI_SERIAL_LEN,
292						skb->data[CAPI_MSG_BASELEN + 16]);
293
294				memset(ctrl->serial, 0, CAPI_SERIAL_LEN);
295				strncpy(ctrl->serial,
296					skb->data + CAPI_MSG_BASELEN + 17, len);
297			}
298
299			break;
300		}
301
302		break;
303
304	case CAPI_IND:
305		if (skb->len < CAPI_MSG_BASELEN + 6)
306			break;
307
308		func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 3);
309
310		if (func == CAPI_FUNCTION_LOOPBACK) {
311			int len = min_t(uint, skb->len - CAPI_MSG_BASELEN - 6,
312						skb->data[CAPI_MSG_BASELEN + 5]);
313			appl = CAPIMSG_APPID(skb->data);
314			msgnum = CAPIMSG_MSGID(skb->data);
315			cmtp_send_interopmsg(session, CAPI_RESP, appl, msgnum, func,
316						skb->data + CAPI_MSG_BASELEN + 6, len);
317		}
318
319		break;
320	}
321
322	kfree_skb(skb);
323}
324
325void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb)
326{
327	struct capi_ctr *ctrl = &session->ctrl;
328	struct cmtp_application *application;
329	__u16 appl;
330	__u32 contr;
331
332	BT_DBG("session %p skb %p len %d", session, skb, skb->len);
333
334	if (skb->len < CAPI_MSG_BASELEN)
335		return;
336
337	if (CAPIMSG_COMMAND(skb->data) == CAPI_INTEROPERABILITY) {
338		cmtp_recv_interopmsg(session, skb);
339		return;
340	}
341
342	if (session->flags & (1 << CMTP_LOOPBACK)) {
343		kfree_skb(skb);
344		return;
345	}
346
347	appl = CAPIMSG_APPID(skb->data);
348	contr = CAPIMSG_CONTROL(skb->data);
349
350	application = cmtp_application_get(session, CMTP_MAPPING, appl);
351	if (application) {
352		appl = application->appl;
353		CAPIMSG_SETAPPID(skb->data, appl);
354	} else {
355		BT_ERR("Can't find application with id %d", appl);
356		kfree_skb(skb);
357		return;
358	}
359
360	if ((contr & 0x7f) == 0x01) {
361		contr = (contr & 0xffffff80) | session->num;
362		CAPIMSG_SETCONTROL(skb->data, contr);
363	}
364
365	if (!ctrl) {
366		BT_ERR("Can't find controller %d for message", session->num);
367		kfree_skb(skb);
368		return;
369	}
370
371	capi_ctr_handle_message(ctrl, appl, skb);
372}
373
374static int cmtp_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
375{
376	BT_DBG("ctrl %p data %p", ctrl, data);
377
378	return 0;
379}
380
381static void cmtp_reset_ctr(struct capi_ctr *ctrl)
382{
383	struct cmtp_session *session = ctrl->driverdata;
384
385	BT_DBG("ctrl %p", ctrl);
386
387	capi_ctr_down(ctrl);
388
389	atomic_inc(&session->terminate);
390	wake_up_process(session->task);
391}
392
393static void cmtp_register_appl(struct capi_ctr *ctrl, __u16 appl, capi_register_params *rp)
394{
395	DECLARE_WAITQUEUE(wait, current);
396	struct cmtp_session *session = ctrl->driverdata;
397	struct cmtp_application *application;
398	unsigned long timeo = CMTP_INTEROP_TIMEOUT;
399	unsigned char buf[8];
400	int err = 0, nconn, want = rp->level3cnt;
401
402	BT_DBG("ctrl %p appl %d level3cnt %d datablkcnt %d datablklen %d",
403		ctrl, appl, rp->level3cnt, rp->datablkcnt, rp->datablklen);
404
405	application = cmtp_application_add(session, appl);
406	if (!application) {
407		BT_ERR("Can't allocate memory for new application");
408		return;
409	}
410
411	if (want < 0)
412		nconn = ctrl->profile.nbchannel * -want;
413	else
414		nconn = want;
415
416	if (nconn == 0)
417		nconn = ctrl->profile.nbchannel;
418
419	capimsg_setu16(buf, 0, nconn);
420	capimsg_setu16(buf, 2, rp->datablkcnt);
421	capimsg_setu16(buf, 4, rp->datablklen);
422
423	application->state = BT_CONFIG;
424	application->msgnum = cmtp_msgnum_get(session);
425
426	cmtp_send_interopmsg(session, CAPI_REQ, 0x0000, application->msgnum,
427				CAPI_FUNCTION_REGISTER, buf, 6);
428
429	add_wait_queue(&session->wait, &wait);
430	while (1) {
431		set_current_state(TASK_INTERRUPTIBLE);
432
433		if (!timeo) {
434			err = -EAGAIN;
435			break;
436		}
437
438		if (application->state == BT_CLOSED) {
439			err = -application->err;
440			break;
441		}
442
443		if (application->state == BT_CONNECTED)
444			break;
445
446		if (signal_pending(current)) {
447			err = -EINTR;
448			break;
449		}
450
451		timeo = schedule_timeout(timeo);
452	}
453	set_current_state(TASK_RUNNING);
454	remove_wait_queue(&session->wait, &wait);
455
456	if (err) {
457		cmtp_application_del(session, application);
458		return;
459	}
460}
461
462static void cmtp_release_appl(struct capi_ctr *ctrl, __u16 appl)
463{
464	struct cmtp_session *session = ctrl->driverdata;
465	struct cmtp_application *application;
466
467	BT_DBG("ctrl %p appl %d", ctrl, appl);
468
469	application = cmtp_application_get(session, CMTP_APPLID, appl);
470	if (!application) {
471		BT_ERR("Can't find application");
472		return;
473	}
474
475	application->msgnum = cmtp_msgnum_get(session);
476
477	cmtp_send_interopmsg(session, CAPI_REQ, application->mapping, application->msgnum,
478				CAPI_FUNCTION_RELEASE, NULL, 0);
479
480	wait_event_interruptible_timeout(session->wait,
481			(application->state == BT_CLOSED), CMTP_INTEROP_TIMEOUT);
482
483	cmtp_application_del(session, application);
484}
485
486static u16 cmtp_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
487{
488	struct cmtp_session *session = ctrl->driverdata;
489	struct cmtp_application *application;
490	__u16 appl;
491	__u32 contr;
492
493	BT_DBG("ctrl %p skb %p", ctrl, skb);
494
495	appl = CAPIMSG_APPID(skb->data);
496	contr = CAPIMSG_CONTROL(skb->data);
497
498	application = cmtp_application_get(session, CMTP_APPLID, appl);
499	if ((!application) || (application->state != BT_CONNECTED)) {
500		BT_ERR("Can't find application with id %d", appl);
501		return CAPI_ILLAPPNR;
502	}
503
504	CAPIMSG_SETAPPID(skb->data, application->mapping);
505
506	if ((contr & 0x7f) == session->num) {
507		contr = (contr & 0xffffff80) | 0x01;
508		CAPIMSG_SETCONTROL(skb->data, contr);
509	}
510
511	cmtp_send_capimsg(session, skb);
512
513	return CAPI_NOERROR;
514}
515
516static char *cmtp_procinfo(struct capi_ctr *ctrl)
517{
518	return "CAPI Message Transport Protocol";
519}
520
521static int cmtp_proc_show(struct seq_file *m, void *v)
522{
523	struct capi_ctr *ctrl = m->private;
524	struct cmtp_session *session = ctrl->driverdata;
525	struct cmtp_application *app;
526	struct list_head *p, *n;
527
528	seq_printf(m, "%s\n\n", cmtp_procinfo(ctrl));
529	seq_printf(m, "addr %s\n", session->name);
530	seq_printf(m, "ctrl %d\n", session->num);
531
532	list_for_each_safe(p, n, &session->applications) {
533		app = list_entry(p, struct cmtp_application, list);
534		seq_printf(m, "appl %d -> %d\n", app->appl, app->mapping);
535	}
536
537	return 0;
538}
539
540static int cmtp_proc_open(struct inode *inode, struct file *file)
541{
542	return single_open(file, cmtp_proc_show, PDE(inode)->data);
543}
544
545static const struct file_operations cmtp_proc_fops = {
546	.owner		= THIS_MODULE,
547	.open		= cmtp_proc_open,
548	.read		= seq_read,
549	.llseek		= seq_lseek,
550	.release	= single_release,
551};
552
553int cmtp_attach_device(struct cmtp_session *session)
554{
555	unsigned char buf[4];
556	long ret;
557
558	BT_DBG("session %p", session);
559
560	capimsg_setu32(buf, 0, 0);
561
562	cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, CMTP_INITIAL_MSGNUM,
563				CAPI_FUNCTION_GET_PROFILE, buf, 4);
564
565	ret = wait_event_interruptible_timeout(session->wait,
566			session->ncontroller, CMTP_INTEROP_TIMEOUT);
567
568	BT_INFO("Found %d CAPI controller(s) on device %s", session->ncontroller, session->name);
569
570	if (!ret)
571		return -ETIMEDOUT;
572
573	if (!session->ncontroller)
574		return -ENODEV;
575
576	if (session->ncontroller > 1)
577		BT_INFO("Setting up only CAPI controller 1");
578
579	session->ctrl.owner      = THIS_MODULE;
580	session->ctrl.driverdata = session;
581	strcpy(session->ctrl.name, session->name);
582
583	session->ctrl.driver_name   = "cmtp";
584	session->ctrl.load_firmware = cmtp_load_firmware;
585	session->ctrl.reset_ctr     = cmtp_reset_ctr;
586	session->ctrl.register_appl = cmtp_register_appl;
587	session->ctrl.release_appl  = cmtp_release_appl;
588	session->ctrl.send_message  = cmtp_send_message;
589
590	session->ctrl.procinfo      = cmtp_procinfo;
591	session->ctrl.proc_fops = &cmtp_proc_fops;
592
593	if (attach_capi_ctr(&session->ctrl) < 0) {
594		BT_ERR("Can't attach new controller");
595		return -EBUSY;
596	}
597
598	session->num = session->ctrl.cnr;
599
600	BT_DBG("session %p num %d", session, session->num);
601
602	capimsg_setu32(buf, 0, 1);
603
604	cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
605				CAPI_FUNCTION_GET_MANUFACTURER, buf, 4);
606
607	cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
608				CAPI_FUNCTION_GET_VERSION, buf, 4);
609
610	cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
611				CAPI_FUNCTION_GET_SERIAL_NUMBER, buf, 4);
612
613	cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
614				CAPI_FUNCTION_GET_PROFILE, buf, 4);
615
616	return 0;
617}
618
619void cmtp_detach_device(struct cmtp_session *session)
620{
621	BT_DBG("session %p", session);
622
623	detach_capi_ctr(&session->ctrl);
624}