Merge branch 'linux_next' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab...
[linux-2.6-block.git] / net / bluetooth / cmtp / capi.c
CommitLineData
8e87d142 1/*
1da177e4
LT
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
8e87d142
YH
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
1da177e4
LT
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
8e87d142
YH
18 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
19 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
1da177e4
LT
20 SOFTWARE IS DISCLAIMED.
21*/
22
2ad8f54b 23#include <linux/export.h>
9a58a80a
AD
24#include <linux/proc_fs.h>
25#include <linux/seq_file.h>
1da177e4
LT
26#include <linux/types.h>
27#include <linux/errno.h>
28#include <linux/kernel.h>
1da177e4
LT
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>
fada4ac3 38#include <linux/kthread.h>
1da177e4
LT
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
1da177e4
LT
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{
25ea6db0 75 struct cmtp_application *app = kzalloc(sizeof(*app), GFP_KERNEL);
1da177e4
LT
76
77 BT_DBG("session %p application %p appl %d", session, app, appl);
78
79 if (!app)
80 return NULL;
81
1da177e4
LT
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
fada4ac3 147 wake_up_interruptible(sk_sleep(session->sock->sk));
1da177e4
LT
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
5a08ecce
AE
159 skb = alloc_skb(CAPI_MSG_BASELEN + 6 + len, GFP_ATOMIC);
160 if (!skb) {
1da177e4
LT
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:
f4777569
MH
197 if (skb->len < CAPI_MSG_BASELEN + 10)
198 break;
199
1da177e4
LT
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:
f4777569
MH
230 if (skb->len < CAPI_MSG_BASELEN + 11 + sizeof(capi_profile))
231 break;
232
1da177e4
LT
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:
f4777569
MH
253 if (skb->len < CAPI_MSG_BASELEN + 15)
254 break;
255
1da177e4
LT
256 controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 10);
257
258 if (!info && ctrl) {
f4777569
MH
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);
1da177e4 263 strncpy(ctrl->manu,
f4777569 264 skb->data + CAPI_MSG_BASELEN + 15, len);
1da177e4
LT
265 }
266
267 break;
268
269 case CAPI_FUNCTION_GET_VERSION:
f4777569
MH
270 if (skb->len < CAPI_MSG_BASELEN + 32)
271 break;
272
1da177e4
LT
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:
f4777569
MH
285 if (skb->len < CAPI_MSG_BASELEN + 17)
286 break;
287
1da177e4
LT
288 controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 12);
289
290 if (!info && ctrl) {
f4777569
MH
291 int len = min_t(uint, CAPI_SERIAL_LEN,
292 skb->data[CAPI_MSG_BASELEN + 16]);
293
1da177e4
LT
294 memset(ctrl->serial, 0, CAPI_SERIAL_LEN);
295 strncpy(ctrl->serial,
f4777569 296 skb->data + CAPI_MSG_BASELEN + 17, len);
1da177e4
LT
297 }
298
299 break;
300 }
301
302 break;
303
304 case CAPI_IND:
f4777569
MH
305 if (skb->len < CAPI_MSG_BASELEN + 6)
306 break;
307
1da177e4
LT
308 func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 3);
309
310 if (func == CAPI_FUNCTION_LOOPBACK) {
f4777569
MH
311 int len = min_t(uint, skb->len - CAPI_MSG_BASELEN - 6,
312 skb->data[CAPI_MSG_BASELEN + 5]);
1da177e4
LT
313 appl = CAPIMSG_APPID(skb->data);
314 msgnum = CAPIMSG_MSGID(skb->data);
315 cmtp_send_interopmsg(session, CAPI_RESP, appl, msgnum, func,
f4777569 316 skb->data + CAPI_MSG_BASELEN + 6, len);
1da177e4
LT
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;
d29d04ce 329 __u16 appl;
1da177e4
LT
330 __u32 contr;
331
332 BT_DBG("session %p skb %p len %d", session, skb, skb->len);
333
f4777569
MH
334 if (skb->len < CAPI_MSG_BASELEN)
335 return;
336
1da177e4
LT
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
1da177e4
LT
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
1da177e4
LT
365 capi_ctr_handle_message(ctrl, appl, skb);
366}
367
368static int cmtp_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
369{
370 BT_DBG("ctrl %p data %p", ctrl, data);
371
372 return 0;
373}
374
375static void cmtp_reset_ctr(struct capi_ctr *ctrl)
376{
377 struct cmtp_session *session = ctrl->driverdata;
378
379 BT_DBG("ctrl %p", ctrl);
380
4e329972 381 capi_ctr_down(ctrl);
1da177e4 382
7176522c
PH
383 atomic_inc(&session->terminate);
384 wake_up_process(session->task);
1da177e4
LT
385}
386
387static void cmtp_register_appl(struct capi_ctr *ctrl, __u16 appl, capi_register_params *rp)
388{
389 DECLARE_WAITQUEUE(wait, current);
390 struct cmtp_session *session = ctrl->driverdata;
391 struct cmtp_application *application;
392 unsigned long timeo = CMTP_INTEROP_TIMEOUT;
393 unsigned char buf[8];
394 int err = 0, nconn, want = rp->level3cnt;
395
396 BT_DBG("ctrl %p appl %d level3cnt %d datablkcnt %d datablklen %d",
397 ctrl, appl, rp->level3cnt, rp->datablkcnt, rp->datablklen);
398
399 application = cmtp_application_add(session, appl);
400 if (!application) {
401 BT_ERR("Can't allocate memory for new application");
402 return;
403 }
404
405 if (want < 0)
406 nconn = ctrl->profile.nbchannel * -want;
407 else
408 nconn = want;
409
410 if (nconn == 0)
411 nconn = ctrl->profile.nbchannel;
412
413 capimsg_setu16(buf, 0, nconn);
414 capimsg_setu16(buf, 2, rp->datablkcnt);
415 capimsg_setu16(buf, 4, rp->datablklen);
416
417 application->state = BT_CONFIG;
418 application->msgnum = cmtp_msgnum_get(session);
419
420 cmtp_send_interopmsg(session, CAPI_REQ, 0x0000, application->msgnum,
421 CAPI_FUNCTION_REGISTER, buf, 6);
422
423 add_wait_queue(&session->wait, &wait);
424 while (1) {
425 set_current_state(TASK_INTERRUPTIBLE);
426
427 if (!timeo) {
428 err = -EAGAIN;
429 break;
430 }
431
432 if (application->state == BT_CLOSED) {
433 err = -application->err;
434 break;
435 }
436
437 if (application->state == BT_CONNECTED)
438 break;
439
440 if (signal_pending(current)) {
441 err = -EINTR;
442 break;
443 }
444
445 timeo = schedule_timeout(timeo);
446 }
447 set_current_state(TASK_RUNNING);
448 remove_wait_queue(&session->wait, &wait);
449
450 if (err) {
451 cmtp_application_del(session, application);
452 return;
453 }
454}
455
456static void cmtp_release_appl(struct capi_ctr *ctrl, __u16 appl)
457{
458 struct cmtp_session *session = ctrl->driverdata;
459 struct cmtp_application *application;
460
461 BT_DBG("ctrl %p appl %d", ctrl, appl);
462
463 application = cmtp_application_get(session, CMTP_APPLID, appl);
464 if (!application) {
465 BT_ERR("Can't find application");
466 return;
467 }
468
469 application->msgnum = cmtp_msgnum_get(session);
470
471 cmtp_send_interopmsg(session, CAPI_REQ, application->mapping, application->msgnum,
472 CAPI_FUNCTION_RELEASE, NULL, 0);
473
474 wait_event_interruptible_timeout(session->wait,
475 (application->state == BT_CLOSED), CMTP_INTEROP_TIMEOUT);
476
477 cmtp_application_del(session, application);
478}
479
480static u16 cmtp_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
481{
482 struct cmtp_session *session = ctrl->driverdata;
483 struct cmtp_application *application;
484 __u16 appl;
485 __u32 contr;
486
487 BT_DBG("ctrl %p skb %p", ctrl, skb);
488
489 appl = CAPIMSG_APPID(skb->data);
490 contr = CAPIMSG_CONTROL(skb->data);
491
492 application = cmtp_application_get(session, CMTP_APPLID, appl);
493 if ((!application) || (application->state != BT_CONNECTED)) {
494 BT_ERR("Can't find application with id %d", appl);
495 return CAPI_ILLAPPNR;
496 }
497
498 CAPIMSG_SETAPPID(skb->data, application->mapping);
499
500 if ((contr & 0x7f) == session->num) {
501 contr = (contr & 0xffffff80) | 0x01;
502 CAPIMSG_SETCONTROL(skb->data, contr);
503 }
504
505 cmtp_send_capimsg(session, skb);
506
507 return CAPI_NOERROR;
508}
509
510static char *cmtp_procinfo(struct capi_ctr *ctrl)
511{
512 return "CAPI Message Transport Protocol";
513}
514
9a58a80a 515static int cmtp_proc_show(struct seq_file *m, void *v)
1da177e4 516{
9a58a80a 517 struct capi_ctr *ctrl = m->private;
1da177e4
LT
518 struct cmtp_session *session = ctrl->driverdata;
519 struct cmtp_application *app;
520 struct list_head *p, *n;
1da177e4 521
9a58a80a
AD
522 seq_printf(m, "%s\n\n", cmtp_procinfo(ctrl));
523 seq_printf(m, "addr %s\n", session->name);
524 seq_printf(m, "ctrl %d\n", session->num);
1da177e4
LT
525
526 list_for_each_safe(p, n, &session->applications) {
527 app = list_entry(p, struct cmtp_application, list);
9a58a80a 528 seq_printf(m, "appl %d -> %d\n", app->appl, app->mapping);
1da177e4
LT
529 }
530
9a58a80a
AD
531 return 0;
532}
1da177e4 533
9a58a80a
AD
534static int cmtp_proc_open(struct inode *inode, struct file *file)
535{
d9dda78b 536 return single_open(file, cmtp_proc_show, PDE_DATA(inode));
1da177e4
LT
537}
538
9a58a80a
AD
539static const struct file_operations cmtp_proc_fops = {
540 .owner = THIS_MODULE,
541 .open = cmtp_proc_open,
542 .read = seq_read,
543 .llseek = seq_lseek,
544 .release = single_release,
545};
1da177e4
LT
546
547int cmtp_attach_device(struct cmtp_session *session)
548{
549 unsigned char buf[4];
550 long ret;
551
552 BT_DBG("session %p", session);
553
554 capimsg_setu32(buf, 0, 0);
555
556 cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, CMTP_INITIAL_MSGNUM,
557 CAPI_FUNCTION_GET_PROFILE, buf, 4);
558
559 ret = wait_event_interruptible_timeout(session->wait,
560 session->ncontroller, CMTP_INTEROP_TIMEOUT);
8e87d142 561
1da177e4
LT
562 BT_INFO("Found %d CAPI controller(s) on device %s", session->ncontroller, session->name);
563
564 if (!ret)
565 return -ETIMEDOUT;
566
567 if (!session->ncontroller)
568 return -ENODEV;
569
570 if (session->ncontroller > 1)
571 BT_INFO("Setting up only CAPI controller 1");
572
573 session->ctrl.owner = THIS_MODULE;
574 session->ctrl.driverdata = session;
575 strcpy(session->ctrl.name, session->name);
576
577 session->ctrl.driver_name = "cmtp";
578 session->ctrl.load_firmware = cmtp_load_firmware;
579 session->ctrl.reset_ctr = cmtp_reset_ctr;
580 session->ctrl.register_appl = cmtp_register_appl;
581 session->ctrl.release_appl = cmtp_release_appl;
582 session->ctrl.send_message = cmtp_send_message;
583
584 session->ctrl.procinfo = cmtp_procinfo;
9a58a80a 585 session->ctrl.proc_fops = &cmtp_proc_fops;
1da177e4
LT
586
587 if (attach_capi_ctr(&session->ctrl) < 0) {
588 BT_ERR("Can't attach new controller");
589 return -EBUSY;
590 }
591
592 session->num = session->ctrl.cnr;
593
594 BT_DBG("session %p num %d", session, session->num);
595
596 capimsg_setu32(buf, 0, 1);
597
598 cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
599 CAPI_FUNCTION_GET_MANUFACTURER, buf, 4);
600
601 cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
602 CAPI_FUNCTION_GET_VERSION, buf, 4);
603
604 cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
605 CAPI_FUNCTION_GET_SERIAL_NUMBER, buf, 4);
606
607 cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
608 CAPI_FUNCTION_GET_PROFILE, buf, 4);
609
610 return 0;
611}
612
613void cmtp_detach_device(struct cmtp_session *session)
614{
615 BT_DBG("session %p", session);
616
617 detach_capi_ctr(&session->ctrl);
618}