aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth/cmtp
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /net/bluetooth/cmtp
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'net/bluetooth/cmtp')
-rw-r--r--net/bluetooth/cmtp/Kconfig11
-rw-r--r--net/bluetooth/cmtp/Makefile7
-rw-r--r--net/bluetooth/cmtp/capi.c600
-rw-r--r--net/bluetooth/cmtp/cmtp.h135
-rw-r--r--net/bluetooth/cmtp/core.c504
-rw-r--r--net/bluetooth/cmtp/sock.c226
6 files changed, 1483 insertions, 0 deletions
diff --git a/net/bluetooth/cmtp/Kconfig b/net/bluetooth/cmtp/Kconfig
new file mode 100644
index 000000000000..d6b0382f6f3a
--- /dev/null
+++ b/net/bluetooth/cmtp/Kconfig
@@ -0,0 +1,11 @@
1config BT_CMTP
2 tristate "CMTP protocol support"
3 depends on BT && BT_L2CAP && ISDN_CAPI
4 help
5 CMTP (CAPI Message Transport Protocol) is a transport layer
6 for CAPI messages. CMTP is required for the Bluetooth Common
7 ISDN Access Profile.
8
9 Say Y here to compile CMTP support into the kernel or say M to
10 compile it as module (cmtp).
11
diff --git a/net/bluetooth/cmtp/Makefile b/net/bluetooth/cmtp/Makefile
new file mode 100644
index 000000000000..890a9a5a6861
--- /dev/null
+++ b/net/bluetooth/cmtp/Makefile
@@ -0,0 +1,7 @@
1#
2# Makefile for the Linux Bluetooth CMTP layer
3#
4
5obj-$(CONFIG_BT_CMTP) += cmtp.o
6
7cmtp-objs := core.o sock.o capi.o
diff --git a/net/bluetooth/cmtp/capi.c b/net/bluetooth/cmtp/capi.c
new file mode 100644
index 000000000000..1e5c030b72ad
--- /dev/null
+++ b/net/bluetooth/cmtp/capi.c
@@ -0,0 +1,600 @@
1/*
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
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/config.h>
24#include <linux/module.h>
25
26#include <linux/types.h>
27#include <linux/errno.h>
28#include <linux/kernel.h>
29#include <linux/major.h>
30#include <linux/sched.h>
31#include <linux/slab.h>
32#include <linux/poll.h>
33#include <linux/fcntl.h>
34#include <linux/skbuff.h>
35#include <linux/socket.h>
36#include <linux/ioctl.h>
37#include <linux/file.h>
38#include <linux/wait.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#ifndef CONFIG_BT_CMTP_DEBUG
48#undef BT_DBG
49#define BT_DBG(D...)
50#endif
51
52#define CAPI_INTEROPERABILITY 0x20
53
54#define CAPI_INTEROPERABILITY_REQ CAPICMD(CAPI_INTEROPERABILITY, CAPI_REQ)
55#define CAPI_INTEROPERABILITY_CONF CAPICMD(CAPI_INTEROPERABILITY, CAPI_CONF)
56#define CAPI_INTEROPERABILITY_IND CAPICMD(CAPI_INTEROPERABILITY, CAPI_IND)
57#define CAPI_INTEROPERABILITY_RESP CAPICMD(CAPI_INTEROPERABILITY, CAPI_RESP)
58
59#define CAPI_INTEROPERABILITY_REQ_LEN (CAPI_MSG_BASELEN + 2)
60#define CAPI_INTEROPERABILITY_CONF_LEN (CAPI_MSG_BASELEN + 4)
61#define CAPI_INTEROPERABILITY_IND_LEN (CAPI_MSG_BASELEN + 2)
62#define CAPI_INTEROPERABILITY_RESP_LEN (CAPI_MSG_BASELEN + 2)
63
64#define CAPI_FUNCTION_REGISTER 0
65#define CAPI_FUNCTION_RELEASE 1
66#define CAPI_FUNCTION_GET_PROFILE 2
67#define CAPI_FUNCTION_GET_MANUFACTURER 3
68#define CAPI_FUNCTION_GET_VERSION 4
69#define CAPI_FUNCTION_GET_SERIAL_NUMBER 5
70#define CAPI_FUNCTION_MANUFACTURER 6
71#define CAPI_FUNCTION_LOOPBACK 7
72
73
74#define CMTP_MSGNUM 1
75#define CMTP_APPLID 2
76#define CMTP_MAPPING 3
77
78static struct cmtp_application *cmtp_application_add(struct cmtp_session *session, __u16 appl)
79{
80 struct cmtp_application *app = kmalloc(sizeof(*app), GFP_KERNEL);
81
82 BT_DBG("session %p application %p appl %d", session, app, appl);
83
84 if (!app)
85 return NULL;
86
87 memset(app, 0, sizeof(*app));
88
89 app->state = BT_OPEN;
90 app->appl = appl;
91
92 list_add_tail(&app->list, &session->applications);
93
94 return app;
95}
96
97static void cmtp_application_del(struct cmtp_session *session, struct cmtp_application *app)
98{
99 BT_DBG("session %p application %p", session, app);
100
101 if (app) {
102 list_del(&app->list);
103 kfree(app);
104 }
105}
106
107static struct cmtp_application *cmtp_application_get(struct cmtp_session *session, int pattern, __u16 value)
108{
109 struct cmtp_application *app;
110 struct list_head *p, *n;
111
112 list_for_each_safe(p, n, &session->applications) {
113 app = list_entry(p, struct cmtp_application, list);
114 switch (pattern) {
115 case CMTP_MSGNUM:
116 if (app->msgnum == value)
117 return app;
118 break;
119 case CMTP_APPLID:
120 if (app->appl == value)
121 return app;
122 break;
123 case CMTP_MAPPING:
124 if (app->mapping == value)
125 return app;
126 break;
127 }
128 }
129
130 return NULL;
131}
132
133static int cmtp_msgnum_get(struct cmtp_session *session)
134{
135 session->msgnum++;
136
137 if ((session->msgnum & 0xff) > 200)
138 session->msgnum = CMTP_INITIAL_MSGNUM + 1;
139
140 return session->msgnum;
141}
142
143static void cmtp_send_capimsg(struct cmtp_session *session, struct sk_buff *skb)
144{
145 struct cmtp_scb *scb = (void *) skb->cb;
146
147 BT_DBG("session %p skb %p len %d", session, skb, skb->len);
148
149 scb->id = -1;
150 scb->data = (CAPIMSG_COMMAND(skb->data) == CAPI_DATA_B3);
151
152 skb_queue_tail(&session->transmit, skb);
153
154 cmtp_schedule(session);
155}
156
157static void cmtp_send_interopmsg(struct cmtp_session *session,
158 __u8 subcmd, __u16 appl, __u16 msgnum,
159 __u16 function, unsigned char *buf, int len)
160{
161 struct sk_buff *skb;
162 unsigned char *s;
163
164 BT_DBG("session %p subcmd 0x%02x appl %d msgnum %d", session, subcmd, appl, msgnum);
165
166 if (!(skb = alloc_skb(CAPI_MSG_BASELEN + 6 + len, GFP_ATOMIC))) {
167 BT_ERR("Can't allocate memory for interoperability packet");
168 return;
169 }
170
171 s = skb_put(skb, CAPI_MSG_BASELEN + 6 + len);
172
173 capimsg_setu16(s, 0, CAPI_MSG_BASELEN + 6 + len);
174 capimsg_setu16(s, 2, appl);
175 capimsg_setu8 (s, 4, CAPI_INTEROPERABILITY);
176 capimsg_setu8 (s, 5, subcmd);
177 capimsg_setu16(s, 6, msgnum);
178
179 /* Interoperability selector (Bluetooth Device Management) */
180 capimsg_setu16(s, 8, 0x0001);
181
182 capimsg_setu8 (s, 10, 3 + len);
183 capimsg_setu16(s, 11, function);
184 capimsg_setu8 (s, 13, len);
185
186 if (len > 0)
187 memcpy(s + 14, buf, len);
188
189 cmtp_send_capimsg(session, skb);
190}
191
192static void cmtp_recv_interopmsg(struct cmtp_session *session, struct sk_buff *skb)
193{
194 struct capi_ctr *ctrl = &session->ctrl;
195 struct cmtp_application *application;
196 __u16 appl, msgnum, func, info;
197 __u32 controller;
198
199 BT_DBG("session %p skb %p len %d", session, skb, skb->len);
200
201 switch (CAPIMSG_SUBCOMMAND(skb->data)) {
202 case CAPI_CONF:
203 func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 5);
204 info = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 8);
205
206 switch (func) {
207 case CAPI_FUNCTION_REGISTER:
208 msgnum = CAPIMSG_MSGID(skb->data);
209
210 application = cmtp_application_get(session, CMTP_MSGNUM, msgnum);
211 if (application) {
212 application->state = BT_CONNECTED;
213 application->msgnum = 0;
214 application->mapping = CAPIMSG_APPID(skb->data);
215 wake_up_interruptible(&session->wait);
216 }
217
218 break;
219
220 case CAPI_FUNCTION_RELEASE:
221 appl = CAPIMSG_APPID(skb->data);
222
223 application = cmtp_application_get(session, CMTP_MAPPING, appl);
224 if (application) {
225 application->state = BT_CLOSED;
226 application->msgnum = 0;
227 wake_up_interruptible(&session->wait);
228 }
229
230 break;
231
232 case CAPI_FUNCTION_GET_PROFILE:
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 controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 10);
254
255 if (!info && ctrl) {
256 strncpy(ctrl->manu,
257 skb->data + CAPI_MSG_BASELEN + 15,
258 skb->data[CAPI_MSG_BASELEN + 14]);
259 }
260
261 break;
262
263 case CAPI_FUNCTION_GET_VERSION:
264 controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 12);
265
266 if (!info && ctrl) {
267 ctrl->version.majorversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 16);
268 ctrl->version.minorversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 20);
269 ctrl->version.majormanuversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 24);
270 ctrl->version.minormanuversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 28);
271 }
272
273 break;
274
275 case CAPI_FUNCTION_GET_SERIAL_NUMBER:
276 controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 12);
277
278 if (!info && ctrl) {
279 memset(ctrl->serial, 0, CAPI_SERIAL_LEN);
280 strncpy(ctrl->serial,
281 skb->data + CAPI_MSG_BASELEN + 17,
282 skb->data[CAPI_MSG_BASELEN + 16]);
283 }
284
285 break;
286 }
287
288 break;
289
290 case CAPI_IND:
291 func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 3);
292
293 if (func == CAPI_FUNCTION_LOOPBACK) {
294 appl = CAPIMSG_APPID(skb->data);
295 msgnum = CAPIMSG_MSGID(skb->data);
296 cmtp_send_interopmsg(session, CAPI_RESP, appl, msgnum, func,
297 skb->data + CAPI_MSG_BASELEN + 6,
298 skb->data[CAPI_MSG_BASELEN + 5]);
299 }
300
301 break;
302 }
303
304 kfree_skb(skb);
305}
306
307void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb)
308{
309 struct capi_ctr *ctrl = &session->ctrl;
310 struct cmtp_application *application;
311 __u16 cmd, appl;
312 __u32 contr;
313
314 BT_DBG("session %p skb %p len %d", session, skb, skb->len);
315
316 if (CAPIMSG_COMMAND(skb->data) == CAPI_INTEROPERABILITY) {
317 cmtp_recv_interopmsg(session, skb);
318 return;
319 }
320
321 if (session->flags & (1 << CMTP_LOOPBACK)) {
322 kfree_skb(skb);
323 return;
324 }
325
326 cmd = CAPICMD(CAPIMSG_COMMAND(skb->data), CAPIMSG_SUBCOMMAND(skb->data));
327 appl = CAPIMSG_APPID(skb->data);
328 contr = CAPIMSG_CONTROL(skb->data);
329
330 application = cmtp_application_get(session, CMTP_MAPPING, appl);
331 if (application) {
332 appl = application->appl;
333 CAPIMSG_SETAPPID(skb->data, appl);
334 } else {
335 BT_ERR("Can't find application with id %d", appl);
336 kfree_skb(skb);
337 return;
338 }
339
340 if ((contr & 0x7f) == 0x01) {
341 contr = (contr & 0xffffff80) | session->num;
342 CAPIMSG_SETCONTROL(skb->data, contr);
343 }
344
345 if (!ctrl) {
346 BT_ERR("Can't find controller %d for message", session->num);
347 kfree_skb(skb);
348 return;
349 }
350
351 capi_ctr_handle_message(ctrl, appl, skb);
352}
353
354static int cmtp_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
355{
356 BT_DBG("ctrl %p data %p", ctrl, data);
357
358 return 0;
359}
360
361static void cmtp_reset_ctr(struct capi_ctr *ctrl)
362{
363 struct cmtp_session *session = ctrl->driverdata;
364
365 BT_DBG("ctrl %p", ctrl);
366
367 capi_ctr_reseted(ctrl);
368
369 atomic_inc(&session->terminate);
370 cmtp_schedule(session);
371}
372
373static void cmtp_register_appl(struct capi_ctr *ctrl, __u16 appl, capi_register_params *rp)
374{
375 DECLARE_WAITQUEUE(wait, current);
376 struct cmtp_session *session = ctrl->driverdata;
377 struct cmtp_application *application;
378 unsigned long timeo = CMTP_INTEROP_TIMEOUT;
379 unsigned char buf[8];
380 int err = 0, nconn, want = rp->level3cnt;
381
382 BT_DBG("ctrl %p appl %d level3cnt %d datablkcnt %d datablklen %d",
383 ctrl, appl, rp->level3cnt, rp->datablkcnt, rp->datablklen);
384
385 application = cmtp_application_add(session, appl);
386 if (!application) {
387 BT_ERR("Can't allocate memory for new application");
388 return;
389 }
390
391 if (want < 0)
392 nconn = ctrl->profile.nbchannel * -want;
393 else
394 nconn = want;
395
396 if (nconn == 0)
397 nconn = ctrl->profile.nbchannel;
398
399 capimsg_setu16(buf, 0, nconn);
400 capimsg_setu16(buf, 2, rp->datablkcnt);
401 capimsg_setu16(buf, 4, rp->datablklen);
402
403 application->state = BT_CONFIG;
404 application->msgnum = cmtp_msgnum_get(session);
405
406 cmtp_send_interopmsg(session, CAPI_REQ, 0x0000, application->msgnum,
407 CAPI_FUNCTION_REGISTER, buf, 6);
408
409 add_wait_queue(&session->wait, &wait);
410 while (1) {
411 set_current_state(TASK_INTERRUPTIBLE);
412
413 if (!timeo) {
414 err = -EAGAIN;
415 break;
416 }
417
418 if (application->state == BT_CLOSED) {
419 err = -application->err;
420 break;
421 }
422
423 if (application->state == BT_CONNECTED)
424 break;
425
426 if (signal_pending(current)) {
427 err = -EINTR;
428 break;
429 }
430
431 timeo = schedule_timeout(timeo);
432 }
433 set_current_state(TASK_RUNNING);
434 remove_wait_queue(&session->wait, &wait);
435
436 if (err) {
437 cmtp_application_del(session, application);
438 return;
439 }
440}
441
442static void cmtp_release_appl(struct capi_ctr *ctrl, __u16 appl)
443{
444 struct cmtp_session *session = ctrl->driverdata;
445 struct cmtp_application *application;
446
447 BT_DBG("ctrl %p appl %d", ctrl, appl);
448
449 application = cmtp_application_get(session, CMTP_APPLID, appl);
450 if (!application) {
451 BT_ERR("Can't find application");
452 return;
453 }
454
455 application->msgnum = cmtp_msgnum_get(session);
456
457 cmtp_send_interopmsg(session, CAPI_REQ, application->mapping, application->msgnum,
458 CAPI_FUNCTION_RELEASE, NULL, 0);
459
460 wait_event_interruptible_timeout(session->wait,
461 (application->state == BT_CLOSED), CMTP_INTEROP_TIMEOUT);
462
463 cmtp_application_del(session, application);
464}
465
466static u16 cmtp_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
467{
468 struct cmtp_session *session = ctrl->driverdata;
469 struct cmtp_application *application;
470 __u16 appl;
471 __u32 contr;
472
473 BT_DBG("ctrl %p skb %p", ctrl, skb);
474
475 appl = CAPIMSG_APPID(skb->data);
476 contr = CAPIMSG_CONTROL(skb->data);
477
478 application = cmtp_application_get(session, CMTP_APPLID, appl);
479 if ((!application) || (application->state != BT_CONNECTED)) {
480 BT_ERR("Can't find application with id %d", appl);
481 return CAPI_ILLAPPNR;
482 }
483
484 CAPIMSG_SETAPPID(skb->data, application->mapping);
485
486 if ((contr & 0x7f) == session->num) {
487 contr = (contr & 0xffffff80) | 0x01;
488 CAPIMSG_SETCONTROL(skb->data, contr);
489 }
490
491 cmtp_send_capimsg(session, skb);
492
493 return CAPI_NOERROR;
494}
495
496static char *cmtp_procinfo(struct capi_ctr *ctrl)
497{
498 return "CAPI Message Transport Protocol";
499}
500
501static int cmtp_ctr_read_proc(char *page, char **start, off_t off, int count, int *eof, struct capi_ctr *ctrl)
502{
503 struct cmtp_session *session = ctrl->driverdata;
504 struct cmtp_application *app;
505 struct list_head *p, *n;
506 int len = 0;
507
508 len += sprintf(page + len, "%s\n\n", cmtp_procinfo(ctrl));
509 len += sprintf(page + len, "addr %s\n", session->name);
510 len += sprintf(page + len, "ctrl %d\n", session->num);
511
512 list_for_each_safe(p, n, &session->applications) {
513 app = list_entry(p, struct cmtp_application, list);
514 len += sprintf(page + len, "appl %d -> %d\n", app->appl, app->mapping);
515 }
516
517 if (off + count >= len)
518 *eof = 1;
519
520 if (len < off)
521 return 0;
522
523 *start = page + off;
524
525 return ((count < len - off) ? count : len - off);
526}
527
528
529int cmtp_attach_device(struct cmtp_session *session)
530{
531 unsigned char buf[4];
532 long ret;
533
534 BT_DBG("session %p", session);
535
536 capimsg_setu32(buf, 0, 0);
537
538 cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, CMTP_INITIAL_MSGNUM,
539 CAPI_FUNCTION_GET_PROFILE, buf, 4);
540
541 ret = wait_event_interruptible_timeout(session->wait,
542 session->ncontroller, CMTP_INTEROP_TIMEOUT);
543
544 BT_INFO("Found %d CAPI controller(s) on device %s", session->ncontroller, session->name);
545
546 if (!ret)
547 return -ETIMEDOUT;
548
549 if (!session->ncontroller)
550 return -ENODEV;
551
552 if (session->ncontroller > 1)
553 BT_INFO("Setting up only CAPI controller 1");
554
555 session->ctrl.owner = THIS_MODULE;
556 session->ctrl.driverdata = session;
557 strcpy(session->ctrl.name, session->name);
558
559 session->ctrl.driver_name = "cmtp";
560 session->ctrl.load_firmware = cmtp_load_firmware;
561 session->ctrl.reset_ctr = cmtp_reset_ctr;
562 session->ctrl.register_appl = cmtp_register_appl;
563 session->ctrl.release_appl = cmtp_release_appl;
564 session->ctrl.send_message = cmtp_send_message;
565
566 session->ctrl.procinfo = cmtp_procinfo;
567 session->ctrl.ctr_read_proc = cmtp_ctr_read_proc;
568
569 if (attach_capi_ctr(&session->ctrl) < 0) {
570 BT_ERR("Can't attach new controller");
571 return -EBUSY;
572 }
573
574 session->num = session->ctrl.cnr;
575
576 BT_DBG("session %p num %d", session, session->num);
577
578 capimsg_setu32(buf, 0, 1);
579
580 cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
581 CAPI_FUNCTION_GET_MANUFACTURER, buf, 4);
582
583 cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
584 CAPI_FUNCTION_GET_VERSION, buf, 4);
585
586 cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
587 CAPI_FUNCTION_GET_SERIAL_NUMBER, buf, 4);
588
589 cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
590 CAPI_FUNCTION_GET_PROFILE, buf, 4);
591
592 return 0;
593}
594
595void cmtp_detach_device(struct cmtp_session *session)
596{
597 BT_DBG("session %p", session);
598
599 detach_capi_ctr(&session->ctrl);
600}
diff --git a/net/bluetooth/cmtp/cmtp.h b/net/bluetooth/cmtp/cmtp.h
new file mode 100644
index 000000000000..40e3dfec0cc8
--- /dev/null
+++ b/net/bluetooth/cmtp/cmtp.h
@@ -0,0 +1,135 @@
1/*
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
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#ifndef __CMTP_H
24#define __CMTP_H
25
26#include <linux/types.h>
27#include <net/bluetooth/bluetooth.h>
28
29#define BTNAMSIZ 18
30
31/* CMTP ioctl defines */
32#define CMTPCONNADD _IOW('C', 200, int)
33#define CMTPCONNDEL _IOW('C', 201, int)
34#define CMTPGETCONNLIST _IOR('C', 210, int)
35#define CMTPGETCONNINFO _IOR('C', 211, int)
36
37#define CMTP_LOOPBACK 0
38
39struct cmtp_connadd_req {
40 int sock; // Connected socket
41 __u32 flags;
42};
43
44struct cmtp_conndel_req {
45 bdaddr_t bdaddr;
46 __u32 flags;
47};
48
49struct cmtp_conninfo {
50 bdaddr_t bdaddr;
51 __u32 flags;
52 __u16 state;
53 int num;
54};
55
56struct cmtp_connlist_req {
57 __u32 cnum;
58 struct cmtp_conninfo __user *ci;
59};
60
61int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock);
62int cmtp_del_connection(struct cmtp_conndel_req *req);
63int cmtp_get_connlist(struct cmtp_connlist_req *req);
64int cmtp_get_conninfo(struct cmtp_conninfo *ci);
65
66/* CMTP session defines */
67#define CMTP_INTEROP_TIMEOUT (HZ * 5)
68#define CMTP_INITIAL_MSGNUM 0xff00
69
70struct cmtp_session {
71 struct list_head list;
72
73 struct socket *sock;
74
75 bdaddr_t bdaddr;
76
77 unsigned long state;
78 unsigned long flags;
79
80 uint mtu;
81
82 char name[BTNAMSIZ];
83
84 atomic_t terminate;
85
86 wait_queue_head_t wait;
87
88 int ncontroller;
89 int num;
90 struct capi_ctr ctrl;
91
92 struct list_head applications;
93
94 unsigned long blockids;
95 int msgnum;
96
97 struct sk_buff_head transmit;
98
99 struct sk_buff *reassembly[16];
100};
101
102struct cmtp_application {
103 struct list_head list;
104
105 unsigned long state;
106 int err;
107
108 __u16 appl;
109 __u16 mapping;
110
111 __u16 msgnum;
112};
113
114struct cmtp_scb {
115 int id;
116 int data;
117};
118
119int cmtp_attach_device(struct cmtp_session *session);
120void cmtp_detach_device(struct cmtp_session *session);
121
122void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb);
123
124static inline void cmtp_schedule(struct cmtp_session *session)
125{
126 struct sock *sk = session->sock->sk;
127
128 wake_up_interruptible(sk->sk_sleep);
129}
130
131/* CMTP init defines */
132int cmtp_init_sockets(void);
133void cmtp_cleanup_sockets(void);
134
135#endif /* __CMTP_H */
diff --git a/net/bluetooth/cmtp/core.c b/net/bluetooth/cmtp/core.c
new file mode 100644
index 000000000000..20ce04f2be8b
--- /dev/null
+++ b/net/bluetooth/cmtp/core.c
@@ -0,0 +1,504 @@
1/*
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
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/config.h>
24#include <linux/module.h>
25
26#include <linux/types.h>
27#include <linux/errno.h>
28#include <linux/kernel.h>
29#include <linux/major.h>
30#include <linux/sched.h>
31#include <linux/slab.h>
32#include <linux/poll.h>
33#include <linux/fcntl.h>
34#include <linux/skbuff.h>
35#include <linux/socket.h>
36#include <linux/ioctl.h>
37#include <linux/file.h>
38#include <linux/init.h>
39#include <net/sock.h>
40
41#include <linux/isdn/capilli.h>
42
43#include <net/bluetooth/bluetooth.h>
44#include <net/bluetooth/l2cap.h>
45
46#include "cmtp.h"
47
48#ifndef CONFIG_BT_CMTP_DEBUG
49#undef BT_DBG
50#define BT_DBG(D...)
51#endif
52
53#define VERSION "1.0"
54
55static DECLARE_RWSEM(cmtp_session_sem);
56static LIST_HEAD(cmtp_session_list);
57
58static struct cmtp_session *__cmtp_get_session(bdaddr_t *bdaddr)
59{
60 struct cmtp_session *session;
61 struct list_head *p;
62
63 BT_DBG("");
64
65 list_for_each(p, &cmtp_session_list) {
66 session = list_entry(p, struct cmtp_session, list);
67 if (!bacmp(bdaddr, &session->bdaddr))
68 return session;
69 }
70 return NULL;
71}
72
73static void __cmtp_link_session(struct cmtp_session *session)
74{
75 __module_get(THIS_MODULE);
76 list_add(&session->list, &cmtp_session_list);
77}
78
79static void __cmtp_unlink_session(struct cmtp_session *session)
80{
81 list_del(&session->list);
82 module_put(THIS_MODULE);
83}
84
85static void __cmtp_copy_session(struct cmtp_session *session, struct cmtp_conninfo *ci)
86{
87 bacpy(&ci->bdaddr, &session->bdaddr);
88
89 ci->flags = session->flags;
90 ci->state = session->state;
91
92 ci->num = session->num;
93}
94
95
96static inline int cmtp_alloc_block_id(struct cmtp_session *session)
97{
98 int i, id = -1;
99
100 for (i = 0; i < 16; i++)
101 if (!test_and_set_bit(i, &session->blockids)) {
102 id = i;
103 break;
104 }
105
106 return id;
107}
108
109static inline void cmtp_free_block_id(struct cmtp_session *session, int id)
110{
111 clear_bit(id, &session->blockids);
112}
113
114static inline void cmtp_add_msgpart(struct cmtp_session *session, int id, const unsigned char *buf, int count)
115{
116 struct sk_buff *skb = session->reassembly[id], *nskb;
117 int size;
118
119 BT_DBG("session %p buf %p count %d", session, buf, count);
120
121 size = (skb) ? skb->len + count : count;
122
123 if (!(nskb = alloc_skb(size, GFP_ATOMIC))) {
124 BT_ERR("Can't allocate memory for CAPI message");
125 return;
126 }
127
128 if (skb && (skb->len > 0))
129 memcpy(skb_put(nskb, skb->len), skb->data, skb->len);
130
131 memcpy(skb_put(nskb, count), buf, count);
132
133 session->reassembly[id] = nskb;
134
135 if (skb)
136 kfree_skb(skb);
137}
138
139static inline int cmtp_recv_frame(struct cmtp_session *session, struct sk_buff *skb)
140{
141 __u8 hdr, hdrlen, id;
142 __u16 len;
143
144 BT_DBG("session %p skb %p len %d", session, skb, skb->len);
145
146 while (skb->len > 0) {
147 hdr = skb->data[0];
148
149 switch (hdr & 0xc0) {
150 case 0x40:
151 hdrlen = 2;
152 len = skb->data[1];
153 break;
154 case 0x80:
155 hdrlen = 3;
156 len = skb->data[1] | (skb->data[2] << 8);
157 break;
158 default:
159 hdrlen = 1;
160 len = 0;
161 break;
162 }
163
164 id = (hdr & 0x3c) >> 2;
165
166 BT_DBG("hdr 0x%02x hdrlen %d len %d id %d", hdr, hdrlen, len, id);
167
168 if (hdrlen + len > skb->len) {
169 BT_ERR("Wrong size or header information in CMTP frame");
170 break;
171 }
172
173 if (len == 0) {
174 skb_pull(skb, hdrlen);
175 continue;
176 }
177
178 switch (hdr & 0x03) {
179 case 0x00:
180 cmtp_add_msgpart(session, id, skb->data + hdrlen, len);
181 cmtp_recv_capimsg(session, session->reassembly[id]);
182 session->reassembly[id] = NULL;
183 break;
184 case 0x01:
185 cmtp_add_msgpart(session, id, skb->data + hdrlen, len);
186 break;
187 default:
188 if (session->reassembly[id] != NULL)
189 kfree_skb(session->reassembly[id]);
190 session->reassembly[id] = NULL;
191 break;
192 }
193
194 skb_pull(skb, hdrlen + len);
195 }
196
197 kfree_skb(skb);
198 return 0;
199}
200
201static int cmtp_send_frame(struct cmtp_session *session, unsigned char *data, int len)
202{
203 struct socket *sock = session->sock;
204 struct kvec iv = { data, len };
205 struct msghdr msg;
206
207 BT_DBG("session %p data %p len %d", session, data, len);
208
209 if (!len)
210 return 0;
211
212 memset(&msg, 0, sizeof(msg));
213
214 return kernel_sendmsg(sock, &msg, &iv, 1, len);
215}
216
217static int cmtp_process_transmit(struct cmtp_session *session)
218{
219 struct sk_buff *skb, *nskb;
220 unsigned char *hdr;
221 unsigned int size, tail;
222
223 BT_DBG("session %p", session);
224
225 if (!(nskb = alloc_skb(session->mtu, GFP_ATOMIC))) {
226 BT_ERR("Can't allocate memory for new frame");
227 return -ENOMEM;
228 }
229
230 while ((skb = skb_dequeue(&session->transmit))) {
231 struct cmtp_scb *scb = (void *) skb->cb;
232
233 if ((tail = (session->mtu - nskb->len)) < 5) {
234 cmtp_send_frame(session, nskb->data, nskb->len);
235 skb_trim(nskb, 0);
236 tail = session->mtu;
237 }
238
239 size = min_t(uint, ((tail < 258) ? (tail - 2) : (tail - 3)), skb->len);
240
241 if ((scb->id < 0) && ((scb->id = cmtp_alloc_block_id(session)) < 0)) {
242 skb_queue_head(&session->transmit, skb);
243 break;
244 }
245
246 if (size < 256) {
247 hdr = skb_put(nskb, 2);
248 hdr[0] = 0x40
249 | ((scb->id << 2) & 0x3c)
250 | ((skb->len == size) ? 0x00 : 0x01);
251 hdr[1] = size;
252 } else {
253 hdr = skb_put(nskb, 3);
254 hdr[0] = 0x80
255 | ((scb->id << 2) & 0x3c)
256 | ((skb->len == size) ? 0x00 : 0x01);
257 hdr[1] = size & 0xff;
258 hdr[2] = size >> 8;
259 }
260
261 memcpy(skb_put(nskb, size), skb->data, size);
262 skb_pull(skb, size);
263
264 if (skb->len > 0) {
265 skb_queue_head(&session->transmit, skb);
266 } else {
267 cmtp_free_block_id(session, scb->id);
268 if (scb->data) {
269 cmtp_send_frame(session, nskb->data, nskb->len);
270 skb_trim(nskb, 0);
271 }
272 kfree_skb(skb);
273 }
274 }
275
276 cmtp_send_frame(session, nskb->data, nskb->len);
277
278 kfree_skb(nskb);
279
280 return skb_queue_len(&session->transmit);
281}
282
283static int cmtp_session(void *arg)
284{
285 struct cmtp_session *session = arg;
286 struct sock *sk = session->sock->sk;
287 struct sk_buff *skb;
288 wait_queue_t wait;
289
290 BT_DBG("session %p", session);
291
292 daemonize("kcmtpd_ctr_%d", session->num);
293 set_user_nice(current, -15);
294 current->flags |= PF_NOFREEZE;
295
296 init_waitqueue_entry(&wait, current);
297 add_wait_queue(sk->sk_sleep, &wait);
298 while (!atomic_read(&session->terminate)) {
299 set_current_state(TASK_INTERRUPTIBLE);
300
301 if (sk->sk_state != BT_CONNECTED)
302 break;
303
304 while ((skb = skb_dequeue(&sk->sk_receive_queue))) {
305 skb_orphan(skb);
306 cmtp_recv_frame(session, skb);
307 }
308
309 cmtp_process_transmit(session);
310
311 schedule();
312 }
313 set_current_state(TASK_RUNNING);
314 remove_wait_queue(sk->sk_sleep, &wait);
315
316 down_write(&cmtp_session_sem);
317
318 if (!(session->flags & (1 << CMTP_LOOPBACK)))
319 cmtp_detach_device(session);
320
321 fput(session->sock->file);
322
323 __cmtp_unlink_session(session);
324
325 up_write(&cmtp_session_sem);
326
327 kfree(session);
328 return 0;
329}
330
331int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock)
332{
333 struct cmtp_session *session, *s;
334 bdaddr_t src, dst;
335 int i, err;
336
337 BT_DBG("");
338
339 baswap(&src, &bt_sk(sock->sk)->src);
340 baswap(&dst, &bt_sk(sock->sk)->dst);
341
342 session = kmalloc(sizeof(struct cmtp_session), GFP_KERNEL);
343 if (!session)
344 return -ENOMEM;
345 memset(session, 0, sizeof(struct cmtp_session));
346
347 down_write(&cmtp_session_sem);
348
349 s = __cmtp_get_session(&bt_sk(sock->sk)->dst);
350 if (s && s->state == BT_CONNECTED) {
351 err = -EEXIST;
352 goto failed;
353 }
354
355 bacpy(&session->bdaddr, &bt_sk(sock->sk)->dst);
356
357 session->mtu = min_t(uint, l2cap_pi(sock->sk)->omtu, l2cap_pi(sock->sk)->imtu);
358
359 BT_DBG("mtu %d", session->mtu);
360
361 sprintf(session->name, "%s", batostr(&dst));
362
363 session->sock = sock;
364 session->state = BT_CONFIG;
365
366 init_waitqueue_head(&session->wait);
367
368 session->msgnum = CMTP_INITIAL_MSGNUM;
369
370 INIT_LIST_HEAD(&session->applications);
371
372 skb_queue_head_init(&session->transmit);
373
374 for (i = 0; i < 16; i++)
375 session->reassembly[i] = NULL;
376
377 session->flags = req->flags;
378
379 __cmtp_link_session(session);
380
381 err = kernel_thread(cmtp_session, session, CLONE_KERNEL);
382 if (err < 0)
383 goto unlink;
384
385 if (!(session->flags & (1 << CMTP_LOOPBACK))) {
386 err = cmtp_attach_device(session);
387 if (err < 0)
388 goto detach;
389 }
390
391 up_write(&cmtp_session_sem);
392 return 0;
393
394detach:
395 cmtp_detach_device(session);
396
397unlink:
398 __cmtp_unlink_session(session);
399
400failed:
401 up_write(&cmtp_session_sem);
402 kfree(session);
403 return err;
404}
405
406int cmtp_del_connection(struct cmtp_conndel_req *req)
407{
408 struct cmtp_session *session;
409 int err = 0;
410
411 BT_DBG("");
412
413 down_read(&cmtp_session_sem);
414
415 session = __cmtp_get_session(&req->bdaddr);
416 if (session) {
417 /* Flush the transmit queue */
418 skb_queue_purge(&session->transmit);
419
420 /* Kill session thread */
421 atomic_inc(&session->terminate);
422 cmtp_schedule(session);
423 } else
424 err = -ENOENT;
425
426 up_read(&cmtp_session_sem);
427 return err;
428}
429
430int cmtp_get_connlist(struct cmtp_connlist_req *req)
431{
432 struct list_head *p;
433 int err = 0, n = 0;
434
435 BT_DBG("");
436
437 down_read(&cmtp_session_sem);
438
439 list_for_each(p, &cmtp_session_list) {
440 struct cmtp_session *session;
441 struct cmtp_conninfo ci;
442
443 session = list_entry(p, struct cmtp_session, list);
444
445 __cmtp_copy_session(session, &ci);
446
447 if (copy_to_user(req->ci, &ci, sizeof(ci))) {
448 err = -EFAULT;
449 break;
450 }
451
452 if (++n >= req->cnum)
453 break;
454
455 req->ci++;
456 }
457 req->cnum = n;
458
459 up_read(&cmtp_session_sem);
460 return err;
461}
462
463int cmtp_get_conninfo(struct cmtp_conninfo *ci)
464{
465 struct cmtp_session *session;
466 int err = 0;
467
468 down_read(&cmtp_session_sem);
469
470 session = __cmtp_get_session(&ci->bdaddr);
471 if (session)
472 __cmtp_copy_session(session, ci);
473 else
474 err = -ENOENT;
475
476 up_read(&cmtp_session_sem);
477 return err;
478}
479
480
481static int __init cmtp_init(void)
482{
483 l2cap_load();
484
485 BT_INFO("CMTP (CAPI Emulation) ver %s", VERSION);
486
487 cmtp_init_sockets();
488
489 return 0;
490}
491
492static void __exit cmtp_exit(void)
493{
494 cmtp_cleanup_sockets();
495}
496
497module_init(cmtp_init);
498module_exit(cmtp_exit);
499
500MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
501MODULE_DESCRIPTION("Bluetooth CMTP ver " VERSION);
502MODULE_VERSION(VERSION);
503MODULE_LICENSE("GPL");
504MODULE_ALIAS("bt-proto-5");
diff --git a/net/bluetooth/cmtp/sock.c b/net/bluetooth/cmtp/sock.c
new file mode 100644
index 000000000000..4c7f9e20dade
--- /dev/null
+++ b/net/bluetooth/cmtp/sock.c
@@ -0,0 +1,226 @@
1/*
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
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/config.h>
24#include <linux/module.h>
25
26#include <linux/types.h>
27#include <linux/errno.h>
28#include <linux/kernel.h>
29#include <linux/major.h>
30#include <linux/sched.h>
31#include <linux/slab.h>
32#include <linux/poll.h>
33#include <linux/fcntl.h>
34#include <linux/skbuff.h>
35#include <linux/socket.h>
36#include <linux/ioctl.h>
37#include <linux/file.h>
38#include <net/sock.h>
39
40#include <linux/isdn/capilli.h>
41
42#include <asm/system.h>
43#include <asm/uaccess.h>
44
45#include "cmtp.h"
46
47#ifndef CONFIG_BT_CMTP_DEBUG
48#undef BT_DBG
49#define BT_DBG(D...)
50#endif
51
52static int cmtp_sock_release(struct socket *sock)
53{
54 struct sock *sk = sock->sk;
55
56 BT_DBG("sock %p sk %p", sock, sk);
57
58 if (!sk)
59 return 0;
60
61 sock_orphan(sk);
62 sock_put(sk);
63
64 return 0;
65}
66
67static int cmtp_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
68{
69 struct cmtp_connadd_req ca;
70 struct cmtp_conndel_req cd;
71 struct cmtp_connlist_req cl;
72 struct cmtp_conninfo ci;
73 struct socket *nsock;
74 void __user *argp = (void __user *)arg;
75 int err;
76
77 BT_DBG("cmd %x arg %lx", cmd, arg);
78
79 switch (cmd) {
80 case CMTPCONNADD:
81 if (!capable(CAP_NET_ADMIN))
82 return -EACCES;
83
84 if (copy_from_user(&ca, argp, sizeof(ca)))
85 return -EFAULT;
86
87 nsock = sockfd_lookup(ca.sock, &err);
88 if (!nsock)
89 return err;
90
91 if (nsock->sk->sk_state != BT_CONNECTED) {
92 fput(nsock->file);
93 return -EBADFD;
94 }
95
96 err = cmtp_add_connection(&ca, nsock);
97 if (!err) {
98 if (copy_to_user(argp, &ca, sizeof(ca)))
99 err = -EFAULT;
100 } else
101 fput(nsock->file);
102
103 return err;
104
105 case CMTPCONNDEL:
106 if (!capable(CAP_NET_ADMIN))
107 return -EACCES;
108
109 if (copy_from_user(&cd, argp, sizeof(cd)))
110 return -EFAULT;
111
112 return cmtp_del_connection(&cd);
113
114 case CMTPGETCONNLIST:
115 if (copy_from_user(&cl, argp, sizeof(cl)))
116 return -EFAULT;
117
118 if (cl.cnum <= 0)
119 return -EINVAL;
120
121 err = cmtp_get_connlist(&cl);
122 if (!err && copy_to_user(argp, &cl, sizeof(cl)))
123 return -EFAULT;
124
125 return err;
126
127 case CMTPGETCONNINFO:
128 if (copy_from_user(&ci, argp, sizeof(ci)))
129 return -EFAULT;
130
131 err = cmtp_get_conninfo(&ci);
132 if (!err && copy_to_user(argp, &ci, sizeof(ci)))
133 return -EFAULT;
134
135 return err;
136 }
137
138 return -EINVAL;
139}
140
141static struct proto_ops cmtp_sock_ops = {
142 .family = PF_BLUETOOTH,
143 .owner = THIS_MODULE,
144 .release = cmtp_sock_release,
145 .ioctl = cmtp_sock_ioctl,
146 .bind = sock_no_bind,
147 .getname = sock_no_getname,
148 .sendmsg = sock_no_sendmsg,
149 .recvmsg = sock_no_recvmsg,
150 .poll = sock_no_poll,
151 .listen = sock_no_listen,
152 .shutdown = sock_no_shutdown,
153 .setsockopt = sock_no_setsockopt,
154 .getsockopt = sock_no_getsockopt,
155 .connect = sock_no_connect,
156 .socketpair = sock_no_socketpair,
157 .accept = sock_no_accept,
158 .mmap = sock_no_mmap
159};
160
161static struct proto cmtp_proto = {
162 .name = "CMTP",
163 .owner = THIS_MODULE,
164 .obj_size = sizeof(struct bt_sock)
165};
166
167static int cmtp_sock_create(struct socket *sock, int protocol)
168{
169 struct sock *sk;
170
171 BT_DBG("sock %p", sock);
172
173 if (sock->type != SOCK_RAW)
174 return -ESOCKTNOSUPPORT;
175
176 sk = sk_alloc(PF_BLUETOOTH, GFP_KERNEL, &cmtp_proto, 1);
177 if (!sk)
178 return -ENOMEM;
179
180 sock_init_data(sock, sk);
181
182 sock->ops = &cmtp_sock_ops;
183
184 sock->state = SS_UNCONNECTED;
185
186 sock_reset_flag(sk, SOCK_ZAPPED);
187
188 sk->sk_protocol = protocol;
189 sk->sk_state = BT_OPEN;
190
191 return 0;
192}
193
194static struct net_proto_family cmtp_sock_family_ops = {
195 .family = PF_BLUETOOTH,
196 .owner = THIS_MODULE,
197 .create = cmtp_sock_create
198};
199
200int cmtp_init_sockets(void)
201{
202 int err;
203
204 err = proto_register(&cmtp_proto, 0);
205 if (err < 0)
206 return err;
207
208 err = bt_sock_register(BTPROTO_CMTP, &cmtp_sock_family_ops);
209 if (err < 0)
210 goto error;
211
212 return 0;
213
214error:
215 BT_ERR("Can't register CMTP socket");
216 proto_unregister(&cmtp_proto);
217 return err;
218}
219
220void cmtp_cleanup_sockets(void)
221{
222 if (bt_sock_unregister(BTPROTO_CMTP) < 0)
223 BT_ERR("Can't unregister CMTP socket");
224
225 proto_unregister(&cmtp_proto);
226}