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/signal.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
 104        list_for_each_entry(app, &session->applications, 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;
 118                }
 119        }
 120
 121        return NULL;
 122}
 123
 124static int cmtp_msgnum_get(struct cmtp_session *session)
 125{
 126        session->msgnum++;
 127
 128        if ((session->msgnum & 0xff) > 200)
 129                session->msgnum = CMTP_INITIAL_MSGNUM + 1;
 130
 131        return session->msgnum;
 132}
 133
 134static void cmtp_send_capimsg(struct cmtp_session *session, struct sk_buff *skb)
 135{
 136        struct cmtp_scb *scb = (void *) skb->cb;
 137
 138        BT_DBG("session %p skb %p len %d", session, skb, skb->len);
 139
 140        scb->id = -1;
 141        scb->data = (CAPIMSG_COMMAND(skb->data) == CAPI_DATA_B3);
 142
 143        skb_queue_tail(&session->transmit, skb);
 144
 145        wake_up_interruptible(sk_sleep(session->sock->sk));
 146}
 147
 148static void cmtp_send_interopmsg(struct cmtp_session *session,
 149                                        __u8 subcmd, __u16 appl, __u16 msgnum,
 150                                        __u16 function, unsigned char *buf, int len)
 151{
 152        struct sk_buff *skb;
 153        unsigned char *s;
 154
 155        BT_DBG("session %p subcmd 0x%02x appl %d msgnum %d", session, subcmd, appl, msgnum);
 156
 157        skb = alloc_skb(CAPI_MSG_BASELEN + 6 + len, GFP_ATOMIC);
 158        if (!skb) {
 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
 184static 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                        if (!info && ctrl) {
 255                                int len = min_t(uint, CAPI_MANUFACTURER_LEN,
 256                                                skb->data[CAPI_MSG_BASELEN + 14]);
 257
 258                                memset(ctrl->manu, 0, CAPI_MANUFACTURER_LEN);
 259                                strncpy(ctrl->manu,
 260                                        skb->data + CAPI_MSG_BASELEN + 15, len);
 261                        }
 262
 263                        break;
 264
 265                case CAPI_FUNCTION_GET_VERSION:
 266                        if (skb->len < CAPI_MSG_BASELEN + 32)
 267                                break;
 268
 269                        if (!info && ctrl) {
 270                                ctrl->version.majorversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 16);
 271                                ctrl->version.minorversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 20);
 272                                ctrl->version.majormanuversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 24);
 273                                ctrl->version.minormanuversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 28);
 274                        }
 275
 276                        break;
 277
 278                case CAPI_FUNCTION_GET_SERIAL_NUMBER:
 279                        if (skb->len < CAPI_MSG_BASELEN + 17)
 280                                break;
 281
 282                        if (!info && ctrl) {
 283                                int len = min_t(uint, CAPI_SERIAL_LEN,
 284                                                skb->data[CAPI_MSG_BASELEN + 16]);
 285
 286                                memset(ctrl->serial, 0, CAPI_SERIAL_LEN);
 287                                strncpy(ctrl->serial,
 288                                        skb->data + CAPI_MSG_BASELEN + 17, len);
 289                        }
 290
 291                        break;
 292                }
 293
 294                break;
 295
 296        case CAPI_IND:
 297                if (skb->len < CAPI_MSG_BASELEN + 6)
 298                        break;
 299
 300                func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 3);
 301
 302                if (func == CAPI_FUNCTION_LOOPBACK) {
 303                        int len = min_t(uint, skb->len - CAPI_MSG_BASELEN - 6,
 304                                                skb->data[CAPI_MSG_BASELEN + 5]);
 305                        appl = CAPIMSG_APPID(skb->data);
 306                        msgnum = CAPIMSG_MSGID(skb->data);
 307                        cmtp_send_interopmsg(session, CAPI_RESP, appl, msgnum, func,
 308                                                skb->data + CAPI_MSG_BASELEN + 6, len);
 309                }
 310
 311                break;
 312        }
 313
 314        kfree_skb(skb);
 315}
 316
 317void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb)
 318{
 319        struct capi_ctr *ctrl = &session->ctrl;
 320        struct cmtp_application *application;
 321        __u16 appl;
 322        __u32 contr;
 323
 324        BT_DBG("session %p skb %p len %d", session, skb, skb->len);
 325
 326        if (skb->len < CAPI_MSG_BASELEN)
 327                return;
 328
 329        if (CAPIMSG_COMMAND(skb->data) == CAPI_INTEROPERABILITY) {
 330                cmtp_recv_interopmsg(session, skb);
 331                return;
 332        }
 333
 334        if (session->flags & BIT(CMTP_LOOPBACK)) {
 335                kfree_skb(skb);
 336                return;
 337        }
 338
 339        appl = CAPIMSG_APPID(skb->data);
 340        contr = CAPIMSG_CONTROL(skb->data);
 341
 342        application = cmtp_application_get(session, CMTP_MAPPING, appl);
 343        if (application) {
 344                appl = application->appl;
 345                CAPIMSG_SETAPPID(skb->data, appl);
 346        } else {
 347                BT_ERR("Can't find application with id %d", appl);
 348                kfree_skb(skb);
 349                return;
 350        }
 351
 352        if ((contr & 0x7f) == 0x01) {
 353                contr = (contr & 0xffffff80) | session->num;
 354                CAPIMSG_SETCONTROL(skb->data, contr);
 355        }
 356
 357        capi_ctr_handle_message(ctrl, appl, skb);
 358}
 359
 360static int cmtp_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
 361{
 362        BT_DBG("ctrl %p data %p", ctrl, data);
 363
 364        return 0;
 365}
 366
 367static void cmtp_reset_ctr(struct capi_ctr *ctrl)
 368{
 369        struct cmtp_session *session = ctrl->driverdata;
 370
 371        BT_DBG("ctrl %p", ctrl);
 372
 373        capi_ctr_down(ctrl);
 374
 375        atomic_inc(&session->terminate);
 376        wake_up_process(session->task);
 377}
 378
 379static void cmtp_register_appl(struct capi_ctr *ctrl, __u16 appl, capi_register_params *rp)
 380{
 381        DECLARE_WAITQUEUE(wait, current);
 382        struct cmtp_session *session = ctrl->driverdata;
 383        struct cmtp_application *application;
 384        unsigned long timeo = CMTP_INTEROP_TIMEOUT;
 385        unsigned char buf[8];
 386        int err = 0, nconn, want = rp->level3cnt;
 387
 388        BT_DBG("ctrl %p appl %d level3cnt %d datablkcnt %d datablklen %d",
 389                ctrl, appl, rp->level3cnt, rp->datablkcnt, rp->datablklen);
 390
 391        application = cmtp_application_add(session, appl);
 392        if (!application) {
 393                BT_ERR("Can't allocate memory for new application");
 394                return;
 395        }
 396
 397        if (want < 0)
 398                nconn = ctrl->profile.nbchannel * -want;
 399        else
 400                nconn = want;
 401
 402        if (nconn == 0)
 403                nconn = ctrl->profile.nbchannel;
 404
 405        capimsg_setu16(buf, 0, nconn);
 406        capimsg_setu16(buf, 2, rp->datablkcnt);
 407        capimsg_setu16(buf, 4, rp->datablklen);
 408
 409        application->state = BT_CONFIG;
 410        application->msgnum = cmtp_msgnum_get(session);
 411
 412        cmtp_send_interopmsg(session, CAPI_REQ, 0x0000, application->msgnum,
 413                                CAPI_FUNCTION_REGISTER, buf, 6);
 414
 415        add_wait_queue(&session->wait, &wait);
 416        while (1) {
 417                set_current_state(TASK_INTERRUPTIBLE);
 418
 419                if (!timeo) {
 420                        err = -EAGAIN;
 421                        break;
 422                }
 423
 424                if (application->state == BT_CLOSED) {
 425                        err = -application->err;
 426                        break;
 427                }
 428
 429                if (application->state == BT_CONNECTED)
 430                        break;
 431
 432                if (signal_pending(current)) {
 433                        err = -EINTR;
 434                        break;
 435                }
 436
 437                timeo = schedule_timeout(timeo);
 438        }
 439        set_current_state(TASK_RUNNING);
 440        remove_wait_queue(&session->wait, &wait);
 441
 442        if (err) {
 443                cmtp_application_del(session, application);
 444                return;
 445        }
 446}
 447
 448static void cmtp_release_appl(struct capi_ctr *ctrl, __u16 appl)
 449{
 450        struct cmtp_session *session = ctrl->driverdata;
 451        struct cmtp_application *application;
 452
 453        BT_DBG("ctrl %p appl %d", ctrl, appl);
 454
 455        application = cmtp_application_get(session, CMTP_APPLID, appl);
 456        if (!application) {
 457                BT_ERR("Can't find application");
 458                return;
 459        }
 460
 461        application->msgnum = cmtp_msgnum_get(session);
 462
 463        cmtp_send_interopmsg(session, CAPI_REQ, application->mapping, application->msgnum,
 464                                CAPI_FUNCTION_RELEASE, NULL, 0);
 465
 466        wait_event_interruptible_timeout(session->wait,
 467                        (application->state == BT_CLOSED), CMTP_INTEROP_TIMEOUT);
 468
 469        cmtp_application_del(session, application);
 470}
 471
 472static u16 cmtp_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
 473{
 474        struct cmtp_session *session = ctrl->driverdata;
 475        struct cmtp_application *application;
 476        __u16 appl;
 477        __u32 contr;
 478
 479        BT_DBG("ctrl %p skb %p", ctrl, skb);
 480
 481        appl = CAPIMSG_APPID(skb->data);
 482        contr = CAPIMSG_CONTROL(skb->data);
 483
 484        application = cmtp_application_get(session, CMTP_APPLID, appl);
 485        if ((!application) || (application->state != BT_CONNECTED)) {
 486                BT_ERR("Can't find application with id %d", appl);
 487                return CAPI_ILLAPPNR;
 488        }
 489
 490        CAPIMSG_SETAPPID(skb->data, application->mapping);
 491
 492        if ((contr & 0x7f) == session->num) {
 493                contr = (contr & 0xffffff80) | 0x01;
 494                CAPIMSG_SETCONTROL(skb->data, contr);
 495        }
 496
 497        cmtp_send_capimsg(session, skb);
 498
 499        return CAPI_NOERROR;
 500}
 501
 502static char *cmtp_procinfo(struct capi_ctr *ctrl)
 503{
 504        return "CAPI Message Transport Protocol";
 505}
 506
 507static int cmtp_proc_show(struct seq_file *m, void *v)
 508{
 509        struct capi_ctr *ctrl = m->private;
 510        struct cmtp_session *session = ctrl->driverdata;
 511        struct cmtp_application *app;
 512
 513        seq_printf(m, "%s\n\n", cmtp_procinfo(ctrl));
 514        seq_printf(m, "addr %s\n", session->name);
 515        seq_printf(m, "ctrl %d\n", session->num);
 516
 517        list_for_each_entry(app, &session->applications, list) {
 518                seq_printf(m, "appl %d -> %d\n", app->appl, app->mapping);
 519        }
 520
 521        return 0;
 522}
 523
 524int cmtp_attach_device(struct cmtp_session *session)
 525{
 526        unsigned char buf[4];
 527        long ret;
 528
 529        BT_DBG("session %p", session);
 530
 531        capimsg_setu32(buf, 0, 0);
 532
 533        cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, CMTP_INITIAL_MSGNUM,
 534                                CAPI_FUNCTION_GET_PROFILE, buf, 4);
 535
 536        ret = wait_event_interruptible_timeout(session->wait,
 537                        session->ncontroller, CMTP_INTEROP_TIMEOUT);
 538
 539        BT_INFO("Found %d CAPI controller(s) on device %s", session->ncontroller, session->name);
 540
 541        if (!ret)
 542                return -ETIMEDOUT;
 543
 544        if (!session->ncontroller)
 545                return -ENODEV;
 546
 547        if (session->ncontroller > 1)
 548                BT_INFO("Setting up only CAPI controller 1");
 549
 550        session->ctrl.owner      = THIS_MODULE;
 551        session->ctrl.driverdata = session;
 552        strcpy(session->ctrl.name, session->name);
 553
 554        session->ctrl.driver_name   = "cmtp";
 555        session->ctrl.load_firmware = cmtp_load_firmware;
 556        session->ctrl.reset_ctr     = cmtp_reset_ctr;
 557        session->ctrl.register_appl = cmtp_register_appl;
 558        session->ctrl.release_appl  = cmtp_release_appl;
 559        session->ctrl.send_message  = cmtp_send_message;
 560
 561        session->ctrl.procinfo      = cmtp_procinfo;
 562        session->ctrl.proc_show     = cmtp_proc_show;
 563
 564        if (attach_capi_ctr(&session->ctrl) < 0) {
 565                BT_ERR("Can't attach new controller");
 566                return -EBUSY;
 567        }
 568
 569        session->num = session->ctrl.cnr;
 570
 571        BT_DBG("session %p num %d", session, session->num);
 572
 573        capimsg_setu32(buf, 0, 1);
 574
 575        cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
 576                                CAPI_FUNCTION_GET_MANUFACTURER, buf, 4);
 577
 578        cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
 579                                CAPI_FUNCTION_GET_VERSION, buf, 4);
 580
 581        cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
 582                                CAPI_FUNCTION_GET_SERIAL_NUMBER, buf, 4);
 583
 584        cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
 585                                CAPI_FUNCTION_GET_PROFILE, buf, 4);
 586
 587        return 0;
 588}
 589
 590void cmtp_detach_device(struct cmtp_session *session)
 591{
 592        BT_DBG("session %p", session);
 593
 594        detach_capi_ctr(&session->ctrl);
 595}
 596