Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/net/bluetooth/cmtp/capi.c
15112 views
1
/*
2
CMTP implementation for Linux Bluetooth stack (BlueZ).
3
Copyright (C) 2002-2003 Marcel Holtmann <[email protected]>
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
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.
17
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.
21
*/
22
23
#include <linux/module.h>
24
#include <linux/proc_fs.h>
25
#include <linux/seq_file.h>
26
#include <linux/types.h>
27
#include <linux/errno.h>
28
#include <linux/kernel.h>
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>
38
#include <linux/kthread.h>
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
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
73
static struct cmtp_application *cmtp_application_add(struct cmtp_session *session, __u16 appl)
74
{
75
struct cmtp_application *app = kzalloc(sizeof(*app), GFP_KERNEL);
76
77
BT_DBG("session %p application %p appl %d", session, app, appl);
78
79
if (!app)
80
return NULL;
81
82
app->state = BT_OPEN;
83
app->appl = appl;
84
85
list_add_tail(&app->list, &session->applications);
86
87
return app;
88
}
89
90
static 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
100
static 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
126
static 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
136
static 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
147
wake_up_interruptible(sk_sleep(session->sock->sk));
148
}
149
150
static 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
159
skb = alloc_skb(CAPI_MSG_BASELEN + 6 + len, GFP_ATOMIC);
160
if (!skb) {
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
186
static 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:
197
if (skb->len < CAPI_MSG_BASELEN + 10)
198
break;
199
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:
230
if (skb->len < CAPI_MSG_BASELEN + 11 + sizeof(capi_profile))
231
break;
232
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:
253
if (skb->len < CAPI_MSG_BASELEN + 15)
254
break;
255
256
controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 10);
257
258
if (!info && ctrl) {
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);
263
strncpy(ctrl->manu,
264
skb->data + CAPI_MSG_BASELEN + 15, len);
265
}
266
267
break;
268
269
case CAPI_FUNCTION_GET_VERSION:
270
if (skb->len < CAPI_MSG_BASELEN + 32)
271
break;
272
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:
285
if (skb->len < CAPI_MSG_BASELEN + 17)
286
break;
287
288
controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 12);
289
290
if (!info && ctrl) {
291
int len = min_t(uint, CAPI_SERIAL_LEN,
292
skb->data[CAPI_MSG_BASELEN + 16]);
293
294
memset(ctrl->serial, 0, CAPI_SERIAL_LEN);
295
strncpy(ctrl->serial,
296
skb->data + CAPI_MSG_BASELEN + 17, len);
297
}
298
299
break;
300
}
301
302
break;
303
304
case CAPI_IND:
305
if (skb->len < CAPI_MSG_BASELEN + 6)
306
break;
307
308
func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 3);
309
310
if (func == CAPI_FUNCTION_LOOPBACK) {
311
int len = min_t(uint, skb->len - CAPI_MSG_BASELEN - 6,
312
skb->data[CAPI_MSG_BASELEN + 5]);
313
appl = CAPIMSG_APPID(skb->data);
314
msgnum = CAPIMSG_MSGID(skb->data);
315
cmtp_send_interopmsg(session, CAPI_RESP, appl, msgnum, func,
316
skb->data + CAPI_MSG_BASELEN + 6, len);
317
}
318
319
break;
320
}
321
322
kfree_skb(skb);
323
}
324
325
void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb)
326
{
327
struct capi_ctr *ctrl = &session->ctrl;
328
struct cmtp_application *application;
329
__u16 cmd, appl;
330
__u32 contr;
331
332
BT_DBG("session %p skb %p len %d", session, skb, skb->len);
333
334
if (skb->len < CAPI_MSG_BASELEN)
335
return;
336
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
347
cmd = CAPICMD(CAPIMSG_COMMAND(skb->data), CAPIMSG_SUBCOMMAND(skb->data));
348
appl = CAPIMSG_APPID(skb->data);
349
contr = CAPIMSG_CONTROL(skb->data);
350
351
application = cmtp_application_get(session, CMTP_MAPPING, appl);
352
if (application) {
353
appl = application->appl;
354
CAPIMSG_SETAPPID(skb->data, appl);
355
} else {
356
BT_ERR("Can't find application with id %d", appl);
357
kfree_skb(skb);
358
return;
359
}
360
361
if ((contr & 0x7f) == 0x01) {
362
contr = (contr & 0xffffff80) | session->num;
363
CAPIMSG_SETCONTROL(skb->data, contr);
364
}
365
366
if (!ctrl) {
367
BT_ERR("Can't find controller %d for message", session->num);
368
kfree_skb(skb);
369
return;
370
}
371
372
capi_ctr_handle_message(ctrl, appl, skb);
373
}
374
375
static int cmtp_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
376
{
377
BT_DBG("ctrl %p data %p", ctrl, data);
378
379
return 0;
380
}
381
382
static void cmtp_reset_ctr(struct capi_ctr *ctrl)
383
{
384
struct cmtp_session *session = ctrl->driverdata;
385
386
BT_DBG("ctrl %p", ctrl);
387
388
capi_ctr_down(ctrl);
389
390
kthread_stop(session->task);
391
}
392
393
static void cmtp_register_appl(struct capi_ctr *ctrl, __u16 appl, capi_register_params *rp)
394
{
395
DECLARE_WAITQUEUE(wait, current);
396
struct cmtp_session *session = ctrl->driverdata;
397
struct cmtp_application *application;
398
unsigned long timeo = CMTP_INTEROP_TIMEOUT;
399
unsigned char buf[8];
400
int err = 0, nconn, want = rp->level3cnt;
401
402
BT_DBG("ctrl %p appl %d level3cnt %d datablkcnt %d datablklen %d",
403
ctrl, appl, rp->level3cnt, rp->datablkcnt, rp->datablklen);
404
405
application = cmtp_application_add(session, appl);
406
if (!application) {
407
BT_ERR("Can't allocate memory for new application");
408
return;
409
}
410
411
if (want < 0)
412
nconn = ctrl->profile.nbchannel * -want;
413
else
414
nconn = want;
415
416
if (nconn == 0)
417
nconn = ctrl->profile.nbchannel;
418
419
capimsg_setu16(buf, 0, nconn);
420
capimsg_setu16(buf, 2, rp->datablkcnt);
421
capimsg_setu16(buf, 4, rp->datablklen);
422
423
application->state = BT_CONFIG;
424
application->msgnum = cmtp_msgnum_get(session);
425
426
cmtp_send_interopmsg(session, CAPI_REQ, 0x0000, application->msgnum,
427
CAPI_FUNCTION_REGISTER, buf, 6);
428
429
add_wait_queue(&session->wait, &wait);
430
while (1) {
431
set_current_state(TASK_INTERRUPTIBLE);
432
433
if (!timeo) {
434
err = -EAGAIN;
435
break;
436
}
437
438
if (application->state == BT_CLOSED) {
439
err = -application->err;
440
break;
441
}
442
443
if (application->state == BT_CONNECTED)
444
break;
445
446
if (signal_pending(current)) {
447
err = -EINTR;
448
break;
449
}
450
451
timeo = schedule_timeout(timeo);
452
}
453
set_current_state(TASK_RUNNING);
454
remove_wait_queue(&session->wait, &wait);
455
456
if (err) {
457
cmtp_application_del(session, application);
458
return;
459
}
460
}
461
462
static void cmtp_release_appl(struct capi_ctr *ctrl, __u16 appl)
463
{
464
struct cmtp_session *session = ctrl->driverdata;
465
struct cmtp_application *application;
466
467
BT_DBG("ctrl %p appl %d", ctrl, appl);
468
469
application = cmtp_application_get(session, CMTP_APPLID, appl);
470
if (!application) {
471
BT_ERR("Can't find application");
472
return;
473
}
474
475
application->msgnum = cmtp_msgnum_get(session);
476
477
cmtp_send_interopmsg(session, CAPI_REQ, application->mapping, application->msgnum,
478
CAPI_FUNCTION_RELEASE, NULL, 0);
479
480
wait_event_interruptible_timeout(session->wait,
481
(application->state == BT_CLOSED), CMTP_INTEROP_TIMEOUT);
482
483
cmtp_application_del(session, application);
484
}
485
486
static u16 cmtp_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
487
{
488
struct cmtp_session *session = ctrl->driverdata;
489
struct cmtp_application *application;
490
__u16 appl;
491
__u32 contr;
492
493
BT_DBG("ctrl %p skb %p", ctrl, skb);
494
495
appl = CAPIMSG_APPID(skb->data);
496
contr = CAPIMSG_CONTROL(skb->data);
497
498
application = cmtp_application_get(session, CMTP_APPLID, appl);
499
if ((!application) || (application->state != BT_CONNECTED)) {
500
BT_ERR("Can't find application with id %d", appl);
501
return CAPI_ILLAPPNR;
502
}
503
504
CAPIMSG_SETAPPID(skb->data, application->mapping);
505
506
if ((contr & 0x7f) == session->num) {
507
contr = (contr & 0xffffff80) | 0x01;
508
CAPIMSG_SETCONTROL(skb->data, contr);
509
}
510
511
cmtp_send_capimsg(session, skb);
512
513
return CAPI_NOERROR;
514
}
515
516
static char *cmtp_procinfo(struct capi_ctr *ctrl)
517
{
518
return "CAPI Message Transport Protocol";
519
}
520
521
static int cmtp_proc_show(struct seq_file *m, void *v)
522
{
523
struct capi_ctr *ctrl = m->private;
524
struct cmtp_session *session = ctrl->driverdata;
525
struct cmtp_application *app;
526
struct list_head *p, *n;
527
528
seq_printf(m, "%s\n\n", cmtp_procinfo(ctrl));
529
seq_printf(m, "addr %s\n", session->name);
530
seq_printf(m, "ctrl %d\n", session->num);
531
532
list_for_each_safe(p, n, &session->applications) {
533
app = list_entry(p, struct cmtp_application, list);
534
seq_printf(m, "appl %d -> %d\n", app->appl, app->mapping);
535
}
536
537
return 0;
538
}
539
540
static int cmtp_proc_open(struct inode *inode, struct file *file)
541
{
542
return single_open(file, cmtp_proc_show, PDE(inode)->data);
543
}
544
545
static const struct file_operations cmtp_proc_fops = {
546
.owner = THIS_MODULE,
547
.open = cmtp_proc_open,
548
.read = seq_read,
549
.llseek = seq_lseek,
550
.release = single_release,
551
};
552
553
int cmtp_attach_device(struct cmtp_session *session)
554
{
555
unsigned char buf[4];
556
long ret;
557
558
BT_DBG("session %p", session);
559
560
capimsg_setu32(buf, 0, 0);
561
562
cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, CMTP_INITIAL_MSGNUM,
563
CAPI_FUNCTION_GET_PROFILE, buf, 4);
564
565
ret = wait_event_interruptible_timeout(session->wait,
566
session->ncontroller, CMTP_INTEROP_TIMEOUT);
567
568
BT_INFO("Found %d CAPI controller(s) on device %s", session->ncontroller, session->name);
569
570
if (!ret)
571
return -ETIMEDOUT;
572
573
if (!session->ncontroller)
574
return -ENODEV;
575
576
if (session->ncontroller > 1)
577
BT_INFO("Setting up only CAPI controller 1");
578
579
session->ctrl.owner = THIS_MODULE;
580
session->ctrl.driverdata = session;
581
strcpy(session->ctrl.name, session->name);
582
583
session->ctrl.driver_name = "cmtp";
584
session->ctrl.load_firmware = cmtp_load_firmware;
585
session->ctrl.reset_ctr = cmtp_reset_ctr;
586
session->ctrl.register_appl = cmtp_register_appl;
587
session->ctrl.release_appl = cmtp_release_appl;
588
session->ctrl.send_message = cmtp_send_message;
589
590
session->ctrl.procinfo = cmtp_procinfo;
591
session->ctrl.proc_fops = &cmtp_proc_fops;
592
593
if (attach_capi_ctr(&session->ctrl) < 0) {
594
BT_ERR("Can't attach new controller");
595
return -EBUSY;
596
}
597
598
session->num = session->ctrl.cnr;
599
600
BT_DBG("session %p num %d", session, session->num);
601
602
capimsg_setu32(buf, 0, 1);
603
604
cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
605
CAPI_FUNCTION_GET_MANUFACTURER, buf, 4);
606
607
cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
608
CAPI_FUNCTION_GET_VERSION, buf, 4);
609
610
cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
611
CAPI_FUNCTION_GET_SERIAL_NUMBER, buf, 4);
612
613
cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
614
CAPI_FUNCTION_GET_PROFILE, buf, 4);
615
616
return 0;
617
}
618
619
void cmtp_detach_device(struct cmtp_session *session)
620
{
621
BT_DBG("session %p", session);
622
623
detach_capi_ctr(&session->ctrl);
624
}
625
626