linux/net/bluetooth/cmtp/capi.c
<<
>>
Prefs
   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
  73static 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
  90static 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
 100static 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, *n;
 104
 105        list_for_each_safe(p, n, &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
 126static 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
 136static 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
 150static 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
 186static 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
 319void 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
 362static 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
 369static 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
 381static 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
 450static 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
 474static 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
 504static char *cmtp_procinfo(struct capi_ctr *ctrl)
 505{
 506        return "CAPI Message Transport Protocol";
 507}
 508
 509static 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, *n;
 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_safe(p, n, &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
 528static int cmtp_proc_open(struct inode *inode, struct file *file)
 529{
 530        return single_open(file, cmtp_proc_show, PDE_DATA(inode));
 531}
 532
 533static 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
 541int 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
 607void cmtp_detach_device(struct cmtp_session *session)
 608{
 609        BT_DBG("session %p", session);
 610
 611        detach_capi_ctr(&session->ctrl);
 612}
 613