1*1da177e4SLinus Torvalds /* 2*1da177e4SLinus Torvalds CMTP implementation for Linux Bluetooth stack (BlueZ). 3*1da177e4SLinus Torvalds Copyright (C) 2002-2003 Marcel Holtmann <marcel@holtmann.org> 4*1da177e4SLinus Torvalds 5*1da177e4SLinus Torvalds This program is free software; you can redistribute it and/or modify 6*1da177e4SLinus Torvalds it under the terms of the GNU General Public License version 2 as 7*1da177e4SLinus Torvalds published by the Free Software Foundation; 8*1da177e4SLinus Torvalds 9*1da177e4SLinus Torvalds THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 10*1da177e4SLinus Torvalds OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 11*1da177e4SLinus Torvalds FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. 12*1da177e4SLinus Torvalds IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY 13*1da177e4SLinus Torvalds CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 14*1da177e4SLinus Torvalds WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15*1da177e4SLinus Torvalds ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16*1da177e4SLinus Torvalds OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17*1da177e4SLinus Torvalds 18*1da177e4SLinus Torvalds ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 19*1da177e4SLinus Torvalds COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 20*1da177e4SLinus Torvalds SOFTWARE IS DISCLAIMED. 21*1da177e4SLinus Torvalds */ 22*1da177e4SLinus Torvalds 23*1da177e4SLinus Torvalds #include <linux/config.h> 24*1da177e4SLinus Torvalds #include <linux/module.h> 25*1da177e4SLinus Torvalds 26*1da177e4SLinus Torvalds #include <linux/types.h> 27*1da177e4SLinus Torvalds #include <linux/errno.h> 28*1da177e4SLinus Torvalds #include <linux/kernel.h> 29*1da177e4SLinus Torvalds #include <linux/major.h> 30*1da177e4SLinus Torvalds #include <linux/sched.h> 31*1da177e4SLinus Torvalds #include <linux/slab.h> 32*1da177e4SLinus Torvalds #include <linux/poll.h> 33*1da177e4SLinus Torvalds #include <linux/fcntl.h> 34*1da177e4SLinus Torvalds #include <linux/skbuff.h> 35*1da177e4SLinus Torvalds #include <linux/socket.h> 36*1da177e4SLinus Torvalds #include <linux/ioctl.h> 37*1da177e4SLinus Torvalds #include <linux/file.h> 38*1da177e4SLinus Torvalds #include <linux/wait.h> 39*1da177e4SLinus Torvalds #include <net/sock.h> 40*1da177e4SLinus Torvalds 41*1da177e4SLinus Torvalds #include <linux/isdn/capilli.h> 42*1da177e4SLinus Torvalds #include <linux/isdn/capicmd.h> 43*1da177e4SLinus Torvalds #include <linux/isdn/capiutil.h> 44*1da177e4SLinus Torvalds 45*1da177e4SLinus Torvalds #include "cmtp.h" 46*1da177e4SLinus Torvalds 47*1da177e4SLinus Torvalds #ifndef CONFIG_BT_CMTP_DEBUG 48*1da177e4SLinus Torvalds #undef BT_DBG 49*1da177e4SLinus Torvalds #define BT_DBG(D...) 50*1da177e4SLinus Torvalds #endif 51*1da177e4SLinus Torvalds 52*1da177e4SLinus Torvalds #define CAPI_INTEROPERABILITY 0x20 53*1da177e4SLinus Torvalds 54*1da177e4SLinus Torvalds #define CAPI_INTEROPERABILITY_REQ CAPICMD(CAPI_INTEROPERABILITY, CAPI_REQ) 55*1da177e4SLinus Torvalds #define CAPI_INTEROPERABILITY_CONF CAPICMD(CAPI_INTEROPERABILITY, CAPI_CONF) 56*1da177e4SLinus Torvalds #define CAPI_INTEROPERABILITY_IND CAPICMD(CAPI_INTEROPERABILITY, CAPI_IND) 57*1da177e4SLinus Torvalds #define CAPI_INTEROPERABILITY_RESP CAPICMD(CAPI_INTEROPERABILITY, CAPI_RESP) 58*1da177e4SLinus Torvalds 59*1da177e4SLinus Torvalds #define CAPI_INTEROPERABILITY_REQ_LEN (CAPI_MSG_BASELEN + 2) 60*1da177e4SLinus Torvalds #define CAPI_INTEROPERABILITY_CONF_LEN (CAPI_MSG_BASELEN + 4) 61*1da177e4SLinus Torvalds #define CAPI_INTEROPERABILITY_IND_LEN (CAPI_MSG_BASELEN + 2) 62*1da177e4SLinus Torvalds #define CAPI_INTEROPERABILITY_RESP_LEN (CAPI_MSG_BASELEN + 2) 63*1da177e4SLinus Torvalds 64*1da177e4SLinus Torvalds #define CAPI_FUNCTION_REGISTER 0 65*1da177e4SLinus Torvalds #define CAPI_FUNCTION_RELEASE 1 66*1da177e4SLinus Torvalds #define CAPI_FUNCTION_GET_PROFILE 2 67*1da177e4SLinus Torvalds #define CAPI_FUNCTION_GET_MANUFACTURER 3 68*1da177e4SLinus Torvalds #define CAPI_FUNCTION_GET_VERSION 4 69*1da177e4SLinus Torvalds #define CAPI_FUNCTION_GET_SERIAL_NUMBER 5 70*1da177e4SLinus Torvalds #define CAPI_FUNCTION_MANUFACTURER 6 71*1da177e4SLinus Torvalds #define CAPI_FUNCTION_LOOPBACK 7 72*1da177e4SLinus Torvalds 73*1da177e4SLinus Torvalds 74*1da177e4SLinus Torvalds #define CMTP_MSGNUM 1 75*1da177e4SLinus Torvalds #define CMTP_APPLID 2 76*1da177e4SLinus Torvalds #define CMTP_MAPPING 3 77*1da177e4SLinus Torvalds 78*1da177e4SLinus Torvalds static struct cmtp_application *cmtp_application_add(struct cmtp_session *session, __u16 appl) 79*1da177e4SLinus Torvalds { 80*1da177e4SLinus Torvalds struct cmtp_application *app = kmalloc(sizeof(*app), GFP_KERNEL); 81*1da177e4SLinus Torvalds 82*1da177e4SLinus Torvalds BT_DBG("session %p application %p appl %d", session, app, appl); 83*1da177e4SLinus Torvalds 84*1da177e4SLinus Torvalds if (!app) 85*1da177e4SLinus Torvalds return NULL; 86*1da177e4SLinus Torvalds 87*1da177e4SLinus Torvalds memset(app, 0, sizeof(*app)); 88*1da177e4SLinus Torvalds 89*1da177e4SLinus Torvalds app->state = BT_OPEN; 90*1da177e4SLinus Torvalds app->appl = appl; 91*1da177e4SLinus Torvalds 92*1da177e4SLinus Torvalds list_add_tail(&app->list, &session->applications); 93*1da177e4SLinus Torvalds 94*1da177e4SLinus Torvalds return app; 95*1da177e4SLinus Torvalds } 96*1da177e4SLinus Torvalds 97*1da177e4SLinus Torvalds static void cmtp_application_del(struct cmtp_session *session, struct cmtp_application *app) 98*1da177e4SLinus Torvalds { 99*1da177e4SLinus Torvalds BT_DBG("session %p application %p", session, app); 100*1da177e4SLinus Torvalds 101*1da177e4SLinus Torvalds if (app) { 102*1da177e4SLinus Torvalds list_del(&app->list); 103*1da177e4SLinus Torvalds kfree(app); 104*1da177e4SLinus Torvalds } 105*1da177e4SLinus Torvalds } 106*1da177e4SLinus Torvalds 107*1da177e4SLinus Torvalds static struct cmtp_application *cmtp_application_get(struct cmtp_session *session, int pattern, __u16 value) 108*1da177e4SLinus Torvalds { 109*1da177e4SLinus Torvalds struct cmtp_application *app; 110*1da177e4SLinus Torvalds struct list_head *p, *n; 111*1da177e4SLinus Torvalds 112*1da177e4SLinus Torvalds list_for_each_safe(p, n, &session->applications) { 113*1da177e4SLinus Torvalds app = list_entry(p, struct cmtp_application, list); 114*1da177e4SLinus Torvalds switch (pattern) { 115*1da177e4SLinus Torvalds case CMTP_MSGNUM: 116*1da177e4SLinus Torvalds if (app->msgnum == value) 117*1da177e4SLinus Torvalds return app; 118*1da177e4SLinus Torvalds break; 119*1da177e4SLinus Torvalds case CMTP_APPLID: 120*1da177e4SLinus Torvalds if (app->appl == value) 121*1da177e4SLinus Torvalds return app; 122*1da177e4SLinus Torvalds break; 123*1da177e4SLinus Torvalds case CMTP_MAPPING: 124*1da177e4SLinus Torvalds if (app->mapping == value) 125*1da177e4SLinus Torvalds return app; 126*1da177e4SLinus Torvalds break; 127*1da177e4SLinus Torvalds } 128*1da177e4SLinus Torvalds } 129*1da177e4SLinus Torvalds 130*1da177e4SLinus Torvalds return NULL; 131*1da177e4SLinus Torvalds } 132*1da177e4SLinus Torvalds 133*1da177e4SLinus Torvalds static int cmtp_msgnum_get(struct cmtp_session *session) 134*1da177e4SLinus Torvalds { 135*1da177e4SLinus Torvalds session->msgnum++; 136*1da177e4SLinus Torvalds 137*1da177e4SLinus Torvalds if ((session->msgnum & 0xff) > 200) 138*1da177e4SLinus Torvalds session->msgnum = CMTP_INITIAL_MSGNUM + 1; 139*1da177e4SLinus Torvalds 140*1da177e4SLinus Torvalds return session->msgnum; 141*1da177e4SLinus Torvalds } 142*1da177e4SLinus Torvalds 143*1da177e4SLinus Torvalds static void cmtp_send_capimsg(struct cmtp_session *session, struct sk_buff *skb) 144*1da177e4SLinus Torvalds { 145*1da177e4SLinus Torvalds struct cmtp_scb *scb = (void *) skb->cb; 146*1da177e4SLinus Torvalds 147*1da177e4SLinus Torvalds BT_DBG("session %p skb %p len %d", session, skb, skb->len); 148*1da177e4SLinus Torvalds 149*1da177e4SLinus Torvalds scb->id = -1; 150*1da177e4SLinus Torvalds scb->data = (CAPIMSG_COMMAND(skb->data) == CAPI_DATA_B3); 151*1da177e4SLinus Torvalds 152*1da177e4SLinus Torvalds skb_queue_tail(&session->transmit, skb); 153*1da177e4SLinus Torvalds 154*1da177e4SLinus Torvalds cmtp_schedule(session); 155*1da177e4SLinus Torvalds } 156*1da177e4SLinus Torvalds 157*1da177e4SLinus Torvalds static void cmtp_send_interopmsg(struct cmtp_session *session, 158*1da177e4SLinus Torvalds __u8 subcmd, __u16 appl, __u16 msgnum, 159*1da177e4SLinus Torvalds __u16 function, unsigned char *buf, int len) 160*1da177e4SLinus Torvalds { 161*1da177e4SLinus Torvalds struct sk_buff *skb; 162*1da177e4SLinus Torvalds unsigned char *s; 163*1da177e4SLinus Torvalds 164*1da177e4SLinus Torvalds BT_DBG("session %p subcmd 0x%02x appl %d msgnum %d", session, subcmd, appl, msgnum); 165*1da177e4SLinus Torvalds 166*1da177e4SLinus Torvalds if (!(skb = alloc_skb(CAPI_MSG_BASELEN + 6 + len, GFP_ATOMIC))) { 167*1da177e4SLinus Torvalds BT_ERR("Can't allocate memory for interoperability packet"); 168*1da177e4SLinus Torvalds return; 169*1da177e4SLinus Torvalds } 170*1da177e4SLinus Torvalds 171*1da177e4SLinus Torvalds s = skb_put(skb, CAPI_MSG_BASELEN + 6 + len); 172*1da177e4SLinus Torvalds 173*1da177e4SLinus Torvalds capimsg_setu16(s, 0, CAPI_MSG_BASELEN + 6 + len); 174*1da177e4SLinus Torvalds capimsg_setu16(s, 2, appl); 175*1da177e4SLinus Torvalds capimsg_setu8 (s, 4, CAPI_INTEROPERABILITY); 176*1da177e4SLinus Torvalds capimsg_setu8 (s, 5, subcmd); 177*1da177e4SLinus Torvalds capimsg_setu16(s, 6, msgnum); 178*1da177e4SLinus Torvalds 179*1da177e4SLinus Torvalds /* Interoperability selector (Bluetooth Device Management) */ 180*1da177e4SLinus Torvalds capimsg_setu16(s, 8, 0x0001); 181*1da177e4SLinus Torvalds 182*1da177e4SLinus Torvalds capimsg_setu8 (s, 10, 3 + len); 183*1da177e4SLinus Torvalds capimsg_setu16(s, 11, function); 184*1da177e4SLinus Torvalds capimsg_setu8 (s, 13, len); 185*1da177e4SLinus Torvalds 186*1da177e4SLinus Torvalds if (len > 0) 187*1da177e4SLinus Torvalds memcpy(s + 14, buf, len); 188*1da177e4SLinus Torvalds 189*1da177e4SLinus Torvalds cmtp_send_capimsg(session, skb); 190*1da177e4SLinus Torvalds } 191*1da177e4SLinus Torvalds 192*1da177e4SLinus Torvalds static void cmtp_recv_interopmsg(struct cmtp_session *session, struct sk_buff *skb) 193*1da177e4SLinus Torvalds { 194*1da177e4SLinus Torvalds struct capi_ctr *ctrl = &session->ctrl; 195*1da177e4SLinus Torvalds struct cmtp_application *application; 196*1da177e4SLinus Torvalds __u16 appl, msgnum, func, info; 197*1da177e4SLinus Torvalds __u32 controller; 198*1da177e4SLinus Torvalds 199*1da177e4SLinus Torvalds BT_DBG("session %p skb %p len %d", session, skb, skb->len); 200*1da177e4SLinus Torvalds 201*1da177e4SLinus Torvalds switch (CAPIMSG_SUBCOMMAND(skb->data)) { 202*1da177e4SLinus Torvalds case CAPI_CONF: 203*1da177e4SLinus Torvalds func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 5); 204*1da177e4SLinus Torvalds info = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 8); 205*1da177e4SLinus Torvalds 206*1da177e4SLinus Torvalds switch (func) { 207*1da177e4SLinus Torvalds case CAPI_FUNCTION_REGISTER: 208*1da177e4SLinus Torvalds msgnum = CAPIMSG_MSGID(skb->data); 209*1da177e4SLinus Torvalds 210*1da177e4SLinus Torvalds application = cmtp_application_get(session, CMTP_MSGNUM, msgnum); 211*1da177e4SLinus Torvalds if (application) { 212*1da177e4SLinus Torvalds application->state = BT_CONNECTED; 213*1da177e4SLinus Torvalds application->msgnum = 0; 214*1da177e4SLinus Torvalds application->mapping = CAPIMSG_APPID(skb->data); 215*1da177e4SLinus Torvalds wake_up_interruptible(&session->wait); 216*1da177e4SLinus Torvalds } 217*1da177e4SLinus Torvalds 218*1da177e4SLinus Torvalds break; 219*1da177e4SLinus Torvalds 220*1da177e4SLinus Torvalds case CAPI_FUNCTION_RELEASE: 221*1da177e4SLinus Torvalds appl = CAPIMSG_APPID(skb->data); 222*1da177e4SLinus Torvalds 223*1da177e4SLinus Torvalds application = cmtp_application_get(session, CMTP_MAPPING, appl); 224*1da177e4SLinus Torvalds if (application) { 225*1da177e4SLinus Torvalds application->state = BT_CLOSED; 226*1da177e4SLinus Torvalds application->msgnum = 0; 227*1da177e4SLinus Torvalds wake_up_interruptible(&session->wait); 228*1da177e4SLinus Torvalds } 229*1da177e4SLinus Torvalds 230*1da177e4SLinus Torvalds break; 231*1da177e4SLinus Torvalds 232*1da177e4SLinus Torvalds case CAPI_FUNCTION_GET_PROFILE: 233*1da177e4SLinus Torvalds controller = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 11); 234*1da177e4SLinus Torvalds msgnum = CAPIMSG_MSGID(skb->data); 235*1da177e4SLinus Torvalds 236*1da177e4SLinus Torvalds if (!info && (msgnum == CMTP_INITIAL_MSGNUM)) { 237*1da177e4SLinus Torvalds session->ncontroller = controller; 238*1da177e4SLinus Torvalds wake_up_interruptible(&session->wait); 239*1da177e4SLinus Torvalds break; 240*1da177e4SLinus Torvalds } 241*1da177e4SLinus Torvalds 242*1da177e4SLinus Torvalds if (!info && ctrl) { 243*1da177e4SLinus Torvalds memcpy(&ctrl->profile, 244*1da177e4SLinus Torvalds skb->data + CAPI_MSG_BASELEN + 11, 245*1da177e4SLinus Torvalds sizeof(capi_profile)); 246*1da177e4SLinus Torvalds session->state = BT_CONNECTED; 247*1da177e4SLinus Torvalds capi_ctr_ready(ctrl); 248*1da177e4SLinus Torvalds } 249*1da177e4SLinus Torvalds 250*1da177e4SLinus Torvalds break; 251*1da177e4SLinus Torvalds 252*1da177e4SLinus Torvalds case CAPI_FUNCTION_GET_MANUFACTURER: 253*1da177e4SLinus Torvalds controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 10); 254*1da177e4SLinus Torvalds 255*1da177e4SLinus Torvalds if (!info && ctrl) { 256*1da177e4SLinus Torvalds strncpy(ctrl->manu, 257*1da177e4SLinus Torvalds skb->data + CAPI_MSG_BASELEN + 15, 258*1da177e4SLinus Torvalds skb->data[CAPI_MSG_BASELEN + 14]); 259*1da177e4SLinus Torvalds } 260*1da177e4SLinus Torvalds 261*1da177e4SLinus Torvalds break; 262*1da177e4SLinus Torvalds 263*1da177e4SLinus Torvalds case CAPI_FUNCTION_GET_VERSION: 264*1da177e4SLinus Torvalds controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 12); 265*1da177e4SLinus Torvalds 266*1da177e4SLinus Torvalds if (!info && ctrl) { 267*1da177e4SLinus Torvalds ctrl->version.majorversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 16); 268*1da177e4SLinus Torvalds ctrl->version.minorversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 20); 269*1da177e4SLinus Torvalds ctrl->version.majormanuversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 24); 270*1da177e4SLinus Torvalds ctrl->version.minormanuversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 28); 271*1da177e4SLinus Torvalds } 272*1da177e4SLinus Torvalds 273*1da177e4SLinus Torvalds break; 274*1da177e4SLinus Torvalds 275*1da177e4SLinus Torvalds case CAPI_FUNCTION_GET_SERIAL_NUMBER: 276*1da177e4SLinus Torvalds controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 12); 277*1da177e4SLinus Torvalds 278*1da177e4SLinus Torvalds if (!info && ctrl) { 279*1da177e4SLinus Torvalds memset(ctrl->serial, 0, CAPI_SERIAL_LEN); 280*1da177e4SLinus Torvalds strncpy(ctrl->serial, 281*1da177e4SLinus Torvalds skb->data + CAPI_MSG_BASELEN + 17, 282*1da177e4SLinus Torvalds skb->data[CAPI_MSG_BASELEN + 16]); 283*1da177e4SLinus Torvalds } 284*1da177e4SLinus Torvalds 285*1da177e4SLinus Torvalds break; 286*1da177e4SLinus Torvalds } 287*1da177e4SLinus Torvalds 288*1da177e4SLinus Torvalds break; 289*1da177e4SLinus Torvalds 290*1da177e4SLinus Torvalds case CAPI_IND: 291*1da177e4SLinus Torvalds func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 3); 292*1da177e4SLinus Torvalds 293*1da177e4SLinus Torvalds if (func == CAPI_FUNCTION_LOOPBACK) { 294*1da177e4SLinus Torvalds appl = CAPIMSG_APPID(skb->data); 295*1da177e4SLinus Torvalds msgnum = CAPIMSG_MSGID(skb->data); 296*1da177e4SLinus Torvalds cmtp_send_interopmsg(session, CAPI_RESP, appl, msgnum, func, 297*1da177e4SLinus Torvalds skb->data + CAPI_MSG_BASELEN + 6, 298*1da177e4SLinus Torvalds skb->data[CAPI_MSG_BASELEN + 5]); 299*1da177e4SLinus Torvalds } 300*1da177e4SLinus Torvalds 301*1da177e4SLinus Torvalds break; 302*1da177e4SLinus Torvalds } 303*1da177e4SLinus Torvalds 304*1da177e4SLinus Torvalds kfree_skb(skb); 305*1da177e4SLinus Torvalds } 306*1da177e4SLinus Torvalds 307*1da177e4SLinus Torvalds void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb) 308*1da177e4SLinus Torvalds { 309*1da177e4SLinus Torvalds struct capi_ctr *ctrl = &session->ctrl; 310*1da177e4SLinus Torvalds struct cmtp_application *application; 311*1da177e4SLinus Torvalds __u16 cmd, appl; 312*1da177e4SLinus Torvalds __u32 contr; 313*1da177e4SLinus Torvalds 314*1da177e4SLinus Torvalds BT_DBG("session %p skb %p len %d", session, skb, skb->len); 315*1da177e4SLinus Torvalds 316*1da177e4SLinus Torvalds if (CAPIMSG_COMMAND(skb->data) == CAPI_INTEROPERABILITY) { 317*1da177e4SLinus Torvalds cmtp_recv_interopmsg(session, skb); 318*1da177e4SLinus Torvalds return; 319*1da177e4SLinus Torvalds } 320*1da177e4SLinus Torvalds 321*1da177e4SLinus Torvalds if (session->flags & (1 << CMTP_LOOPBACK)) { 322*1da177e4SLinus Torvalds kfree_skb(skb); 323*1da177e4SLinus Torvalds return; 324*1da177e4SLinus Torvalds } 325*1da177e4SLinus Torvalds 326*1da177e4SLinus Torvalds cmd = CAPICMD(CAPIMSG_COMMAND(skb->data), CAPIMSG_SUBCOMMAND(skb->data)); 327*1da177e4SLinus Torvalds appl = CAPIMSG_APPID(skb->data); 328*1da177e4SLinus Torvalds contr = CAPIMSG_CONTROL(skb->data); 329*1da177e4SLinus Torvalds 330*1da177e4SLinus Torvalds application = cmtp_application_get(session, CMTP_MAPPING, appl); 331*1da177e4SLinus Torvalds if (application) { 332*1da177e4SLinus Torvalds appl = application->appl; 333*1da177e4SLinus Torvalds CAPIMSG_SETAPPID(skb->data, appl); 334*1da177e4SLinus Torvalds } else { 335*1da177e4SLinus Torvalds BT_ERR("Can't find application with id %d", appl); 336*1da177e4SLinus Torvalds kfree_skb(skb); 337*1da177e4SLinus Torvalds return; 338*1da177e4SLinus Torvalds } 339*1da177e4SLinus Torvalds 340*1da177e4SLinus Torvalds if ((contr & 0x7f) == 0x01) { 341*1da177e4SLinus Torvalds contr = (contr & 0xffffff80) | session->num; 342*1da177e4SLinus Torvalds CAPIMSG_SETCONTROL(skb->data, contr); 343*1da177e4SLinus Torvalds } 344*1da177e4SLinus Torvalds 345*1da177e4SLinus Torvalds if (!ctrl) { 346*1da177e4SLinus Torvalds BT_ERR("Can't find controller %d for message", session->num); 347*1da177e4SLinus Torvalds kfree_skb(skb); 348*1da177e4SLinus Torvalds return; 349*1da177e4SLinus Torvalds } 350*1da177e4SLinus Torvalds 351*1da177e4SLinus Torvalds capi_ctr_handle_message(ctrl, appl, skb); 352*1da177e4SLinus Torvalds } 353*1da177e4SLinus Torvalds 354*1da177e4SLinus Torvalds static int cmtp_load_firmware(struct capi_ctr *ctrl, capiloaddata *data) 355*1da177e4SLinus Torvalds { 356*1da177e4SLinus Torvalds BT_DBG("ctrl %p data %p", ctrl, data); 357*1da177e4SLinus Torvalds 358*1da177e4SLinus Torvalds return 0; 359*1da177e4SLinus Torvalds } 360*1da177e4SLinus Torvalds 361*1da177e4SLinus Torvalds static void cmtp_reset_ctr(struct capi_ctr *ctrl) 362*1da177e4SLinus Torvalds { 363*1da177e4SLinus Torvalds struct cmtp_session *session = ctrl->driverdata; 364*1da177e4SLinus Torvalds 365*1da177e4SLinus Torvalds BT_DBG("ctrl %p", ctrl); 366*1da177e4SLinus Torvalds 367*1da177e4SLinus Torvalds capi_ctr_reseted(ctrl); 368*1da177e4SLinus Torvalds 369*1da177e4SLinus Torvalds atomic_inc(&session->terminate); 370*1da177e4SLinus Torvalds cmtp_schedule(session); 371*1da177e4SLinus Torvalds } 372*1da177e4SLinus Torvalds 373*1da177e4SLinus Torvalds static void cmtp_register_appl(struct capi_ctr *ctrl, __u16 appl, capi_register_params *rp) 374*1da177e4SLinus Torvalds { 375*1da177e4SLinus Torvalds DECLARE_WAITQUEUE(wait, current); 376*1da177e4SLinus Torvalds struct cmtp_session *session = ctrl->driverdata; 377*1da177e4SLinus Torvalds struct cmtp_application *application; 378*1da177e4SLinus Torvalds unsigned long timeo = CMTP_INTEROP_TIMEOUT; 379*1da177e4SLinus Torvalds unsigned char buf[8]; 380*1da177e4SLinus Torvalds int err = 0, nconn, want = rp->level3cnt; 381*1da177e4SLinus Torvalds 382*1da177e4SLinus Torvalds BT_DBG("ctrl %p appl %d level3cnt %d datablkcnt %d datablklen %d", 383*1da177e4SLinus Torvalds ctrl, appl, rp->level3cnt, rp->datablkcnt, rp->datablklen); 384*1da177e4SLinus Torvalds 385*1da177e4SLinus Torvalds application = cmtp_application_add(session, appl); 386*1da177e4SLinus Torvalds if (!application) { 387*1da177e4SLinus Torvalds BT_ERR("Can't allocate memory for new application"); 388*1da177e4SLinus Torvalds return; 389*1da177e4SLinus Torvalds } 390*1da177e4SLinus Torvalds 391*1da177e4SLinus Torvalds if (want < 0) 392*1da177e4SLinus Torvalds nconn = ctrl->profile.nbchannel * -want; 393*1da177e4SLinus Torvalds else 394*1da177e4SLinus Torvalds nconn = want; 395*1da177e4SLinus Torvalds 396*1da177e4SLinus Torvalds if (nconn == 0) 397*1da177e4SLinus Torvalds nconn = ctrl->profile.nbchannel; 398*1da177e4SLinus Torvalds 399*1da177e4SLinus Torvalds capimsg_setu16(buf, 0, nconn); 400*1da177e4SLinus Torvalds capimsg_setu16(buf, 2, rp->datablkcnt); 401*1da177e4SLinus Torvalds capimsg_setu16(buf, 4, rp->datablklen); 402*1da177e4SLinus Torvalds 403*1da177e4SLinus Torvalds application->state = BT_CONFIG; 404*1da177e4SLinus Torvalds application->msgnum = cmtp_msgnum_get(session); 405*1da177e4SLinus Torvalds 406*1da177e4SLinus Torvalds cmtp_send_interopmsg(session, CAPI_REQ, 0x0000, application->msgnum, 407*1da177e4SLinus Torvalds CAPI_FUNCTION_REGISTER, buf, 6); 408*1da177e4SLinus Torvalds 409*1da177e4SLinus Torvalds add_wait_queue(&session->wait, &wait); 410*1da177e4SLinus Torvalds while (1) { 411*1da177e4SLinus Torvalds set_current_state(TASK_INTERRUPTIBLE); 412*1da177e4SLinus Torvalds 413*1da177e4SLinus Torvalds if (!timeo) { 414*1da177e4SLinus Torvalds err = -EAGAIN; 415*1da177e4SLinus Torvalds break; 416*1da177e4SLinus Torvalds } 417*1da177e4SLinus Torvalds 418*1da177e4SLinus Torvalds if (application->state == BT_CLOSED) { 419*1da177e4SLinus Torvalds err = -application->err; 420*1da177e4SLinus Torvalds break; 421*1da177e4SLinus Torvalds } 422*1da177e4SLinus Torvalds 423*1da177e4SLinus Torvalds if (application->state == BT_CONNECTED) 424*1da177e4SLinus Torvalds break; 425*1da177e4SLinus Torvalds 426*1da177e4SLinus Torvalds if (signal_pending(current)) { 427*1da177e4SLinus Torvalds err = -EINTR; 428*1da177e4SLinus Torvalds break; 429*1da177e4SLinus Torvalds } 430*1da177e4SLinus Torvalds 431*1da177e4SLinus Torvalds timeo = schedule_timeout(timeo); 432*1da177e4SLinus Torvalds } 433*1da177e4SLinus Torvalds set_current_state(TASK_RUNNING); 434*1da177e4SLinus Torvalds remove_wait_queue(&session->wait, &wait); 435*1da177e4SLinus Torvalds 436*1da177e4SLinus Torvalds if (err) { 437*1da177e4SLinus Torvalds cmtp_application_del(session, application); 438*1da177e4SLinus Torvalds return; 439*1da177e4SLinus Torvalds } 440*1da177e4SLinus Torvalds } 441*1da177e4SLinus Torvalds 442*1da177e4SLinus Torvalds static void cmtp_release_appl(struct capi_ctr *ctrl, __u16 appl) 443*1da177e4SLinus Torvalds { 444*1da177e4SLinus Torvalds struct cmtp_session *session = ctrl->driverdata; 445*1da177e4SLinus Torvalds struct cmtp_application *application; 446*1da177e4SLinus Torvalds 447*1da177e4SLinus Torvalds BT_DBG("ctrl %p appl %d", ctrl, appl); 448*1da177e4SLinus Torvalds 449*1da177e4SLinus Torvalds application = cmtp_application_get(session, CMTP_APPLID, appl); 450*1da177e4SLinus Torvalds if (!application) { 451*1da177e4SLinus Torvalds BT_ERR("Can't find application"); 452*1da177e4SLinus Torvalds return; 453*1da177e4SLinus Torvalds } 454*1da177e4SLinus Torvalds 455*1da177e4SLinus Torvalds application->msgnum = cmtp_msgnum_get(session); 456*1da177e4SLinus Torvalds 457*1da177e4SLinus Torvalds cmtp_send_interopmsg(session, CAPI_REQ, application->mapping, application->msgnum, 458*1da177e4SLinus Torvalds CAPI_FUNCTION_RELEASE, NULL, 0); 459*1da177e4SLinus Torvalds 460*1da177e4SLinus Torvalds wait_event_interruptible_timeout(session->wait, 461*1da177e4SLinus Torvalds (application->state == BT_CLOSED), CMTP_INTEROP_TIMEOUT); 462*1da177e4SLinus Torvalds 463*1da177e4SLinus Torvalds cmtp_application_del(session, application); 464*1da177e4SLinus Torvalds } 465*1da177e4SLinus Torvalds 466*1da177e4SLinus Torvalds static u16 cmtp_send_message(struct capi_ctr *ctrl, struct sk_buff *skb) 467*1da177e4SLinus Torvalds { 468*1da177e4SLinus Torvalds struct cmtp_session *session = ctrl->driverdata; 469*1da177e4SLinus Torvalds struct cmtp_application *application; 470*1da177e4SLinus Torvalds __u16 appl; 471*1da177e4SLinus Torvalds __u32 contr; 472*1da177e4SLinus Torvalds 473*1da177e4SLinus Torvalds BT_DBG("ctrl %p skb %p", ctrl, skb); 474*1da177e4SLinus Torvalds 475*1da177e4SLinus Torvalds appl = CAPIMSG_APPID(skb->data); 476*1da177e4SLinus Torvalds contr = CAPIMSG_CONTROL(skb->data); 477*1da177e4SLinus Torvalds 478*1da177e4SLinus Torvalds application = cmtp_application_get(session, CMTP_APPLID, appl); 479*1da177e4SLinus Torvalds if ((!application) || (application->state != BT_CONNECTED)) { 480*1da177e4SLinus Torvalds BT_ERR("Can't find application with id %d", appl); 481*1da177e4SLinus Torvalds return CAPI_ILLAPPNR; 482*1da177e4SLinus Torvalds } 483*1da177e4SLinus Torvalds 484*1da177e4SLinus Torvalds CAPIMSG_SETAPPID(skb->data, application->mapping); 485*1da177e4SLinus Torvalds 486*1da177e4SLinus Torvalds if ((contr & 0x7f) == session->num) { 487*1da177e4SLinus Torvalds contr = (contr & 0xffffff80) | 0x01; 488*1da177e4SLinus Torvalds CAPIMSG_SETCONTROL(skb->data, contr); 489*1da177e4SLinus Torvalds } 490*1da177e4SLinus Torvalds 491*1da177e4SLinus Torvalds cmtp_send_capimsg(session, skb); 492*1da177e4SLinus Torvalds 493*1da177e4SLinus Torvalds return CAPI_NOERROR; 494*1da177e4SLinus Torvalds } 495*1da177e4SLinus Torvalds 496*1da177e4SLinus Torvalds static char *cmtp_procinfo(struct capi_ctr *ctrl) 497*1da177e4SLinus Torvalds { 498*1da177e4SLinus Torvalds return "CAPI Message Transport Protocol"; 499*1da177e4SLinus Torvalds } 500*1da177e4SLinus Torvalds 501*1da177e4SLinus Torvalds static int cmtp_ctr_read_proc(char *page, char **start, off_t off, int count, int *eof, struct capi_ctr *ctrl) 502*1da177e4SLinus Torvalds { 503*1da177e4SLinus Torvalds struct cmtp_session *session = ctrl->driverdata; 504*1da177e4SLinus Torvalds struct cmtp_application *app; 505*1da177e4SLinus Torvalds struct list_head *p, *n; 506*1da177e4SLinus Torvalds int len = 0; 507*1da177e4SLinus Torvalds 508*1da177e4SLinus Torvalds len += sprintf(page + len, "%s\n\n", cmtp_procinfo(ctrl)); 509*1da177e4SLinus Torvalds len += sprintf(page + len, "addr %s\n", session->name); 510*1da177e4SLinus Torvalds len += sprintf(page + len, "ctrl %d\n", session->num); 511*1da177e4SLinus Torvalds 512*1da177e4SLinus Torvalds list_for_each_safe(p, n, &session->applications) { 513*1da177e4SLinus Torvalds app = list_entry(p, struct cmtp_application, list); 514*1da177e4SLinus Torvalds len += sprintf(page + len, "appl %d -> %d\n", app->appl, app->mapping); 515*1da177e4SLinus Torvalds } 516*1da177e4SLinus Torvalds 517*1da177e4SLinus Torvalds if (off + count >= len) 518*1da177e4SLinus Torvalds *eof = 1; 519*1da177e4SLinus Torvalds 520*1da177e4SLinus Torvalds if (len < off) 521*1da177e4SLinus Torvalds return 0; 522*1da177e4SLinus Torvalds 523*1da177e4SLinus Torvalds *start = page + off; 524*1da177e4SLinus Torvalds 525*1da177e4SLinus Torvalds return ((count < len - off) ? count : len - off); 526*1da177e4SLinus Torvalds } 527*1da177e4SLinus Torvalds 528*1da177e4SLinus Torvalds 529*1da177e4SLinus Torvalds int cmtp_attach_device(struct cmtp_session *session) 530*1da177e4SLinus Torvalds { 531*1da177e4SLinus Torvalds unsigned char buf[4]; 532*1da177e4SLinus Torvalds long ret; 533*1da177e4SLinus Torvalds 534*1da177e4SLinus Torvalds BT_DBG("session %p", session); 535*1da177e4SLinus Torvalds 536*1da177e4SLinus Torvalds capimsg_setu32(buf, 0, 0); 537*1da177e4SLinus Torvalds 538*1da177e4SLinus Torvalds cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, CMTP_INITIAL_MSGNUM, 539*1da177e4SLinus Torvalds CAPI_FUNCTION_GET_PROFILE, buf, 4); 540*1da177e4SLinus Torvalds 541*1da177e4SLinus Torvalds ret = wait_event_interruptible_timeout(session->wait, 542*1da177e4SLinus Torvalds session->ncontroller, CMTP_INTEROP_TIMEOUT); 543*1da177e4SLinus Torvalds 544*1da177e4SLinus Torvalds BT_INFO("Found %d CAPI controller(s) on device %s", session->ncontroller, session->name); 545*1da177e4SLinus Torvalds 546*1da177e4SLinus Torvalds if (!ret) 547*1da177e4SLinus Torvalds return -ETIMEDOUT; 548*1da177e4SLinus Torvalds 549*1da177e4SLinus Torvalds if (!session->ncontroller) 550*1da177e4SLinus Torvalds return -ENODEV; 551*1da177e4SLinus Torvalds 552*1da177e4SLinus Torvalds if (session->ncontroller > 1) 553*1da177e4SLinus Torvalds BT_INFO("Setting up only CAPI controller 1"); 554*1da177e4SLinus Torvalds 555*1da177e4SLinus Torvalds session->ctrl.owner = THIS_MODULE; 556*1da177e4SLinus Torvalds session->ctrl.driverdata = session; 557*1da177e4SLinus Torvalds strcpy(session->ctrl.name, session->name); 558*1da177e4SLinus Torvalds 559*1da177e4SLinus Torvalds session->ctrl.driver_name = "cmtp"; 560*1da177e4SLinus Torvalds session->ctrl.load_firmware = cmtp_load_firmware; 561*1da177e4SLinus Torvalds session->ctrl.reset_ctr = cmtp_reset_ctr; 562*1da177e4SLinus Torvalds session->ctrl.register_appl = cmtp_register_appl; 563*1da177e4SLinus Torvalds session->ctrl.release_appl = cmtp_release_appl; 564*1da177e4SLinus Torvalds session->ctrl.send_message = cmtp_send_message; 565*1da177e4SLinus Torvalds 566*1da177e4SLinus Torvalds session->ctrl.procinfo = cmtp_procinfo; 567*1da177e4SLinus Torvalds session->ctrl.ctr_read_proc = cmtp_ctr_read_proc; 568*1da177e4SLinus Torvalds 569*1da177e4SLinus Torvalds if (attach_capi_ctr(&session->ctrl) < 0) { 570*1da177e4SLinus Torvalds BT_ERR("Can't attach new controller"); 571*1da177e4SLinus Torvalds return -EBUSY; 572*1da177e4SLinus Torvalds } 573*1da177e4SLinus Torvalds 574*1da177e4SLinus Torvalds session->num = session->ctrl.cnr; 575*1da177e4SLinus Torvalds 576*1da177e4SLinus Torvalds BT_DBG("session %p num %d", session, session->num); 577*1da177e4SLinus Torvalds 578*1da177e4SLinus Torvalds capimsg_setu32(buf, 0, 1); 579*1da177e4SLinus Torvalds 580*1da177e4SLinus Torvalds cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session), 581*1da177e4SLinus Torvalds CAPI_FUNCTION_GET_MANUFACTURER, buf, 4); 582*1da177e4SLinus Torvalds 583*1da177e4SLinus Torvalds cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session), 584*1da177e4SLinus Torvalds CAPI_FUNCTION_GET_VERSION, buf, 4); 585*1da177e4SLinus Torvalds 586*1da177e4SLinus Torvalds cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session), 587*1da177e4SLinus Torvalds CAPI_FUNCTION_GET_SERIAL_NUMBER, buf, 4); 588*1da177e4SLinus Torvalds 589*1da177e4SLinus Torvalds cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session), 590*1da177e4SLinus Torvalds CAPI_FUNCTION_GET_PROFILE, buf, 4); 591*1da177e4SLinus Torvalds 592*1da177e4SLinus Torvalds return 0; 593*1da177e4SLinus Torvalds } 594*1da177e4SLinus Torvalds 595*1da177e4SLinus Torvalds void cmtp_detach_device(struct cmtp_session *session) 596*1da177e4SLinus Torvalds { 597*1da177e4SLinus Torvalds BT_DBG("session %p", session); 598*1da177e4SLinus Torvalds 599*1da177e4SLinus Torvalds detach_capi_ctr(&session->ctrl); 600*1da177e4SLinus Torvalds } 601