Committer: Michael Beasley <mike@snafu.setup>
[mikesnafu-overlay.git] / net / bluetooth / cmtp / capi.c
blob3e9d5bb3fefb6de364353c62684efd5b7629e9d4
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 if (skb->len < CAPI_MSG_BASELEN + 10)
200 break;
202 func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 5);
203 info = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 8);
205 switch (func) {
206 case CAPI_FUNCTION_REGISTER:
207 msgnum = CAPIMSG_MSGID(skb->data);
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);
217 break;
219 case CAPI_FUNCTION_RELEASE:
220 appl = CAPIMSG_APPID(skb->data);
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);
229 break;
231 case CAPI_FUNCTION_GET_PROFILE:
232 if (skb->len < CAPI_MSG_BASELEN + 11 + sizeof(capi_profile))
233 break;
235 controller = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 11);
236 msgnum = CAPIMSG_MSGID(skb->data);
238 if (!info && (msgnum == CMTP_INITIAL_MSGNUM)) {
239 session->ncontroller = controller;
240 wake_up_interruptible(&session->wait);
241 break;
244 if (!info && ctrl) {
245 memcpy(&ctrl->profile,
246 skb->data + CAPI_MSG_BASELEN + 11,
247 sizeof(capi_profile));
248 session->state = BT_CONNECTED;
249 capi_ctr_ready(ctrl);
252 break;
254 case CAPI_FUNCTION_GET_MANUFACTURER:
255 if (skb->len < CAPI_MSG_BASELEN + 15)
256 break;
258 controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 10);
260 if (!info && ctrl) {
261 int len = min_t(uint, CAPI_MANUFACTURER_LEN,
262 skb->data[CAPI_MSG_BASELEN + 14]);
264 memset(ctrl->manu, 0, CAPI_MANUFACTURER_LEN);
265 strncpy(ctrl->manu,
266 skb->data + CAPI_MSG_BASELEN + 15, len);
269 break;
271 case CAPI_FUNCTION_GET_VERSION:
272 if (skb->len < CAPI_MSG_BASELEN + 32)
273 break;
275 controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 12);
277 if (!info && ctrl) {
278 ctrl->version.majorversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 16);
279 ctrl->version.minorversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 20);
280 ctrl->version.majormanuversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 24);
281 ctrl->version.minormanuversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 28);
284 break;
286 case CAPI_FUNCTION_GET_SERIAL_NUMBER:
287 if (skb->len < CAPI_MSG_BASELEN + 17)
288 break;
290 controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 12);
292 if (!info && ctrl) {
293 int len = min_t(uint, CAPI_SERIAL_LEN,
294 skb->data[CAPI_MSG_BASELEN + 16]);
296 memset(ctrl->serial, 0, CAPI_SERIAL_LEN);
297 strncpy(ctrl->serial,
298 skb->data + CAPI_MSG_BASELEN + 17, len);
301 break;
304 break;
306 case CAPI_IND:
307 if (skb->len < CAPI_MSG_BASELEN + 6)
308 break;
310 func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 3);
312 if (func == CAPI_FUNCTION_LOOPBACK) {
313 int len = min_t(uint, skb->len - CAPI_MSG_BASELEN - 6,
314 skb->data[CAPI_MSG_BASELEN + 5]);
315 appl = CAPIMSG_APPID(skb->data);
316 msgnum = CAPIMSG_MSGID(skb->data);
317 cmtp_send_interopmsg(session, CAPI_RESP, appl, msgnum, func,
318 skb->data + CAPI_MSG_BASELEN + 6, len);
321 break;
324 kfree_skb(skb);
327 void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb)
329 struct capi_ctr *ctrl = &session->ctrl;
330 struct cmtp_application *application;
331 __u16 cmd, appl;
332 __u32 contr;
334 BT_DBG("session %p skb %p len %d", session, skb, skb->len);
336 if (skb->len < CAPI_MSG_BASELEN)
337 return;
339 if (CAPIMSG_COMMAND(skb->data) == CAPI_INTEROPERABILITY) {
340 cmtp_recv_interopmsg(session, skb);
341 return;
344 if (session->flags & (1 << CMTP_LOOPBACK)) {
345 kfree_skb(skb);
346 return;
349 cmd = CAPICMD(CAPIMSG_COMMAND(skb->data), CAPIMSG_SUBCOMMAND(skb->data));
350 appl = CAPIMSG_APPID(skb->data);
351 contr = CAPIMSG_CONTROL(skb->data);
353 application = cmtp_application_get(session, CMTP_MAPPING, appl);
354 if (application) {
355 appl = application->appl;
356 CAPIMSG_SETAPPID(skb->data, appl);
357 } else {
358 BT_ERR("Can't find application with id %d", appl);
359 kfree_skb(skb);
360 return;
363 if ((contr & 0x7f) == 0x01) {
364 contr = (contr & 0xffffff80) | session->num;
365 CAPIMSG_SETCONTROL(skb->data, contr);
368 if (!ctrl) {
369 BT_ERR("Can't find controller %d for message", session->num);
370 kfree_skb(skb);
371 return;
374 capi_ctr_handle_message(ctrl, appl, skb);
377 static int cmtp_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
379 BT_DBG("ctrl %p data %p", ctrl, data);
381 return 0;
384 static void cmtp_reset_ctr(struct capi_ctr *ctrl)
386 struct cmtp_session *session = ctrl->driverdata;
388 BT_DBG("ctrl %p", ctrl);
390 capi_ctr_reseted(ctrl);
392 atomic_inc(&session->terminate);
393 cmtp_schedule(session);
396 static void cmtp_register_appl(struct capi_ctr *ctrl, __u16 appl, capi_register_params *rp)
398 DECLARE_WAITQUEUE(wait, current);
399 struct cmtp_session *session = ctrl->driverdata;
400 struct cmtp_application *application;
401 unsigned long timeo = CMTP_INTEROP_TIMEOUT;
402 unsigned char buf[8];
403 int err = 0, nconn, want = rp->level3cnt;
405 BT_DBG("ctrl %p appl %d level3cnt %d datablkcnt %d datablklen %d",
406 ctrl, appl, rp->level3cnt, rp->datablkcnt, rp->datablklen);
408 application = cmtp_application_add(session, appl);
409 if (!application) {
410 BT_ERR("Can't allocate memory for new application");
411 return;
414 if (want < 0)
415 nconn = ctrl->profile.nbchannel * -want;
416 else
417 nconn = want;
419 if (nconn == 0)
420 nconn = ctrl->profile.nbchannel;
422 capimsg_setu16(buf, 0, nconn);
423 capimsg_setu16(buf, 2, rp->datablkcnt);
424 capimsg_setu16(buf, 4, rp->datablklen);
426 application->state = BT_CONFIG;
427 application->msgnum = cmtp_msgnum_get(session);
429 cmtp_send_interopmsg(session, CAPI_REQ, 0x0000, application->msgnum,
430 CAPI_FUNCTION_REGISTER, buf, 6);
432 add_wait_queue(&session->wait, &wait);
433 while (1) {
434 set_current_state(TASK_INTERRUPTIBLE);
436 if (!timeo) {
437 err = -EAGAIN;
438 break;
441 if (application->state == BT_CLOSED) {
442 err = -application->err;
443 break;
446 if (application->state == BT_CONNECTED)
447 break;
449 if (signal_pending(current)) {
450 err = -EINTR;
451 break;
454 timeo = schedule_timeout(timeo);
456 set_current_state(TASK_RUNNING);
457 remove_wait_queue(&session->wait, &wait);
459 if (err) {
460 cmtp_application_del(session, application);
461 return;
465 static void cmtp_release_appl(struct capi_ctr *ctrl, __u16 appl)
467 struct cmtp_session *session = ctrl->driverdata;
468 struct cmtp_application *application;
470 BT_DBG("ctrl %p appl %d", ctrl, appl);
472 application = cmtp_application_get(session, CMTP_APPLID, appl);
473 if (!application) {
474 BT_ERR("Can't find application");
475 return;
478 application->msgnum = cmtp_msgnum_get(session);
480 cmtp_send_interopmsg(session, CAPI_REQ, application->mapping, application->msgnum,
481 CAPI_FUNCTION_RELEASE, NULL, 0);
483 wait_event_interruptible_timeout(session->wait,
484 (application->state == BT_CLOSED), CMTP_INTEROP_TIMEOUT);
486 cmtp_application_del(session, application);
489 static u16 cmtp_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
491 struct cmtp_session *session = ctrl->driverdata;
492 struct cmtp_application *application;
493 __u16 appl;
494 __u32 contr;
496 BT_DBG("ctrl %p skb %p", ctrl, skb);
498 appl = CAPIMSG_APPID(skb->data);
499 contr = CAPIMSG_CONTROL(skb->data);
501 application = cmtp_application_get(session, CMTP_APPLID, appl);
502 if ((!application) || (application->state != BT_CONNECTED)) {
503 BT_ERR("Can't find application with id %d", appl);
504 return CAPI_ILLAPPNR;
507 CAPIMSG_SETAPPID(skb->data, application->mapping);
509 if ((contr & 0x7f) == session->num) {
510 contr = (contr & 0xffffff80) | 0x01;
511 CAPIMSG_SETCONTROL(skb->data, contr);
514 cmtp_send_capimsg(session, skb);
516 return CAPI_NOERROR;
519 static char *cmtp_procinfo(struct capi_ctr *ctrl)
521 return "CAPI Message Transport Protocol";
524 static int cmtp_ctr_read_proc(char *page, char **start, off_t off, int count, int *eof, struct capi_ctr *ctrl)
526 struct cmtp_session *session = ctrl->driverdata;
527 struct cmtp_application *app;
528 struct list_head *p, *n;
529 int len = 0;
531 len += sprintf(page + len, "%s\n\n", cmtp_procinfo(ctrl));
532 len += sprintf(page + len, "addr %s\n", session->name);
533 len += sprintf(page + len, "ctrl %d\n", session->num);
535 list_for_each_safe(p, n, &session->applications) {
536 app = list_entry(p, struct cmtp_application, list);
537 len += sprintf(page + len, "appl %d -> %d\n", app->appl, app->mapping);
540 if (off + count >= len)
541 *eof = 1;
543 if (len < off)
544 return 0;
546 *start = page + off;
548 return ((count < len - off) ? count : len - off);
552 int cmtp_attach_device(struct cmtp_session *session)
554 unsigned char buf[4];
555 long ret;
557 BT_DBG("session %p", session);
559 capimsg_setu32(buf, 0, 0);
561 cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, CMTP_INITIAL_MSGNUM,
562 CAPI_FUNCTION_GET_PROFILE, buf, 4);
564 ret = wait_event_interruptible_timeout(session->wait,
565 session->ncontroller, CMTP_INTEROP_TIMEOUT);
567 BT_INFO("Found %d CAPI controller(s) on device %s", session->ncontroller, session->name);
569 if (!ret)
570 return -ETIMEDOUT;
572 if (!session->ncontroller)
573 return -ENODEV;
575 if (session->ncontroller > 1)
576 BT_INFO("Setting up only CAPI controller 1");
578 session->ctrl.owner = THIS_MODULE;
579 session->ctrl.driverdata = session;
580 strcpy(session->ctrl.name, session->name);
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;
589 session->ctrl.procinfo = cmtp_procinfo;
590 session->ctrl.ctr_read_proc = cmtp_ctr_read_proc;
592 if (attach_capi_ctr(&session->ctrl) < 0) {
593 BT_ERR("Can't attach new controller");
594 return -EBUSY;
597 session->num = session->ctrl.cnr;
599 BT_DBG("session %p num %d", session, session->num);
601 capimsg_setu32(buf, 0, 1);
603 cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
604 CAPI_FUNCTION_GET_MANUFACTURER, buf, 4);
606 cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
607 CAPI_FUNCTION_GET_VERSION, buf, 4);
609 cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
610 CAPI_FUNCTION_GET_SERIAL_NUMBER, buf, 4);
612 cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
613 CAPI_FUNCTION_GET_PROFILE, buf, 4);
615 return 0;
618 void cmtp_detach_device(struct cmtp_session *session)
620 BT_DBG("session %p", session);
622 detach_capi_ctr(&session->ctrl);