Merge branch 'drm-tda998x-devel' of git://ftp.arm.linux.org.uk/~rmk/linux-arm into...
[deliverable/linux.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;
54c9ee39 103 struct list_head *p;
1da177e4 104
54c9ee39 105 list_for_each(p, &session->applications) {
1da177e4
LT
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 256 if (!info && ctrl) {
f4777569
MH
257 int len = min_t(uint, CAPI_MANUFACTURER_LEN,
258 skb->data[CAPI_MSG_BASELEN + 14]);
259
260 memset(ctrl->manu, 0, CAPI_MANUFACTURER_LEN);
1da177e4 261 strncpy(ctrl->manu,
f4777569 262 skb->data + CAPI_MSG_BASELEN + 15, len);
1da177e4
LT
263 }
264
265 break;
266
267 case CAPI_FUNCTION_GET_VERSION:
f4777569
MH
268 if (skb->len < CAPI_MSG_BASELEN + 32)
269 break;
270
1da177e4
LT
271 if (!info && ctrl) {
272 ctrl->version.majorversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 16);
273 ctrl->version.minorversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 20);
274 ctrl->version.majormanuversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 24);
275 ctrl->version.minormanuversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 28);
276 }
277
278 break;
279
280 case CAPI_FUNCTION_GET_SERIAL_NUMBER:
f4777569
MH
281 if (skb->len < CAPI_MSG_BASELEN + 17)
282 break;
283
1da177e4 284 if (!info && ctrl) {
f4777569
MH
285 int len = min_t(uint, CAPI_SERIAL_LEN,
286 skb->data[CAPI_MSG_BASELEN + 16]);
287
1da177e4
LT
288 memset(ctrl->serial, 0, CAPI_SERIAL_LEN);
289 strncpy(ctrl->serial,
f4777569 290 skb->data + CAPI_MSG_BASELEN + 17, len);
1da177e4
LT
291 }
292
293 break;
294 }
295
296 break;
297
298 case CAPI_IND:
f4777569
MH
299 if (skb->len < CAPI_MSG_BASELEN + 6)
300 break;
301
1da177e4
LT
302 func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 3);
303
304 if (func == CAPI_FUNCTION_LOOPBACK) {
f4777569
MH
305 int len = min_t(uint, skb->len - CAPI_MSG_BASELEN - 6,
306 skb->data[CAPI_MSG_BASELEN + 5]);
1da177e4
LT
307 appl = CAPIMSG_APPID(skb->data);
308 msgnum = CAPIMSG_MSGID(skb->data);
309 cmtp_send_interopmsg(session, CAPI_RESP, appl, msgnum, func,
f4777569 310 skb->data + CAPI_MSG_BASELEN + 6, len);
1da177e4
LT
311 }
312
313 break;
314 }
315
316 kfree_skb(skb);
317}
318
319void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb)
320{
321 struct capi_ctr *ctrl = &session->ctrl;
322 struct cmtp_application *application;
d29d04ce 323 __u16 appl;
1da177e4
LT
324 __u32 contr;
325
326 BT_DBG("session %p skb %p len %d", session, skb, skb->len);
327
f4777569
MH
328 if (skb->len < CAPI_MSG_BASELEN)
329 return;
330
1da177e4
LT
331 if (CAPIMSG_COMMAND(skb->data) == CAPI_INTEROPERABILITY) {
332 cmtp_recv_interopmsg(session, skb);
333 return;
334 }
335
b2ddeb11 336 if (session->flags & BIT(CMTP_LOOPBACK)) {
1da177e4
LT
337 kfree_skb(skb);
338 return;
339 }
340
1da177e4
LT
341 appl = CAPIMSG_APPID(skb->data);
342 contr = CAPIMSG_CONTROL(skb->data);
343
344 application = cmtp_application_get(session, CMTP_MAPPING, appl);
345 if (application) {
346 appl = application->appl;
347 CAPIMSG_SETAPPID(skb->data, appl);
348 } else {
349 BT_ERR("Can't find application with id %d", appl);
350 kfree_skb(skb);
351 return;
352 }
353
354 if ((contr & 0x7f) == 0x01) {
355 contr = (contr & 0xffffff80) | session->num;
356 CAPIMSG_SETCONTROL(skb->data, contr);
357 }
358
1da177e4
LT
359 capi_ctr_handle_message(ctrl, appl, skb);
360}
361
362static int cmtp_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
363{
364 BT_DBG("ctrl %p data %p", ctrl, data);
365
366 return 0;
367}
368
369static void cmtp_reset_ctr(struct capi_ctr *ctrl)
370{
371 struct cmtp_session *session = ctrl->driverdata;
372
373 BT_DBG("ctrl %p", ctrl);
374
4e329972 375 capi_ctr_down(ctrl);
1da177e4 376
7176522c
PH
377 atomic_inc(&session->terminate);
378 wake_up_process(session->task);
1da177e4
LT
379}
380
381static void cmtp_register_appl(struct capi_ctr *ctrl, __u16 appl, capi_register_params *rp)
382{
383 DECLARE_WAITQUEUE(wait, current);
384 struct cmtp_session *session = ctrl->driverdata;
385 struct cmtp_application *application;
386 unsigned long timeo = CMTP_INTEROP_TIMEOUT;
387 unsigned char buf[8];
388 int err = 0, nconn, want = rp->level3cnt;
389
390 BT_DBG("ctrl %p appl %d level3cnt %d datablkcnt %d datablklen %d",
391 ctrl, appl, rp->level3cnt, rp->datablkcnt, rp->datablklen);
392
393 application = cmtp_application_add(session, appl);
394 if (!application) {
395 BT_ERR("Can't allocate memory for new application");
396 return;
397 }
398
399 if (want < 0)
400 nconn = ctrl->profile.nbchannel * -want;
401 else
402 nconn = want;
403
404 if (nconn == 0)
405 nconn = ctrl->profile.nbchannel;
406
407 capimsg_setu16(buf, 0, nconn);
408 capimsg_setu16(buf, 2, rp->datablkcnt);
409 capimsg_setu16(buf, 4, rp->datablklen);
410
411 application->state = BT_CONFIG;
412 application->msgnum = cmtp_msgnum_get(session);
413
414 cmtp_send_interopmsg(session, CAPI_REQ, 0x0000, application->msgnum,
415 CAPI_FUNCTION_REGISTER, buf, 6);
416
417 add_wait_queue(&session->wait, &wait);
418 while (1) {
419 set_current_state(TASK_INTERRUPTIBLE);
420
421 if (!timeo) {
422 err = -EAGAIN;
423 break;
424 }
425
426 if (application->state == BT_CLOSED) {
427 err = -application->err;
428 break;
429 }
430
431 if (application->state == BT_CONNECTED)
432 break;
433
434 if (signal_pending(current)) {
435 err = -EINTR;
436 break;
437 }
438
439 timeo = schedule_timeout(timeo);
440 }
441 set_current_state(TASK_RUNNING);
442 remove_wait_queue(&session->wait, &wait);
443
444 if (err) {
445 cmtp_application_del(session, application);
446 return;
447 }
448}
449
450static void cmtp_release_appl(struct capi_ctr *ctrl, __u16 appl)
451{
452 struct cmtp_session *session = ctrl->driverdata;
453 struct cmtp_application *application;
454
455 BT_DBG("ctrl %p appl %d", ctrl, appl);
456
457 application = cmtp_application_get(session, CMTP_APPLID, appl);
458 if (!application) {
459 BT_ERR("Can't find application");
460 return;
461 }
462
463 application->msgnum = cmtp_msgnum_get(session);
464
465 cmtp_send_interopmsg(session, CAPI_REQ, application->mapping, application->msgnum,
466 CAPI_FUNCTION_RELEASE, NULL, 0);
467
468 wait_event_interruptible_timeout(session->wait,
469 (application->state == BT_CLOSED), CMTP_INTEROP_TIMEOUT);
470
471 cmtp_application_del(session, application);
472}
473
474static u16 cmtp_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
475{
476 struct cmtp_session *session = ctrl->driverdata;
477 struct cmtp_application *application;
478 __u16 appl;
479 __u32 contr;
480
481 BT_DBG("ctrl %p skb %p", ctrl, skb);
482
483 appl = CAPIMSG_APPID(skb->data);
484 contr = CAPIMSG_CONTROL(skb->data);
485
486 application = cmtp_application_get(session, CMTP_APPLID, appl);
487 if ((!application) || (application->state != BT_CONNECTED)) {
488 BT_ERR("Can't find application with id %d", appl);
489 return CAPI_ILLAPPNR;
490 }
491
492 CAPIMSG_SETAPPID(skb->data, application->mapping);
493
494 if ((contr & 0x7f) == session->num) {
495 contr = (contr & 0xffffff80) | 0x01;
496 CAPIMSG_SETCONTROL(skb->data, contr);
497 }
498
499 cmtp_send_capimsg(session, skb);
500
501 return CAPI_NOERROR;
502}
503
504static char *cmtp_procinfo(struct capi_ctr *ctrl)
505{
506 return "CAPI Message Transport Protocol";
507}
508
9a58a80a 509static int cmtp_proc_show(struct seq_file *m, void *v)
1da177e4 510{
9a58a80a 511 struct capi_ctr *ctrl = m->private;
1da177e4
LT
512 struct cmtp_session *session = ctrl->driverdata;
513 struct cmtp_application *app;
54c9ee39 514 struct list_head *p;
1da177e4 515
9a58a80a
AD
516 seq_printf(m, "%s\n\n", cmtp_procinfo(ctrl));
517 seq_printf(m, "addr %s\n", session->name);
518 seq_printf(m, "ctrl %d\n", session->num);
1da177e4 519
54c9ee39 520 list_for_each(p, &session->applications) {
1da177e4 521 app = list_entry(p, struct cmtp_application, list);
9a58a80a 522 seq_printf(m, "appl %d -> %d\n", app->appl, app->mapping);
1da177e4
LT
523 }
524
9a58a80a
AD
525 return 0;
526}
1da177e4 527
9a58a80a
AD
528static int cmtp_proc_open(struct inode *inode, struct file *file)
529{
d9dda78b 530 return single_open(file, cmtp_proc_show, PDE_DATA(inode));
1da177e4
LT
531}
532
9a58a80a
AD
533static const struct file_operations cmtp_proc_fops = {
534 .owner = THIS_MODULE,
535 .open = cmtp_proc_open,
536 .read = seq_read,
537 .llseek = seq_lseek,
538 .release = single_release,
539};
1da177e4
LT
540
541int cmtp_attach_device(struct cmtp_session *session)
542{
543 unsigned char buf[4];
544 long ret;
545
546 BT_DBG("session %p", session);
547
548 capimsg_setu32(buf, 0, 0);
549
550 cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, CMTP_INITIAL_MSGNUM,
551 CAPI_FUNCTION_GET_PROFILE, buf, 4);
552
553 ret = wait_event_interruptible_timeout(session->wait,
554 session->ncontroller, CMTP_INTEROP_TIMEOUT);
8e87d142 555
1da177e4
LT
556 BT_INFO("Found %d CAPI controller(s) on device %s", session->ncontroller, session->name);
557
558 if (!ret)
559 return -ETIMEDOUT;
560
561 if (!session->ncontroller)
562 return -ENODEV;
563
564 if (session->ncontroller > 1)
565 BT_INFO("Setting up only CAPI controller 1");
566
567 session->ctrl.owner = THIS_MODULE;
568 session->ctrl.driverdata = session;
569 strcpy(session->ctrl.name, session->name);
570
571 session->ctrl.driver_name = "cmtp";
572 session->ctrl.load_firmware = cmtp_load_firmware;
573 session->ctrl.reset_ctr = cmtp_reset_ctr;
574 session->ctrl.register_appl = cmtp_register_appl;
575 session->ctrl.release_appl = cmtp_release_appl;
576 session->ctrl.send_message = cmtp_send_message;
577
578 session->ctrl.procinfo = cmtp_procinfo;
9a58a80a 579 session->ctrl.proc_fops = &cmtp_proc_fops;
1da177e4
LT
580
581 if (attach_capi_ctr(&session->ctrl) < 0) {
582 BT_ERR("Can't attach new controller");
583 return -EBUSY;
584 }
585
586 session->num = session->ctrl.cnr;
587
588 BT_DBG("session %p num %d", session, session->num);
589
590 capimsg_setu32(buf, 0, 1);
591
592 cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
593 CAPI_FUNCTION_GET_MANUFACTURER, buf, 4);
594
595 cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
596 CAPI_FUNCTION_GET_VERSION, buf, 4);
597
598 cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
599 CAPI_FUNCTION_GET_SERIAL_NUMBER, buf, 4);
600
601 cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
602 CAPI_FUNCTION_GET_PROFILE, buf, 4);
603
604 return 0;
605}
606
607void cmtp_detach_device(struct cmtp_session *session)
608{
609 BT_DBG("session %p", session);
610
611 detach_capi_ctr(&session->ctrl);
612}
This page took 0.79927 seconds and 5 git commands to generate.