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