linux/net/bluetooth/bnep/core.c
<<
>>
Prefs
   1/*
   2   BNEP implementation for Linux Bluetooth stack (BlueZ).
   3   Copyright (C) 2001-2002 Inventel Systemes
   4   Written 2001-2002 by
   5        Clément Moreau <clement.moreau@inventel.fr>
   6        David Libault  <david.libault@inventel.fr>
   7
   8   Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
   9
  10   This program is free software; you can redistribute it and/or modify
  11   it under the terms of the GNU General Public License version 2 as
  12   published by the Free Software Foundation;
  13
  14   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  15   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
  17   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
  18   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
  19   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  20   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  21   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  22
  23   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
  24   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
  25   SOFTWARE IS DISCLAIMED.
  26*/
  27
  28#include <linux/module.h>
  29
  30#include <linux/kernel.h>
  31#include <linux/sched.h>
  32#include <linux/signal.h>
  33#include <linux/init.h>
  34#include <linux/wait.h>
  35#include <linux/freezer.h>
  36#include <linux/errno.h>
  37#include <linux/net.h>
  38#include <net/sock.h>
  39
  40#include <linux/socket.h>
  41#include <linux/file.h>
  42
  43#include <linux/netdevice.h>
  44#include <linux/etherdevice.h>
  45#include <linux/skbuff.h>
  46
  47#include <asm/unaligned.h>
  48
  49#include <net/bluetooth/bluetooth.h>
  50#include <net/bluetooth/hci_core.h>
  51#include <net/bluetooth/l2cap.h>
  52
  53#include "bnep.h"
  54
  55#define VERSION "1.3"
  56
  57static int compress_src = 1;
  58static int compress_dst = 1;
  59
  60static LIST_HEAD(bnep_session_list);
  61static DECLARE_RWSEM(bnep_session_sem);
  62
  63static struct bnep_session *__bnep_get_session(u8 *dst)
  64{
  65        struct bnep_session *s;
  66        struct list_head *p;
  67
  68        BT_DBG("");
  69
  70        list_for_each(p, &bnep_session_list) {
  71                s = list_entry(p, struct bnep_session, list);
  72                if (!compare_ether_addr(dst, s->eh.h_source))
  73                        return s;
  74        }
  75        return NULL;
  76}
  77
  78static void __bnep_link_session(struct bnep_session *s)
  79{
  80        /* It's safe to call __module_get() here because sessions are added
  81           by the socket layer which has to hold the refference to this module.
  82         */
  83        __module_get(THIS_MODULE);
  84        list_add(&s->list, &bnep_session_list);
  85}
  86
  87static void __bnep_unlink_session(struct bnep_session *s)
  88{
  89        list_del(&s->list);
  90        module_put(THIS_MODULE);
  91}
  92
  93static int bnep_send(struct bnep_session *s, void *data, size_t len)
  94{
  95        struct socket *sock = s->sock;
  96        struct kvec iv = { data, len };
  97
  98        return kernel_sendmsg(sock, &s->msg, &iv, 1, len);
  99}
 100
 101static int bnep_send_rsp(struct bnep_session *s, u8 ctrl, u16 resp)
 102{
 103        struct bnep_control_rsp rsp;
 104        rsp.type = BNEP_CONTROL;
 105        rsp.ctrl = ctrl;
 106        rsp.resp = htons(resp);
 107        return bnep_send(s, &rsp, sizeof(rsp));
 108}
 109
 110#ifdef CONFIG_BT_BNEP_PROTO_FILTER
 111static inline void bnep_set_default_proto_filter(struct bnep_session *s)
 112{
 113        /* (IPv4, ARP)  */
 114        s->proto_filter[0].start = ETH_P_IP;
 115        s->proto_filter[0].end   = ETH_P_ARP;
 116        /* (RARP, AppleTalk) */
 117        s->proto_filter[1].start = ETH_P_RARP;
 118        s->proto_filter[1].end   = ETH_P_AARP;
 119        /* (IPX, IPv6) */
 120        s->proto_filter[2].start = ETH_P_IPX;
 121        s->proto_filter[2].end   = ETH_P_IPV6;
 122}
 123#endif
 124
 125static int bnep_ctrl_set_netfilter(struct bnep_session *s, __be16 *data, int len)
 126{
 127        int n;
 128
 129        if (len < 2)
 130                return -EILSEQ;
 131
 132        n = get_unaligned_be16(data);
 133        data++; len -= 2;
 134
 135        if (len < n)
 136                return -EILSEQ;
 137
 138        BT_DBG("filter len %d", n);
 139
 140#ifdef CONFIG_BT_BNEP_PROTO_FILTER
 141        n /= 4;
 142        if (n <= BNEP_MAX_PROTO_FILTERS) {
 143                struct bnep_proto_filter *f = s->proto_filter;
 144                int i;
 145
 146                for (i = 0; i < n; i++) {
 147                        f[i].start = get_unaligned_be16(data++);
 148                        f[i].end   = get_unaligned_be16(data++);
 149
 150                        BT_DBG("proto filter start %d end %d",
 151                                f[i].start, f[i].end);
 152                }
 153
 154                if (i < BNEP_MAX_PROTO_FILTERS)
 155                        memset(f + i, 0, sizeof(*f));
 156
 157                if (n == 0)
 158                        bnep_set_default_proto_filter(s);
 159
 160                bnep_send_rsp(s, BNEP_FILTER_NET_TYPE_RSP, BNEP_SUCCESS);
 161        } else {
 162                bnep_send_rsp(s, BNEP_FILTER_NET_TYPE_RSP, BNEP_FILTER_LIMIT_REACHED);
 163        }
 164#else
 165        bnep_send_rsp(s, BNEP_FILTER_NET_TYPE_RSP, BNEP_FILTER_UNSUPPORTED_REQ);
 166#endif
 167        return 0;
 168}
 169
 170static int bnep_ctrl_set_mcfilter(struct bnep_session *s, u8 *data, int len)
 171{
 172        int n;
 173
 174        if (len < 2)
 175                return -EILSEQ;
 176
 177        n = get_unaligned_be16(data);
 178        data += 2; len -= 2;
 179
 180        if (len < n)
 181                return -EILSEQ;
 182
 183        BT_DBG("filter len %d", n);
 184
 185#ifdef CONFIG_BT_BNEP_MC_FILTER
 186        n /= (ETH_ALEN * 2);
 187
 188        if (n > 0) {
 189                s->mc_filter = 0;
 190
 191                /* Always send broadcast */
 192                set_bit(bnep_mc_hash(s->dev->broadcast), (ulong *) &s->mc_filter);
 193
 194                /* Add address ranges to the multicast hash */
 195                for (; n > 0; n--) {
 196                        u8 a1[6], *a2;
 197
 198                        memcpy(a1, data, ETH_ALEN); data += ETH_ALEN;
 199                        a2 = data; data += ETH_ALEN;
 200
 201                        BT_DBG("mc filter %s -> %s",
 202                                batostr((void *) a1), batostr((void *) a2));
 203
 204                        #define INCA(a) { int i = 5; while (i >=0 && ++a[i--] == 0); }
 205
 206                        /* Iterate from a1 to a2 */
 207                        set_bit(bnep_mc_hash(a1), (ulong *) &s->mc_filter);
 208                        while (memcmp(a1, a2, 6) < 0 && s->mc_filter != ~0LL) {
 209                                INCA(a1);
 210                                set_bit(bnep_mc_hash(a1), (ulong *) &s->mc_filter);
 211                        }
 212                }
 213        }
 214
 215        BT_DBG("mc filter hash 0x%llx", s->mc_filter);
 216
 217        bnep_send_rsp(s, BNEP_FILTER_MULTI_ADDR_RSP, BNEP_SUCCESS);
 218#else
 219        bnep_send_rsp(s, BNEP_FILTER_MULTI_ADDR_RSP, BNEP_FILTER_UNSUPPORTED_REQ);
 220#endif
 221        return 0;
 222}
 223
 224static int bnep_rx_control(struct bnep_session *s, void *data, int len)
 225{
 226        u8  cmd = *(u8 *)data;
 227        int err = 0;
 228
 229        data++; len--;
 230
 231        switch (cmd) {
 232        case BNEP_CMD_NOT_UNDERSTOOD:
 233        case BNEP_SETUP_CONN_REQ:
 234        case BNEP_SETUP_CONN_RSP:
 235        case BNEP_FILTER_NET_TYPE_RSP:
 236        case BNEP_FILTER_MULTI_ADDR_RSP:
 237                /* Ignore these for now */
 238                break;
 239
 240        case BNEP_FILTER_NET_TYPE_SET:
 241                err = bnep_ctrl_set_netfilter(s, data, len);
 242                break;
 243
 244        case BNEP_FILTER_MULTI_ADDR_SET:
 245                err = bnep_ctrl_set_mcfilter(s, data, len);
 246                break;
 247
 248        default: {
 249                        u8 pkt[3];
 250                        pkt[0] = BNEP_CONTROL;
 251                        pkt[1] = BNEP_CMD_NOT_UNDERSTOOD;
 252                        pkt[2] = cmd;
 253                        bnep_send(s, pkt, sizeof(pkt));
 254                }
 255                break;
 256        }
 257
 258        return err;
 259}
 260
 261static int bnep_rx_extension(struct bnep_session *s, struct sk_buff *skb)
 262{
 263        struct bnep_ext_hdr *h;
 264        int err = 0;
 265
 266        do {
 267                h = (void *) skb->data;
 268                if (!skb_pull(skb, sizeof(*h))) {
 269                        err = -EILSEQ;
 270                        break;
 271                }
 272
 273                BT_DBG("type 0x%x len %d", h->type, h->len);
 274
 275                switch (h->type & BNEP_TYPE_MASK) {
 276                case BNEP_EXT_CONTROL:
 277                        bnep_rx_control(s, skb->data, skb->len);
 278                        break;
 279
 280                default:
 281                        /* Unknown extension, skip it. */
 282                        break;
 283                }
 284
 285                if (!skb_pull(skb, h->len)) {
 286                        err = -EILSEQ;
 287                        break;
 288                }
 289        } while (!err && (h->type & BNEP_EXT_HEADER));
 290
 291        return err;
 292}
 293
 294static u8 __bnep_rx_hlen[] = {
 295        ETH_HLEN,     /* BNEP_GENERAL */
 296        0,            /* BNEP_CONTROL */
 297        2,            /* BNEP_COMPRESSED */
 298        ETH_ALEN + 2, /* BNEP_COMPRESSED_SRC_ONLY */
 299        ETH_ALEN + 2  /* BNEP_COMPRESSED_DST_ONLY */
 300};
 301#define BNEP_RX_TYPES   (sizeof(__bnep_rx_hlen) - 1)
 302
 303static inline int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb)
 304{
 305        struct net_device *dev = s->dev;
 306        struct sk_buff *nskb;
 307        u8 type;
 308
 309        dev->stats.rx_bytes += skb->len;
 310
 311        type = *(u8 *) skb->data; skb_pull(skb, 1);
 312
 313        if ((type & BNEP_TYPE_MASK) > BNEP_RX_TYPES)
 314                goto badframe;
 315
 316        if ((type & BNEP_TYPE_MASK) == BNEP_CONTROL) {
 317                bnep_rx_control(s, skb->data, skb->len);
 318                kfree_skb(skb);
 319                return 0;
 320        }
 321
 322        skb_reset_mac_header(skb);
 323
 324        /* Verify and pull out header */
 325        if (!skb_pull(skb, __bnep_rx_hlen[type & BNEP_TYPE_MASK]))
 326                goto badframe;
 327
 328        s->eh.h_proto = get_unaligned((__be16 *) (skb->data - 2));
 329
 330        if (type & BNEP_EXT_HEADER) {
 331                if (bnep_rx_extension(s, skb) < 0)
 332                        goto badframe;
 333        }
 334
 335        /* Strip 802.1p header */
 336        if (ntohs(s->eh.h_proto) == 0x8100) {
 337                if (!skb_pull(skb, 4))
 338                        goto badframe;
 339                s->eh.h_proto = get_unaligned((__be16 *) (skb->data - 2));
 340        }
 341
 342        /* We have to alloc new skb and copy data here :(. Because original skb
 343         * may not be modified and because of the alignment requirements. */
 344        nskb = alloc_skb(2 + ETH_HLEN + skb->len, GFP_KERNEL);
 345        if (!nskb) {
 346                dev->stats.rx_dropped++;
 347                kfree_skb(skb);
 348                return -ENOMEM;
 349        }
 350        skb_reserve(nskb, 2);
 351
 352        /* Decompress header and construct ether frame */
 353        switch (type & BNEP_TYPE_MASK) {
 354        case BNEP_COMPRESSED:
 355                memcpy(__skb_put(nskb, ETH_HLEN), &s->eh, ETH_HLEN);
 356                break;
 357
 358        case BNEP_COMPRESSED_SRC_ONLY:
 359                memcpy(__skb_put(nskb, ETH_ALEN), s->eh.h_dest, ETH_ALEN);
 360                memcpy(__skb_put(nskb, ETH_ALEN), skb_mac_header(skb), ETH_ALEN);
 361                put_unaligned(s->eh.h_proto, (__be16 *) __skb_put(nskb, 2));
 362                break;
 363
 364        case BNEP_COMPRESSED_DST_ONLY:
 365                memcpy(__skb_put(nskb, ETH_ALEN), skb_mac_header(skb),
 366                       ETH_ALEN);
 367                memcpy(__skb_put(nskb, ETH_ALEN + 2), s->eh.h_source,
 368                       ETH_ALEN + 2);
 369                break;
 370
 371        case BNEP_GENERAL:
 372                memcpy(__skb_put(nskb, ETH_ALEN * 2), skb_mac_header(skb),
 373                       ETH_ALEN * 2);
 374                put_unaligned(s->eh.h_proto, (__be16 *) __skb_put(nskb, 2));
 375                break;
 376        }
 377
 378        skb_copy_from_linear_data(skb, __skb_put(nskb, skb->len), skb->len);
 379        kfree_skb(skb);
 380
 381        dev->stats.rx_packets++;
 382        nskb->ip_summed = CHECKSUM_NONE;
 383        nskb->protocol  = eth_type_trans(nskb, dev);
 384        netif_rx_ni(nskb);
 385        return 0;
 386
 387badframe:
 388        dev->stats.rx_errors++;
 389        kfree_skb(skb);
 390        return 0;
 391}
 392
 393static u8 __bnep_tx_types[] = {
 394        BNEP_GENERAL,
 395        BNEP_COMPRESSED_SRC_ONLY,
 396        BNEP_COMPRESSED_DST_ONLY,
 397        BNEP_COMPRESSED
 398};
 399
 400static inline int bnep_tx_frame(struct bnep_session *s, struct sk_buff *skb)
 401{
 402        struct ethhdr *eh = (void *) skb->data;
 403        struct socket *sock = s->sock;
 404        struct kvec iv[3];
 405        int len = 0, il = 0;
 406        u8 type = 0;
 407
 408        BT_DBG("skb %p dev %p type %d", skb, skb->dev, skb->pkt_type);
 409
 410        if (!skb->dev) {
 411                /* Control frame sent by us */
 412                goto send;
 413        }
 414
 415        iv[il++] = (struct kvec) { &type, 1 };
 416        len++;
 417
 418        if (compress_src && !compare_ether_addr(eh->h_dest, s->eh.h_source))
 419                type |= 0x01;
 420
 421        if (compress_dst && !compare_ether_addr(eh->h_source, s->eh.h_dest))
 422                type |= 0x02;
 423
 424        if (type)
 425                skb_pull(skb, ETH_ALEN * 2);
 426
 427        type = __bnep_tx_types[type];
 428        switch (type) {
 429        case BNEP_COMPRESSED_SRC_ONLY:
 430                iv[il++] = (struct kvec) { eh->h_source, ETH_ALEN };
 431                len += ETH_ALEN;
 432                break;
 433
 434        case BNEP_COMPRESSED_DST_ONLY:
 435                iv[il++] = (struct kvec) { eh->h_dest, ETH_ALEN };
 436                len += ETH_ALEN;
 437                break;
 438        }
 439
 440send:
 441        iv[il++] = (struct kvec) { skb->data, skb->len };
 442        len += skb->len;
 443
 444        /* FIXME: linearize skb */
 445        {
 446                len = kernel_sendmsg(sock, &s->msg, iv, il, len);
 447        }
 448        kfree_skb(skb);
 449
 450        if (len > 0) {
 451                s->dev->stats.tx_bytes += len;
 452                s->dev->stats.tx_packets++;
 453                return 0;
 454        }
 455
 456        return len;
 457}
 458
 459static int bnep_session(void *arg)
 460{
 461        struct bnep_session *s = arg;
 462        struct net_device *dev = s->dev;
 463        struct sock *sk = s->sock->sk;
 464        struct sk_buff *skb;
 465        wait_queue_t wait;
 466
 467        BT_DBG("");
 468
 469        daemonize("kbnepd %s", dev->name);
 470        set_user_nice(current, -15);
 471
 472        init_waitqueue_entry(&wait, current);
 473        add_wait_queue(sk->sk_sleep, &wait);
 474        while (!atomic_read(&s->killed)) {
 475                set_current_state(TASK_INTERRUPTIBLE);
 476
 477                // RX
 478                while ((skb = skb_dequeue(&sk->sk_receive_queue))) {
 479                        skb_orphan(skb);
 480                        bnep_rx_frame(s, skb);
 481                }
 482
 483                if (sk->sk_state != BT_CONNECTED)
 484                        break;
 485
 486                // TX
 487                while ((skb = skb_dequeue(&sk->sk_write_queue)))
 488                        if (bnep_tx_frame(s, skb))
 489                                break;
 490                netif_wake_queue(dev);
 491
 492                schedule();
 493        }
 494        set_current_state(TASK_RUNNING);
 495        remove_wait_queue(sk->sk_sleep, &wait);
 496
 497        /* Cleanup session */
 498        down_write(&bnep_session_sem);
 499
 500        /* Delete network device */
 501        unregister_netdev(dev);
 502
 503        /* Wakeup user-space polling for socket errors */
 504        s->sock->sk->sk_err = EUNATCH;
 505
 506        wake_up_interruptible(s->sock->sk->sk_sleep);
 507
 508        /* Release the socket */
 509        fput(s->sock->file);
 510
 511        __bnep_unlink_session(s);
 512
 513        up_write(&bnep_session_sem);
 514        free_netdev(dev);
 515        return 0;
 516}
 517
 518static struct device *bnep_get_device(struct bnep_session *session)
 519{
 520        bdaddr_t *src = &bt_sk(session->sock->sk)->src;
 521        bdaddr_t *dst = &bt_sk(session->sock->sk)->dst;
 522        struct hci_dev *hdev;
 523        struct hci_conn *conn;
 524
 525        hdev = hci_get_route(dst, src);
 526        if (!hdev)
 527                return NULL;
 528
 529        conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
 530
 531        hci_dev_put(hdev);
 532
 533        return conn ? &conn->dev : NULL;
 534}
 535
 536static struct device_type bnep_type = {
 537        .name   = "bluetooth",
 538};
 539
 540int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock)
 541{
 542        struct net_device *dev;
 543        struct bnep_session *s, *ss;
 544        u8 dst[ETH_ALEN], src[ETH_ALEN];
 545        int err;
 546
 547        BT_DBG("");
 548
 549        baswap((void *) dst, &bt_sk(sock->sk)->dst);
 550        baswap((void *) src, &bt_sk(sock->sk)->src);
 551
 552        /* session struct allocated as private part of net_device */
 553        dev = alloc_netdev(sizeof(struct bnep_session),
 554                           (*req->device) ? req->device : "bnep%d",
 555                           bnep_net_setup);
 556        if (!dev)
 557                return -ENOMEM;
 558
 559        down_write(&bnep_session_sem);
 560
 561        ss = __bnep_get_session(dst);
 562        if (ss && ss->state == BT_CONNECTED) {
 563                err = -EEXIST;
 564                goto failed;
 565        }
 566
 567        s = netdev_priv(dev);
 568
 569        /* This is rx header therefore addresses are swapped.
 570         * ie eh.h_dest is our local address. */
 571        memcpy(s->eh.h_dest,   &src, ETH_ALEN);
 572        memcpy(s->eh.h_source, &dst, ETH_ALEN);
 573        memcpy(dev->dev_addr, s->eh.h_dest, ETH_ALEN);
 574
 575        s->dev   = dev;
 576        s->sock  = sock;
 577        s->role  = req->role;
 578        s->state = BT_CONNECTED;
 579
 580        s->msg.msg_flags = MSG_NOSIGNAL;
 581
 582#ifdef CONFIG_BT_BNEP_MC_FILTER
 583        /* Set default mc filter */
 584        set_bit(bnep_mc_hash(dev->broadcast), (ulong *) &s->mc_filter);
 585#endif
 586
 587#ifdef CONFIG_BT_BNEP_PROTO_FILTER
 588        /* Set default protocol filter */
 589        bnep_set_default_proto_filter(s);
 590#endif
 591
 592        SET_NETDEV_DEV(dev, bnep_get_device(s));
 593        SET_NETDEV_DEVTYPE(dev, &bnep_type);
 594
 595        err = register_netdev(dev);
 596        if (err) {
 597                goto failed;
 598        }
 599
 600        __bnep_link_session(s);
 601
 602        err = kernel_thread(bnep_session, s, CLONE_KERNEL);
 603        if (err < 0) {
 604                /* Session thread start failed, gotta cleanup. */
 605                unregister_netdev(dev);
 606                __bnep_unlink_session(s);
 607                goto failed;
 608        }
 609
 610        up_write(&bnep_session_sem);
 611        strcpy(req->device, dev->name);
 612        return 0;
 613
 614failed:
 615        up_write(&bnep_session_sem);
 616        free_netdev(dev);
 617        return err;
 618}
 619
 620int bnep_del_connection(struct bnep_conndel_req *req)
 621{
 622        struct bnep_session *s;
 623        int  err = 0;
 624
 625        BT_DBG("");
 626
 627        down_read(&bnep_session_sem);
 628
 629        s = __bnep_get_session(req->dst);
 630        if (s) {
 631                /* Wakeup user-space which is polling for socket errors.
 632                 * This is temporary hack untill we have shutdown in L2CAP */
 633                s->sock->sk->sk_err = EUNATCH;
 634
 635                /* Kill session thread */
 636                atomic_inc(&s->killed);
 637                wake_up_interruptible(s->sock->sk->sk_sleep);
 638        } else
 639                err = -ENOENT;
 640
 641        up_read(&bnep_session_sem);
 642        return err;
 643}
 644
 645static void __bnep_copy_ci(struct bnep_conninfo *ci, struct bnep_session *s)
 646{
 647        memcpy(ci->dst, s->eh.h_source, ETH_ALEN);
 648        strcpy(ci->device, s->dev->name);
 649        ci->flags = s->flags;
 650        ci->state = s->state;
 651        ci->role  = s->role;
 652}
 653
 654int bnep_get_connlist(struct bnep_connlist_req *req)
 655{
 656        struct list_head *p;
 657        int err = 0, n = 0;
 658
 659        down_read(&bnep_session_sem);
 660
 661        list_for_each(p, &bnep_session_list) {
 662                struct bnep_session *s;
 663                struct bnep_conninfo ci;
 664
 665                s = list_entry(p, struct bnep_session, list);
 666
 667                __bnep_copy_ci(&ci, s);
 668
 669                if (copy_to_user(req->ci, &ci, sizeof(ci))) {
 670                        err = -EFAULT;
 671                        break;
 672                }
 673
 674                if (++n >= req->cnum)
 675                        break;
 676
 677                req->ci++;
 678        }
 679        req->cnum = n;
 680
 681        up_read(&bnep_session_sem);
 682        return err;
 683}
 684
 685int bnep_get_conninfo(struct bnep_conninfo *ci)
 686{
 687        struct bnep_session *s;
 688        int err = 0;
 689
 690        down_read(&bnep_session_sem);
 691
 692        s = __bnep_get_session(ci->dst);
 693        if (s)
 694                __bnep_copy_ci(ci, s);
 695        else
 696                err = -ENOENT;
 697
 698        up_read(&bnep_session_sem);
 699        return err;
 700}
 701
 702static int __init bnep_init(void)
 703{
 704        char flt[50] = "";
 705
 706        l2cap_load();
 707
 708#ifdef CONFIG_BT_BNEP_PROTO_FILTER
 709        strcat(flt, "protocol ");
 710#endif
 711
 712#ifdef CONFIG_BT_BNEP_MC_FILTER
 713        strcat(flt, "multicast");
 714#endif
 715
 716        BT_INFO("BNEP (Ethernet Emulation) ver %s", VERSION);
 717        if (flt[0])
 718                BT_INFO("BNEP filters: %s", flt);
 719
 720        bnep_sock_init();
 721        return 0;
 722}
 723
 724static void __exit bnep_exit(void)
 725{
 726        bnep_sock_cleanup();
 727}
 728
 729module_init(bnep_init);
 730module_exit(bnep_exit);
 731
 732module_param(compress_src, bool, 0644);
 733MODULE_PARM_DESC(compress_src, "Compress sources headers");
 734
 735module_param(compress_dst, bool, 0644);
 736MODULE_PARM_DESC(compress_dst, "Compress destination headers");
 737
 738MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
 739MODULE_DESCRIPTION("Bluetooth BNEP ver " VERSION);
 740MODULE_VERSION(VERSION);
 741MODULE_LICENSE("GPL");
 742MODULE_ALIAS("bt-proto-4");
 743
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.