page-allocator: maintain rolling count of pages to free from the PCP
[linux/fpc-iii.git] / net / bluetooth / cmtp / capi.c
blob97f8d68d574daf16880a08b4396d7e1c604c7c93
1 /*
2 CMTP implementation for Linux Bluetooth stack (BlueZ).
3 Copyright (C) 2002-2003 Marcel Holtmann <marcel@holtmann.org>
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;
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.
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.
23 #include <linux/module.h>
25 #include <linux/types.h>
26 #include <linux/errno.h>
27 #include <linux/kernel.h>
28 #include <linux/sched.h>
29 #include <linux/slab.h>
30 #include <linux/poll.h>
31 #include <linux/fcntl.h>
32 #include <linux/skbuff.h>
33 #include <linux/socket.h>
34 #include <linux/ioctl.h>
35 #include <linux/file.h>
36 #include <linux/wait.h>
37 #include <net/sock.h>
39 #include <linux/isdn/capilli.h>
40 #include <linux/isdn/capicmd.h>
41 #include <linux/isdn/capiutil.h>
43 #include "cmtp.h"
45 #define CAPI_INTEROPERABILITY 0x20
47 #define CAPI_INTEROPERABILITY_REQ CAPICMD(CAPI_INTEROPERABILITY, CAPI_REQ)
48 #define CAPI_INTEROPERABILITY_CONF CAPICMD(CAPI_INTEROPERABILITY, CAPI_CONF)
49 #define CAPI_INTEROPERABILITY_IND CAPICMD(CAPI_INTEROPERABILITY, CAPI_IND)
50 #define CAPI_INTEROPERABILITY_RESP CAPICMD(CAPI_INTEROPERABILITY, CAPI_RESP)
52 #define CAPI_INTEROPERABILITY_REQ_LEN (CAPI_MSG_BASELEN + 2)
53 #define CAPI_INTEROPERABILITY_CONF_LEN (CAPI_MSG_BASELEN + 4)
54 #define CAPI_INTEROPERABILITY_IND_LEN (CAPI_MSG_BASELEN + 2)
55 #define CAPI_INTEROPERABILITY_RESP_LEN (CAPI_MSG_BASELEN + 2)
57 #define CAPI_FUNCTION_REGISTER 0
58 #define CAPI_FUNCTION_RELEASE 1
59 #define CAPI_FUNCTION_GET_PROFILE 2
60 #define CAPI_FUNCTION_GET_MANUFACTURER 3
61 #define CAPI_FUNCTION_GET_VERSION 4
62 #define CAPI_FUNCTION_GET_SERIAL_NUMBER 5
63 #define CAPI_FUNCTION_MANUFACTURER 6
64 #define CAPI_FUNCTION_LOOPBACK 7
67 #define CMTP_MSGNUM 1
68 #define CMTP_APPLID 2
69 #define CMTP_MAPPING 3
71 static struct cmtp_application *cmtp_application_add(struct cmtp_session *session, __u16 appl)
73 struct cmtp_application *app = kzalloc(sizeof(*app), GFP_KERNEL);
75 BT_DBG("session %p application %p appl %d", session, app, appl);
77 if (!app)
78 return NULL;
80 app->state = BT_OPEN;
81 app->appl = appl;
83 list_add_tail(&app->list, &session->applications);
85 return app;
88 static void cmtp_application_del(struct cmtp_session *session, struct cmtp_application *app)
90 BT_DBG("session %p application %p", session, app);
92 if (app) {
93 list_del(&app->list);
94 kfree(app);
98 static struct cmtp_application *cmtp_application_get(struct cmtp_session *session, int pattern, __u16 value)
100 struct cmtp_application *app;
101 struct list_head *p, *n;
103 list_for_each_safe(p, n, &session->applications) {
104 app = list_entry(p, struct cmtp_application, 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;
121 return NULL;
124 static int cmtp_msgnum_get(struct cmtp_session *session)
126 session->msgnum++;
128 if ((session->msgnum & 0xff) > 200)
129 session->msgnum = CMTP_INITIAL_MSGNUM + 1;
131 return session->msgnum;
134 static void cmtp_send_capimsg(struct cmtp_session *session, struct sk_buff *skb)
136 struct cmtp_scb *scb = (void *) skb->cb;
138 BT_DBG("session %p skb %p len %d", session, skb, skb->len);
140 scb->id = -1;
141 scb->data = (CAPIMSG_COMMAND(skb->data) == CAPI_DATA_B3);
143 skb_queue_tail(&session->transmit, skb);
145 cmtp_schedule(session);
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)
152 struct sk_buff *skb;
153 unsigned char *s;
155 BT_DBG("session %p subcmd 0x%02x appl %d msgnum %d", session, subcmd, appl, msgnum);
157 if (!(skb = alloc_skb(CAPI_MSG_BASELEN + 6 + len, GFP_ATOMIC))) {
158 BT_ERR("Can't allocate memory for interoperability packet");
159 return;
162 s = skb_put(skb, CAPI_MSG_BASELEN + 6 + len);
164 capimsg_setu16(s, 0, CAPI_MSG_BASELEN + 6 + len);
165 capimsg_setu16(s, 2, appl);
166 capimsg_setu8 (s, 4, CAPI_INTEROPERABILITY);
167 capimsg_setu8 (s, 5, subcmd);
168 capimsg_setu16(s, 6, msgnum);
170 /* Interoperability selector (Bluetooth Device Management) */
171 capimsg_setu16(s, 8, 0x0001);
173 capimsg_setu8 (s, 10, 3 + len);
174 capimsg_setu16(s, 11, function);
175 capimsg_setu8 (s, 13, len);
177 if (len > 0)
178 memcpy(s + 14, buf, len);
180 cmtp_send_capimsg(session, skb);
183 static void cmtp_recv_interopmsg(struct cmtp_session *session, struct sk_buff *skb)
185 struct capi_ctr *ctrl = &session->ctrl;
186 struct cmtp_application *application;
187 __u16 appl, msgnum, func, info;
188 __u32 controller;
190 BT_DBG("session %p skb %p len %d", session, skb, skb->len);
192 switch (CAPIMSG_SUBCOMMAND(skb->data)) {
193 case CAPI_CONF:
194 if (skb->len < CAPI_MSG_BASELEN + 10)
195 break;
197 func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 5);
198 info = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 8);
200 switch (func) {
201 case CAPI_FUNCTION_REGISTER:
202 msgnum = CAPIMSG_MSGID(skb->data);
204 application = cmtp_application_get(session, CMTP_MSGNUM, msgnum);
205 if (application) {
206 application->state = BT_CONNECTED;
207 application->msgnum = 0;
208 application->mapping = CAPIMSG_APPID(skb->data);
209 wake_up_interruptible(&session->wait);
212 break;
214 case CAPI_FUNCTION_RELEASE:
215 appl = CAPIMSG_APPID(skb->data);
217 application = cmtp_application_get(session, CMTP_MAPPING, appl);
218 if (application) {
219 application->state = BT_CLOSED;
220 application->msgnum = 0;
221 wake_up_interruptible(&session->wait);
224 break;
226 case CAPI_FUNCTION_GET_PROFILE:
227 if (skb->len < CAPI_MSG_BASELEN + 11 + sizeof(capi_profile))
228 break;
230 controller = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 11);
231 msgnum = CAPIMSG_MSGID(skb->data);
233 if (!info && (msgnum == CMTP_INITIAL_MSGNUM)) {
234 session->ncontroller = controller;
235 wake_up_interruptible(&session->wait);
236 break;
239 if (!info && ctrl) {
240 memcpy(&ctrl->profile,
241 skb->data + CAPI_MSG_BASELEN + 11,
242 sizeof(capi_profile));
243 session->state = BT_CONNECTED;
244 capi_ctr_ready(ctrl);
247 break;
249 case CAPI_FUNCTION_GET_MANUFACTURER:
250 if (skb->len < CAPI_MSG_BASELEN + 15)
251 break;
253 controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 10);
255 if (!info && ctrl) {
256 int len = min_t(uint, CAPI_MANUFACTURER_LEN,
257 skb->data[CAPI_MSG_BASELEN + 14]);
259 memset(ctrl->manu, 0, CAPI_MANUFACTURER_LEN);
260 strncpy(ctrl->manu,
261 skb->data + CAPI_MSG_BASELEN + 15, len);
264 break;
266 case CAPI_FUNCTION_GET_VERSION:
267 if (skb->len < CAPI_MSG_BASELEN + 32)
268 break;
270 controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 12);
272 if (!info && ctrl) {
273 ctrl->version.majorversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 16);
274 ctrl->version.minorversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 20);
275 ctrl->version.majormanuversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 24);
276 ctrl->version.minormanuversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 28);
279 break;
281 case CAPI_FUNCTION_GET_SERIAL_NUMBER:
282 if (skb->len < CAPI_MSG_BASELEN + 17)
283 break;
285 controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 12);
287 if (!info && ctrl) {
288 int len = min_t(uint, CAPI_SERIAL_LEN,
289 skb->data[CAPI_MSG_BASELEN + 16]);
291 memset(ctrl->serial, 0, CAPI_SERIAL_LEN);
292 strncpy(ctrl->serial,
293 skb->data + CAPI_MSG_BASELEN + 17, len);
296 break;
299 break;
301 case CAPI_IND:
302 if (skb->len < CAPI_MSG_BASELEN + 6)
303 break;
305 func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 3);
307 if (func == CAPI_FUNCTION_LOOPBACK) {
308 int len = min_t(uint, skb->len - CAPI_MSG_BASELEN - 6,
309 skb->data[CAPI_MSG_BASELEN + 5]);
310 appl = CAPIMSG_APPID(skb->data);
311 msgnum = CAPIMSG_MSGID(skb->data);
312 cmtp_send_interopmsg(session, CAPI_RESP, appl, msgnum, func,
313 skb->data + CAPI_MSG_BASELEN + 6, len);
316 break;
319 kfree_skb(skb);
322 void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb)
324 struct capi_ctr *ctrl = &session->ctrl;
325 struct cmtp_application *application;
326 __u16 cmd, appl;
327 __u32 contr;
329 BT_DBG("session %p skb %p len %d", session, skb, skb->len);
331 if (skb->len < CAPI_MSG_BASELEN)
332 return;
334 if (CAPIMSG_COMMAND(skb->data) == CAPI_INTEROPERABILITY) {
335 cmtp_recv_interopmsg(session, skb);
336 return;
339 if (session->flags & (1 << CMTP_LOOPBACK)) {
340 kfree_skb(skb);
341 return;
344 cmd = CAPICMD(CAPIMSG_COMMAND(skb->data), CAPIMSG_SUBCOMMAND(skb->data));
345 appl = CAPIMSG_APPID(skb->data);
346 contr = CAPIMSG_CONTROL(skb->data);
348 application = cmtp_application_get(session, CMTP_MAPPING, appl);
349 if (application) {
350 appl = application->appl;
351 CAPIMSG_SETAPPID(skb->data, appl);
352 } else {
353 BT_ERR("Can't find application with id %d", appl);
354 kfree_skb(skb);
355 return;
358 if ((contr & 0x7f) == 0x01) {
359 contr = (contr & 0xffffff80) | session->num;
360 CAPIMSG_SETCONTROL(skb->data, contr);
363 if (!ctrl) {
364 BT_ERR("Can't find controller %d for message", session->num);
365 kfree_skb(skb);
366 return;
369 capi_ctr_handle_message(ctrl, appl, skb);
372 static int cmtp_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
374 BT_DBG("ctrl %p data %p", ctrl, data);
376 return 0;
379 static void cmtp_reset_ctr(struct capi_ctr *ctrl)
381 struct cmtp_session *session = ctrl->driverdata;
383 BT_DBG("ctrl %p", ctrl);
385 capi_ctr_down(ctrl);
387 atomic_inc(&session->terminate);
388 cmtp_schedule(session);
391 static void cmtp_register_appl(struct capi_ctr *ctrl, __u16 appl, capi_register_params *rp)
393 DECLARE_WAITQUEUE(wait, current);
394 struct cmtp_session *session = ctrl->driverdata;
395 struct cmtp_application *application;
396 unsigned long timeo = CMTP_INTEROP_TIMEOUT;
397 unsigned char buf[8];
398 int err = 0, nconn, want = rp->level3cnt;
400 BT_DBG("ctrl %p appl %d level3cnt %d datablkcnt %d datablklen %d",
401 ctrl, appl, rp->level3cnt, rp->datablkcnt, rp->datablklen);
403 application = cmtp_application_add(session, appl);
404 if (!application) {
405 BT_ERR("Can't allocate memory for new application");
406 return;
409 if (want < 0)
410 nconn = ctrl->profile.nbchannel * -want;
411 else
412 nconn = want;
414 if (nconn == 0)
415 nconn = ctrl->profile.nbchannel;
417 capimsg_setu16(buf, 0, nconn);
418 capimsg_setu16(buf, 2, rp->datablkcnt);
419 capimsg_setu16(buf, 4, rp->datablklen);
421 application->state = BT_CONFIG;
422 application->msgnum = cmtp_msgnum_get(session);
424 cmtp_send_interopmsg(session, CAPI_REQ, 0x0000, application->msgnum,
425 CAPI_FUNCTION_REGISTER, buf, 6);
427 add_wait_queue(&session->wait, &wait);
428 while (1) {
429 set_current_state(TASK_INTERRUPTIBLE);
431 if (!timeo) {
432 err = -EAGAIN;
433 break;
436 if (application->state == BT_CLOSED) {
437 err = -application->err;
438 break;
441 if (application->state == BT_CONNECTED)
442 break;
444 if (signal_pending(current)) {
445 err = -EINTR;
446 break;
449 timeo = schedule_timeout(timeo);
451 set_current_state(TASK_RUNNING);
452 remove_wait_queue(&session->wait, &wait);
454 if (err) {
455 cmtp_application_del(session, application);
456 return;
460 static void cmtp_release_appl(struct capi_ctr *ctrl, __u16 appl)
462 struct cmtp_session *session = ctrl->driverdata;
463 struct cmtp_application *application;
465 BT_DBG("ctrl %p appl %d", ctrl, appl);
467 application = cmtp_application_get(session, CMTP_APPLID, appl);
468 if (!application) {
469 BT_ERR("Can't find application");
470 return;
473 application->msgnum = cmtp_msgnum_get(session);
475 cmtp_send_interopmsg(session, CAPI_REQ, application->mapping, application->msgnum,
476 CAPI_FUNCTION_RELEASE, NULL, 0);
478 wait_event_interruptible_timeout(session->wait,
479 (application->state == BT_CLOSED), CMTP_INTEROP_TIMEOUT);
481 cmtp_application_del(session, application);
484 static u16 cmtp_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
486 struct cmtp_session *session = ctrl->driverdata;
487 struct cmtp_application *application;
488 __u16 appl;
489 __u32 contr;
491 BT_DBG("ctrl %p skb %p", ctrl, skb);
493 appl = CAPIMSG_APPID(skb->data);
494 contr = CAPIMSG_CONTROL(skb->data);
496 application = cmtp_application_get(session, CMTP_APPLID, appl);
497 if ((!application) || (application->state != BT_CONNECTED)) {
498 BT_ERR("Can't find application with id %d", appl);
499 return CAPI_ILLAPPNR;
502 CAPIMSG_SETAPPID(skb->data, application->mapping);
504 if ((contr & 0x7f) == session->num) {
505 contr = (contr & 0xffffff80) | 0x01;
506 CAPIMSG_SETCONTROL(skb->data, contr);
509 cmtp_send_capimsg(session, skb);
511 return CAPI_NOERROR;
514 static char *cmtp_procinfo(struct capi_ctr *ctrl)
516 return "CAPI Message Transport Protocol";
519 static int cmtp_ctr_read_proc(char *page, char **start, off_t off, int count, int *eof, struct capi_ctr *ctrl)
521 struct cmtp_session *session = ctrl->driverdata;
522 struct cmtp_application *app;
523 struct list_head *p, *n;
524 int len = 0;
526 len += sprintf(page + len, "%s\n\n", cmtp_procinfo(ctrl));
527 len += sprintf(page + len, "addr %s\n", session->name);
528 len += sprintf(page + len, "ctrl %d\n", session->num);
530 list_for_each_safe(p, n, &session->applications) {
531 app = list_entry(p, struct cmtp_application, list);
532 len += sprintf(page + len, "appl %d -> %d\n", app->appl, app->mapping);
535 if (off + count >= len)
536 *eof = 1;
538 if (len < off)
539 return 0;
541 *start = page + off;
543 return ((count < len - off) ? count : len - off);
547 int cmtp_attach_device(struct cmtp_session *session)
549 unsigned char buf[4];
550 long ret;
552 BT_DBG("session %p", session);
554 capimsg_setu32(buf, 0, 0);
556 cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, CMTP_INITIAL_MSGNUM,
557 CAPI_FUNCTION_GET_PROFILE, buf, 4);
559 ret = wait_event_interruptible_timeout(session->wait,
560 session->ncontroller, CMTP_INTEROP_TIMEOUT);
562 BT_INFO("Found %d CAPI controller(s) on device %s", session->ncontroller, session->name);
564 if (!ret)
565 return -ETIMEDOUT;
567 if (!session->ncontroller)
568 return -ENODEV;
570 if (session->ncontroller > 1)
571 BT_INFO("Setting up only CAPI controller 1");
573 session->ctrl.owner = THIS_MODULE;
574 session->ctrl.driverdata = session;
575 strcpy(session->ctrl.name, session->name);
577 session->ctrl.driver_name = "cmtp";
578 session->ctrl.load_firmware = cmtp_load_firmware;
579 session->ctrl.reset_ctr = cmtp_reset_ctr;
580 session->ctrl.register_appl = cmtp_register_appl;
581 session->ctrl.release_appl = cmtp_release_appl;
582 session->ctrl.send_message = cmtp_send_message;
584 session->ctrl.procinfo = cmtp_procinfo;
585 session->ctrl.ctr_read_proc = cmtp_ctr_read_proc;
587 if (attach_capi_ctr(&session->ctrl) < 0) {
588 BT_ERR("Can't attach new controller");
589 return -EBUSY;
592 session->num = session->ctrl.cnr;
594 BT_DBG("session %p num %d", session, session->num);
596 capimsg_setu32(buf, 0, 1);
598 cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
599 CAPI_FUNCTION_GET_MANUFACTURER, buf, 4);
601 cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
602 CAPI_FUNCTION_GET_VERSION, buf, 4);
604 cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
605 CAPI_FUNCTION_GET_SERIAL_NUMBER, buf, 4);
607 cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
608 CAPI_FUNCTION_GET_PROFILE, buf, 4);
610 return 0;
613 void cmtp_detach_device(struct cmtp_session *session)
615 BT_DBG("session %p", session);
617 detach_capi_ctr(&session->ctrl);