fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / net / bluetooth / af_bluetooth.c
index 74b70f7..67df99e 100644 (file)
    SOFTWARE IS DISCLAIMED.
 */
 
-/*
- *  Bluetooth address family and sockets.
- *
- * $Id: af_bluetooth.c,v 1.3 2002/04/17 17:37:15 maxk Exp $
- */
-#define VERSION "2.4"
-
-#include <linux/config.h>
+/* Bluetooth address family and sockets. */
+
 #include <linux/module.h>
 
 #include <linux/types.h>
 #include <linux/list.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
-#include <linux/major.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/skbuff.h>
 #include <linux/init.h>
 #include <linux/poll.h>
-#include <linux/proc_fs.h>
 #include <net/sock.h>
 
 #if defined(CONFIG_KMOD)
 
 #ifndef CONFIG_BT_SOCK_DEBUG
 #undef  BT_DBG
-#define BT_DBG( A... )
+#define BT_DBG(D...)
 #endif
 
-struct proc_dir_entry *proc_bt;
+#define VERSION "2.11"
 
 /* Bluetooth sockets */
-#define BT_MAX_PROTO   6
+#define BT_MAX_PROTO   8
 static struct net_proto_family *bt_proto[BT_MAX_PROTO];
-
-static kmem_cache_t *bt_sock_cache;
+static DEFINE_RWLOCK(bt_proto_lock);
 
 int bt_sock_register(int proto, struct net_proto_family *ops)
 {
-       if (proto >= BT_MAX_PROTO)
+       int err = 0;
+
+       if (proto < 0 || proto >= BT_MAX_PROTO)
                return -EINVAL;
 
+       write_lock(&bt_proto_lock);
+
        if (bt_proto[proto])
-               return -EEXIST;
+               err = -EEXIST;
+       else
+               bt_proto[proto] = ops;
 
-       bt_proto[proto] = ops;
-       return 0;
+       write_unlock(&bt_proto_lock);
+
+       return err;
 }
+EXPORT_SYMBOL(bt_sock_register);
 
 int bt_sock_unregister(int proto)
 {
-       if (proto >= BT_MAX_PROTO)
+       int err = 0;
+
+       if (proto < 0 || proto >= BT_MAX_PROTO)
                return -EINVAL;
 
+       write_lock(&bt_proto_lock);
+
        if (!bt_proto[proto])
-               return -ENOENT;
+               err = -ENOENT;
+       else
+               bt_proto[proto] = NULL;
 
-       bt_proto[proto] = NULL;
-       return 0;
+       write_unlock(&bt_proto_lock);
+
+       return err;
 }
+EXPORT_SYMBOL(bt_sock_unregister);
 
 static int bt_sock_create(struct socket *sock, int proto)
 {
-       int err = 0;
+       int err;
 
-       if (proto >= BT_MAX_PROTO)
+       if (proto < 0 || proto >= BT_MAX_PROTO)
                return -EINVAL;
 
 #if defined(CONFIG_KMOD)
@@ -100,41 +107,19 @@ static int bt_sock_create(struct socket *sock, int proto)
                request_module("bt-proto-%d", proto);
        }
 #endif
+
        err = -EPROTONOSUPPORT;
+
+       read_lock(&bt_proto_lock);
+
        if (bt_proto[proto] && try_module_get(bt_proto[proto]->owner)) {
                err = bt_proto[proto]->create(sock, proto);
                module_put(bt_proto[proto]->owner);
        }
-       return err; 
-}
 
-struct sock *bt_sock_alloc(struct socket *sock, int proto, int pi_size, int prio)
-{
-       struct sock *sk;
-       void *pi;
-
-       sk = sk_alloc(PF_BLUETOOTH, prio, sizeof(struct bt_sock), bt_sock_cache);
-       if (!sk)
-               return NULL;
-       
-       if (pi_size) {
-               pi = kmalloc(pi_size, prio);
-               if (!pi) {
-                       sk_free(sk);
-                       return NULL;
-               }
-               memset(pi, 0, pi_size);
-               sk->sk_protinfo = pi;
-       }
+       read_unlock(&bt_proto_lock);
 
-       sock_init_data(sock, sk);
-       INIT_LIST_HEAD(&bt_sk(sk)->accept_q);
-       
-       sk->sk_zapped   = 0;
-       sk->sk_protocol = proto;
-       sk->sk_state    = BT_OPEN;
-
-       return sk;
+       return err; 
 }
 
 void bt_sock_link(struct bt_sock_list *l, struct sock *sk)
@@ -143,6 +128,7 @@ void bt_sock_link(struct bt_sock_list *l, struct sock *sk)
        sk_add_node(sk, &l->head);
        write_unlock_bh(&l->lock);
 }
+EXPORT_SYMBOL(bt_sock_link);
 
 void bt_sock_unlink(struct bt_sock_list *l, struct sock *sk)
 {
@@ -150,6 +136,7 @@ void bt_sock_unlink(struct bt_sock_list *l, struct sock *sk)
        sk_del_node_init(sk);
        write_unlock_bh(&l->lock);
 }
+EXPORT_SYMBOL(bt_sock_unlink);
 
 void bt_accept_enqueue(struct sock *parent, struct sock *sk)
 {
@@ -160,8 +147,9 @@ void bt_accept_enqueue(struct sock *parent, struct sock *sk)
        bt_sk(sk)->parent = parent;
        parent->sk_ack_backlog++;
 }
