Back to home page

OSCL-LXR

 
 

    


0001 /*
0002    CMTP implementation for Linux Bluetooth stack (BlueZ).
0003    Copyright (C) 2002-2003 Marcel Holtmann <marcel@holtmann.org>
0004 
0005    This program is free software; you can redistribute it and/or modify
0006    it under the terms of the GNU General Public License version 2 as
0007    published by the Free Software Foundation;
0008 
0009    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
0010    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0011    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
0012    IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
0013    CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
0014    WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
0015    ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
0016    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
0017 
0018    ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
0019    COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
0020    SOFTWARE IS DISCLAIMED.
0021 */
0022 
0023 #include <linux/export.h>
0024 #include <linux/proc_fs.h>
0025 #include <linux/seq_file.h>
0026 #include <linux/types.h>
0027 #include <linux/errno.h>
0028 #include <linux/kernel.h>
0029 #include <linux/sched/signal.h>
0030 #include <linux/slab.h>
0031 #include <linux/poll.h>
0032 #include <linux/fcntl.h>
0033 #include <linux/skbuff.h>
0034 #include <linux/socket.h>
0035 #include <linux/ioctl.h>
0036 #include <linux/file.h>
0037 #include <linux/wait.h>
0038 #include <linux/kthread.h>
0039 #include <net/sock.h>
0040 
0041 #include <linux/isdn/capilli.h>
0042 #include <linux/isdn/capicmd.h>
0043 #include <linux/isdn/capiutil.h>
0044 
0045 #include "cmtp.h"
0046 
0047 #define CAPI_INTEROPERABILITY       0x20
0048 
0049 #define CAPI_INTEROPERABILITY_REQ   CAPICMD(CAPI_INTEROPERABILITY, CAPI_REQ)
0050 #define CAPI_INTEROPERABILITY_CONF  CAPICMD(CAPI_INTEROPERABILITY, CAPI_CONF)
0051 #define CAPI_INTEROPERABILITY_IND   CAPICMD(CAPI_INTEROPERABILITY, CAPI_IND)
0052 #define CAPI_INTEROPERABILITY_RESP  CAPICMD(CAPI_INTEROPERABILITY, CAPI_RESP)
0053 
0054 #define CAPI_INTEROPERABILITY_REQ_LEN   (CAPI_MSG_BASELEN + 2)
0055 #define CAPI_INTEROPERABILITY_CONF_LEN  (CAPI_MSG_BASELEN + 4)
0056 #define CAPI_INTEROPERABILITY_IND_LEN   (CAPI_MSG_BASELEN + 2)
0057 #define CAPI_INTEROPERABILITY_RESP_LEN  (CAPI_MSG_BASELEN + 2)
0058 
0059 #define CAPI_FUNCTION_REGISTER      0
0060 #define CAPI_FUNCTION_RELEASE       1
0061 #define CAPI_FUNCTION_GET_PROFILE   2
0062 #define CAPI_FUNCTION_GET_MANUFACTURER  3
0063 #define CAPI_FUNCTION_GET_VERSION   4
0064 #define CAPI_FUNCTION_GET_SERIAL_NUMBER 5
0065 #define CAPI_FUNCTION_MANUFACTURER  6
0066 #define CAPI_FUNCTION_LOOPBACK      7
0067 
0068 
0069 #define CMTP_MSGNUM 1
0070 #define CMTP_APPLID 2
0071 #define CMTP_MAPPING    3
0072 
0073 static struct cmtp_application *cmtp_application_add(struct cmtp_session *session, __u16 appl)
0074 {
0075     struct cmtp_application *app = kzalloc(sizeof(*app), GFP_KERNEL);
0076 
0077     BT_DBG("session %p application %p appl %u", session, app, appl);
0078 
0079     if (!app)
0080         return NULL;
0081 
0082     app->state = BT_OPEN;
0083     app->appl = appl;
0084 
0085     list_add_tail(&app->list, &session->applications);
0086 
0087     return app;
0088 }
0089 
0090 static void cmtp_application_del(struct cmtp_session *session, struct cmtp_application *app)
0091 {
0092     BT_DBG("session %p application %p", session, app);
0093 
0094     if (app) {
0095         list_del(&app->list);
0096         kfree(app);
0097     }
0098 }
0099 
0100 static struct cmtp_application *cmtp_application_get(struct cmtp_session *session, int pattern, __u16 value)
0101 {
0102     struct cmtp_application *app;
0103 
0104     list_for_each_entry(app, &session->applications, list) {
0105         switch (pattern) {
0106         case CMTP_MSGNUM:
0107             if (app->msgnum == value)
0108                 return app;
0109             break;
0110         case CMTP_APPLID:
0111             if (app->appl == value)
0112                 return app;
0113             break;
0114         case CMTP_MAPPING:
0115             if (app->mapping == value)
0116                 return app;
0117             break;
0118         }
0119     }
0120 
0121     return NULL;
0122 }
0123 
0124 static int cmtp_msgnum_get(struct cmtp_session *session)
0125 {
0126     session->msgnum++;
0127 
0128     if ((session->msgnum & 0xff) > 200)
0129         session->msgnum = CMTP_INITIAL_MSGNUM + 1;
0130 
0131     return session->msgnum;
0132 }
0133 
0134 static void cmtp_send_capimsg(struct cmtp_session *session, struct sk_buff *skb)
0135 {
0136     struct cmtp_scb *scb = (void *) skb->cb;
0137 
0138     BT_DBG("session %p skb %p len %u", session, skb, skb->len);
0139 
0140     scb->id = -1;
0141     scb->data = (CAPIMSG_COMMAND(skb->data) == CAPI_DATA_B3);
0142 
0143     skb_queue_tail(&session->transmit, skb);
0144 
0145     wake_up_interruptible(sk_sleep(session->sock->sk));
0146 }
0147 
0148 static void cmtp_send_interopmsg(struct cmtp_session *session,
0149                     __u8 subcmd, __u16 appl, __u16 msgnum,
0150                     __u16 function, unsigned char *buf, int len)
0151 {
0152     struct sk_buff *skb;
0153     unsigned char *s;
0154 
0155     BT_DBG("session %p subcmd 0x%02x appl %u msgnum %u", session, subcmd, appl, msgnum);
0156 
0157     skb = alloc_skb(CAPI_MSG_BASELEN + 6 + len, GFP_ATOMIC);
0158     if (!skb) {
0159         BT_ERR("Can't allocate memory for interoperability packet");
0160         return;
0161     }
0162 
0163     s = skb_put(skb, CAPI_MSG_BASELEN + 6 + len);
0164 
0165     capimsg_setu16(s, 0, CAPI_MSG_BASELEN + 6 + len);
0166     capimsg_setu16(s, 2, appl);
0167     capimsg_setu8 (s, 4, CAPI_INTEROPERABILITY);
0168     capimsg_setu8 (s, 5, subcmd);
0169     capimsg_setu16(s, 6, msgnum);
0170 
0171     /* Interoperability selector (Bluetooth Device Management) */
0172     capimsg_setu16(s, 8, 0x0001);
0173 
0174     capimsg_setu8 (s, 10, 3 + len);
0175     capimsg_setu16(s, 11, function);
0176     capimsg_setu8 (s, 13, len);
0177 
0178     if (len > 0)
0179         memcpy(s + 14, buf, len);
0180 
0181     cmtp_send_capimsg(session, skb);
0182 }
0183 
0184 static void cmtp_recv_interopmsg(struct cmtp_session *session, struct sk_buff *skb)
0185 {
0186     struct capi_ctr *ctrl = &session->ctrl;
0187     struct cmtp_application *application;
0188     __u16 appl, msgnum, func, info;
0189     __u32 controller;
0190 
0191     BT_DBG("session %p skb %p len %u", session, skb, skb->len);
0192 
0193     switch (CAPIMSG_SUBCOMMAND(skb->data)) {
0194     case CAPI_CONF:
0195         if (skb->len < CAPI_MSG_BASELEN + 10)
0196             break;
0197 
0198         func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 5);
0199         info = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 8);
0200 
0201         switch (func) {
0202         case CAPI_FUNCTION_REGISTER:
0203             msgnum = CAPIMSG_MSGID(skb->data);
0204 
0205             application = cmtp_application_get(session, CMTP_MSGNUM, msgnum);
0206             if (application) {
0207                 application->state = BT_CONNECTED;
0208                 application->msgnum = 0;
0209                 application->mapping = CAPIMSG_APPID(skb->data);
0210                 wake_up_interruptible(&session->wait);
0211             }
0212 
0213             break;
0214 
0215         case CAPI_FUNCTION_RELEASE:
0216             appl = CAPIMSG_APPID(skb->data);
0217 
0218             application = cmtp_application_get(session, CMTP_MAPPING, appl);
0219             if (application) {
0220                 application->state = BT_CLOSED;
0221                 application->msgnum = 0;
0222                 wake_up_interruptible(&session->wait);
0223             }
0224 
0225             break;
0226 
0227         case CAPI_FUNCTION_GET_PROFILE:
0228             if (skb->len < CAPI_MSG_BASELEN + 11 + sizeof(capi_profile))
0229                 break;
0230 
0231             controller = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 11);
0232             msgnum = CAPIMSG_MSGID(skb->data);
0233 
0234             if (!info && (msgnum == CMTP_INITIAL_MSGNUM)) {
0235                 session->ncontroller = controller;
0236                 wake_up_interruptible(&session->wait);
0237                 break;
0238             }
0239 
0240             if (!info && ctrl) {
0241                 memcpy(&ctrl->profile,
0242                     skb->data + CAPI_MSG_BASELEN + 11,
0243                     sizeof(capi_profile));
0244                 session->state = BT_CONNECTED;
0245                 capi_ctr_ready(ctrl);
0246             }
0247 
0248             break;
0249 
0250         case CAPI_FUNCTION_GET_MANUFACTURER:
0251             if (skb->len < CAPI_MSG_BASELEN + 15)
0252                 break;
0253 
0254             if (!info && ctrl) {
0255                 int len = min_t(uint, CAPI_MANUFACTURER_LEN,
0256                         skb->data[CAPI_MSG_BASELEN + 14]);
0257 
0258                 memset(ctrl->manu, 0, CAPI_MANUFACTURER_LEN);
0259                 strncpy(ctrl->manu,
0260                     skb->data + CAPI_MSG_BASELEN + 15, len);
0261             }
0262 
0263             break;
0264 
0265         case CAPI_FUNCTION_GET_VERSION:
0266             if (skb->len < CAPI_MSG_BASELEN + 32)
0267                 break;
0268 
0269             if (!info && ctrl) {
0270                 ctrl->version.majorversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 16);
0271                 ctrl->version.minorversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 20);
0272                 ctrl->version.majormanuversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 24);
0273                 ctrl->version.minormanuversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 28);
0274             }
0275 
0276             break;
0277 
0278         case CAPI_FUNCTION_GET_SERIAL_NUMBER:
0279             if (skb->len < CAPI_MSG_BASELEN + 17)
0280                 break;
0281 
0282             if (!info && ctrl) {
0283                 int len = min_t(uint, CAPI_SERIAL_LEN,
0284                         skb->data[CAPI_MSG_BASELEN + 16]);
0285 
0286                 memset(ctrl->serial, 0, CAPI_SERIAL_LEN);
0287                 strncpy(ctrl->serial,
0288                     skb->data + CAPI_MSG_BASELEN + 17, len);
0289             }
0290 
0291             break;
0292         }
0293 
0294         break;
0295 
0296     case CAPI_IND:
0297         if (skb->len < CAPI_MSG_BASELEN + 6)
0298             break;
0299 
0300         func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 3);
0301 
0302         if (func == CAPI_FUNCTION_LOOPBACK) {
0303             int len = min_t(uint, skb->len - CAPI_MSG_BASELEN - 6,
0304                         skb->data[CAPI_MSG_BASELEN + 5]);
0305             appl = CAPIMSG_APPID(skb->data);
0306             msgnum = CAPIMSG_MSGID(skb->data);
0307             cmtp_send_interopmsg(session, CAPI_RESP, appl, msgnum, func,
0308                         skb->data + CAPI_MSG_BASELEN + 6, len);
0309         }
0310 
0311         break;
0312     }
0313 
0314     kfree_skb(skb);
0315 }
0316 
0317 void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb)
0318 {
0319     struct capi_ctr *ctrl = &session->ctrl;
0320     struct cmtp_application *application;
0321     __u16 appl;
0322     __u32 contr;
0323 
0324     BT_DBG("session %p skb %p len %u", session, skb, skb->len);
0325 
0326     if (skb->len < CAPI_MSG_BASELEN)
0327         return;
0328 
0329     if (CAPIMSG_COMMAND(skb->data) == CAPI_INTEROPERABILITY) {
0330         cmtp_recv_interopmsg(session, skb);
0331         return;
0332     }
0333 
0334     if (session->flags & BIT(CMTP_LOOPBACK)) {
0335         kfree_skb(skb);
0336         return;
0337     }
0338 
0339     appl = CAPIMSG_APPID(skb->data);
0340     contr = CAPIMSG_CONTROL(skb->data);
0341 
0342     application = cmtp_application_get(session, CMTP_MAPPING, appl);
0343     if (application) {
0344         appl = application->appl;
0345         CAPIMSG_SETAPPID(skb->data, appl);
0346     } else {
0347         BT_ERR("Can't find application with id %u", appl);
0348         kfree_skb(skb);
0349         return;
0350     }
0351 
0352     if ((contr & 0x7f) == 0x01) {
0353         contr = (contr & 0xffffff80) | session->num;
0354         CAPIMSG_SETCONTROL(skb->data, contr);
0355     }
0356 
0357     capi_ctr_handle_message(ctrl, appl, skb);
0358 }
0359 
0360 static int cmtp_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
0361 {
0362     BT_DBG("ctrl %p data %p", ctrl, data);
0363 
0364     return 0;
0365 }
0366 
0367 static void cmtp_reset_ctr(struct capi_ctr *ctrl)
0368 {
0369     struct cmtp_session *session = ctrl->driverdata;
0370 
0371     BT_DBG("ctrl %p", ctrl);
0372 
0373     capi_ctr_down(ctrl);
0374 
0375     atomic_inc(&session->terminate);
0376     wake_up_process(session->task);
0377 }
0378 
0379 static void cmtp_register_appl(struct capi_ctr *ctrl, __u16 appl, capi_register_params *rp)
0380 {
0381     DECLARE_WAITQUEUE(wait, current);
0382     struct cmtp_session *session = ctrl->driverdata;
0383     struct cmtp_application *application;
0384     unsigned long timeo = CMTP_INTEROP_TIMEOUT;
0385     unsigned char buf[8];
0386     int err = 0, nconn, want = rp->level3cnt;
0387 
0388     BT_DBG("ctrl %p appl %u level3cnt %u datablkcnt %u datablklen %u",
0389            ctrl, appl, rp->level3cnt, rp->datablkcnt, rp->datablklen);
0390 
0391     application = cmtp_application_add(session, appl);
0392     if (!application) {
0393         BT_ERR("Can't allocate memory for new application");
0394         return;
0395     }
0396 
0397     if (want < 0)
0398         nconn = ctrl->profile.nbchannel * -want;
0399     else
0400         nconn = want;
0401 
0402     if (nconn == 0)
0403         nconn = ctrl->profile.nbchannel;
0404 
0405     capimsg_setu16(buf, 0, nconn);
0406     capimsg_setu16(buf, 2, rp->datablkcnt);
0407     capimsg_setu16(buf, 4, rp->datablklen);
0408 
0409     application->state = BT_CONFIG;
0410     application->msgnum = cmtp_msgnum_get(session);
0411 
0412     cmtp_send_interopmsg(session, CAPI_REQ, 0x0000, application->msgnum,
0413                 CAPI_FUNCTION_REGISTER, buf, 6);
0414 
0415     add_wait_queue(&session->wait, &wait);
0416     while (1) {
0417         set_current_state(TASK_INTERRUPTIBLE);
0418 
0419         if (!timeo) {
0420             err = -EAGAIN;
0421             break;
0422         }
0423 
0424         if (application->state == BT_CLOSED) {
0425             err = -application->err;
0426             break;
0427         }
0428 
0429         if (application->state == BT_CONNECTED)
0430             break;
0431 
0432         if (signal_pending(current)) {
0433             err = -EINTR;
0434             break;
0435         }
0436 
0437         timeo = schedule_timeout(timeo);
0438     }
0439     set_current_state(TASK_RUNNING);
0440     remove_wait_queue(&session->wait, &wait);
0441 
0442     if (err) {
0443         cmtp_application_del(session, application);
0444         return;
0445     }
0446 }
0447 
0448 static void cmtp_release_appl(struct capi_ctr *ctrl, __u16 appl)
0449 {
0450     struct cmtp_session *session = ctrl->driverdata;
0451     struct cmtp_application *application;
0452 
0453     BT_DBG("ctrl %p appl %u", ctrl, appl);
0454 
0455     application = cmtp_application_get(session, CMTP_APPLID, appl);
0456     if (!application) {
0457         BT_ERR("Can't find application");
0458         return;
0459     }
0460 
0461     application->msgnum = cmtp_msgnum_get(session);
0462 
0463     cmtp_send_interopmsg(session, CAPI_REQ, application->mapping, application->msgnum,
0464                 CAPI_FUNCTION_RELEASE, NULL, 0);
0465 
0466     wait_event_interruptible_timeout(session->wait,
0467             (application->state == BT_CLOSED), CMTP_INTEROP_TIMEOUT);
0468 
0469     cmtp_application_del(session, application);
0470 }
0471 
0472 static u16 cmtp_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
0473 {
0474     struct cmtp_session *session = ctrl->driverdata;
0475     struct cmtp_application *application;
0476     __u16 appl;
0477     __u32 contr;
0478 
0479     BT_DBG("ctrl %p skb %p", ctrl, skb);
0480 
0481     appl = CAPIMSG_APPID(skb->data);
0482     contr = CAPIMSG_CONTROL(skb->data);
0483 
0484     application = cmtp_application_get(session, CMTP_APPLID, appl);
0485     if ((!application) || (application->state != BT_CONNECTED)) {
0486         BT_ERR("Can't find application with id %u", appl);
0487         return CAPI_ILLAPPNR;
0488     }
0489 
0490     CAPIMSG_SETAPPID(skb->data, application->mapping);
0491 
0492     if ((contr & 0x7f) == session->num) {
0493         contr = (contr & 0xffffff80) | 0x01;
0494         CAPIMSG_SETCONTROL(skb->data, contr);
0495     }
0496 
0497     cmtp_send_capimsg(session, skb);
0498 
0499     return CAPI_NOERROR;
0500 }
0501 
0502 static char *cmtp_procinfo(struct capi_ctr *ctrl)
0503 {
0504     return "CAPI Message Transport Protocol";
0505 }
0506 
0507 static int cmtp_proc_show(struct seq_file *m, void *v)
0508 {
0509     struct capi_ctr *ctrl = m->private;
0510     struct cmtp_session *session = ctrl->driverdata;
0511     struct cmtp_application *app;
0512 
0513     seq_printf(m, "%s\n\n", cmtp_procinfo(ctrl));
0514     seq_printf(m, "addr %s\n", session->name);
0515     seq_printf(m, "ctrl %d\n", session->num);
0516 
0517     list_for_each_entry(app, &session->applications, list) {
0518         seq_printf(m, "appl %u -> %u\n", app->appl, app->mapping);
0519     }
0520 
0521     return 0;
0522 }
0523 
0524 int cmtp_attach_device(struct cmtp_session *session)
0525 {
0526     unsigned char buf[4];
0527     long ret;
0528 
0529     BT_DBG("session %p", session);
0530 
0531     capimsg_setu32(buf, 0, 0);
0532 
0533     cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, CMTP_INITIAL_MSGNUM,
0534                 CAPI_FUNCTION_GET_PROFILE, buf, 4);
0535 
0536     ret = wait_event_interruptible_timeout(session->wait,
0537             session->ncontroller, CMTP_INTEROP_TIMEOUT);
0538 
0539     BT_INFO("Found %d CAPI controller(s) on device %s", session->ncontroller, session->name);
0540 
0541     if (!ret)
0542         return -ETIMEDOUT;
0543 
0544     if (!session->ncontroller)
0545         return -ENODEV;
0546 
0547     if (session->ncontroller > 1)
0548         BT_INFO("Setting up only CAPI controller 1");
0549 
0550     session->ctrl.owner      = THIS_MODULE;
0551     session->ctrl.driverdata = session;
0552     strcpy(session->ctrl.name, session->name);
0553 
0554     session->ctrl.driver_name   = "cmtp";
0555     session->ctrl.load_firmware = cmtp_load_firmware;
0556     session->ctrl.reset_ctr     = cmtp_reset_ctr;
0557     session->ctrl.register_appl = cmtp_register_appl;
0558     session->ctrl.release_appl  = cmtp_release_appl;
0559     session->ctrl.send_message  = cmtp_send_message;
0560 
0561     session->ctrl.procinfo      = cmtp_procinfo;
0562     session->ctrl.proc_show     = cmtp_proc_show;
0563 
0564     if (attach_capi_ctr(&session->ctrl) < 0) {
0565         BT_ERR("Can't attach new controller");
0566         return -EBUSY;
0567     }
0568 
0569     session->num = session->ctrl.cnr;
0570 
0571     BT_DBG("session %p num %d", session, session->num);
0572 
0573     capimsg_setu32(buf, 0, 1);
0574 
0575     cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
0576                 CAPI_FUNCTION_GET_MANUFACTURER, buf, 4);
0577 
0578     cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
0579                 CAPI_FUNCTION_GET_VERSION, buf, 4);
0580 
0581     cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
0582                 CAPI_FUNCTION_GET_SERIAL_NUMBER, buf, 4);
0583 
0584     cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
0585                 CAPI_FUNCTION_GET_PROFILE, buf, 4);
0586 
0587     return 0;
0588 }
0589 
0590 void cmtp_detach_device(struct cmtp_session *session)
0591 {
0592     BT_DBG("session %p", session);
0593 
0594     detach_capi_ctr(&session->ctrl);
0595 }