initial commit with v2.6.9
[linux-2.6.9-moxart.git] / net / bluetooth / cmtp / capi.c
blob7e03820c2bfbc8f05994cdc576eaf9e6dd76bf91
1 /*
2 CMTP implementation for Linux Bluetooth stack (BlueZ).
3 Copyright (C) 2002-2003 Marcel Holtmann <marcel@holtmann.org>
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;
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.
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.
23 #include <linux/config.h>
24 #include <linux/module.h>
26 #include <linux/types.h>
27 #include <linux/errno.h>
28 #include <linux/kernel.h>
29 #include <linux/major.h>
30 #include <linux/sched.h>
31 #include <linux/slab.h>
32 #include <linux/poll.h>
33 #include <linux/fcntl.h>
34 #include <linux/skbuff.h>
35 #include <linux/socket.h>
36 #include <linux/ioctl.h>
37 #include <linux/file.h>
38 #include <net/sock.h>
40 #include <linux/isdn/capilli.h>
41 #include <linux/isdn/capicmd.h>
42 #include <linux/isdn/capiutil.h>
44 #include "cmtp.h"
46 #ifndef CONFIG_BT_CMTP_DEBUG
47 #undef BT_DBG
48 #define BT_DBG(D...)
49 #endif
51 #define CAPI_INTEROPERABILITY 0x20
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)
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)
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
73 #define CMTP_MSGNUM 1
74 #define CMTP_APPLID 2
75 #define CMTP_MAPPING 3
77 static struct cmtp_application *cmtp_application_add(struct cmtp_session *session, __u16 appl)
79 struct cmtp_application *app = kmalloc(sizeof(*app), GFP_KERNEL);
81 BT_DBG("session %p application %p appl %d", session, app, appl);
83 if (!app)
84 return NULL;
86 memset(app, 0, sizeof(*app));
88 app->state = BT_OPEN;
89 app->appl = appl;
91 list_add_tail(&app->list, &session->applications);
93 return app;
96 static void cmtp_application_del(struct cmtp_session *session, struct cmtp_application *app)
98 BT_DBG("session %p application %p", session, app);
100 if (app) {
101 list_del(&app->list);
102 kfree(app);
106 static struct cmtp_application *cmtp_application_get(struct cmtp_session *session, int pattern, __u16 value)
108 struct cmtp_application *app;
109 struct list_head *p, *n;
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;
129 return NULL;
132 static int cmtp_msgnum_get(struct cmtp_session *session)
134 session->msgnum++;
136 if ((session->msgnum & 0xff) > 200)
137 session->msgnum = CMTP_INITIAL_MSGNUM + 1;
139 return session->msgnum;
143 static void cmtp_send_interopmsg(struct cmtp_session *session,
144 __u8 subcmd, __u16 appl, __u16 msgnum,
145 __u16 function, unsigned char *buf, int len)
147 struct sk_buff *skb;
148 unsigned char *s;
150 BT_DBG("session %p subcmd 0x%02x appl %d msgnum %d", session, subcmd, appl, msgnum);
152 if (!(skb = alloc_skb(CAPI_MSG_BASELEN + 6 + len, GFP_ATOMIC))) {
153 BT_ERR("Can't allocate memory for interoperability packet");
154 return;
157 s = skb_put(skb, CAPI_MSG_BASELEN + 6 + len);
159 capimsg_setu16(s, 0, CAPI_MSG_BASELEN + 6 + len);
160 capimsg_setu16(s, 2, appl);
161 capimsg_setu8 (s, 4, CAPI_INTEROPERABILITY);
162 capimsg_setu8 (s, 5, subcmd);
163 capimsg_setu16(s, 6, msgnum);
165 /* Interoperability selector (Bluetooth Device Management) */
166 capimsg_setu16(s, 8, 0x0001);
168 capimsg_setu8 (s, 10, 3 + len);
169 capimsg_setu16(s, 11, function);
170 capimsg_setu8 (s, 13, len);
172 if (len > 0)
173 memcpy(s + 14, buf, len);
175 cmtp_send_capimsg(session, skb);
178 static void cmtp_recv_interopmsg(struct cmtp_session *session, struct sk_buff *skb)
180 struct capi_ctr *ctrl = &session->ctrl;
181 struct cmtp_application *application;
182 __u16 appl, msgnum, func, info;
183 __u32 controller;
185 BT_DBG("session %p skb %p len %d", session, skb, skb->len);
187 switch (CAPIMSG_SUBCOMMAND(skb->data)) {
188 case CAPI_CONF:
189 func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 5);
190 info = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 8);
192 switch (func) {
193 case CAPI_FUNCTION_REGISTER:
194 msgnum = CAPIMSG_MSGID(skb->data);
196 application = cmtp_application_get(session, CMTP_MSGNUM, msgnum);
197 if (application) {
198 application->state = BT_CONNECTED;
199 application->msgnum = 0;
200 application->mapping = CAPIMSG_APPID(skb->data);
201 wake_up_interruptible(&session->wait);
204 break;
206 case CAPI_FUNCTION_RELEASE:
207 appl = CAPIMSG_APPID(skb->data);
209 application = cmtp_application_get(session, CMTP_MAPPING, appl);
210 if (application) {
211 application->state = BT_CLOSED;
212 application->msgnum = 0;
213 wake_up_interruptible(&session->wait);
216 break;
218 case CAPI_FUNCTION_GET_PROFILE:
219 controller = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 11);
220 msgnum = CAPIMSG_MSGID(skb->data);
222 if (!info && (msgnum == CMTP_INITIAL_MSGNUM)) {
223 session->ncontroller = controller;
224 wake_up_interruptible(&session->wait);
225 break;
228 if (!info && ctrl) {
229 memcpy(&ctrl->profile,
230 skb->data + CAPI_MSG_BASELEN + 11,
231 sizeof(capi_profile));
232 session->state = BT_CONNECTED;
233 capi_ctr_ready(ctrl);
236 break;
238 case CAPI_FUNCTION_GET_MANUFACTURER:
239 controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 10);
241 if (!info && ctrl) {
242 strncpy(ctrl->manu,
243 skb->data + CAPI_MSG_BASELEN + 15,
244 skb->data[CAPI_MSG_BASELEN + 14]);
247 break;
249 case CAPI_FUNCTION_GET_VERSION:
250 controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 12);
252 if (!info && ctrl) {
253 ctrl->version.majorversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 16);
254 ctrl->version.minorversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 20);
255 ctrl->version.majormanuversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 24);
256 ctrl->version.minormanuversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 28);
259 break;
261 case CAPI_FUNCTION_GET_SERIAL_NUMBER:
262 controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 12);
264 if (!info && ctrl) {
265 memset(ctrl->serial, 0, CAPI_SERIAL_LEN);
266 strncpy(ctrl->serial,
267 skb->data + CAPI_MSG_BASELEN + 17,
268 skb->data[CAPI_MSG_BASELEN + 16]);
271 break;
274 break;
276 case CAPI_IND:
277 func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 3);
279 if (func == CAPI_FUNCTION_LOOPBACK) {
280 appl = CAPIMSG_APPID(skb->data);
281 msgnum = CAPIMSG_MSGID(skb->data);
282 cmtp_send_interopmsg(session, CAPI_RESP, appl, msgnum, func,
283 skb->data + CAPI_MSG_BASELEN + 6,
284 skb->data[CAPI_MSG_BASELEN + 5]);
287 break;
290 kfree_skb(skb);
293 void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb)
295 struct capi_ctr *ctrl = &session->ctrl;
296 struct cmtp_application *application;
297 __u16 cmd, appl;
298 __u32 contr;
300 BT_DBG("session %p skb %p len %d", session, skb, skb->len);
302 if (CAPIMSG_COMMAND(skb->data) == CAPI_INTEROPERABILITY) {
303 cmtp_recv_interopmsg(session, skb);
304 return;
307 if (session->flags & (1 << CMTP_LOOPBACK)) {
308 kfree_skb(skb);
309 return;
312 cmd = CAPICMD(CAPIMSG_COMMAND(skb->data), CAPIMSG_SUBCOMMAND(skb->data));
313 appl = CAPIMSG_APPID(skb->data);
314 contr = CAPIMSG_CONTROL(skb->data);
316 application = cmtp_application_get(session, CMTP_MAPPING, appl);
317 if (application) {
318 appl = application->appl;
319 CAPIMSG_SETAPPID(skb->data, appl);
320 } else {
321 BT_ERR("Can't find application with id %d", appl);
322 kfree_skb(skb);
323 return;
326 if ((contr & 0x7f) == 0x01) {
327 contr = (contr & 0xffffff80) | session->num;
328 CAPIMSG_SETCONTROL(skb->data, contr);
331 if (!ctrl) {
332 BT_ERR("Can't find controller %d for message", session->num);
333 kfree_skb(skb);
334 return;
337 capi_ctr_handle_message(ctrl, appl, skb);
340 void cmtp_send_capimsg(struct cmtp_session *session, struct sk_buff *skb)
342 struct cmtp_scb *scb = (void *) skb->cb;
344 BT_DBG("session %p skb %p len %d", session, skb, skb->len);
346 scb->id = -1;
347 scb->data = (CAPIMSG_COMMAND(skb->data) == CAPI_DATA_B3);
349 skb_queue_tail(&session->transmit, skb);
351 cmtp_schedule(session);
355 static int cmtp_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
357 BT_DBG("ctrl %p data %p", ctrl, data);
359 return 0;
362 static void cmtp_reset_ctr(struct capi_ctr *ctrl)
364 struct cmtp_session *session = ctrl->driverdata;
366 BT_DBG("ctrl %p", ctrl);
368 capi_ctr_reseted(ctrl);
370 atomic_inc(&session->terminate);
371 cmtp_schedule(session);
374 static void cmtp_register_appl(struct capi_ctr *ctrl, __u16 appl, capi_register_params *rp)
376 DECLARE_WAITQUEUE(wait, current);
377 struct cmtp_session *session = ctrl->driverdata;
378 struct cmtp_application *application;
379 unsigned long timeo = CMTP_INTEROP_TIMEOUT;
380 unsigned char buf[8];
381 int err = 0, nconn, want = rp->level3cnt;
383 BT_DBG("ctrl %p appl %d level3cnt %d datablkcnt %d datablklen %d",
384 ctrl, appl, rp->level3cnt, rp->datablkcnt, rp->datablklen);
386 application = cmtp_application_add(session, appl);
387 if (!application) {
388 BT_ERR("Can't allocate memory for new application");
389 return;
392 if (want < 0)
393 nconn = ctrl->profile.nbchannel * -want;
394 else
395 nconn = want;
397 if (nconn == 0)
398 nconn = ctrl->profile.nbchannel;
400 capimsg_setu16(buf, 0, nconn);
401 capimsg_setu16(buf, 2, rp->datablkcnt);
402 capimsg_setu16(buf, 4, rp->datablklen);
404 application->state = BT_CONFIG;
405 application->msgnum = cmtp_msgnum_get(session);
407 cmtp_send_interopmsg(session, CAPI_REQ, 0x0000, application->msgnum,
408 CAPI_FUNCTION_REGISTER, buf, 6);
410 add_wait_queue(&session->wait, &wait);
411 while (1) {
412 set_current_state(TASK_INTERRUPTIBLE);
414 if (!timeo) {
415 err = -EAGAIN;
416 break;
419 if (application->state == BT_CLOSED) {
420 err = -application->err;
421 break;
424 if (application->state == BT_CONNECTED)
425 break;
427 if (signal_pending(current)) {
428 err = -EINTR;
429 break;
432 timeo = schedule_timeout(timeo);
434 set_current_state(TASK_RUNNING);
435 remove_wait_queue(&session->wait, &wait);
437 if (err) {
438 cmtp_application_del(session, application);
439 return;
443 static void cmtp_release_appl(struct capi_ctr *ctrl, __u16 appl)
445 DECLARE_WAITQUEUE(wait, current);
446 struct cmtp_session *session = ctrl->driverdata;
447 struct cmtp_application *application;
448 unsigned long timeo = CMTP_INTEROP_TIMEOUT;
450 BT_DBG("ctrl %p appl %d", ctrl, appl);
452 application = cmtp_application_get(session, CMTP_APPLID, appl);
453 if (!application) {
454 BT_ERR("Can't find application");
455 return;
458 application->msgnum = cmtp_msgnum_get(session);
460 cmtp_send_interopmsg(session, CAPI_REQ, application->mapping, application->msgnum,
461 CAPI_FUNCTION_RELEASE, NULL, 0);
463 add_wait_queue(&session->wait, &wait);
464 while (timeo) {
465 set_current_state(TASK_INTERRUPTIBLE);
467 if (application->state == BT_CLOSED)
468 break;
470 if (signal_pending(current))
471 break;
473 timeo = schedule_timeout(timeo);
475 set_current_state(TASK_RUNNING);
476 remove_wait_queue(&session->wait, &wait);
478 cmtp_application_del(session, application);
481 static u16 cmtp_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
483 struct cmtp_session *session = ctrl->driverdata;
484 struct cmtp_application *application;
485 __u16 appl;
486 __u32 contr;
488 BT_DBG("ctrl %p skb %p", ctrl, skb);
490 appl = CAPIMSG_APPID(skb->data);
491 contr = CAPIMSG_CONTROL(skb->data);
493 application = cmtp_application_get(session, CMTP_APPLID, appl);
494 if ((!application) || (application->state != BT_CONNECTED)) {
495 BT_ERR("Can't find application with id %d", appl);
496 kfree_skb(skb);
497 return CAPI_ILLAPPNR;
500 CAPIMSG_SETAPPID(skb->data, application->mapping);
502 if ((contr & 0x7f) == session->num) {
503 contr = (contr & 0xffffff80) | 0x01;
504 CAPIMSG_SETCONTROL(skb->data, contr);
507 cmtp_send_capimsg(session, skb);
509 return CAPI_NOERROR;
512 static char *cmtp_procinfo(struct capi_ctr *ctrl)
514 return "CAPI Message Transport Protocol";
517 static int cmtp_ctr_read_proc(char *page, char **start, off_t off, int count, int *eof, struct capi_ctr *ctrl)
519 struct cmtp_session *session = ctrl->driverdata;
520 struct cmtp_application *app;
521 struct list_head *p, *n;
522 int len = 0;
524 len += sprintf(page + len, "%s\n\n", cmtp_procinfo(ctrl));
525 len += sprintf(page + len, "addr %s\n", session->name);
526 len += sprintf(page + len, "ctrl %d\n", session->num);
528 list_for_each_safe(p, n, &session->applications) {
529 app = list_entry(p, struct cmtp_application, list);
530 len += sprintf(page + len, "appl %d -> %d\n", app->appl, app->mapping);
533 if (off + count >= len)
534 *eof = 1;
536 if (len < off)
537 return 0;
539 *start = page + off;
541 return ((count < len - off) ? count : len - off);
545 int cmtp_attach_device(struct cmtp_session *session)
547 DECLARE_WAITQUEUE(wait, current);
548 unsigned long timeo = CMTP_INTEROP_TIMEOUT;
549 unsigned char buf[4];
551 BT_DBG("session %p", session);
553 capimsg_setu32(buf, 0, 0);
555 cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, CMTP_INITIAL_MSGNUM,
556 CAPI_FUNCTION_GET_PROFILE, buf, 4);
558 add_wait_queue(&session->wait, &wait);
559 while (timeo) {
560 set_current_state(TASK_INTERRUPTIBLE);
562 if (session->ncontroller)
563 break;
565 if (signal_pending(current))
566 break;
568 timeo = schedule_timeout(timeo);
570 set_current_state(TASK_RUNNING);
571 remove_wait_queue(&session->wait, &wait);
573 BT_INFO("Found %d CAPI controller(s) on device %s", session->ncontroller, session->name);
575 if (!timeo)
576 return -ETIMEDOUT;
578 if (!session->ncontroller)
579 return -ENODEV;
582 if (session->ncontroller > 1)
583 BT_INFO("Setting up only CAPI controller 1");
585 session->ctrl.owner = THIS_MODULE;
586 session->ctrl.driverdata = session;
587 strcpy(session->ctrl.name, session->name);
589 session->ctrl.driver_name = "cmtp";
590 session->ctrl.load_firmware = cmtp_load_firmware;
591 session->ctrl.reset_ctr = cmtp_reset_ctr;
592 session->ctrl.register_appl = cmtp_register_appl;
593 session->ctrl.release_appl = cmtp_release_appl;
594 session->ctrl.send_message = cmtp_send_message;
596 session->ctrl.procinfo = cmtp_procinfo;
597 session->ctrl.ctr_read_proc = cmtp_ctr_read_proc;
599 if (attach_capi_ctr(&session->ctrl) < 0) {
600 BT_ERR("Can't attach new controller");
601 return -EBUSY;
604 session->num = session->ctrl.cnr;
606 BT_DBG("session %p num %d", session, session->num);
608 capimsg_setu32(buf, 0, 1);
610 cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
611 CAPI_FUNCTION_GET_MANUFACTURER, buf, 4);
613 cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
614 CAPI_FUNCTION_GET_VERSION, buf, 4);
616 cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
617 CAPI_FUNCTION_GET_SERIAL_NUMBER, buf, 4);
619 cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
620 CAPI_FUNCTION_GET_PROFILE, buf, 4);
622 return 0;
625 void cmtp_detach_device(struct cmtp_session *session)
627 BT_DBG("session %p", session);
629 detach_capi_ctr(&session->ctrl);