linux/net/bluetooth/cmtp/core.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/module.h>
  24
  25#include <linux/types.h>
  26#include <linux/errno.h>
  27#include <linux/kernel.h>
  28#include <linux/sched.h>
  29#include <linux/slab.h>
  30#include <linux/poll.h>
  31#include <linux/fcntl.h>
  32#include <linux/freezer.h>
  33#include <linux/skbuff.h>
  34#include <linux/socket.h>
  35#include <linux/ioctl.h>
  36#include <linux/file.h>
  37#include <linux/init.h>
  38#include <net/sock.h>
  39
  40#include <linux/isdn/capilli.h>
  41
  42#include <net/bluetooth/bluetooth.h>
  43#include <net/bluetooth/l2cap.h>
  44
  45#include "cmtp.h"
  46
  47#ifndef CONFIG_BT_CMTP_DEBUG
  48#undef  BT_DBG
  49#define BT_DBG(D...)
  50#endif
  51
  52#define VERSION "1.0"
  53
  54static DECLARE_RWSEM(cmtp_session_sem);
  55static LIST_HEAD(cmtp_session_list);
  56
  57static struct cmtp_session *__cmtp_get_session(bdaddr_t *bdaddr)
  58{
  59        struct cmtp_session *session;
  60        struct list_head *p;
  61
  62        BT_DBG("");
  63
  64        list_for_each(p, &cmtp_session_list) {
  65                session = list_entry(p, struct cmtp_session, list);
  66                if (!bacmp(bdaddr, &session->bdaddr))
  67                        return session;
  68        }
  69        return NULL;
  70}
  71
  72static void __cmtp_link_session(struct cmtp_session *session)
  73{
  74        __module_get(THIS_MODULE);
  75        list_add(&session->list, &cmtp_session_list);
  76}
  77
  78static void __cmtp_unlink_session(struct cmtp_session *session)
  79{
  80        list_del(&session->list);
  81        module_put(THIS_MODULE);
  82}
  83
  84static void __cmtp_copy_session(struct cmtp_session *session, struct cmtp_conninfo *ci)
  85{
  86        bacpy(&ci->bdaddr, &session->bdaddr);
  87
  88        ci->flags = session->flags;
  89        ci->state = session->state;
  90
  91        ci->num = session->num;
  92}
  93
  94
  95static inline int cmtp_alloc_block_id(struct cmtp_session *session)
  96{
  97        int i, id = -1;
  98
  99        for (i = 0; i < 16; i++)
 100                if (!test_and_set_bit(i, &session->blockids)) {
 101                        id = i;
 102                        break;
 103                }
 104
 105        return id;
 106}
 107
 108static inline void cmtp_free_block_id(struct cmtp_session *session, int id)
 109{
 110        clear_bit(id, &session->blockids);
 111}
 112
 113static inline void cmtp_add_msgpart(struct cmtp_session *session, int id, const unsigned char *buf, int count)
 114{
 115        struct sk_buff *skb = session->reassembly[id], *nskb;
 116        int size;
 117
 118        BT_DBG("session %p buf %p count %d", session, buf, count);
 119
 120        size = (skb) ? skb->len + count : count;
 121
 122        if (!(nskb = alloc_skb(size, GFP_ATOMIC))) {
 123                BT_ERR("Can't allocate memory for CAPI message");
 124                return;
 125        }
 126
 127        if (skb && (skb->len > 0))
 128                skb_copy_from_linear_data(skb, skb_put(nskb, skb->len), skb->len);
 129
 130        memcpy(skb_put(nskb, count), buf, count);
 131
 132        session->reassembly[id] = nskb;
 133
 134        if (skb)
 135                kfree_skb(skb);
 136}
 137
 138static inline int cmtp_recv_frame(struct cmtp_session *session, struct sk_buff *skb)
 139{
 140        __u8 hdr, hdrlen, id;
 141        __u16 len;
 142
 143        BT_DBG("session %p skb %p len %d", session, skb, skb->len);
 144
 145        while (skb->len > 0) {
 146                hdr = skb->data[0];
 147
 148                switch (hdr & 0xc0) {
 149                case 0x40:
 150                        hdrlen = 2;
 151                        len = skb->data[1];
 152                        break;
 153                case 0x80:
 154                        hdrlen = 3;
 155                        len = skb->data[1] | (skb->data[2] << 8);
 156                        break;
 157                default:
 158                        hdrlen = 1;
 159                        len = 0;
 160                        break;
 161                }
 162
 163                id = (hdr & 0x3c) >> 2;
 164
 165                BT_DBG("hdr 0x%02x hdrlen %d len %d id %d", hdr, hdrlen, len, id);
 166
 167                if (hdrlen + len > skb->len) {
 168                        BT_ERR("Wrong size or header information in CMTP frame");
 169                        break;
 170                }
 171
 172                if (len == 0) {
 173                        skb_pull(skb, hdrlen);
 174                        continue;
 175                }
 176
 177                switch (hdr & 0x03) {
 178                case 0x00:
 179                        cmtp_add_msgpart(session, id, skb->data + hdrlen, len);
 180                        cmtp_recv_capimsg(session, session->reassembly[id]);
 181                        session->reassembly[id] = NULL;
 182                        break;
 183                case 0x01:
 184                        cmtp_add_msgpart(session, id, skb->data + hdrlen, len);
 185                        break;
 186                default:
 187                        if (session->reassembly[id] != NULL)
 188                                kfree_skb(session->reassembly[id]);
 189                        session->reassembly[id] = NULL;
 190                        break;
 191                }
 192
 193                skb_pull(skb, hdrlen + len);
 194        }
 195
 196        kfree_skb(skb);
 197        return 0;
 198}
 199
 200static int cmtp_send_frame(struct cmtp_session *session, unsigned char *data, int len)
 201{
 202        struct socket *sock = session->sock;
 203        struct kvec iv = { data, len };
 204        struct msghdr msg;
 205
 206        BT_DBG("session %p data %p len %d", session, data, len);
 207
 208        if (!len)
 209                return 0;
 210
 211        memset(&msg, 0, sizeof(msg));
 212
 213        return kernel_sendmsg(sock, &msg, &iv, 1, len);
 214}
 215
 216static void cmtp_process_transmit(struct cmtp_session *session)
 217{
 218        struct sk_buff *skb, *nskb;
 219        unsigned char *hdr;
 220        unsigned int size, tail;
 221
 222        BT_DBG("session %p", session);
 223
 224        if (!(nskb = alloc_skb(session->mtu, GFP_ATOMIC))) {
 225                BT_ERR("Can't allocate memory for new frame");
 226                return;
 227        }
 228
 229        while ((skb = skb_dequeue(&session->transmit))) {
 230                struct cmtp_scb *scb = (void *) skb->cb;
 231
 232                if ((tail = (session->mtu - nskb->len)) < 5) {
 233                        cmtp_send_frame(session, nskb->data, nskb->len);
 234                        skb_trim(nskb, 0);
 235                        tail = session->mtu;
 236                }
 237
 238                size = min_t(uint, ((tail < 258) ? (tail - 2) : (tail - 3)), skb->len);
 239
 240                if ((scb->id < 0) && ((scb->id = cmtp_alloc_block_id(session)) < 0)) {
 241                        skb_queue_head(&session->transmit, skb);
 242                        break;
 243                }
 244
 245                if (size < 256) {
 246                        hdr = skb_put(nskb, 2);
 247                        hdr[0] = 0x40
 248                                | ((scb->id << 2) & 0x3c)
 249                                | ((skb->len == size) ? 0x00 : 0x01);
 250                        hdr[1] = size;
 251                } else {
 252                        hdr = skb_put(nskb, 3);
 253                        hdr[0] = 0x80
 254                                | ((scb->id << 2) & 0x3c)
 255                                | ((skb->len == size) ? 0x00 : 0x01);
 256                        hdr[1] = size & 0xff;
 257                        hdr[2] = size >> 8;
 258                }
 259
 260                skb_copy_from_linear_data(skb, skb_put(nskb, size), size);
 261                skb_pull(skb, size);
 262
 263                if (skb->len > 0) {
 264                        skb_queue_head(&session->transmit, skb);
 265                } else {
 266                        cmtp_free_block_id(session, scb->id);
 267                        if (scb->data) {
 268                                cmtp_send_frame(session, nskb->data, nskb->len);
 269                                skb_trim(nskb, 0);
 270                        }
 271                        kfree_skb(skb);
 272                }
 273        }
 274
 275        cmtp_send_frame(session, nskb->data, nskb->len);
 276
 277        kfree_skb(nskb);
 278}
 279
 280static int cmtp_session(void *arg)
 281{
 282        struct cmtp_session *session = arg;
 283        struct sock *sk = session->sock->sk;
 284        struct sk_buff *skb;
 285        wait_queue_t wait;
 286
 287        BT_DBG("session %p", session);
 288
 289        daemonize("kcmtpd_ctr_%d", session->num);
 290        set_user_nice(current, -15);
 291
 292        init_waitqueue_entry(&wait, current);
 293        add_wait_queue(sk->sk_sleep, &wait);
 294        while (!atomic_read(&session->terminate)) {
 295                set_current_state(TASK_INTERRUPTIBLE);
 296
 297                if (sk->sk_state != BT_CONNECTED)
 298                        break;
 299
 300                while ((skb = skb_dequeue(&sk->sk_receive_queue))) {
 301                        skb_orphan(skb);
 302                        cmtp_recv_frame(session, skb);
 303                }
 304
 305                cmtp_process_transmit(session);
 306
 307                schedule();
 308        }
 309        set_current_state(TASK_RUNNING);
 310        remove_wait_queue(sk->sk_sleep, &wait);
 311
 312        down_write(&cmtp_session_sem);
 313
 314        if (!(session->flags & (1 << CMTP_LOOPBACK)))
 315                cmtp_detach_device(session);
 316
 317        fput(session->sock->file);
 318
 319        __cmtp_unlink_session(session);
 320
 321        up_write(&cmtp_session_sem);
 322
 323        kfree(session);
 324        return 0;
 325}
 326
 327int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock)
 328{
 329        struct cmtp_session *session, *s;
 330        bdaddr_t src, dst;
 331        int i, err;
 332
 333        BT_DBG("");
 334
 335        baswap(&src, &bt_sk(sock->sk)->src);
 336        baswap(&dst, &bt_sk(sock->sk)->dst);
 337
 338        session = kzalloc(sizeof(struct cmtp_session), GFP_KERNEL);
 339        if (!session)
 340                return -ENOMEM;
 341
 342        down_write(&cmtp_session_sem);
 343
 344        s = __cmtp_get_session(&bt_sk(sock->sk)->dst);
 345        if (s && s->state == BT_CONNECTED) {
 346                err = -EEXIST;
 347                goto failed;
 348        }
 349
 350        bacpy(&session->bdaddr, &bt_sk(sock->sk)->dst);
 351
 352        session->mtu = min_t(uint, l2cap_pi(sock->sk)->omtu, l2cap_pi(sock->sk)->imtu);
 353
 354        BT_DBG("mtu %d", session->mtu);
 355
 356        sprintf(session->name, "%s", batostr(&dst));
 357
 358        session->sock  = sock;
 359        session->state = BT_CONFIG;
 360
 361        init_waitqueue_head(&session->wait);
 362
 363        session->msgnum = CMTP_INITIAL_MSGNUM;
 364
 365        INIT_LIST_HEAD(&session->applications);
 366
 367        skb_queue_head_init(&session->transmit);
 368
 369        for (i = 0; i < 16; i++)
 370                session->reassembly[i] = NULL;
 371
 372        session->flags = req->flags;
 373
 374        __cmtp_link_session(session);
 375
 376        err = kernel_thread(cmtp_session, session, CLONE_KERNEL);
 377        if (err < 0)
 378                goto unlink;
 379
 380        if (!(session->flags & (1 << CMTP_LOOPBACK))) {
 381                err = cmtp_attach_device(session);
 382                if (err < 0)
 383                        goto detach;
 384        }
 385
 386        up_write(&cmtp_session_sem);
 387        return 0;
 388
 389detach:
 390        cmtp_detach_device(session);
 391
 392unlink:
 393        __cmtp_unlink_session(session);
 394
 395failed:
 396        up_write(&cmtp_session_sem);
 397        kfree(session);
 398        return err;
 399}
 400
 401int cmtp_del_connection(struct cmtp_conndel_req *req)
 402{
 403        struct cmtp_session *session;
 404        int err = 0;
 405
 406        BT_DBG("");
 407
 408        down_read(&cmtp_session_sem);
 409
 410        session = __cmtp_get_session(&req->bdaddr);
 411        if (session) {
 412                /* Flush the transmit queue */
 413                skb_queue_purge(&session->transmit);
 414
 415                /* Kill session thread */
 416                atomic_inc(&session->terminate);
 417                cmtp_schedule(session);
 418        } else
 419                err = -ENOENT;
 420
 421        up_read(&cmtp_session_sem);
 422        return err;
 423}
 424
 425int cmtp_get_connlist(struct cmtp_connlist_req *req)
 426{
 427        struct list_head *p;
 428        int err = 0, n = 0;
 429
 430        BT_DBG("");
 431
 432        down_read(&cmtp_session_sem);
 433
 434        list_for_each(p, &cmtp_session_list) {
 435                struct cmtp_session *session;
 436                struct cmtp_conninfo ci;
 437
 438                session = list_entry(p, struct cmtp_session, list);
 439
 440                __cmtp_copy_session(session, &ci);
 441
 442                if (copy_to_user(req->ci, &ci, sizeof(ci))) {
 443                        err = -EFAULT;
 444                        break;
 445                }
 446
 447                if (++n >= req->cnum)
 448                        break;
 449
 450                req->ci++;
 451        }
 452        req->cnum = n;
 453
 454        up_read(&cmtp_session_sem);
 455        return err;
 456}
 457
 458int cmtp_get_conninfo(struct cmtp_conninfo *ci)
 459{
 460        struct cmtp_session *session;
 461        int err = 0;
 462
 463        down_read(&cmtp_session_sem);
 464
 465        session = __cmtp_get_session(&ci->bdaddr);
 466        if (session)
 467                __cmtp_copy_session(session, ci);
 468        else
 469                err = -ENOENT;
 470
 471        up_read(&cmtp_session_sem);
 472        return err;
 473}
 474
 475
 476static int __init cmtp_init(void)
 477{
 478        l2cap_load();
 479
 480        BT_INFO("CMTP (CAPI Emulation) ver %s", VERSION);
 481
 482        cmtp_init_sockets();
 483
 484        return 0;
 485}
 486
 487static void __exit cmtp_exit(void)
 488{
 489        cmtp_cleanup_sockets();
 490}
 491
 492module_init(cmtp_init);
 493module_exit(cmtp_exit);
 494
 495MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
 496MODULE_DESCRIPTION("Bluetooth CMTP ver " VERSION);
 497MODULE_VERSION(VERSION);
 498MODULE_LICENSE("GPL");
 499MODULE_ALIAS("bt-proto-5");
 500