proc_fops: convert drivers/isdn/ to seq_file
[safe/jmp/linux-2.6] / 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/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 <net/sock.h>
39
40 #include <linux/isdn/capilli.h>
41 #include <linux/isdn/capicmd.h>
42 #include <linux/isdn/capiutil.h>
43
44 #include "cmtp.h"
45
46 #define CAPI_INTEROPERABILITY           0x20
47
48 #define CAPI_INTEROPERABILITY_REQ       CAPICMD(CAPI_INTEROPERABILITY, CAPI_REQ)
49 #define CAPI_INTEROPERABILITY_CONF      CAPICMD(CAPI_INTEROPERABILITY, CAPI_CONF)
50 #define CAPI_INTEROPERABILITY_IND       CAPICMD(CAPI_INTEROPERABILITY, CAPI_IND)
51 #define CAPI_INTEROPERABILITY_RESP      CAPICMD(CAPI_INTEROPERABILITY, CAPI_RESP)
52
53 #define CAPI_INTEROPERABILITY_REQ_LEN   (CAPI_MSG_BASELEN + 2)
54 #define CAPI_INTEROPERABILITY_CONF_LEN  (CAPI_MSG_BASELEN + 4)
55 #define CAPI_INTEROPERABILITY_IND_LEN   (CAPI_MSG_BASELEN + 2)
56 #define CAPI_INTEROPERABILITY_RESP_LEN  (CAPI_MSG_BASELEN + 2)
57
58 #define CAPI_FUNCTION_REGISTER          0
59 #define CAPI_FUNCTION_RELEASE           1
60 #define CAPI_FUNCTION_GET_PROFILE       2
61 #define CAPI_FUNCTION_GET_MANUFACTURER  3
62 #define CAPI_FUNCTION_GET_VERSION       4
63 #define CAPI_FUNCTION_GET_SERIAL_NUMBER 5
64 #define CAPI_FUNCTION_MANUFACTURER      6
65 #define CAPI_FUNCTION_LOOPBACK          7
66
67
68 #define CMTP_MSGNUM     1
69 #define CMTP_APPLID     2
70 #define CMTP_MAPPING    3
71
72 static struct cmtp_application *cmtp_application_add(struct cmtp_session *session, __u16 appl)
73 {
74         struct cmtp_application *app = kzalloc(sizeof(*app), GFP_KERNEL);
75
76         BT_DBG("session %p application %p appl %d", session, app, appl);
77
78         if (!app)
79                 return NULL;
80
81         app->state = BT_OPEN;
82         app->appl = appl;
83
84         list_add_tail(&app->list, &session->applications);
85
86         return app;
87 }
88
89 static void cmtp_application_del(struct cmtp_session *session, struct cmtp_application *app)
90 {
91         BT_DBG("session %p application %p", session, app);
92
93         if (app) {
94                 list_del(&app->list);
95                 kfree(app);
96         }
97 }
98
99 static struct cmtp_application *cmtp_application_get(struct cmtp_session *session, int pattern, __u16 value)
100 {
101         struct cmtp_application *app;
102         struct list_head *p, *n;
103
104         list_for_each_safe(p, n, &session->applications) {
105                 app = list_entry(p, struct cmtp_application, list);
106                 switch (pattern) {
107                 case CMTP_MSGNUM:
108                         if (app->msgnum == value)
109                                 return app;
110                         break;
111                 case CMTP_APPLID:
112                         if (app->appl == value)
113                                 return app;
114                         break;
115                 case CMTP_MAPPING:
116                         if (app->mapping == value)
117                                 return app;
118                         break;
119                 }
120         }
121
122         return NULL;
123 }
124
125 static int cmtp_msgnum_get(struct cmtp_session *session)
126 {
127         session->msgnum++;
128
129         if ((session->msgnum & 0xff) > 200)
130                 session->msgnum = CMTP_INITIAL_MSGNUM + 1;
131
132         return session->msgnum;
133 }
134
135 static void cmtp_send_capimsg(struct cmtp_session *session, struct sk_buff *skb)
136 {
137         struct cmtp_scb *scb = (void *) skb->cb;
138
139         BT_DBG("session %p skb %p len %d", session, skb, skb->len);
140
141         scb->id = -1;
142         scb->data = (CAPIMSG_COMMAND(skb->data) == CAPI_DATA_B3);
143
144         skb_queue_tail(&session->transmit, skb);
145
146         cmtp_schedule(session);
147 }
148
149 static void cmtp_send_interopmsg(struct cmtp_session *session,
150                                         __u8 subcmd, __u16 appl, __u16 msgnum,
151                                         __u16 function, unsigned char *buf, int len)
152 {
153         struct sk_buff *skb;
154         unsigned char *s;
155
156         BT_DBG("session %p subcmd 0x%02x appl %d msgnum %d", session, subcmd, appl, msgnum);
157
158         if (!(skb = alloc_skb(CAPI_MSG_BASELEN + 6 + len, GFP_ATOMIC))) {
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 %d", 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 (skb->len < CAPI_MSG_BASELEN + 15)
252                                 break;
253
254                         controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 10);
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                         controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 12);
272
273                         if (!info && ctrl) {
274                                 ctrl->version.majorversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 16);
275                                 ctrl->version.minorversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 20);
276                                 ctrl->version.majormanuversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 24);
277                                 ctrl->version.minormanuversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 28);
278                         }
279
280                         break;
281
282                 case CAPI_FUNCTION_GET_SERIAL_NUMBER:
283                         if (skb->len < CAPI_MSG_BASELEN + 17)
284                                 break;
285
286                         controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 12);
287
288                         if (!info && ctrl) {
289                                 int len = min_t(uint, CAPI_SERIAL_LEN,
290                                                 skb->data[CAPI_MSG_BASELEN + 16]);
291
292                                 memset(ctrl->serial, 0, CAPI_SERIAL_LEN);
293                                 strncpy(ctrl->serial,
294                                         skb->data + CAPI_MSG_BASELEN + 17, len);
295                         }
296
297                         break;
298                 }
299
300                 break;
301
302         case CAPI_IND:
303                 if (skb->len < CAPI_MSG_BASELEN + 6)
304                         break;
305
306                 func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 3);
307
308                 if (func == CAPI_FUNCTION_LOOPBACK) {
309                         int len = min_t(uint, skb->len - CAPI_MSG_BASELEN - 6,
310                                                 skb->data[CAPI_MSG_BASELEN + 5]);
311                         appl = CAPIMSG_APPID(skb->data);
312                         msgnum = CAPIMSG_MSGID(skb->data);
313                         cmtp_send_interopmsg(session, CAPI_RESP, appl, msgnum, func,
314                                                 skb->data + CAPI_MSG_BASELEN + 6, len);
315                 }
316
317                 break;
318         }
319
320         kfree_skb(skb);
321 }
322
323 void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb)
324 {
325         struct capi_ctr *ctrl = &session->ctrl;
326         struct cmtp_application *application;
327         __u16 cmd, appl;
328         __u32 contr;
329
330         BT_DBG("session %p skb %p len %d", session, skb, skb->len);
331
332         if (skb->len < CAPI_MSG_BASELEN)
333                 return;
334
335         if (CAPIMSG_COMMAND(skb->data) == CAPI_INTEROPERABILITY) {
336                 cmtp_recv_interopmsg(session, skb);
337                 return;
338         }
339
340         if (session->flags & (1 << CMTP_LOOPBACK)) {
341                 kfree_skb(skb);
342                 return;
343         }
344
345         cmd = CAPICMD(CAPIMSG_COMMAND(skb->data), CAPIMSG_SUBCOMMAND(skb->data));
346         appl = CAPIMSG_APPID(skb->data);
347         contr = CAPIMSG_CONTROL(skb->data);
348
349         application = cmtp_application_get(session, CMTP_MAPPING, appl);
350         if (application) {
351                 appl = application->appl;
352                 CAPIMSG_SETAPPID(skb->data, appl);
353         } else {
354                 BT_ERR("Can't find application with id %d", appl);
355                 kfree_skb(skb);
356                 return;
357         }
358
359         if ((contr & 0x7f) == 0x01) {
360                 contr = (contr & 0xffffff80) | session->num;
361                 CAPIMSG_SETCONTROL(skb->data, contr);
362         }
363
364         if (!ctrl) {
365                 BT_ERR("Can't find controller %d for message", session->num);
366                 kfree_skb(skb);
367                 return;
368         }
369
370         capi_ctr_handle_message(ctrl, appl, skb);
371 }
372
373 static int cmtp_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
374 {
375         BT_DBG("ctrl %p data %p", ctrl, data);
376
377         return 0;
378 }
379
380 static void cmtp_reset_ctr(struct capi_ctr *ctrl)
381 {
382         struct cmtp_session *session = ctrl->driverdata;
383
384         BT_DBG("ctrl %p", ctrl);
385
386         capi_ctr_down(ctrl);
387
388         atomic_inc(&session->terminate);
389         cmtp_schedule(session);
390 }
391
392 static void cmtp_register_appl(struct capi_ctr *ctrl, __u16 appl, capi_register_params *rp)
393 {
394         DECLARE_WAITQUEUE(wait, current);
395         struct cmtp_session *session = ctrl->driverdata;
396         struct cmtp_application *application;
397         unsigned long timeo = CMTP_INTEROP_TIMEOUT;
398         unsigned char buf[8];
399         int err = 0, nconn, want = rp->level3cnt;
400
401         BT_DBG("ctrl %p appl %d level3cnt %d datablkcnt %d datablklen %d",
402                 ctrl, appl, rp->level3cnt, rp->datablkcnt, rp->datablklen);
403
404         application = cmtp_application_add(session, appl);
405         if (!application) {
406                 BT_ERR("Can't allocate memory for new application");
407                 return;
408         }
409
410         if (want < 0)
411                 nconn = ctrl->profile.nbchannel * -want;
412         else
413                 nconn = want;
414
415         if (nconn == 0)
416                 nconn = ctrl->profile.nbchannel;
417
418         capimsg_setu16(buf, 0, nconn);
419         capimsg_setu16(buf, 2, rp->datablkcnt);
420         capimsg_setu16(buf, 4, rp->datablklen);
421
422         application->state = BT_CONFIG;
423         application->msgnum = cmtp_msgnum_get(session);
424
425         cmtp_send_interopmsg(session, CAPI_REQ, 0x0000, application->msgnum,
426                                 CAPI_FUNCTION_REGISTER, buf, 6);
427
428         add_wait_queue(&session->wait, &wait);
429         while (1) {
430                 set_current_state(TASK_INTERRUPTIBLE);
431
432                 if (!timeo) {
433                         err = -EAGAIN;
434                         break;
435                 }
436
437                 if (application->state == BT_CLOSED) {
438                         err = -application->err;
439                         break;
440                 }
441
442                 if (application->state == BT_CONNECTED)
443                         break;
444
445                 if (signal_pending(current)) {
446                         err = -EINTR;
447                         break;
448                 }
449
450                 timeo = schedule_timeout(timeo);
451         }
452         set_current_state(TASK_RUNNING);
453         remove_wait_queue(&session->wait, &wait);
454
455         if (err) {
456                 cmtp_application_del(session, application);
457                 return;
458         }
459 }
460
461 static void cmtp_release_appl(struct capi_ctr *ctrl, __u16 appl)
462 {
463         struct cmtp_session *session = ctrl->driverdata;
464         struct cmtp_application *application;
465
466         BT_DBG("ctrl %p appl %d", ctrl, appl);
467
468         application = cmtp_application_get(session, CMTP_APPLID, appl);
469         if (!application) {
470                 BT_ERR("Can't find application");
471                 return;
472         }
473
474         application->msgnum = cmtp_msgnum_get(session);
475
476         cmtp_send_interopmsg(session, CAPI_REQ, application->mapping, application->msgnum,
477                                 CAPI_FUNCTION_RELEASE, NULL, 0);
478
479         wait_event_interruptible_timeout(session->wait,
480                         (application->state == BT_CLOSED), CMTP_INTEROP_TIMEOUT);
481
482         cmtp_application_del(session, application);
483 }
484
485 static u16 cmtp_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
486 {
487         struct cmtp_session *session = ctrl->driverdata;
488         struct cmtp_application *application;
489         __u16 appl;
490         __u32 contr;
491
492         BT_DBG("ctrl %p skb %p", ctrl, skb);
493
494         appl = CAPIMSG_APPID(skb->data);
495         contr = CAPIMSG_CONTROL(skb->data);
496
497         application = cmtp_application_get(session, CMTP_APPLID, appl);
498         if ((!application) || (application->state != BT_CONNECTED)) {
499                 BT_ERR("Can't find application with id %d", appl);
500                 return CAPI_ILLAPPNR;
501         }
502
503         CAPIMSG_SETAPPID(skb->data, application->mapping);
504
505         if ((contr & 0x7f) == session->num) {
506                 contr = (contr & 0xffffff80) | 0x01;
507                 CAPIMSG_SETCONTROL(skb->data, contr);
508         }
509
510         cmtp_send_capimsg(session, skb);
511
512         return CAPI_NOERROR;
513 }
514
515 static char *cmtp_procinfo(struct capi_ctr *ctrl)
516 {
517         return "CAPI Message Transport Protocol";
518 }
519
520 static int cmtp_proc_show(struct seq_file *m, void *v)
521 {
522         struct capi_ctr *ctrl = m->private;
523         struct cmtp_session *session = ctrl->driverdata;
524         struct cmtp_application *app;
525         struct list_head *p, *n;
526
527         seq_printf(m, "%s\n\n", cmtp_procinfo(ctrl));
528         seq_printf(m, "addr %s\n", session->name);
529         seq_printf(m, "ctrl %d\n", session->num);
530
531         list_for_each_safe(p, n, &session->applications) {
532                 app = list_entry(p, struct cmtp_application, list);
533                 seq_printf(m, "appl %d -> %d\n", app->appl, app->mapping);
534         }
535
536         return 0;
537 }
538
539 static int cmtp_proc_open(struct inode *inode, struct file *file)
540 {
541         return single_open(file, cmtp_proc_show, PDE(inode)->data);
542 }
543
544 static const struct file_operations cmtp_proc_fops = {
545         .owner          = THIS_MODULE,
546         .open           = cmtp_proc_open,
547         .read           = seq_read,
548         .llseek         = seq_lseek,
549         .release        = single_release,
550 };
551
552 int cmtp_attach_device(struct cmtp_session *session)
553 {
554         unsigned char buf[4];
555         long ret;
556
557         BT_DBG("session %p", session);
558
559         capimsg_setu32(buf, 0, 0);
560
561         cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, CMTP_INITIAL_MSGNUM,
562                                 CAPI_FUNCTION_GET_PROFILE, buf, 4);
563
564         ret = wait_event_interruptible_timeout(session->wait,
565                         session->ncontroller, CMTP_INTEROP_TIMEOUT);
566
567         BT_INFO("Found %d CAPI controller(s) on device %s", session->ncontroller, session->name);
568
569         if (!ret)
570                 return -ETIMEDOUT;
571
572         if (!session->ncontroller)
573                 return -ENODEV;
574
575         if (session->ncontroller > 1)
576                 BT_INFO("Setting up only CAPI controller 1");
577
578         session->ctrl.owner      = THIS_MODULE;
579         session->ctrl.driverdata = session;
580         strcpy(session->ctrl.name, session->name);
581
582         session->ctrl.driver_name   = "cmtp";
583         session->ctrl.load_firmware = cmtp_load_firmware;
584         session->ctrl.reset_ctr     = cmtp_reset_ctr;
585         session->ctrl.register_appl = cmtp_register_appl;
586         session->ctrl.release_appl  = cmtp_release_appl;
587         session->ctrl.send_message  = cmtp_send_message;
588
589         session->ctrl.procinfo      = cmtp_procinfo;
590         session->ctrl.proc_fops = &cmtp_proc_fops;
591
592         if (attach_capi_ctr(&session->ctrl) < 0) {
593                 BT_ERR("Can't attach new controller");
594                 return -EBUSY;
595         }
596
597         session->num = session->ctrl.cnr;
598
599         BT_DBG("session %p num %d", session, session->num);
600
601         capimsg_setu32(buf, 0, 1);
602
603         cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
604                                 CAPI_FUNCTION_GET_MANUFACTURER, buf, 4);
605
606         cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
607                                 CAPI_FUNCTION_GET_VERSION, buf, 4);
608
609         cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
610                                 CAPI_FUNCTION_GET_SERIAL_NUMBER, buf, 4);
611
612         cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
613                                 CAPI_FUNCTION_GET_PROFILE, buf, 4);
614
615         return 0;
616 }
617
618 void cmtp_detach_device(struct cmtp_session *session)
619 {
620         BT_DBG("session %p", session);
621
622         detach_capi_ctr(&session->ctrl);
623 }