patch-2.4.19 linux-2.4.19/net/bluetooth/af_bluetooth.c

Next file: linux-2.4.19/net/bluetooth/hci_conn.c
Previous file: linux-2.4.19/net/bluetooth/Makefile
Back to the patch index
Back to the overall index

diff -urN linux-2.4.18/net/bluetooth/af_bluetooth.c linux-2.4.19/net/bluetooth/af_bluetooth.c
@@ -25,14 +25,15 @@
 /*
  * BlueZ Bluetooth address family and sockets.
  *
- * $Id: af_bluetooth.c,v 1.4 2001/07/05 18:42:44 maxk Exp $
+ * $Id: af_bluetooth.c,v 1.6 2002/06/25 22:03:39 maxk Exp $
  */
-#define VERSION "1.1"
+#define VERSION "2.1"
 
 #include <linux/config.h>
 #include <linux/module.h>
 
 #include <linux/types.h>
+#include <linux/list.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/major.h>
@@ -40,6 +41,7 @@
 #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>
 
@@ -48,62 +50,71 @@
 #endif
 
 #include <net/bluetooth/bluetooth.h>
-#include <net/bluetooth/bluez.h>
+
+#ifndef AF_BLUETOOTH_DEBUG
+#undef  BT_DBG
+#define BT_DBG( A... )
+#endif
 
 /* Bluetooth sockets */
-static struct net_proto_family *bluez_sock[BLUEZ_MAX_PROTO];
+#define BLUEZ_MAX_PROTO	5
+static struct net_proto_family *bluez_proto[BLUEZ_MAX_PROTO];
 
 int bluez_sock_register(int proto, struct net_proto_family *ops)
 {
-	if (proto > BLUEZ_MAX_PROTO)
+	if (proto >= BLUEZ_MAX_PROTO)
 		return -EINVAL;
 
-	if (bluez_sock[proto])
+	if (bluez_proto[proto])
 		return -EEXIST;
 
-	bluez_sock[proto] = ops;
+	bluez_proto[proto] = ops;
 	return 0;
 }
 
 int bluez_sock_unregister(int proto)
 {
-	if (proto > BLUEZ_MAX_PROTO)
+	if (proto >= BLUEZ_MAX_PROTO)
 		return -EINVAL;
 
-	if (!bluez_sock[proto])
+	if (!bluez_proto[proto])
 		return -ENOENT;
 
-	bluez_sock[proto] = NULL;
+	bluez_proto[proto] = NULL;
 	return 0;
 }
 
 static int bluez_sock_create(struct socket *sock, int proto)
 {
-	if (proto > BLUEZ_MAX_PROTO)
+	if (proto >= BLUEZ_MAX_PROTO)
 		return -EINVAL;
 
 #if defined(CONFIG_KMOD)
-	if (!bluez_sock[proto]) {
+	if (!bluez_proto[proto]) {
 		char module_name[30];
 		sprintf(module_name, "bt-proto-%d", proto);
 		request_module(module_name);
 	}
 #endif
 
-	if (!bluez_sock[proto])
+	if (!bluez_proto[proto])
 		return -ENOENT;
 
-	return bluez_sock[proto]->create(sock, proto);
+	return bluez_proto[proto]->create(sock, proto);
+}
+
+void bluez_sock_init(struct socket *sock, struct sock *sk)
+{ 
+	sock_init_data(sock, sk);
+	INIT_LIST_HEAD(&bluez_pi(sk)->accept_q);
 }
 
 void bluez_sock_link(struct bluez_sock_list *l, struct sock *sk)
 {
 	write_lock(&l->lock);
-
 	sk->next = l->head;
 	l->head = sk;
 	sock_hold(sk);
-
 	write_unlock(&l->lock);
 }
 
@@ -122,6 +133,162 @@
 	write_unlock(&l->lock);
 }
 
