linux-old/net/bluetooth/af_bluetooth.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 * BlueZ Bluetooth address family and sockets.
  27 *
  28 * $Id: af_bluetooth.c,v 1.8 2002/07/22 20:32:54 maxk Exp $
  29 */
  30#define VERSION "2.4"
  31
  32#include <linux/config.h>
  33#include <linux/module.h>
  34
  35#include <linux/types.h>
  36#include <linux/list.h>
  37#include <linux/errno.h>
  38#include <linux/kernel.h>
  39#include <linux/major.h>
  40#include <linux/sched.h>
  41#include <linux/slab.h>
  42#include <linux/skbuff.h>
  43#include <linux/init.h>
  44#include <linux/poll.h>
  45#include <linux/proc_fs.h>
  46#include <net/sock.h>
  47
  48#if defined(CONFIG_KMOD)
  49#include <linux/kmod.h>
  50#endif
  51
  52#include <net/bluetooth/bluetooth.h>
  53
  54#ifndef AF_BLUETOOTH_DEBUG
  55#undef  BT_DBG
  56#define BT_DBG( A... )
  57#endif
  58
  59/* Bluetooth sockets */
  60#define BLUEZ_MAX_PROTO 7
  61static struct net_proto_family *bluez_proto[BLUEZ_MAX_PROTO];
  62
  63int bluez_sock_register(int proto, struct net_proto_family *ops)
  64{
  65        if (proto < 0 || proto >= BLUEZ_MAX_PROTO)
  66                return -EINVAL;
  67
  68        if (bluez_proto[proto])
  69                return -EEXIST;
  70
  71        bluez_proto[proto] = ops;
  72        return 0;
  73}
  74
  75int bluez_sock_unregister(int proto)
  76{
  77        if (proto < 0 || proto >= BLUEZ_MAX_PROTO)
  78                return -EINVAL;
  79
  80        if (!bluez_proto[proto])
  81                return -ENOENT;
  82
  83        bluez_proto[proto] = NULL;
  84        return 0;
  85}
  86
  87static int bluez_sock_create(struct socket *sock, int proto)
  88{
  89        if (proto < 0 || proto >= BLUEZ_MAX_PROTO)
  90                return -EINVAL;
  91
  92#if defined(CONFIG_KMOD)
  93        if (!bluez_proto[proto]) {
  94                char module_name[30];
  95                sprintf(module_name, "bt-proto-%d", proto);
  96                request_module(module_name);
  97        }
  98#endif
  99
 100        if (!bluez_proto[proto])
 101                return -ENOENT;
 102
 103        return bluez_proto[proto]->create(sock, proto);
 104}
 105
 106void bluez_sock_init(struct socket *sock, struct sock *sk)
 107{ 
 108        sock_init_data(sock, sk);
 109        INIT_LIST_HEAD(&bluez_pi(sk)->accept_q);
 110}
 111
 112void bluez_sock_link(struct bluez_sock_list *l, struct sock *sk)
 113{
 114        write_lock_bh(&l->lock);
 115        sk->next = l->head;
 116        l->head = sk;
 117        sock_hold(sk);
 118        write_unlock_bh(&l->lock);
 119}
 120
 121void bluez_sock_unlink(struct bluez_sock_list *l, struct sock *sk)
 122{
 123        struct sock **skp;
 124
 125        write_lock_bh(&l->lock);
 126        for (skp = &l->head; *skp; skp = &((*skp)->next)) {
 127                if (*skp == sk) {
 128                        *skp = sk->next;
 129                        __sock_put(sk);
 130                        break;
 131                }
 132        }
 133        write_unlock_bh(&l->lock);
 134}
 135
 136void bluez_accept_enqueue(struct sock *parent, struct sock *sk)
 137{
 138        BT_DBG("parent %p, sk %p", parent, sk);
 139
 140        sock_hold(sk);
 141        list_add_tail(&bluez_pi(sk)->accept_q, &bluez_pi(parent)->accept_q);
 142        bluez_pi(sk)->parent = parent;
 143        parent->ack_backlog++;
 144}
 145
 146static void bluez_accept_unlink(struct sock *sk)
 147{
 148        BT_DBG("sk %p state %d", sk, sk->state);
 149
 150        list_del_init(&bluez_pi(sk)->accept_q);
 151        bluez_pi(sk)->parent->ack_backlog--;
 152        bluez_pi(sk)->parent = NULL;
 153        sock_put(sk);
 154}
 155
 156struct sock *bluez_accept_dequeue(struct sock *parent, struct socket *newsock)
 157{
 158        struct list_head *p, *n;
 159        struct bluez_pinfo *pi;
 160        struct sock *sk;
 161        
 162        BT_DBG("parent %p", parent);
 163
 164        list_for_each_safe(p, n, &bluez_pi(parent)->accept_q) {
 165                pi = list_entry(p, struct bluez_pinfo, accept_q);
 166                sk = bluez_sk(pi);
 167                
 168                lock_sock(sk);
 169                if (sk->state == BT_CLOSED) {
 170                        release_sock(sk);
 171                        bluez_accept_unlink(sk);
 172                        continue;
 173                }
 174                
 175                if (sk->state == BT_CONNECTED || !newsock) {
 176                        bluez_accept_unlink(sk);
 177                        if (newsock)
 178                                sock_graft(sk, newsock);
 179                        release_sock(sk);
 180                        return sk;
 181                }
 182                release_sock(sk);
 183        }
 184        return NULL;
 185}
 186
 187int bluez_sock_recvmsg(struct socket *sock, struct msghdr *msg, int len, int flags, struct scm_cookie *scm)
 188{
 189        int noblock = flags & MSG_DONTWAIT;
 190        struct sock *sk = sock->sk;
 191        struct sk_buff *skb;
 192        int copied, err;
 193
 194        BT_DBG("sock %p sk %p len %d", sock, sk, len);
 195
 196        if (flags & (MSG_OOB))
 197                return -EOPNOTSUPP;
 198
 199        if (!(skb = skb_recv_datagram(sk, flags, noblock, &err))) {
 200                if (sk->shutdown & RCV_SHUTDOWN)
 201                        return 0;
 202                return err;
 203        }
 204
 205        msg->msg_namelen = 0;
 206
 207        copied = skb->len;
 208        if (len < copied) {
 209                msg->msg_flags |= MSG_TRUNC;
 210                copied = len;
 211        }
 212
 213        skb->h.raw = skb->data;
 214        err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
 215
 216        skb_free_datagram(sk, skb);
 217
 218        return err ? : copied;
 219}
 220
 221unsigned int bluez_sock_poll(struct file * file, struct socket *sock, poll_table *wait)
 222{
 223        struct sock *sk = sock->sk;
 224        unsigned int mask = 0;
 225
 226        BT_DBG("sock %p, sk %p", sock, sk);
 227
 228        poll_wait(file, sk->sleep, wait);
 229
 230        if (sk->err || !skb_queue_empty(&sk->error_queue))
 231                mask |= POLLERR;
 232
 233        if (sk->shutdown == SHUTDOWN_MASK)
 234                mask |= POLLHUP;
 235
 236        if (!skb_queue_empty(&sk->receive_queue) || 
 237                        !list_empty(&bluez_pi(sk)->accept_q) ||
 238                        (sk->shutdown & RCV_SHUTDOWN))
 239                mask |= POLLIN | POLLRDNORM;
 240
 241        if (sk->state == BT_CLOSED)
 242                mask |= POLLHUP;
 243
 244        if (sk->state == BT_CONNECT ||
 245                        sk->state == BT_CONNECT2 ||
 246                        sk->state == BT_CONFIG)
 247                return mask;
 248
 249        if (sock_writeable(sk))
 250                mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
 251        else
 252                set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags);
 253
 254        return mask;
 255}
 256
 257int bluez_sock_wait_state(struct sock *sk, int state, unsigned long timeo)
 258{
 259        DECLARE_WAITQUEUE(wait, current);
 260        int err = 0;
 261
 262        BT_DBG("sk %p", sk);
 263
 264        add_wait_queue(sk->sleep, &wait);
 265        while (sk->state != state) {
 266                set_current_state(TASK_INTERRUPTIBLE);
 267
 268                if (!timeo) {
 269                        err = -EAGAIN;
 270                        break;
 271                }
 272
 273                if (signal_pending(current)) {
 274                        err = sock_intr_errno(timeo);
 275                        break;
 276                }
 277
 278                release_sock(sk);
 279                timeo = schedule_timeout(timeo);
 280                lock_sock(sk);
 281
 282                if (sk->err) {
 283                        err = sock_error(sk);
 284                        break;
 285                }
 286        }
 287        set_current_state(TASK_RUNNING);
 288        remove_wait_queue(sk->sleep, &wait);
 289        return err;
 290}
 291
 292struct net_proto_family bluez_sock_family_ops =
 293{
 294        PF_BLUETOOTH, bluez_sock_create
 295};
 296
 297int bluez_init(void)
 298{
 299        BT_INFO("BlueZ Core ver %s Copyright (C) 2000,2001 Qualcomm Inc",
 300                 VERSION);
 301        BT_INFO("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
 302
 303        proc_mkdir("bluetooth", NULL);
 304
 305        sock_register(&bluez_sock_family_ops);
 306
 307        /* Init HCI Core */
 308        hci_core_init();
 309
 310        /* Init sockets */
 311        hci_sock_init();
 312
 313        return 0;
 314}
 315
 316void bluez_cleanup(void)
 317{
 318        /* Release socket */
 319        hci_sock_cleanup();
 320
 321        /* Release core */
 322        hci_core_cleanup();
 323
 324        sock_unregister(PF_BLUETOOTH);
 325
 326        remove_proc_entry("bluetooth", NULL);
 327}
 328
 329#ifdef MODULE
 330module_init(bluez_init);
 331module_exit(bluez_cleanup);
 332
 333MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
 334MODULE_DESCRIPTION("BlueZ Core ver " VERSION);
 335MODULE_LICENSE("GPL");
 336#endif
 337
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.