root/net/bluetooth/cmtp/capi.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. cmtp_application_add
  2. cmtp_application_del
  3. cmtp_application_get
  4. cmtp_msgnum_get
  5. cmtp_send_capimsg
  6. cmtp_send_interopmsg
  7. cmtp_recv_interopmsg
  8. cmtp_recv_capimsg
  9. cmtp_load_firmware
  10. cmtp_reset_ctr
  11. cmtp_register_appl
  12. cmtp_release_appl
  13. cmtp_send_message
  14. cmtp_procinfo
  15. cmtp_proc_show
  16. cmtp_attach_device
  17. cmtp_detach_device

   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 
  73 static 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 
  90 static 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 
 100 static 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 
 124 static 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 
 134 static 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 
 148 static void cmtp_send_interopmsg(struct cmtp_session *session,
 149                                         __u8 subcmd, __u16 appl, __u16 msgnum,
 150                                         __u16 function, unsigned char *buf, int len)
 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 
 184 static 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 
 317 void 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 
 360 static 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 
 367 static 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 
 379 static 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 
 448 static 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 
 472 static 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 
 502 static char *cmtp_procinfo(struct capi_ctr *ctrl)
 503 {
 504         return "CAPI Message Transport Protocol";
 505 }
 506 
 507 static 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 
 524 int 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 
 590 void cmtp_detach_device(struct cmtp_session *session)
 591 {
 592         BT_DBG("session %p", session);
 593 
 594         detach_capi_ctr(&session->ctrl);
 595 }

/* [<][>][^][v][top][bottom][index][help] */