Linux 2.6.19-rc6
[cris-mirror.git] / net / bluetooth / cmtp / capi.c
blobbe04e9fb11f604639f92e447451098902a9977d6
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/module.h>
25 #include <linux/types.h>
26 #include <linux/errno.h>
27 #include <linux/kernel.h>
28 #include <linux/sched.h>
29 #include <linux/slab.h>
30 #include <linux/poll.h>
31 #include <linux/fcntl.h>
32 #include <linux/skbuff.h>
33 #include <linux/socket.h>
34 #include <linux/ioctl.h>
35 #include <linux/file.h>
36 #include <linux/wait.h>
37 #include <net/sock.h>
39 #include <linux/isdn/capilli.h>
40 #include <linux/isdn/capicmd.h>
41 #include <linux/isdn/capiutil.h>
43 #include "cmtp.h"
45 #ifndef CONFIG_BT_CMTP_DEBUG
46 #undef BT_DBG
47 #define BT_DBG(D...)
48 #endif
50 #define CAPI_INTEROPERABILITY 0x20
52 #define CAPI_INTEROPERABILITY_REQ CAPICMD(CAPI_INTEROPERABILITY, CAPI_REQ)
53 #define CAPI_INTEROPERABILITY_CONF CAPICMD(CAPI_INTEROPERABILITY, CAPI_CONF)
54 #define CAPI_INTEROPERABILITY_IND CAPICMD(CAPI_INTEROPERABILITY, CAPI_IND)
55 #define CAPI_INTEROPERABILITY_RESP CAPICMD(CAPI_INTEROPERABILITY, CAPI_RESP)
57 #define CAPI_INTEROPERABILITY_REQ_LEN (CAPI_MSG_BASELEN + 2)
58 #define CAPI_INTEROPERABILITY_CONF_LEN (CAPI_MSG_BASELEN + 4)
59 #define CAPI_INTEROPERABILITY_IND_LEN (CAPI_MSG_BASELEN + 2)
60 #define CAPI_INTEROPERABILITY_RESP_LEN (CAPI_MSG_BASELEN + 2)
62 #define CAPI_FUNCTION_REGISTER 0
63 #define CAPI_FUNCTION_RELEASE 1
64 #define CAPI_FUNCTION_GET_PROFILE 2
65 #define CAPI_FUNCTION_GET_MANUFACTURER 3
66 #define CAPI_FUNCTION_GET_VERSION 4
67 #define CAPI_FUNCTION_GET_SERIAL_NUMBER 5
68 #define CAPI_FUNCTION_MANUFACTURER 6
69 #define CAPI_FUNCTION_LOOPBACK 7
72 #define CMTP_MSGNUM 1
73 #define CMTP_APPLID 2
74 #define CMTP_MAPPING 3
76 static struct cmtp_application *cmtp_application_add(struct cmtp_session *session, __u16 appl)
78 struct cmtp_application *app = kzalloc(sizeof(*app), GFP_KERNEL);
80 BT_DBG("session %p application %p appl %d", session, app, appl);
82 if (!app)
83 return NULL;
85 app->state = BT_OPEN;
86 app->appl = appl;
88 list_add_tail(&app->list, &session->applications);
90 return app;
93 static void cmtp_application_del(struct cmtp_session *session, struct cmtp_application *app)
95 BT_DBG("session %p application %p", session, app);
97 if (app) {
98 list_del(&app->list);
99 kfree(app);
103 static struct cmtp_application *cmtp_application_get(struct cmtp_session *session, int pattern, __u16 value)
105 struct cmtp_application *app;
106 struct list_head *p, *n;
108 list_for_each_safe(p, n, &session->applications) {
109 app = list_entry(p, struct cmtp_application, list);
110 switch (pattern) {
111 case CMTP_MSGNUM:
112 if (app->msgnum == value)
113 return app;
114 break;
115 case CMTP_APPLID:
116 if (app->appl == value)
117 return app;
118 break;
119 case CMTP_MAPPING:
120 if (app->mapping == value)
121 return app;
122 break;
126 return NULL;
129 static int cmtp_msgnum_get(struct cmtp_session *session)
131 session->msgnum++;
133 if ((session->msgnum & 0xff) > 200)
134 session->msgnum = CMTP_INITIAL_MSGNUM + 1;
136 return session->msgnum;
139 static void cmtp_send_capimsg(struct cmtp_session *session, struct sk_buff *skb)
141 struct cmtp_scb *scb = (void *) skb->cb;
143 BT_DBG("session %p skb %p len %d", session, skb, skb->len);
145 scb->id = -1;
146 scb->data = (CAPIMSG_COMMAND(skb->data) == CAPI_DATA_B3);
148 skb_queue_tail(&session->transmit, skb);
150 cmtp_schedule(session);
153 static void cmtp_send_interopmsg(struct cmtp_session *session,
154 __u8 subcmd, __u16 appl, __u16 msgnum,
155 __u16 function, unsigned char *buf, int len)
157 struct sk_buff *skb;
158 unsigned char *s;
160 BT_DBG("session %p subcmd 0x%02x appl %d msgnum %d", session, subcmd, appl, msgnum);
162 if (!(skb = alloc_skb(CAPI_MSG_BASELEN + 6 + len, GFP_ATOMIC))) {
163 BT_ERR("Can't allocate memory for interoperability packet");
164 return;
167 s = skb_put(skb, CAPI_MSG_BASELEN + 6 + len);
169 capimsg_setu16(s, 0, CAPI_MSG_BASELEN + 6 + len);
170 capimsg_setu16(s, 2, appl);
171 capimsg_setu8 (s, 4, CAPI_INTEROPERABILITY);
172 capimsg_setu8 (s, 5, subcmd);
173 capimsg_setu16(s, 6, msgnum);
175 /* Interoperability selector (Bluetooth Device Management) */
176 capimsg_setu16(s, 8, 0x0001);
178 capimsg_setu8 (s, 10, 3 + len);
179 capimsg_setu16(s, 11, function);
180 capimsg_setu8 (s, 13, len);
182 if (len > 0)
183 memcpy(s + 14, buf, len);
185 cmtp_send_capimsg(session, skb);
188 static void cmtp_recv_interopmsg(struct cmtp_session *session, struct sk_buff *skb)
190 struct capi_ctr *ctrl = &session->ctrl;
191 struct cmtp_application *application;
192 __u16 appl, msgnum, func, info;
193 __u32 controller;
195 BT_DBG("session %p skb %p len %d", session, skb, skb->len);
197 switch (CAPIMSG_SUBCOMMAND(skb->data)) {
198 case CAPI_CONF:
199 func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 5);
200 info = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 8);
202 switch (func) {
203 case CAPI_FUNCTION_REGISTER:
204 msgnum = CAPIMSG_MSGID(skb->data);
206 application = cmtp_application_get(session, CMTP_MSGNUM, msgnum);
207 if (application) {
208 application->state = BT_CONNECTED;
209 application->msgnum = 0;
210 application->mapping = CAPIMSG_APPID(skb->data);
211 wake_up_interruptible(&session->wait);
214 break;
216 case CAPI_FUNCTION_RELEASE:
217 appl = CAPIMSG_APPID(skb->data);
219 application = cmtp_application_get(session, CMTP_MAPPING, appl);
220 if (application) {
221 application->state = BT_CLOSED;
222 application->msgnum = 0;
223 wake_up_interruptible(&session->wait);
226 break;
228 case CAPI_FUNCTION_GET_PROFILE:
229 controller = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 11);
230 msgnum = CAPIMSG_MSGID(skb->data);
232 if (!info && (msgnum == CMTP_INITIAL_MSGNUM)) {
233 session->ncontroller = controller;
234 wake_up_interruptible(&session->wait);
235 break;
238 if (!info && ctrl) {
239 memcpy(&ctrl->profile,
240 skb->data + CAPI_MSG_BASELEN + 11,
241 sizeof(capi_profile));
242 session->state = BT_CONNECTED;
243 capi_ctr_ready(ctrl);
246 break;
248 case CAPI_FUNCTION_GET_MANUFACTURER:
249 controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 10);
251 if (!info && ctrl) {
252 strncpy(ctrl->manu,
253 skb->data + CAPI_MSG_BASELEN + 15,
254 skb->data[CAPI_MSG_BASELEN + 14]);
257 break;
259 case CAPI_FUNCTION_GET_VERSION:
260 controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 12);
262 if (!info && ctrl) {
263 ctrl->version.majorversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 16);
264 ctrl->version.minorversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 20);
265 ctrl->version.majormanuversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 24);
266 ctrl->version.minormanuversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 28);
269 break;
271 case CAPI_FUNCTION_GET_SERIAL_NUMBER:
272 controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 12);
274 if (!info && ctrl) {
275 memset(ctrl->serial, 0, CAPI_SERIAL_LEN);
276 strncpy(ctrl->serial,
277 skb->data + CAPI_MSG_BASELEN + 17,
278 skb->data[CAPI_MSG_BASELEN + 16]);
281 break;
284 break;
286 case CAPI_IND:
287 func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 3);
289 if (func == CAPI_FUNCTION_LOOPBACK) {
290 appl = CAPIMSG_APPID(skb->data);
291 msgnum = CAPIMSG_MSGID(skb->data);
292 cmtp_send_interopmsg(session, CAPI_RESP, appl, msgnum, func,
293 skb->data + CAPI_MSG_BASELEN + 6,
294 skb->data[CAPI_MSG_BASELEN + 5]);
297 break;
300 kfree_skb(skb);
303 void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb)
305 struct capi_ctr *ctrl = &session->ctrl;
306 struct cmtp_application *application;
307 __u16 cmd, appl;
308 __u32 contr;
310 BT_DBG("session %p skb %p len %d", session, skb, skb->len);
312 if (CAPIMSG_COMMAND(skb->data) == CAPI_INTEROPERABILITY) {
313 cmtp_recv_interopmsg(session, skb);
314 return;
317 if (session->flags & (1 << CMTP_LOOPBACK)) {
318 kfree_skb(skb);
319 return;
322 cmd = CAPICMD(CAPIMSG_COMMAND(skb->data), CAPIMSG_SUBCOMMAND(skb->data));
323 appl = CAPIMSG_APPID(skb->data);
324 contr = CAPIMSG_CONTROL(skb->data);
326 application = cmtp_application_get(session, CMTP_MAPPING, appl);
327 if (application) {
328 appl = application->appl;
329 CAPIMSG_SETAPPID(skb->data, appl);
330 } else {
331 BT_ERR("Can't find application with id %d", appl);
332 kfree_skb(skb);
333 return;
336 if ((contr & 0x7f) == 0x01) {
337 contr = (contr & 0xffffff80) | session->num;
338 CAPIMSG_SETCONTROL(skb->data, contr);
341 if (!ctrl) {
342 BT_ERR("Can't find controller %d for message", session->num);
343 kfree_skb(skb);
344 return;
347 capi_ctr_handle_message(ctrl, appl, skb);
350 static int cmtp_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
352 BT_DBG("ctrl %p data %p", ctrl, data);
354 return 0;
357 static void cmtp_reset_ctr(struct capi_ctr *ctrl)
359 struct cmtp_session *session = ctrl->driverdata;
361 BT_DBG("ctrl %p", ctrl);
363 capi_ctr_reseted(ctrl);
365 atomic_inc(&session->terminate);
366 cmtp_schedule(session);
369 static void cmtp_register_appl(struct capi_ctr *ctrl, __u16 appl, capi_register_params *rp)
371 DECLARE_WAITQUEUE(wait, current);
372 struct cmtp_session *session = ctrl->driverdata;
373 struct cmtp_application *application;
374 unsigned long timeo = CMTP_INTEROP_TIMEOUT;
375 unsigned char buf[8];
376 int err = 0, nconn, want = rp->level3cnt;
378 BT_DBG("ctrl %p appl %d level3cnt %d datablkcnt %d datablklen %d",
379 ctrl, appl, rp->level3cnt, rp->datablkcnt, rp->datablklen);
381 application = cmtp_application_add(session, appl);
382 if (!application) {
383 BT_ERR("Can't allocate memory for new application");
384 return;
387 if (want < 0)
388 nconn = ctrl->profile.nbchannel * -want;
389 else
390 nconn = want;
392 if (nconn == 0)
393 nconn = ctrl->profile.nbchannel;
395 capimsg_setu16(buf, 0, nconn);
396 capimsg_setu16(buf, 2, rp->datablkcnt);
397 capimsg_setu16(buf, 4, rp->datablklen);
399 application->state = BT_CONFIG;
400 application->msgnum = cmtp_msgnum_get(session);
402 cmtp_send_interopmsg(session, CAPI_REQ, 0x0000, application->msgnum,
403 CAPI_FUNCTION_REGISTER, buf, 6);
405 add_wait_queue(&session->wait, &wait);
406 while (1) {
407 set_current_state(TASK_INTERRUPTIBLE);
409 if (!timeo) {
410 err = -EAGAIN;
411 break;
414 if (application->state == BT_CLOSED) {
415 err = -application->err;
416 break;
419 if (application->state == BT_CONNECTED)
420 break;
422 if (signal_pending(current)) {
423 err = -EINTR;
424 break;
427 timeo = schedule_timeout(timeo);
429 set_current_state(TASK_RUNNING);
430 remove_wait_queue(&session->wait, &wait);
432 if (err) {
433 cmtp_application_del(session, application);
434 return;
438 static void cmtp_release_appl(struct capi_ctr *ctrl, __u16 appl)
440 struct cmtp_session *session = ctrl->driverdata;
441 struct cmtp_application *application;
443 BT_DBG("ctrl %p appl %d", ctrl, appl);
445 application = cmtp_application_get(session, CMTP_APPLID, appl);
446 if (!application) {
447 BT_ERR("Can't find application");
448 return;
451 application->msgnum = cmtp_msgnum_get(session);
453 cmtp_send_interopmsg(session, CAPI_REQ, application->mapping, application->msgnum,
454 CAPI_FUNCTION_RELEASE, NULL, 0);
456 wait_event_interruptible_timeout(session->wait,
457 (application->state == BT_CLOSED), CMTP_INTEROP_TIMEOUT);
459 cmtp_application_del(session, application);
462 static u16 cmtp_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
464 struct cmtp_session *session = ctrl->driverdata;
465 struct cmtp_application *application;
466 __u16 appl;
467 __u32 contr;
469 BT_DBG("ctrl %p skb %p", ctrl, skb);
471 appl = CAPIMSG_APPID(skb->data);
472 contr = CAPIMSG_CONTROL(skb->data);
474 application = cmtp_application_get(session, CMTP_APPLID, appl);
475 if ((!application) || (application->state != BT_CONNECTED)) {
476 BT_ERR("Can't find application with id %d", appl);
477 return CAPI_ILLAPPNR;
480 CAPIMSG_SETAPPID(skb->data, application->mapping);
482 if ((contr & 0x7f) == session->num) {
483 contr = (contr & 0xffffff80) | 0x01;
484 CAPIMSG_SETCONTROL(skb->data, contr);
487 cmtp_send_capimsg(session, skb);
489 return CAPI_NOERROR;
492 static char *cmtp_procinfo(struct capi_ctr *ctrl)
494 return "CAPI Message Transport Protocol";
497 static int cmtp_ctr_read_proc(char *page, char **start, off_t off, int count, int *eof, struct capi_ctr *ctrl)
499 struct cmtp_session *session = ctrl->driverdata;
500 struct cmtp_application *app;
501 struct list_head *p, *n;
502 int len = 0;
504 len += sprintf(page + len, "%s\n\n", cmtp_procinfo(ctrl));
505 len += sprintf(page + len, "addr %s\n", session->name);
506 len += sprintf(page + len, "ctrl %d\n", session->num);
508 list_for_each_safe(p, n, &session->applications) {
509 app = list_entry(p, struct cmtp_application, list);
510 len += sprintf(page + len, "appl %d -> %d\n", app->appl, app->mapping);
513 if (off + count >= len)
514 *eof = 1;
516 if (len < off)
517 return 0;
519 *start = page + off;
521 return ((count < len - off) ? count : len - off);
525 int cmtp_attach_device(struct cmtp_session *session)
527 unsigned char buf[4];
528 long ret;
530 BT_DBG("session %p", session);
532 capimsg_setu32(buf, 0, 0);
534 cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, CMTP_INITIAL_MSGNUM,
535 CAPI_FUNCTION_GET_PROFILE, buf, 4);
537 ret = wait_event_interruptible_timeout(session->wait,
538 session->ncontroller, CMTP_INTEROP_TIMEOUT);
540 BT_INFO("Found %d CAPI controller(s) on device %s", session->ncontroller, session->name);
542 if (!ret)
543 return -ETIMEDOUT;
545 if (!session->ncontroller)
546 return -ENODEV;
548 if (session->ncontroller > 1)
549 BT_INFO("Setting up only CAPI controller 1");
551 session->ctrl.owner = THIS_MODULE;
552 session->ctrl.driverdata = session;
553 strcpy(session->ctrl.name, session->name);
555 session->ctrl.driver_name = "cmtp";
556 session->ctrl.load_firmware = cmtp_load_firmware;
557 session->ctrl.reset_ctr = cmtp_reset_ctr;
558 session->ctrl.register_appl = cmtp_register_appl;
559 session->ctrl.release_appl = cmtp_release_appl;
560 session->ctrl.send_message = cmtp_send_message;
562 session->ctrl.procinfo = cmtp_procinfo;
563 session->ctrl.ctr_read_proc = cmtp_ctr_read_proc;
565 if (attach_capi_ctr(&session->ctrl) < 0) {
566 BT_ERR("Can't attach new controller");
567 return -EBUSY;
570 session->num = session->ctrl.cnr;
572 BT_DBG("session %p num %d", session, session->num);
574 capimsg_setu32(buf, 0, 1);
576 cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
577 CAPI_FUNCTION_GET_MANUFACTURER, buf, 4);
579 cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
580 CAPI_FUNCTION_GET_VERSION, buf, 4);
582 cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
583 CAPI_FUNCTION_GET_SERIAL_NUMBER, buf, 4);
585 cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
586 CAPI_FUNCTION_GET_PROFILE, buf, 4);
588 return 0;
591 void cmtp_detach_device(struct cmtp_session *session)
593 BT_DBG("session %p", session);
595 detach_capi_ctr(&session->ctrl);