+EXPORT_SYMBOL(bt_accept_enqueue);
 
-static void bt_accept_unlink(struct sock *sk)
+void bt_accept_unlink(struct sock *sk)
 {
        BT_DBG("sk %p state %d", sk, sk->sk_state);
 
@@ -170,24 +158,27 @@ static void bt_accept_unlink(struct sock *sk)
        bt_sk(sk)->parent = NULL;
        sock_put(sk);
 }
+EXPORT_SYMBOL(bt_accept_unlink);
 
 struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock)
 {
        struct list_head *p, *n;
        struct sock *sk;
-       
+
        BT_DBG("parent %p", parent);
 
        list_for_each_safe(p, n, &bt_sk(parent)->accept_q) {
                sk = (struct sock *) list_entry(p, struct bt_sock, accept_q);
-               
+
                lock_sock(sk);
+
+               /* FIXME: Is this check still needed */
                if (sk->sk_state == BT_CLOSED) {
                        release_sock(sk);
                        bt_accept_unlink(sk);
                        continue;
                }
-               
+
                if (sk->sk_state == BT_CONNECTED || !newsock) {
                        bt_accept_unlink(sk);
                        if (newsock)
@@ -195,10 +186,12 @@ struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock)
                        release_sock(sk);
                        return sk;
                }
+
                release_sock(sk);
        }
        return NULL;
 }
+EXPORT_SYMBOL(bt_accept_dequeue);
 
 int bt_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
        struct msghdr *msg, size_t len, int flags)
@@ -235,6 +228,7 @@ int bt_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
 
        return err ? : copied;
 }
+EXPORT_SYMBOL(bt_sock_recvmsg);
 
 static inline unsigned int bt_accept_poll(struct sock *parent)
 {
@@ -265,6 +259,9 @@ unsigned int bt_sock_poll(struct file * file, struct socket *sock, poll_table *w
        if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue))
                mask |= POLLERR;
 
+       if (sk->sk_shutdown & RCV_SHUTDOWN)
+               mask |= POLLRDHUP;
+
        if (sk->sk_shutdown == SHUTDOWN_MASK)
                mask |= POLLHUP;
 
@@ -287,6 +284,7 @@ unsigned int bt_sock_poll(struct file * file, struct socket *sock, poll_table *w
 
        return mask;
 }
+EXPORT_SYMBOL(bt_sock_poll);
 
 int bt_sock_wait_state(struct sock *sk, int state, unsigned long timeo)
 {
@@ -300,7 +298,7 @@ int bt_sock_wait_state(struct sock *sk, int state, unsigned long timeo)
                set_current_state(TASK_INTERRUPTIBLE);
 
                if (!timeo) {
-                       err = -EAGAIN;
+                       err = -EINPROGRESS;
                        break;
                }
 
@@ -313,52 +311,40 @@ int bt_sock_wait_state(struct sock *sk, int state, unsigned long timeo)
                timeo = schedule_timeout(timeo);
                lock_sock(sk);
 
-               if (sk->sk_err) {
-                       err = sock_error(sk);
+               err = sock_error(sk);
+               if (err)
                        break;
-               }
        }
        set_current_state(TASK_RUNNING);
        remove_wait_queue(sk->sk_sleep, &wait);
        return err;
 }
+EXPORT_SYMBOL(bt_sock_wait_state);
 
 static struct net_proto_family bt_sock_family_ops = {
-       .owner  = THIS_MODULE,
+       .owner  = THIS_MODULE,
        .family = PF_BLUETOOTH,
        .create = bt_sock_create,
 };
 
-extern int hci_sock_init(void);
-extern int hci_sock_cleanup(void);
-
-extern int bt_sysfs_init(void);
-extern int bt_sysfs_cleanup(void);
-
 static int __init bt_init(void)
 {
+       int err;
+
        BT_INFO("Core ver %s", VERSION);
 
-       proc_bt = proc_mkdir("bluetooth", NULL);
-       if (proc_bt)
-               proc_bt->owner = THIS_MODULE;
-       
-       /* Init socket cache */
-       bt_sock_cache = kmem_cache_create("bt_sock",
-                       sizeof(struct bt_sock), 0,
-                       SLAB_HWCACHE_ALIGN, 0, 0);
-
-       if (!bt_sock_cache) {
-               BT_ERR("Socket cache creation failed");
-               return -ENOMEM;
+       err = bt_sysfs_init();
+       if (err < 0)
+               return err;
+
+       err = sock_register(&bt_sock_family_ops);
+       if (err < 0) {
+               bt_sysfs_cleanup();
+               return err;
        }
-       
-       sock_register(&bt_sock_family_ops);
 
        BT_INFO("HCI device and connection manager initialized");
 
-       bt_sysfs_init();
-
        hci_sock_init();
 
        return 0;
@@ -368,12 +354,9 @@ static void __exit bt_exit(void)
 {
        hci_sock_cleanup();
 
-       bt_sysfs_cleanup();
-
        sock_unregister(PF_BLUETOOTH);
-       kmem_cache_destroy(bt_sock_cache);
 
-       remove_proc_entry("bluetooth", NULL);
+       bt_sysfs_cleanup();
 }
 
 subsys_initcall(bt_init);