linux-old/net/bluetooth/hci_conn.c
<<
>>
Prefs
   1/* 
   2   BlueZ - Bluetooth protocol stack for Linux
   3   Copyright (C) 2000-2001 Qualcomm Incorporated
   4
   5   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
   6
   7   This program is free software; you can redistribute it and/or modify
   8   it under the terms of the GNU General Public License version 2 as
   9   published by the Free Software Foundation;
  10
  11   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  12   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  13   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
  14   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
  15   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
  16   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
  17   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
  18   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  19
  20   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
  21   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
  22   SOFTWARE IS DISCLAIMED.
  23*/
  24
  25/*
  26 * HCI Connection handling.
  27 *
  28 * $Id: hci_conn.c,v 1.5 2002/07/17 18:46:25 maxk Exp $
  29 */
  30
  31#include <linux/config.h>
  32#include <linux/module.h>
  33
  34#include <linux/types.h>
  35#include <linux/errno.h>
  36#include <linux/kernel.h>
  37#include <linux/major.h>
  38#include <linux/sched.h>
  39#include <linux/slab.h>
  40#include <linux/poll.h>
  41#include <linux/fcntl.h>
  42#include <linux/init.h>
  43#include <linux/skbuff.h>
  44#include <linux/interrupt.h>
  45#include <linux/notifier.h>
  46#include <net/sock.h>
  47
  48#include <asm/system.h>
  49#include <asm/uaccess.h>
  50#include <asm/unaligned.h>
  51
  52#include <net/bluetooth/bluetooth.h>
  53#include <net/bluetooth/hci_core.h>
  54
  55#ifndef HCI_CORE_DEBUG
  56#undef  BT_DBG
  57#define BT_DBG( A... )
  58#endif
  59
  60void hci_acl_connect(struct hci_conn *conn)
  61{
  62        struct hci_dev *hdev = conn->hdev;
  63        struct inquiry_entry *ie;
  64        create_conn_cp cp;
  65
  66        BT_DBG("%p", conn);
  67
  68        conn->state = BT_CONNECT;
  69        conn->out   = 1;
  70        conn->link_mode = HCI_LM_MASTER;
  71
  72        memset(&cp, 0, sizeof(cp));
  73        bacpy(&cp.bdaddr, &conn->dst);
  74        cp.pscan_rep_mode = 0x02;
  75
  76        if ((ie = inquiry_cache_lookup(hdev, &conn->dst)) &&
  77                        inquiry_entry_age(ie) <= INQUIRY_ENTRY_AGE_MAX) {
  78                cp.pscan_rep_mode = ie->info.pscan_rep_mode;
  79                cp.pscan_mode     = ie->info.pscan_mode;
  80                cp.clock_offset   = ie->info.clock_offset | __cpu_to_le16(0x8000);
  81        }
  82
  83        cp.pkt_type = __cpu_to_le16(hdev->pkt_type & ACL_PTYPE_MASK);
  84        if (lmp_rswitch_capable(hdev) && !(hdev->link_mode & HCI_LM_MASTER))
  85                cp.role_switch  = 0x01;
  86        else
  87                cp.role_switch  = 0x00;
  88                
  89        hci_send_cmd(hdev, OGF_LINK_CTL, OCF_CREATE_CONN,
  90                                CREATE_CONN_CP_SIZE, &cp);
  91}
  92
  93void hci_acl_disconn(struct hci_conn *conn, __u8 reason)
  94{
  95        disconnect_cp cp;
  96
  97        BT_DBG("%p", conn);
  98
  99        conn->state = BT_DISCONN;
 100
 101        cp.handle = __cpu_to_le16(conn->handle);
 102        cp.reason = reason;
 103        hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_DISCONNECT,
 104                                DISCONNECT_CP_SIZE, &cp);
 105}
 106
 107void hci_add_sco(struct hci_conn *conn, __u16 handle)
 108{
 109        struct hci_dev *hdev = conn->hdev;
 110        add_sco_cp cp;
 111
 112        BT_DBG("%p", conn);
 113
 114        conn->state = BT_CONNECT;
 115        conn->out = 1;
 116
 117        cp.pkt_type = __cpu_to_le16(hdev->pkt_type & SCO_PTYPE_MASK);
 118        cp.handle   = __cpu_to_le16(handle);
 119
 120        hci_send_cmd(hdev, OGF_LINK_CTL, OCF_ADD_SCO, ADD_SCO_CP_SIZE, &cp);
 121}
 122
 123static void hci_conn_timeout(unsigned long arg)
 124{
 125        struct hci_conn *conn = (void *)arg;
 126        struct hci_dev  *hdev = conn->hdev;
 127
 128        BT_DBG("conn %p state %d", conn, conn->state);
 129
 130        if (atomic_read(&conn->refcnt))
 131                return;
 132
 133        hci_dev_lock(hdev);
 134        if (conn->state == BT_CONNECTED)
 135                hci_acl_disconn(conn, 0x13);
 136        else
 137                conn->state = BT_CLOSED;
 138        hci_dev_unlock(hdev);
 139        return;
 140}
 141
 142static void hci_conn_init_timer(struct hci_conn *conn)
 143{
 144        init_timer(&conn->timer);
 145        conn->timer.function = hci_conn_timeout;
 146        conn->timer.data = (unsigned long)conn;
 147}
 148
 149struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
 150{
 151        struct hci_conn *conn;
 152
 153        BT_DBG("%s dst %s", hdev->name, batostr(dst));
 154
 155        if (!(conn = kmalloc(sizeof(struct hci_conn), GFP_ATOMIC)))
 156                return NULL;
 157        memset(conn, 0, sizeof(struct hci_conn));
 158
 159        bacpy(&conn->dst, dst);
 160        conn->type   = type;
 161        conn->hdev   = hdev;
 162        conn->state  = BT_OPEN;
 163
 164        skb_queue_head_init(&conn->data_q);
 165        hci_conn_init_timer(conn);
 166
 167        atomic_set(&conn->refcnt, 0);
 168
 169        hci_dev_hold(hdev);
 170
 171        tasklet_disable(&hdev->tx_task);
 172        conn_hash_add(hdev, conn);
 173        tasklet_enable(&hdev->tx_task);
 174
 175        return conn;
 176}
 177
 178int hci_conn_del(struct hci_conn *conn)
 179{
 180        struct hci_dev  *hdev = conn->hdev;
 181
 182        BT_DBG("%s conn %p handle %d", hdev->name, conn, conn->handle);
 183        
 184        hci_conn_del_timer(conn);
 185
 186        if (conn->type == SCO_LINK) {
 187                struct hci_conn *acl = conn->link;
 188                if (acl) {
 189                        acl->link = NULL;
 190                        hci_conn_put(acl);
 191                }
 192        } else {
 193                struct hci_conn *sco = conn->link;
 194                if (sco)
 195                        sco->link = NULL;
 196
 197                /* Unacked frames */
 198                hdev->acl_cnt += conn->sent;
 199        }
 200
 201        tasklet_disable(&hdev->tx_task);
 202        conn_hash_del(hdev, conn);
 203        tasklet_enable(&hdev->tx_task);
 204
 205        skb_queue_purge(&conn->data_q);
 206
 207        hci_dev_put(hdev);
 208
 209        kfree(conn);
 210        return 0;
 211}
 212
 213struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src)
 214{
 215        int use_src = bacmp(src, BDADDR_ANY);
 216        struct hci_dev *hdev = NULL;
 217        struct list_head *p;
 218
 219        BT_DBG("%s -> %s", batostr(src), batostr(dst));
 220
 221        read_lock_bh(&hdev_list_lock);
 222
 223        list_for_each(p, &hdev_list) {
 224                struct hci_dev *d;
 225                d = list_entry(p, struct hci_dev, list);
 226                
 227                if (!test_bit(HCI_UP, &d->flags))
 228                        continue;
 229
 230                /* Simple routing: 
 231                 *      No source address - find interface with bdaddr != dst 
 232                 *      Source address    - find interface with bdaddr == src 
 233                 */
 234
 235                if (use_src) {
 236                        if (!bacmp(&d->bdaddr, src)) {
 237                                hdev = d; break;
 238                        }
 239                } else {
 240                        if (bacmp(&d->bdaddr, dst)) {
 241                                hdev = d; break;
 242                        }
 243                }
 244        }
 245
 246        if (hdev)
 247                hci_dev_hold(hdev);
 248
 249        read_unlock_bh(&hdev_list_lock);
 250        return hdev;
 251}
 252
 253/* Create SCO or ACL connection.
 254 * Device _must_ be locked */
 255struct hci_conn * hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst)
 256{
 257        struct hci_conn *acl;
 258
 259        BT_DBG("%s dst %s", hdev->name, batostr(dst));
 260
 261        if (!(acl = conn_hash_lookup_ba(hdev, ACL_LINK, dst))) {
 262                if (!(acl = hci_conn_add(hdev, ACL_LINK, dst)))
 263                        return NULL;
 264        }
 265
 266        hci_conn_hold(acl);
 267
 268        if (acl->state == BT_OPEN || acl->state == BT_CLOSED)
 269                hci_acl_connect(acl);
 270
 271        if (type == SCO_LINK) {
 272                struct hci_conn *sco;
 273
 274                if (!(sco = conn_hash_lookup_ba(hdev, SCO_LINK, dst))) {
 275                        if (!(sco = hci_conn_add(hdev, SCO_LINK, dst))) {
 276                                hci_conn_put(acl);
 277                                return NULL;
 278                        }
 279                }
 280                acl->link = sco;
 281                sco->link = acl;
 282
 283                hci_conn_hold(sco);
 284
 285                if (acl->state == BT_CONNECTED && 
 286                                (sco->state == BT_OPEN || sco->state == BT_CLOSED))
 287                        hci_add_sco(sco, acl->handle);
 288
 289                return sco;
 290        } else {
 291                return acl;
 292        }
 293}
 294
 295/* Authenticate remote device */
 296int hci_conn_auth(struct hci_conn *conn)
 297{
 298        BT_DBG("conn %p", conn);
 299        
 300        if (conn->link_mode & HCI_LM_AUTH)
 301                return 1;
 302        
 303        if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
 304                auth_requested_cp ar;
 305                ar.handle = __cpu_to_le16(conn->handle);
 306                hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_AUTH_REQUESTED,
 307                                AUTH_REQUESTED_CP_SIZE, &ar);
 308        }
 309        return 0;
 310}
 311
 312/* Enable encryption */
 313int hci_conn_encrypt(struct hci_conn *conn)
 314{
 315        BT_DBG("conn %p", conn);
 316        
 317        if (conn->link_mode & HCI_LM_ENCRYPT)
 318                return 1;
 319        
 320        if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend))
 321                return 0;
 322
 323        if (hci_conn_auth(conn)) {
 324                set_conn_encrypt_cp ce;
 325                ce.handle  = __cpu_to_le16(conn->handle);
 326                ce.encrypt = 1; 
 327                hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_SET_CONN_ENCRYPT,
 328                                SET_CONN_ENCRYPT_CP_SIZE, &ce);
 329        }
 330        return 0;
 331}
 332
 333/* Drop all connection on the device */
 334void hci_conn_hash_flush(struct hci_dev *hdev)
 335{
 336        struct conn_hash *h = &hdev->conn_hash;
 337        struct list_head *p;
 338
 339        BT_DBG("hdev %s", hdev->name);
 340
 341        p = h->list.next;
 342        while (p != &h->list) {
 343                struct hci_conn *c;
 344
 345                c = list_entry(p, struct hci_conn, list);
 346                p = p->next;
 347
 348                c->state = BT_CLOSED;
 349
 350                hci_proto_disconn_ind(c, 0x16);
 351                hci_conn_del(c);
 352        }
 353}
 354
 355int hci_get_conn_list(unsigned long arg)
 356{
 357        struct hci_conn_list_req req, *cl;
 358        struct hci_conn_info *ci;
 359        struct hci_dev *hdev;
 360        struct list_head *p;
 361        int n = 0, size, err;
 362
 363        if (copy_from_user(&req, (void *) arg, sizeof(req)))
 364                return -EFAULT;
 365
 366        if (!req.conn_num || req.conn_num > (PAGE_SIZE * 2) / sizeof(*ci))
 367                return -EINVAL;
 368
 369        size = sizeof(req) + req.conn_num * sizeof(*ci);
 370
 371        if (!(cl = (void *) kmalloc(size, GFP_KERNEL)))
 372                return -ENOMEM;
 373
 374        if (!(hdev = hci_dev_get(req.dev_id))) {
 375                kfree(cl);
 376                return -ENODEV;
 377        }
 378
 379        ci = cl->conn_info;
 380
 381        hci_dev_lock_bh(hdev);
 382        list_for_each(p, &hdev->conn_hash.list) {
 383                register struct hci_conn *c;
 384                c = list_entry(p, struct hci_conn, list);
 385
 386                bacpy(&(ci + n)->bdaddr, &c->dst);
 387                (ci + n)->handle = c->handle;
 388                (ci + n)->type  = c->type;
 389                (ci + n)->out   = c->out;
 390                (ci + n)->state = c->state;
 391                (ci + n)->link_mode = c->link_mode;
 392                if (++n >= req.conn_num)
 393                        break;
 394        }
 395        hci_dev_unlock_bh(hdev);
 396
 397        cl->dev_id = hdev->id;
 398        cl->conn_num = n;
 399        size = sizeof(req) + n * sizeof(*ci);
 400
 401        hci_dev_put(hdev);
 402
 403        err = copy_to_user((void *) arg, cl, size);
 404        kfree(cl);
 405
 406        return err ? -EFAULT : 0;
 407}
 408
 409int hci_get_conn_info(struct hci_dev *hdev, unsigned long arg)
 410{
 411        struct hci_conn_info_req req;
 412        struct hci_conn_info ci;
 413        struct hci_conn *conn;
 414        char *ptr = (void *) arg + sizeof(req);
 415
 416        if (copy_from_user(&req, (void *) arg, sizeof(req)))
 417                return -EFAULT;
 418
 419        hci_dev_lock_bh(hdev);
 420        conn = conn_hash_lookup_ba(hdev, req.type, &req.bdaddr);
 421        if (conn) {
 422                bacpy(&ci.bdaddr, &conn->dst);
 423                ci.handle = conn->handle;
 424                ci.type  = conn->type;
 425                ci.out   = conn->out;
 426                ci.state = conn->state;
 427                ci.link_mode = conn->link_mode;
 428        }
 429        hci_dev_unlock_bh(hdev);
 430
 431        if (!conn)
 432                return -ENOENT;
 433
 434        return copy_to_user(ptr, &ci, sizeof(ci)) ? -EFAULT : 0;
 435}
 436
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.