Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/net/bluetooth/cmtp/capi.c
26285 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/export.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/signal.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 %u", 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
104
list_for_each_entry(app, &session->applications, list) {
105
switch (pattern) {
106
case CMTP_MSGNUM:
107
if (app->msgnum == value)
108
return app;
109
break;
110
case CMTP_APPLID:
111
if (app->appl == value)
112
return app;
113
break;
114
case CMTP_MAPPING:
115
if (app->mapping == value)
116
return app;
117
break;
118
}
119
}
120
121
return NULL;
122
}
123
124
static int cmtp_msgnum_get(struct cmtp_session *session)
125
{
126
session->msgnum++;
127
128
if ((session->msgnum & 0xff) > 200)
129
session->msgnum = CMTP_INITIAL_MSGNUM + 1;
130
131
return session->msgnum;
132
}
133
134
static void cmtp_send_capimsg(struct cmtp_session *session, struct sk_buff *skb)
135
{
136
struct cmtp_scb *scb = (void *) skb->cb;
137
138
BT_DBG("session %p skb %p len %u", session, skb, skb->len);
139
140
scb->id = -1;
141
scb->data = (CAPIMSG_COMMAND(skb->data) == CAPI_DATA_B3);
142
143
skb_queue_tail(&session->transmit, skb);
144
145
wake_up_interruptible(sk_sleep(session->sock->sk));
146
}
147
148
static void cmtp_send_interopmsg(struct cmtp_session *session,
149
__u8 subcmd, __u16 appl, __u16 msgnum,
150
__u16 function, unsigned char *buf, int len)
151
{
152
struct sk_buff *skb;
153
unsigned char *s;
154
155
BT_DBG("session %p subcmd 0x%02x appl %u msgnum %u", session, subcmd, appl, msgnum);
156
157
skb = alloc_skb(CAPI_MSG_BASELEN + 6 + len, GFP_ATOMIC);
158
if (!skb) {
159
BT_ERR("Can't allocate memory for interoperability packet");
160
return;
161
}
162
163
s = skb_put(skb, CAPI_MSG_BASELEN + 6 + len);
164
165
capimsg_setu16(s, 0, CAPI_MSG_BASELEN + 6 + len);
166
capimsg_setu16(s, 2, appl);
167
capimsg_setu8 (s, 4, CAPI_INTEROPERABILITY);
168
capimsg_setu8 (s, 5, subcmd);
169
capimsg_setu16(s, 6, msgnum);
170
171
/* Interoperability selector (Bluetooth Device Management) */
172
capimsg_setu16(s, 8, 0x0001);
173
174
capimsg_setu8 (s, 10, 3 + len);
175
capimsg_setu16(s, 11, function);
176
capimsg_setu8 (s, 13, len);
177
178
if (len > 0)
179
memcpy(s + 14, buf, len);
180
181
cmtp_send_capimsg(session, skb);
182
}
183
184
static void cmtp_recv_interopmsg(struct cmtp_session *session, struct sk_buff *skb)
185
{
186
struct capi_ctr *ctrl = &session->ctrl;
187
struct cmtp_application *application;
188
__u16 appl, msgnum, func, info;
189
__u32 controller;
190
191
BT_DBG("session %p skb %p len %u", session, skb, skb->len);
192
193
switch (CAPIMSG_SUBCOMMAND(skb->data)) {
194
case CAPI_CONF:
195
if (skb->len < CAPI_MSG_BASELEN + 10)
196
break;
197
198
func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 5);
199
info = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 8);
200
201
switch (func) {
202
case CAPI_FUNCTION_REGISTER:
203
msgnum = CAPIMSG_MSGID(skb->data);
204
205
application = cmtp_application_get(session, CMTP_MSGNUM, msgnum);
206
if (application) {
207
application->state = BT_CONNECTED;
208
application->msgnum = 0;
209
application->mapping = CAPIMSG_APPID(skb->data);
210
wake_up_interruptible(&session->wait);
211
}
212
213
break;
214
215
case CAPI_FUNCTION_RELEASE:
216
appl = CAPIMSG_APPID(skb->data);
217
218
application = cmtp_application_get(session, CMTP_MAPPING, appl);
219
if (application) {
220
application->state = BT_CLOSED;
221
application->msgnum = 0;
222
wake_up_interruptible(&session->wait);
223
}
224
225
break;
226
227
case CAPI_FUNCTION_GET_PROFILE:
228
if (skb->len < CAPI_MSG_BASELEN + 11 + sizeof(capi_profile))
229
break;
230
231
controller = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 11);
232
msgnum = CAPIMSG_MSGID(skb->data);
233
234
if (!info && (msgnum == CMTP_INITIAL_MSGNUM)) {
235
session->ncontroller = controller;
236
wake_up_interruptible(&session->wait);
237
break;
238
}
239
240
if (!info && ctrl) {
241
memcpy(&ctrl->profile,
242
skb->data + CAPI_MSG_BASELEN + 11,
243
sizeof(capi_profile));
244
session->state = BT_CONNECTED;
245
capi_ctr_ready(ctrl);
246
}
247
248
break;
249
250
case CAPI_FUNCTION_GET_MANUFACTURER:
251
if (!info && ctrl && skb->len > CAPI_MSG_BASELEN + 14)
252
strscpy_pad(ctrl->manu,
253
skb->data + CAPI_MSG_BASELEN + 15,
254
skb->data[CAPI_MSG_BASELEN + 14]);
255
break;
256
257
case CAPI_FUNCTION_GET_VERSION:
258
if (skb->len < CAPI_MSG_BASELEN + 32)
259
break;
260
261
if (!info && ctrl) {
262
ctrl->version.majorversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 16);
263
ctrl->version.minorversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 20);
264
ctrl->version.majormanuversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 24);
265
ctrl->version.minormanuversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 28);
266
}
267
268
break;
269
270
case CAPI_FUNCTION_GET_SERIAL_NUMBER:
271
if (!info && ctrl && skb->len > CAPI_MSG_BASELEN + 16)
272
strscpy_pad(ctrl->serial,
273
skb->data + CAPI_MSG_BASELEN + 17,
274
skb->data[CAPI_MSG_BASELEN + 16]);
275
break;
276
}
277
278
break;
279
280
case CAPI_IND:
281
if (skb->len < CAPI_MSG_BASELEN + 6)
282
break;
283
284
func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 3);
285
286
if (func == CAPI_FUNCTION_LOOPBACK) {
287
int len = min_t(uint, skb->len - CAPI_MSG_BASELEN - 6,
288
skb->data[CAPI_MSG_BASELEN + 5]);
289
appl = CAPIMSG_APPID(skb->data);
290
msgnum = CAPIMSG_MSGID(skb->data);
291
cmtp_send_interopmsg(session, CAPI_RESP, appl, msgnum, func,
292
skb->data + CAPI_MSG_BASELEN + 6, len);
293
}
294
295
break;
296
}
297
298
kfree_skb(skb);
299
}
300
301
void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb)
302
{
303
struct capi_ctr *ctrl = &session->ctrl;
304
struct cmtp_application *application;
305
__u16 appl;
306
__u32 contr;
307
308
BT_DBG("session %p skb %p len %u", session, skb, skb->len);
309
310
if (skb->len < CAPI_MSG_BASELEN)
311
return;
312
313
if (CAPIMSG_COMMAND(skb->data) == CAPI_INTEROPERABILITY) {
314
cmtp_recv_interopmsg(session, skb);
315
return;
316
}
317
318
if (session->flags & BIT(CMTP_LOOPBACK)) {
319
kfree_skb(skb);
320
return;
321
}
322
323
appl = CAPIMSG_APPID(skb->data);
324
contr = CAPIMSG_CONTROL(skb->data);
325
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 %u", appl);
332
kfree_skb(skb);
333
return;
334
}
335
336
if ((contr & 0x7f) == 0x01) {
337
contr = (contr & 0xffffff80) | session->num;
338
CAPIMSG_SETCONTROL(skb->data, contr);
339
}
340
341
capi_ctr_handle_message(ctrl, appl, skb);
342
}
343
344
static int cmtp_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
345
{
346
BT_DBG("ctrl %p data %p", ctrl, data);
347
348
return 0;
349
}
350
351
static void cmtp_reset_ctr(struct capi_ctr *ctrl)
352
{
353
struct cmtp_session *session = ctrl->driverdata;
354
355
BT_DBG("ctrl %p", ctrl);
356
357
capi_ctr_down(ctrl);
358
359
atomic_inc(&session->terminate);
360
wake_up_process(session->task);
361
}
362
363
static void cmtp_register_appl(struct capi_ctr *ctrl, __u16 appl, capi_register_params *rp)
364
{
365
DECLARE_WAITQUEUE(wait, current);
366
struct cmtp_session *session = ctrl->driverdata;
367
struct cmtp_application *application;
368
unsigned long timeo = CMTP_INTEROP_TIMEOUT;
369
unsigned char buf[8];
370
int err = 0, nconn, want = rp->level3cnt;
371
372
BT_DBG("ctrl %p appl %u level3cnt %u datablkcnt %u datablklen %u",
373
ctrl, appl, rp->level3cnt, rp->datablkcnt, rp->datablklen);
374
375
application = cmtp_application_add(session, appl);
376
if (!application) {
377
BT_ERR("Can't allocate memory for new application");
378
return;
379
}
380
381
if (want < 0)
382
nconn = ctrl->profile.nbchannel * -want;
383
else
384
nconn = want;
385
386
if (nconn == 0)
387
nconn = ctrl->profile.nbchannel;
388
389
capimsg_setu16(buf, 0, nconn);
390
capimsg_setu16(buf, 2, rp->datablkcnt);
391
capimsg_setu16(buf, 4, rp->datablklen);
392
393
application->state = BT_CONFIG;
394
application->msgnum = cmtp_msgnum_get(session);
395
396
cmtp_send_interopmsg(session, CAPI_REQ, 0x0000, application->msgnum,
397
CAPI_FUNCTION_REGISTER, buf, 6);
398
399
add_wait_queue(&session->wait, &wait);
400
while (1) {
401
set_current_state(TASK_INTERRUPTIBLE);
402
403
if (!timeo) {
404
err = -EAGAIN;
405
break;
406
}
407
408
if (application->state == BT_CLOSED) {
409
err = -application->err;
410
break;
411
}
412
413
if (application->state == BT_CONNECTED)
414
break;
415
416
if (signal_pending(current)) {
417
err = -EINTR;
418
break;
419
}
420
421
timeo = schedule_timeout(timeo);
422
}
423
set_current_state(TASK_RUNNING);
424
remove_wait_queue(&session->wait, &wait);
425
426
if (err) {
427
cmtp_application_del(session, application);
428
return;
429
}
430
}
431
432
static void cmtp_release_appl(struct capi_ctr *ctrl, __u16 appl)
433
{
434
struct cmtp_session *session = ctrl->driverdata;
435
struct cmtp_application *application;
436
437
BT_DBG("ctrl %p appl %u", ctrl, appl);
438
439
application = cmtp_application_get(session, CMTP_APPLID, appl);
440
if (!application) {
441
BT_ERR("Can't find application");
442
return;
443
}
444
445
application->msgnum = cmtp_msgnum_get(session);
446
447
cmtp_send_interopmsg(session, CAPI_REQ, application->mapping, application->msgnum,
448
CAPI_FUNCTION_RELEASE, NULL, 0);
449
450
wait_event_interruptible_timeout(session->wait,
451
(application->state == BT_CLOSED), CMTP_INTEROP_TIMEOUT);
452
453
cmtp_application_del(session, application);
454
}
455
456
static u16 cmtp_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
457
{
458
struct cmtp_session *session = ctrl->driverdata;
459
struct cmtp_application *application;
460
__u16 appl;
461
__u32 contr;
462
463
BT_DBG("ctrl %p skb %p", ctrl, skb);
464
465
appl = CAPIMSG_APPID(skb->data);
466
contr = CAPIMSG_CONTROL(skb->data);
467
468
application = cmtp_application_get(session, CMTP_APPLID, appl);
469
if ((!application) || (application->state != BT_CONNECTED)) {
470
BT_ERR("Can't find application with id %u", appl);
471
return CAPI_ILLAPPNR;
472
}
473
474
CAPIMSG_SETAPPID(skb->data, application->mapping);
475
476
if ((contr & 0x7f) == session->num) {
477
contr = (contr & 0xffffff80) | 0x01;
478
CAPIMSG_SETCONTROL(skb->data, contr);
479
}
480
481
cmtp_send_capimsg(session, skb);
482
483
return CAPI_NOERROR;
484
}
485
486
static char *cmtp_procinfo(struct capi_ctr *ctrl)
487
{
488
return "CAPI Message Transport Protocol";
489
}
490
491
static int cmtp_proc_show(struct seq_file *m, void *v)
492
{
493
struct capi_ctr *ctrl = m->private;
494
struct cmtp_session *session = ctrl->driverdata;
495
struct cmtp_application *app;
496
497
seq_printf(m, "%s\n\n", cmtp_procinfo(ctrl));
498
seq_printf(m, "addr %s\n", session->name);
499
seq_printf(m, "ctrl %d\n", session->num);
500
501
list_for_each_entry(app, &session->applications, list) {
502
seq_printf(m, "appl %u -> %u\n", app->appl, app->mapping);
503
}
504
505
return 0;
506
}
507
508
int cmtp_attach_device(struct cmtp_session *session)
509
{
510
unsigned char buf[4];
511
long ret;
512
513
BT_DBG("session %p", session);
514
515
capimsg_setu32(buf, 0, 0);
516
517
cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, CMTP_INITIAL_MSGNUM,
518
CAPI_FUNCTION_GET_PROFILE, buf, 4);
519
520
ret = wait_event_interruptible_timeout(session->wait,
521
session->ncontroller, CMTP_INTEROP_TIMEOUT);
522
523
BT_INFO("Found %d CAPI controller(s) on device %s", session->ncontroller, session->name);
524
525
if (!ret)
526
return -ETIMEDOUT;
527
528
if (!session->ncontroller)
529
return -ENODEV;
530
531
if (session->ncontroller > 1)
532
BT_INFO("Setting up only CAPI controller 1");
533
534
session->ctrl.owner = THIS_MODULE;
535
session->ctrl.driverdata = session;
536
strcpy(session->ctrl.name, session->name);
537
538
session->ctrl.driver_name = "cmtp";
539
session->ctrl.load_firmware = cmtp_load_firmware;
540
session->ctrl.reset_ctr = cmtp_reset_ctr;
541
session->ctrl.register_appl = cmtp_register_appl;
542
session->ctrl.release_appl = cmtp_release_appl;
543
session->ctrl.send_message = cmtp_send_message;
544
545
session->ctrl.procinfo = cmtp_procinfo;
546
session->ctrl.proc_show = cmtp_proc_show;
547
548
if (attach_capi_ctr(&session->ctrl) < 0) {
549
BT_ERR("Can't attach new controller");
550
return -EBUSY;
551
}
552
553
session->num = session->ctrl.cnr;
554
555
BT_DBG("session %p num %d", session, session->num);
556
557
capimsg_setu32(buf, 0, 1);
558
559
cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
560
CAPI_FUNCTION_GET_MANUFACTURER, buf, 4);
561
562
cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
563
CAPI_FUNCTION_GET_VERSION, buf, 4);
564
565
cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
566
CAPI_FUNCTION_GET_SERIAL_NUMBER, buf, 4);
567
568
cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
569
CAPI_FUNCTION_GET_PROFILE, buf, 4);
570
571
return 0;
572
}
573
574
void cmtp_detach_device(struct cmtp_session *session)
575
{
576
BT_DBG("session %p", session);
577
578
detach_capi_ctr(&session->ctrl);
579
}
580
581