]> git.karo-electronics.de Git - karo-tx-linux.git/blob - net/bluetooth/cmtp/capi.c
Merge branch 'x86-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[karo-tx-linux.git] / net / bluetooth / cmtp / capi.c
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/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.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;
104
105         list_for_each(p, &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                         if (!info && ctrl) {
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);
261                                 strncpy(ctrl->manu,
262                                         skb->data + CAPI_MSG_BASELEN + 15, len);
263                         }
264
265                         break;
266
267                 case CAPI_FUNCTION_GET_VERSION:
268                         if (skb->len < CAPI_MSG_BASELEN + 32)
269                                 break;
270
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:
281                         if (skb->len < CAPI_MSG_BASELEN + 17)
282                                 break;
283
284                         if (!info && ctrl) {
285                                 int len = min_t(uint, CAPI_SERIAL_LEN,
286                                                 skb->data[CAPI_MSG_BASELEN + 16]);
287
288                                 memset(ctrl->serial, 0, CAPI_SERIAL_LEN);
289                                 strncpy(ctrl->serial,
290                                         skb->data + CAPI_MSG_BASELEN + 17, len);
291                         }
292
293                         break;
294                 }
295
296                 break;
297
298         case CAPI_IND:
299                 if (skb->len < CAPI_MSG_BASELEN + 6)
300                         break;
301
302                 func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 3);
303
304                 if (func == CAPI_FUNCTION_LOOPBACK) {
305                         int len = min_t(uint, skb->len - CAPI_MSG_BASELEN - 6,
306                                                 skb->data[CAPI_MSG_BASELEN + 5]);
307                         appl = CAPIMSG_APPID(skb->data);
308                         msgnum = CAPIMSG_MSGID(skb->data);
309                         cmtp_send_interopmsg(session, CAPI_RESP, appl, msgnum, func,
310                                                 skb->data + CAPI_MSG_BASELEN + 6, len);
311                 }
312
313                 break;
314         }
315
316         kfree_skb(skb);
317 }
318
319 void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb)
320 {
321         struct capi_ctr *ctrl = &session->ctrl;
322         struct cmtp_application *application;
323         __u16 appl;
324         __u32 contr;
325
326         BT_DBG("session %p skb %p len %d", session, skb, skb->len);
327
328         if (skb->len < CAPI_MSG_BASELEN)
329                 return;
330
331         if (CAPIMSG_COMMAND(skb->data) == CAPI_INTEROPERABILITY) {
332                 cmtp_recv_interopmsg(session, skb);
333                 return;
334         }
335
336         if (session->flags & BIT(CMTP_LOOPBACK)) {
337                 kfree_skb(skb);
338                 return;
339         }
340
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
359         capi_ctr_handle_message(ctrl, appl, skb);
360 }
361
362 static 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
369 static void cmtp_reset_ctr(struct capi_ctr *ctrl)
370 {
371         struct cmtp_session *session = ctrl->driverdata;
372
373         BT_DBG("ctrl %p", ctrl);
374
375         capi_ctr_down(ctrl);
376
377         atomic_inc(&session->terminate);
378         wake_up_process(session->task);
379 }
380
381 static 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
450 static 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
474 static 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
504 static char *cmtp_procinfo(struct capi_ctr *ctrl)
505 {
506         return "CAPI Message Transport Protocol";
507 }
508
509 static int cmtp_proc_show(struct seq_file *m, void *v)
510 {
511         struct capi_ctr *ctrl = m->private;
512         struct cmtp_session *session = ctrl->driverdata;
513         struct cmtp_application *app;
514         struct list_head *p;
515
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);
519
520         list_for_each(p, &session->applications) {
521                 app = list_entry(p, struct cmtp_application, list);
522                 seq_printf(m, "appl %d -> %d\n", app->appl, app->mapping);
523         }
524
525         return 0;
526 }
527
528 static int cmtp_proc_open(struct inode *inode, struct file *file)
529 {
530         return single_open(file, cmtp_proc_show, PDE_DATA(inode));
531 }
532
533 static 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 };
540
541 int 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);
555
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;
579         session->ctrl.proc_fops = &cmtp_proc_fops;
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
607 void cmtp_detach_device(struct cmtp_session *session)
608 {
609         BT_DBG("session %p", session);
610
611         detach_capi_ctr(&session->ctrl);
612 }