+void bluez_accept_enqueue(struct sock *parent, struct sock *sk)
+{
+	BT_DBG("parent %p, sk %p", parent, sk);
+
+	sock_hold(sk);
+	list_add_tail(&bluez_pi(sk)->accept_q, &bluez_pi(parent)->accept_q);
+	bluez_pi(sk)->parent = parent;
+	parent->ack_backlog++;
+}
+
+static void bluez_accept_unlink(struct sock *sk)
+{
+	BT_DBG("sk %p state %d", sk, sk->state);
+
+	list_del_init(&bluez_pi(sk)->accept_q);
+	bluez_pi(sk)->parent->ack_backlog--;
+	bluez_pi(sk)->parent = NULL;
+	sock_put(sk);
+}
+
+struct sock *bluez_accept_dequeue(struct sock *parent, struct socket *newsock)
+{
+	struct list_head *p, *n;
+	struct bluez_pinfo *pi;
+	struct sock *sk;
+	
+	BT_DBG("parent %p", parent);
+
+	list_for_each_safe(p, n, &bluez_pi(parent)->accept_q) {
+		pi = list_entry(p, struct bluez_pinfo, accept_q);
+		sk = bluez_sk(pi);
+		
+		lock_sock(sk);
+		if (sk->state == BT_CLOSED) {
+			release_sock(sk);
+			bluez_accept_unlink(sk);
+			continue;
+		}
+		
+		if (sk->state == BT_CONNECTED || !newsock) {
+			bluez_accept_unlink(sk);
+			if (newsock)
+				sock_graft(sk, newsock);
+			release_sock(sk);
+			return sk;
+		}
+		release_sock(sk);
+	}
+	return NULL;
+}
+
+int bluez_sock_recvmsg(struct socket *sock, struct msghdr *msg, int len, int flags, struct scm_cookie *scm)
+{
+	int noblock = flags & MSG_DONTWAIT;
+	struct sock *sk = sock->sk;
+	struct sk_buff *skb;
+	int copied, err;
+
+	BT_DBG("sock %p sk %p len %d", sock, sk, len);
+
+	if (flags & (MSG_OOB))
+		return -EOPNOTSUPP;
+
+	if (!(skb = skb_recv_datagram(sk, flags, noblock, &err))) {
+		if (sk->shutdown & RCV_SHUTDOWN)
+			return 0;
+		return err;
+	}
+
+	msg->msg_namelen = 0;
+
+	copied = skb->len;
+	if (len < copied) {
+		msg->msg_flags |= MSG_TRUNC;
+		copied = len;
+	}
+
+	skb->h.raw = skb->data;
+	err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
+
+	skb_free_datagram(sk, skb);
+
+	return err ? : copied;
+}
+
+unsigned int bluez_sock_poll(struct file * file, struct socket *sock, poll_table *wait)
+{
+	struct sock *sk = sock->sk;
+	unsigned int mask;
+
+	BT_DBG("sock %p, sk %p", sock, sk);
+
+	poll_wait(file, sk->sleep, wait);
+	mask = 0;
+
+	if (sk->err || !skb_queue_empty(&sk->error_queue))
+		mask |= POLLERR;
+
+	if (sk->shutdown == SHUTDOWN_MASK)
+		mask |= POLLHUP;
+
+	if (!skb_queue_empty(&sk->receive_queue) || 
+			!list_empty(&bluez_pi(sk)->accept_q) ||
+			(sk->shutdown & RCV_SHUTDOWN))
+		mask |= POLLIN | POLLRDNORM;
+
+	if (sk->state == BT_CLOSED)
+		mask |= POLLHUP;
+
+	if (sock_writeable(sk))
+		mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
+	else
+		set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags);
+
+	return mask;
+}
+
+int bluez_sock_w4_connect(struct sock *sk, int flags)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	long timeo = sock_sndtimeo(sk, flags & O_NONBLOCK);
+	int err = 0;
+
+	BT_DBG("sk %p", sk);
+
+	add_wait_queue(sk->sleep, &wait);
+	while (sk->state != BT_CONNECTED) {
+		set_current_state(TASK_INTERRUPTIBLE);
+		if (!timeo) {
+			err = -EAGAIN;
+			break;
+		}
+
+		release_sock(sk);
+		timeo = schedule_timeout(timeo);
+		lock_sock(sk);
+
+		err = 0;
+		if (sk->state == BT_CONNECTED)
+			break;
+
+		if (sk->err) {
+			err = sock_error(sk);
+			break;
+		}
+
+		if (signal_pending(current)) {
+			err = sock_intr_errno(timeo);
+			break;
+		}
+	}
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(sk->sleep, &wait);
+	return err;
+}
+
 struct net_proto_family bluez_sock_family_ops =
 {
 	PF_BLUETOOTH, bluez_sock_create
@@ -129,9 +296,9 @@
 
 int bluez_init(void)
 {
-	INF("BlueZ HCI Core ver %s Copyright (C) 2000,2001 Qualcomm Inc",
+	BT_INFO("BlueZ Core ver %s Copyright (C) 2000,2001 Qualcomm Inc",
 		 VERSION);
-	INF("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
+	BT_INFO("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
 
 	proc_mkdir("bluetooth", NULL);
 
@@ -164,5 +331,6 @@
 module_exit(bluez_cleanup);
 
 MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
-MODULE_DESCRIPTION("BlueZ HCI Core ver " VERSION);
+MODULE_DESCRIPTION("BlueZ Core ver " VERSION);
+MODULE_LICENSE("GPL");
 #endif

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)