From fcde38d442b6940b8094634835b962c1d8b8a3a7 Mon Sep 17 00:00:00 2001
From: Maxim Krasnyansky <root@viper.(none)>
Date: Thu, 3 Oct 2002 21:34:13 -0700
Subject: [PATCH] Sync up Bluetooth core with 2.4.x. SMP locking fixes. Support
 for Hotplug. Support for L2CAP connectionless channels (SOCK_DGRAM). HCI
 filter handling fixes. Other minor fixes and cleanups.

---
 include/net/bluetooth/bluetooth.h |  11 +-
 include/net/bluetooth/hci.h       |  36 ++--
 include/net/bluetooth/hci_core.h  |  13 +-
 net/bluetooth/af_bluetooth.c      |  15 +-
 net/bluetooth/hci_conn.c          |   9 +-
 net/bluetooth/hci_core.c          | 111 +++++++----
 net/bluetooth/hci_event.c         |  13 +-
 net/bluetooth/hci_sock.c          |  59 ++++--
 net/bluetooth/l2cap.c             | 320 ++++++++++++++++++------------
 net/bluetooth/lib.c               |   2 +-
 net/bluetooth/sco.c               | 130 ++++++------
 11 files changed, 411 insertions(+), 308 deletions(-)

diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h
index baa076bc2cbb..fd561cca76db 100644
--- a/include/net/bluetooth/bluetooth.h
+++ b/include/net/bluetooth/bluetooth.h
@@ -50,6 +50,7 @@
 #define BTPROTO_HCI     1
 #define BTPROTO_SCO   	2
 #define BTPROTO_RFCOMM	3
+#define BTPROTO_BNEP    4
 
 #define SOL_HCI     0
 #define SOL_L2CAP   6
@@ -199,14 +200,4 @@ int hci_sock_cleanup(void);
 
 int bterr(__u16 code);
 
-#ifndef MODULE_LICENSE
-#define MODULE_LICENSE(x)
-#endif
-
-#ifndef list_for_each_safe
-#define list_for_each_safe(pos, n, head) \
-	for (pos = (head)->next, n = pos->next; pos != (head); \
-		pos = n, n = pos->next)
-#endif
-
 #endif /* __BLUETOOTH_H */
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 3fa7b3032c88..b58ebef5397b 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -113,10 +113,10 @@ enum {
 #define ACL_PTYPE_MASK	(~SCO_PTYPE_MASK)
 
 /* ACL flags */
-#define ACL_CONT		0x0001
-#define ACL_START		0x0002
-#define ACL_ACTIVE_BCAST	0x0010
-#define ACL_PICO_BCAST		0x0020
+#define ACL_CONT		0x01
+#define ACL_START		0x02
+#define ACL_ACTIVE_BCAST	0x04
+#define ACL_PICO_BCAST		0x08
 
 /* Baseband links */
 #define SCO_LINK	0x00
@@ -542,7 +542,7 @@ typedef struct {
 	bdaddr_t bdaddr;
 	__u8     role;
 } __attribute__ ((packed)) evt_role_change;
-#define EVT_ROLE_CHANGE_SIZE 1
+#define EVT_ROLE_CHANGE_SIZE 8
 
 #define EVT_PIN_CODE_REQ        0x16
 typedef struct {
@@ -658,9 +658,15 @@ struct sockaddr_hci {
 #define HCI_DEV_NONE	0xffff
 
 struct hci_filter {
-	__u32 type_mask;
-	__u32 event_mask[2];
-	__u16 opcode;
+	unsigned long type_mask;
+	unsigned long event_mask[2];
+	__u16   opcode;
+};
+
+struct hci_ufilter {
+	__u32   type_mask;
+	__u32   event_mask[2];
+	__u16   opcode;
 };
 
 #define HCI_FLT_TYPE_BITS	31
@@ -668,20 +674,6 @@ struct hci_filter {
 #define HCI_FLT_OGF_BITS	63
 #define HCI_FLT_OCF_BITS	127
 
-#if BITS_PER_LONG == 64
-static inline void hci_set_bit(int nr, void *addr)
-{
-	*((__u32 *) addr + (nr >> 5)) |= ((__u32) 1 << (nr & 31));
-}
-static inline int hci_test_bit(int nr, void *addr)
-{
-	return *((__u32 *) addr + (nr >> 5)) & ((__u32) 1 << (nr & 31));
-}
-#else
-#define hci_set_bit	set_bit
-#define hci_test_bit	test_bit
-#endif
-
 /* Ioctl requests structures */
 struct hci_dev_stats {
 	__u32 err_rx;
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 15cca8727616..1740cde1287d 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -149,7 +149,7 @@ struct hci_conn {
 
 extern struct hci_proto *hci_proto[];
 extern struct list_head hdev_list;
-extern spinlock_t hdev_list_lock;
+extern rwlock_t hdev_list_lock;
 
 /* ----- Inquiry cache ----- */
 #define INQUIRY_CACHE_AGE_MAX   (HZ*30)   // 30 seconds
@@ -339,8 +339,8 @@ static inline void hci_sched_tx(struct hci_dev *hdev)
 /* ----- HCI protocols ----- */
 struct hci_proto {
 	char 		*name;
-	__u32		id;
-	__u32		flags;
+	unsigned int	id;
+	unsigned long	flags;
 
 	void		*priv;
 
@@ -450,12 +450,11 @@ struct hci_pinfo {
 #define HCI_SFLT_MAX_OGF 4
 
 struct hci_sec_filter {
-	__u32 type_mask;
-	__u32 event_mask[2];
-	__u32 ocf_mask[HCI_SFLT_MAX_OGF + 1][4];
+	unsigned long type_mask;
+	unsigned long event_mask[2];
+	unsigned long ocf_mask[HCI_SFLT_MAX_OGF + 1][4];
 };
 
-
 /* ----- HCI requests ----- */
 #define HCI_REQ_DONE	  0
 #define HCI_REQ_PEND	  1
diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c
index e62e6dfdaf09..d08a2f1cd552 100644
--- a/net/bluetooth/af_bluetooth.c
+++ b/net/bluetooth/af_bluetooth.c
@@ -27,7 +27,7 @@
  *
  * $Id: af_bluetooth.c,v 1.3 2002/04/17 17:37:15 maxk Exp $
  */
-#define VERSION "2.0"
+#define VERSION "2.2"
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -57,7 +57,7 @@
 #endif
 
 /* Bluetooth sockets */
-#define BLUEZ_MAX_PROTO	4
+#define BLUEZ_MAX_PROTO	5
 static struct net_proto_family *bluez_proto[BLUEZ_MAX_PROTO];
 
 static kmem_cache_t *bluez_sock_cache;
@@ -136,18 +136,18 @@ struct sock *bluez_sock_alloc(struct socket *sock, int proto, int pi_size, int p
 
 void bluez_sock_link(struct bluez_sock_list *l, struct sock *sk)
 {
-	write_lock(&l->lock);
+	write_lock_bh(&l->lock);
 	sk->next = l->head;
 	l->head = sk;
 	sock_hold(sk);
-	write_unlock(&l->lock);
+	write_unlock_bh(&l->lock);
 }
 
 void bluez_sock_unlink(struct bluez_sock_list *l, struct sock *sk)
 {
 	struct sock **skp;
 
-	write_lock(&l->lock);
+	write_lock_bh(&l->lock);
 	for (skp = &l->head; *skp; skp = &((*skp)->next)) {
 		if (*skp == sk) {
 			*skp = sk->next;
@@ -155,7 +155,7 @@ void bluez_sock_unlink(struct bluez_sock_list *l, struct sock *sk)
 			break;
 		}
 	}
-	write_unlock(&l->lock);
+	write_unlock_bh(&l->lock);
 }
 
 void bluez_accept_enqueue(struct sock *parent, struct sock *sk)
@@ -265,6 +265,9 @@ unsigned int bluez_sock_poll(struct file * file, struct socket *sock, poll_table
 	if (sk->state == BT_CLOSED)
 		mask |= POLLHUP;
 
+	if (sk->state == BT_CONNECT || sk->state == BT_CONNECT2)
+		return mask;
+	
 	if (sock_writeable(sk))
 		mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
 	else
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 809ac0dc0c24..536402c9581a 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -73,7 +73,7 @@ void hci_acl_connect(struct hci_conn *conn)
 	bacpy(&cp.bdaddr, &conn->dst);
 
 	if ((ie = inquiry_cache_lookup(hdev, &conn->dst)) &&
-			inquiry_entry_age(ie) > INQUIRY_ENTRY_AGE_MAX) {
+			inquiry_entry_age(ie) <= INQUIRY_ENTRY_AGE_MAX) {
 		cp.pscan_rep_mode = ie->info.pscan_rep_mode;
 		cp.pscan_mode     = ie->info.pscan_mode;
 		cp.clock_offset   = ie->info.clock_offset | __cpu_to_le16(0x8000);
@@ -188,9 +188,6 @@ int hci_conn_del(struct hci_conn *conn)
 			acl->link = NULL;
 			hci_conn_put(acl);
 		}
-
-		/* Unacked frames */
-		hdev->sco_cnt += conn->sent;
 	} else {
 		struct hci_conn *sco = conn->link;
 		if (sco)
@@ -220,7 +217,7 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src)
 
 	BT_DBG("%s -> %s", batostr(src), batostr(dst));
 
-	spin_lock_bh(&hdev_list_lock);
+	read_lock_bh(&hdev_list_lock);
 
 	list_for_each(p, &hdev_list) {
 		struct hci_dev *d;
@@ -248,7 +245,7 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src)
 	if (hdev)
 		hci_dev_hold(hdev);
 
-	spin_unlock_bh(&hdev_list_lock);
+	read_unlock_bh(&hdev_list_lock);
 	return hdev;
 }
 
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 9e715481bac3..f1485ad896bd 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -30,6 +30,7 @@
 
 #include <linux/config.h>
 #include <linux/module.h>
+#include <linux/kmod.h>
 
 #include <linux/types.h>
 #include <linux/errno.h>
@@ -66,7 +67,7 @@ rwlock_t hci_task_lock = RW_LOCK_UNLOCKED;
 
 /* HCI device list */
 LIST_HEAD(hdev_list);
-spinlock_t hdev_list_lock;
+rwlock_t hdev_list_lock = RW_LOCK_UNLOCKED;
 
 /* HCI protocols */
 #define HCI_MAX_PROTO	2
@@ -75,7 +76,6 @@ struct hci_proto *hci_proto[HCI_MAX_PROTO];
 /* HCI notifiers list */
 static struct notifier_block *hci_notifier;
 
-
 /* ---- HCI notifications ---- */
 
 int hci_register_notifier(struct notifier_block *nb)
@@ -93,6 +93,32 @@ void hci_notify(struct hci_dev *hdev, int event)
 	notifier_call_chain(&hci_notifier, event, hdev);
 }
 
+/* ---- HCI hotplug support ---- */
+
+#ifdef CONFIG_HOTPLUG
+
+static int hci_run_hotplug(char *dev, char *action)
+{
+	char *argv[3], *envp[5], dstr[20], astr[32];
+
+	sprintf(dstr, "DEVICE=%s", dev);
+	sprintf(astr, "ACTION=%s", action);
+
+        argv[0] = hotplug_path;
+        argv[1] = "bluetooth";
+        argv[2] = NULL;
+
+	envp[0] = "HOME=/";
+	envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
+	envp[2] = dstr;
+	envp[3] = astr;
+	envp[4] = NULL;
+	
+	return call_usermodehelper(argv[0], argv, envp);
+}
+#else
+#define hci_run_hotplug(A...)
+#endif
 
 /* ---- HCI requests ---- */
 
@@ -270,7 +296,7 @@ struct hci_dev *hci_dev_get(int index)
 	if (index < 0)
 		return NULL;
 
-	spin_lock(&hdev_list_lock);
+	read_lock(&hdev_list_lock);
 	list_for_each(p, &hdev_list) {
 		hdev = list_entry(p, struct hci_dev, list);
 		if (hdev->id == index) {
@@ -280,7 +306,7 @@ struct hci_dev *hci_dev_get(int index)
 	}
 	hdev = NULL;
 done:
-	spin_unlock(&hdev_list_lock);
+	read_unlock(&hdev_list_lock);
 	return hdev;
 }
 
@@ -699,7 +725,7 @@ int hci_get_dev_list(unsigned long arg)
 		return -ENOMEM;
 	dr = dl->dev_req;
 
-	spin_lock_bh(&hdev_list_lock);
+	read_lock_bh(&hdev_list_lock);
 	list_for_each(p, &hdev_list) {
 		struct hci_dev *hdev;
 		hdev = list_entry(p, struct hci_dev, list);
@@ -708,7 +734,7 @@ int hci_get_dev_list(unsigned long arg)
 		if (++n >= dev_num)
 			break;
 	}
-	spin_unlock_bh(&hdev_list_lock);
+	read_unlock_bh(&hdev_list_lock);
 
 	dl->dev_num = n;
 	size = n * sizeof(struct hci_dev_req) + sizeof(__u16);
@@ -768,7 +794,7 @@ int hci_register_dev(struct hci_dev *hdev)
 	if (!hdev->open || !hdev->close || !hdev->destruct)
 		return -EINVAL;
 
-	spin_lock_bh(&hdev_list_lock);
+	write_lock_bh(&hdev_list_lock);
 
 	/* Find first available device id */
 	list_for_each(p, &hdev_list) {
@@ -807,11 +833,12 @@ int hci_register_dev(struct hci_dev *hdev)
 
 	atomic_set(&hdev->promisc, 0);
 		
-	hci_notify(hdev, HCI_DEV_REG);
-
 	MOD_INC_USE_COUNT;
 
-	spin_unlock_bh(&hdev_list_lock);
+	write_unlock_bh(&hdev_list_lock);
+
+	hci_notify(hdev, HCI_DEV_REG);
+	hci_run_hotplug(hdev->name, "register");
 
 	return id;
 }
@@ -821,13 +848,15 @@ int hci_unregister_dev(struct hci_dev *hdev)
 {
 	BT_DBG("%p name %s type %d", hdev, hdev->name, hdev->type);
 
-	spin_lock_bh(&hdev_list_lock);
+	write_lock_bh(&hdev_list_lock);
 	list_del(&hdev->list);
-	spin_unlock_bh(&hdev_list_lock);
+	write_unlock_bh(&hdev_list_lock);
 
 	hci_dev_do_close(hdev);
 
 	hci_notify(hdev, HCI_DEV_UNREG);
+	hci_run_hotplug(hdev->name, "unregister");
+	
 	hci_dev_put(hdev);
 
 	MOD_DEC_USE_COUNT;
@@ -1103,14 +1132,13 @@ static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int
 {
 	struct conn_hash *h = &hdev->conn_hash;
 	struct hci_conn  *conn = NULL;
-	int num = 0, min = 0xffff;
+	int num = 0, min = ~0;
         struct list_head *p;
 
 	/* We don't have to lock device here. Connections are always 
 	 * added and removed with TX task disabled. */
 	list_for_each(p, &h->list) {
 		struct hci_conn *c;
-
 		c = list_entry(p, struct hci_conn, list);
 
 		if (c->type != type || c->state != BT_CONNECTED
@@ -1118,14 +1146,15 @@ static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int
 			continue;
 		num++;
 
-		if (c->sent < min || type == SCO_LINK) {
+		if (c->sent < min) {
 			min  = c->sent;
 			conn = c;
 		}
 	}
 
 	if (conn) {
-		int q = hdev->acl_cnt / num;
+		int cnt = (type == ACL_LINK ? hdev->acl_cnt : hdev->sco_cnt);
+		int q = cnt / num;
 		*quote = q ? q : 1;
 	} else
 		*quote = 0;
@@ -1134,6 +1163,25 @@ static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int
 	return conn;
 }
 
+static inline void hci_acl_tx_to(struct hci_dev *hdev)
+{
+	struct conn_hash *h = &hdev->conn_hash;
+        struct list_head *p;
+	struct hci_conn  *c;
+
+	BT_ERR("%s ACL tx timeout", hdev->name);
+
+	/* Kill stalled connections */
+	list_for_each(p, &h->list) {
+		c = list_entry(p, struct hci_conn, list);
+		if (c->type == ACL_LINK && c->sent) {
+			BT_ERR("%s killing stalled ACL connection %s",
+				hdev->name, batostr(&c->dst));
+			hci_acl_disconn(c, 0x13);
+		}
+	}
+}
+
 static inline void hci_sched_acl(struct hci_dev *hdev)
 {
 	struct hci_conn *conn;
@@ -1142,21 +1190,19 @@ static inline void hci_sched_acl(struct hci_dev *hdev)
 
 	BT_DBG("%s", hdev->name);
 
-	if (!hdev->acl_cnt && (jiffies - hdev->acl_last_tx) > HZ*5) {
-		BT_ERR("%s ACL tx timeout", hdev->name);
-		hdev->acl_cnt++;
-	}
-	
+	/* ACL tx timeout must be longer than maximum
+	 * link supervision timeout (40.9 seconds) */
+	if (!hdev->acl_cnt && (jiffies - hdev->acl_last_tx) > (HZ * 45))
+		hci_acl_tx_to(hdev);
+
 	while (hdev->acl_cnt && (conn = hci_low_sent(hdev, ACL_LINK, &quote))) {
-		while (quote && (skb = skb_dequeue(&conn->data_q))) {
+		while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
 			BT_DBG("skb %p len %d", skb, skb->len);
-
 			hci_send_frame(skb);
 			hdev->acl_last_tx = jiffies;
 
-			conn->sent++;
 			hdev->acl_cnt--;
-			quote--;
+			conn->sent++;
 		}
 	}
 }
@@ -1170,15 +1216,14 @@ static inline void hci_sched_sco(struct hci_dev *hdev)
 
 	BT_DBG("%s", hdev->name);
 
-	while ((conn = hci_low_sent(hdev, SCO_LINK, &quote))) {
-		while (quote && (skb = skb_dequeue(&conn->data_q))) {
+	while (hdev->sco_cnt && (conn = hci_low_sent(hdev, SCO_LINK, &quote))) {
+		while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
 			BT_DBG("skb %p len %d", skb, skb->len);
-
 			hci_send_frame(skb);
 
-			//conn->sent++;
-			//hdev->sco_cnt--;
-			quote--;
+			conn->sent++;
+			if (conn->sent == ~0)
+				conn->sent = 0;
 		}
 	}
 }
@@ -1205,7 +1250,6 @@ static void hci_tx_task(unsigned long arg)
 	read_unlock(&hci_task_lock);
 }
 
-
 /* ----- HCI RX task (incomming data proccessing) ----- */
 
 /* ACL data packet */
@@ -1367,9 +1411,6 @@ static void hci_cmd_task(unsigned long arg)
 
 int hci_core_init(void)
 {
-	/* Init locks */
-	spin_lock_init(&hdev_list_lock);
-
 	return 0;
 }
 
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index a191d622af63..9445e4543416 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -352,15 +352,12 @@ static void hci_cs_link_ctl(struct hci_dev *hdev, __u16 ocf, __u8 status)
 			hci_dev_lock(hdev);
 	
 			acl = conn_hash_lookup_handle(hdev, handle);
-			if (!acl || !(sco = acl->link)) {
-				hci_dev_unlock(hdev);
-				break;
-			}
+			if (acl && (sco = acl->link)) {
+				sco->state = BT_CLOSED;
 
-			sco->state = BT_CLOSED;
-
-			hci_proto_connect_cfm(sco, status);
-			hci_conn_del(sco);
+				hci_proto_connect_cfm(sco, status);
+				hci_conn_del(sco);
+			}
 
 			hci_dev_unlock(hdev);
 		}
diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c
index 682c84c1623f..90a43a804ba6 100644
--- a/net/bluetooth/hci_sock.c
+++ b/net/bluetooth/hci_sock.c
@@ -86,7 +86,7 @@ static struct bluez_sock_list hci_sk_list = {
 /* Send frame to RAW socket */
 void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb)
 {
-	struct sock * sk;
+	struct sock *sk;
 
 	BT_DBG("hdev %p len %d", hdev, skb->len);
 
@@ -105,13 +105,13 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb)
 		/* Apply filter */
 		flt = &hci_pi(sk)->filter;
 
-		if (!hci_test_bit((skb->pkt_type & HCI_FLT_TYPE_BITS), &flt->type_mask))
+		if (!test_bit((skb->pkt_type & HCI_FLT_TYPE_BITS), &flt->type_mask))
 			continue;
 
 		if (skb->pkt_type == HCI_EVENT_PKT) {
 			register int evt = (*(__u8 *)skb->data & HCI_FLT_EVENT_BITS);
 			
-			if (!hci_test_bit(evt, &flt->event_mask))
+			if (!test_bit(evt, flt->event_mask))
 				continue;
 
 			if (flt->opcode && ((evt == EVT_CMD_COMPLETE && 
@@ -249,7 +249,7 @@ static int hci_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long a
 		err = hci_sock_bound_ioctl(sk, cmd, arg);
 		release_sock(sk);
 		return err;
-	};
+	}
 }
 
 static int hci_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
@@ -393,12 +393,12 @@ static int hci_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len,
 		err = -EPERM;
 
 		if (skb->pkt_type == HCI_COMMAND_PKT) {
-			__u16 opcode = __le16_to_cpu(*(__u16 *)skb->data);
-			__u16 ogf = cmd_opcode_ogf(opcode) - 1;
-			__u16 ocf = cmd_opcode_ocf(opcode) & HCI_FLT_OCF_BITS;
+			u16 opcode = __le16_to_cpu(*(__u16 *)skb->data);
+			u16 ogf = cmd_opcode_ogf(opcode) - 1;
+			u16 ocf = cmd_opcode_ocf(opcode) & HCI_FLT_OCF_BITS;
 
 			if (ogf > HCI_SFLT_MAX_OGF ||
-					!hci_test_bit(ocf, &hci_sec_filter.ocf_mask[ogf]))
+					!test_bit(ocf, hci_sec_filter.ocf_mask[ogf]))
 				goto drop;
 		} else
 			goto drop;
@@ -420,8 +420,8 @@ static int hci_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len,
 
 int hci_sock_setsockopt(struct socket *sock, int level, int optname, char *optval, int len)
 {
+	struct hci_ufilter uf = { .opcode = 0 };
 	struct sock *sk = sock->sk;
-	struct hci_filter flt = { opcode: 0 };
 	int err = 0, opt = 0;
 
 	BT_DBG("sk %p, opt %d", sk, optname);
@@ -454,32 +454,40 @@ int hci_sock_setsockopt(struct socket *sock, int level, int optname, char *optva
 		break;
 
 	case HCI_FILTER:
-		len = MIN(len, sizeof(struct hci_filter));
-		if (copy_from_user(&flt, optval, len)) {
+		len = MIN(len, sizeof(uf));
+		if (copy_from_user(&uf, optval, len)) {
 			err = -EFAULT;
 			break;
 		}
 
 		if (!capable(CAP_NET_RAW)) {
-			flt.type_mask     &= hci_sec_filter.type_mask;
-			flt.event_mask[0] &= hci_sec_filter.event_mask[0];
-			flt.event_mask[1] &= hci_sec_filter.event_mask[1];
+			uf.type_mask &= hci_sec_filter.type_mask;
+			uf.event_mask[0] &= *((u32 *) hci_sec_filter.event_mask + 0);
+			uf.event_mask[1] &= *((u32 *) hci_sec_filter.event_mask + 1);
 		}
+
+		{	
+			struct hci_filter *f = &hci_pi(sk)->filter;
 		
-		memcpy(&hci_pi(sk)->filter, &flt, len);
-		break;
+			f->type_mask = uf.type_mask;
+			f->opcode    = uf.opcode;
+			*((u32 *) f->event_mask + 0) = uf.event_mask[0];
+			*((u32 *) f->event_mask + 1) = uf.event_mask[0];
+		}
+		break; 
 
 	default:
 		err = -ENOPROTOOPT;
 		break;
-	};
-
+	}
+	
 	release_sock(sk);
 	return err;
 }
 
 int hci_sock_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen)
 {
+	struct hci_ufilter uf;
 	struct sock *sk = sock->sk;
 	int len, opt; 
 
@@ -508,15 +516,24 @@ int hci_sock_getsockopt(struct socket *sock, int level, int optname, char *optva
 		break;
 
 	case HCI_FILTER:
-		len = MIN(len, sizeof(struct hci_filter));
-		if (copy_to_user(optval, &hci_pi(sk)->filter, len))
+		{
+			struct hci_filter *f = &hci_pi(sk)->filter;
+		
+			uf.type_mask = f->type_mask;
+			uf.opcode    = f->opcode;
+			uf.event_mask[0] = *((u32 *) f->event_mask + 0);
+			uf.event_mask[0] = *((u32 *) f->event_mask + 1);
+		}
+
+		len = MIN(len, sizeof(uf));
+		if (copy_to_user(optval, &uf, len))
 			return -EFAULT;
 		break;
 
 	default:
 		return -ENOPROTOOPT;
 		break;
-	};
+	}
 
 	return 0;
 }
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index 015cc3f06c8a..10df9da60f18 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -25,9 +25,9 @@
 /*
  * BlueZ L2CAP core and sockets.
  *
- * $Id: l2cap.c,v 1.8 2002/04/19 00:01:39 maxk Exp $
+ * $Id: l2cap.c,v 1.15 2002/09/09 01:14:52 maxk Exp $
  */
-#define VERSION "2.0"
+#define VERSION "2.1"
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -51,6 +51,7 @@
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
+#include <asm/unaligned.h>
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
@@ -69,7 +70,7 @@ struct bluez_sock_list l2cap_sk_list = {
 
 static int l2cap_conn_del(struct hci_conn *conn, int err);
 
-static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent);
+static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent);
 static void l2cap_chan_del(struct sock *sk, int err);
 static int  l2cap_chan_send(struct sock *sk, struct msghdr *msg, int len);
 
@@ -177,6 +178,14 @@ static int l2cap_conn_del(struct hci_conn *hcon, int err)
 	return 0;
 }
 
+static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent)
+{
+	struct l2cap_chan_list *l = &conn->chan_list;
+	write_lock(&l->lock);
+	__l2cap_chan_add(conn, sk, parent);
+	write_unlock(&l->lock);
+}
+
 int l2cap_connect(struct sock *sk)
 {
 	bdaddr_t *src = &bluez_sk(sk)->src;
@@ -234,32 +243,26 @@ int l2cap_connect(struct sock *sk)
 }
 
 /* -------- Socket interface ---------- */
-static struct sock *__l2cap_get_sock_by_addr(struct sockaddr_l2 *addr)
+static struct sock *__l2cap_get_sock_by_addr(__u16 psm, bdaddr_t *src)
 {
-	bdaddr_t *src = &addr->l2_bdaddr;
-	__u16 psm = addr->l2_psm;
 	struct sock *sk;
-
 	for (sk = l2cap_sk_list.head; sk; sk = sk->next) {
 		if (l2cap_pi(sk)->psm == psm &&
-		    !bacmp(&bluez_sk(sk)->src, src))
+				!bacmp(&bluez_sk(sk)->src, src))
 			break;
 	}
-
 	return sk;
 }
 
-/* Find socket listening on psm and source bdaddr.
+/* Find socket with psm and source bdaddr.
  * Returns closest match.
  */
-static struct sock *l2cap_get_sock_listen(bdaddr_t *src, __u16 psm)
+static struct sock *__l2cap_get_sock_by_psm(int state, __u16 psm, bdaddr_t *src)
 {
 	struct sock *sk, *sk1 = NULL;
 
-	read_lock(&l2cap_sk_list.lock);
-
 	for (sk = l2cap_sk_list.head; sk; sk = sk->next) {
-		if (sk->state != BT_LISTEN)
+		if (state && sk->state != state)
 			continue;
 
 		if (l2cap_pi(sk)->psm == psm) {
@@ -272,9 +275,19 @@ static struct sock *l2cap_get_sock_listen(bdaddr_t *src, __u16 psm)
 				sk1 = sk;
 		}
 	}
+	return sk ? sk : sk1;
+}
 
+/* Find socket with given address (psm, src).
+ * Returns locked socket */
+static inline struct sock *l2cap_get_sock_by_psm(int state, __u16 psm, bdaddr_t *src)
+{
+	struct sock *s;
+	read_lock(&l2cap_sk_list.lock);
+	s = __l2cap_get_sock_by_psm(state, psm, src);
+	if (s) bh_lock_sock(s);
 	read_unlock(&l2cap_sk_list.lock);
-	return sk ? sk : sk1;
+	return s;
 }
 
 static void l2cap_sock_destruct(struct sock *sk)
@@ -283,7 +296,7 @@ static void l2cap_sock_destruct(struct sock *sk)
 
 	skb_queue_purge(&sk->receive_queue);
 	skb_queue_purge(&sk->write_queue);
-	
+
 	if (sk->protinfo)
 		kfree(sk->protinfo);
 	
@@ -320,8 +333,6 @@ static void l2cap_sock_kill(struct sock *sk)
 	sock_put(sk);
 }
 
-/* Close socket.
- */
 static void __l2cap_sock_close(struct sock *sk, int reason)
 {
 	BT_DBG("sk %p state %d socket %p", sk, sk->state, sk->socket);
@@ -333,6 +344,7 @@ static void __l2cap_sock_close(struct sock *sk, int reason)
 
 	case BT_CONNECTED:
 	case BT_CONFIG:
+	case BT_CONNECT2:
 		if (sk->type == SOCK_SEQPACKET) {
 			struct l2cap_conn *conn = l2cap_pi(sk)->conn;
 			l2cap_disconn_req req;
@@ -349,7 +361,6 @@ static void __l2cap_sock_close(struct sock *sk, int reason)
 		break;
 
 	case BT_CONNECT:
-	case BT_CONNECT2:
 	case BT_DISCONN:
 		l2cap_chan_del(sk, reason);
 		break;
@@ -380,7 +391,6 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent)
 
 	if (parent) {
 		sk->type = parent->type;
-
 		pi->imtu = l2cap_pi(parent)->imtu;
 		pi->omtu = l2cap_pi(parent)->omtu;
 		pi->link_mode = l2cap_pi(parent)->link_mode;
@@ -405,6 +415,8 @@ static struct sock *l2cap_sock_alloc(struct socket *sock, int proto, int prio)
 
 	sk->destruct = l2cap_sock_destruct;
 	sk->sndtimeo = L2CAP_CONN_TIMEOUT;
+
+	sk->protocol = proto;
 	sk->state    = BT_OPEN;
 
 	l2cap_sock_init_timer(sk);
@@ -421,11 +433,12 @@ static int l2cap_sock_create(struct socket *sock, int protocol)
 
 	BT_DBG("sock %p", sock);
 
-	if (sock->type != SOCK_SEQPACKET && sock->type != SOCK_RAW)
+	sock->state = SS_UNCONNECTED;
+
+	if (sock->type != SOCK_SEQPACKET && sock->type != SOCK_DGRAM && sock->type != SOCK_RAW)
 		return -ESOCKTNOSUPPORT;
 
-	sock->state = SS_UNCONNECTED;
-	sock->ops   = &l2cap_sock_ops;
+	sock->ops = &l2cap_sock_ops;
 
 	sk = l2cap_sock_alloc(sock, protocol, GFP_KERNEL);
 	if (!sk)
@@ -453,20 +466,16 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_
 		goto done;
 	}
 
-	write_lock(&l2cap_sk_list.lock);
-
-	if (la->l2_psm && __l2cap_get_sock_by_addr(la)) {
+	write_lock_bh(&l2cap_sk_list.lock);
+	if (la->l2_psm && __l2cap_get_sock_by_addr(la->l2_psm, &la->l2_bdaddr)) {
 		err = -EADDRINUSE;
-		goto unlock;
+	} else {
+		/* Save source address */
+		bacpy(&bluez_sk(sk)->src, &la->l2_bdaddr);
+		l2cap_pi(sk)->psm = la->l2_psm;
+		sk->state = BT_BOUND;
 	}
-
-	/* Save source address */
-	bacpy(&bluez_sk(sk)->src, &la->l2_bdaddr);
-	l2cap_pi(sk)->psm = la->l2_psm;
-	sk->state = BT_BOUND;
-
-unlock:
-	write_unlock(&l2cap_sk_list.lock);
+	write_unlock_bh(&l2cap_sk_list.lock);
 
 done:
 	release_sock(sk);
@@ -629,7 +638,6 @@ static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *l
 		bacpy(&la->l2_bdaddr, &bluez_sk(sk)->src);
 
 	la->l2_psm = l2cap_pi(sk)->psm;
-
 	return 0;
 }
 
@@ -646,6 +654,10 @@ static int l2cap_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len,
 	if (msg->msg_flags & MSG_OOB)
 		return -EOPNOTSUPP;
 
+	/* Check outgoing MTU */
+	if (len > l2cap_pi(sk)->omtu)
+		return -EINVAL;
+
 	lock_sock(sk);
 
 	if (sk->state == BT_CONNECTED)
@@ -691,7 +703,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
 	default:
 		err = -ENOPROTOOPT;
 		break;
-	};
+	}
 
 	release_sock(sk);
 	return err;
@@ -743,20 +755,37 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
 	default:
 		err = -ENOPROTOOPT;
 		break;
-	};
+	}
 
 	release_sock(sk);
 	return err;
 }
 
+static int l2cap_sock_shutdown(struct socket *sock, int how)
+{
+	struct sock *sk = sock->sk;
+
+	BT_DBG("sock %p, sk %p", sock, sk);
+
+	if (!sk) return 0;
+
+	l2cap_sock_clear_timer(sk);
+
+	lock_sock(sk);
+	sk->shutdown = SHUTDOWN_MASK;
+	__l2cap_sock_close(sk, ECONNRESET);
+	release_sock(sk);
+
+	return 0;
+}
+
 static int l2cap_sock_release(struct socket *sock)
 {
 	struct sock *sk = sock->sk;
 
 	BT_DBG("sock %p, sk %p", sock, sk);
 
-	if (!sk)
-		return 0;
+	if (!sk) return 0;
 
 	sock_orphan(sk);
 	l2cap_sock_close(sk);
@@ -767,24 +796,20 @@ static int l2cap_sock_release(struct socket *sock)
 static struct sock * __l2cap_get_chan_by_dcid(struct l2cap_chan_list *l, __u16 cid)
 {
 	struct sock *s;
-
 	for (s = l->head; s; s = l2cap_pi(s)->next_c) {
 		if (l2cap_pi(s)->dcid == cid)
 			break;
 	}
-
 	return s;
 }
 
 static struct sock *__l2cap_get_chan_by_scid(struct l2cap_chan_list *l, __u16 cid)
 {
 	struct sock *s;
-
 	for (s = l->head; s; s = l2cap_pi(s)->next_c) {
 		if (l2cap_pi(s)->scid == cid)
 			break;
 	}
-
 	return s;
 }
 
@@ -850,10 +875,15 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct so
 	l2cap_pi(sk)->conn = conn;
 
 	if (sk->type == SOCK_SEQPACKET) {
-		/* Alloc CID for normal socket */
+		/* Alloc CID for connection-oriented socket */
 		l2cap_pi(sk)->scid = l2cap_alloc_cid(l);
+	} else if (sk->type == SOCK_DGRAM) {
+		/* Connectionless socket */
+		l2cap_pi(sk)->scid = 0x0002;
+		l2cap_pi(sk)->dcid = 0x0002;
+		l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU;
 	} else {
-		/* Raw socket can send only signalling messages */
+		/* Raw socket can send/recv signalling messages only */
 		l2cap_pi(sk)->scid = 0x0001;
 		l2cap_pi(sk)->dcid = 0x0001;
 		l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU;
@@ -865,14 +895,6 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct so
 		bluez_accept_enqueue(parent, sk);
 }
 
-static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent)
-{
-	struct l2cap_chan_list *l = &conn->chan_list;
-	write_lock(&l->lock);
-	__l2cap_chan_add(conn, sk, parent);
-	write_unlock(&l->lock);
-}
-
 /* Delete channel. 
  * Must be called on the locked socket. */
 static void l2cap_chan_del(struct sock *sk, int err)
@@ -984,25 +1006,31 @@ static int l2cap_chan_send(struct sock *sk, struct msghdr *msg, int len)
 {
 	struct l2cap_conn *conn = l2cap_pi(sk)->conn;
 	struct sk_buff *skb, **frag;
-	int err, size, count, sent=0;
+	int err, hlen, count, sent=0;
 	l2cap_hdr *lh;
 
-	/* Check outgoing MTU */
-	if (len > l2cap_pi(sk)->omtu)
-		return -EINVAL;
-
 	BT_DBG("sk %p len %d", sk, len);
 
 	/* First fragment (with L2CAP header) */
-	count = MIN(conn->mtu - L2CAP_HDR_SIZE, len);
-	size  = L2CAP_HDR_SIZE + count;
-	if (!(skb = bluez_skb_send_alloc(sk, size, msg->msg_flags & MSG_DONTWAIT, &err)))
+	if (sk->type == SOCK_DGRAM)
+		hlen = L2CAP_HDR_SIZE + 2;
+	else
+		hlen = L2CAP_HDR_SIZE;
+
+	count = MIN(conn->mtu - hlen, len);
+
+	skb = bluez_skb_send_alloc(sk, hlen + count,
+			msg->msg_flags & MSG_DONTWAIT, &err);
+	if (!skb)
 		return err;
 
 	/* Create L2CAP header */
 	lh = (l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
-	lh->len = __cpu_to_le16(len);
 	lh->cid = __cpu_to_le16(l2cap_pi(sk)->dcid);
+	lh->len = __cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
+
+	if (sk->type == SOCK_DGRAM)
+		put_unaligned(l2cap_pi(sk)->psm, (__u16 *) skb_put(skb, 2));
 
 	if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count)) {
 		err = -EFAULT;
@@ -1315,37 +1343,41 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd,
 	BT_DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid);
 
 	/* Check if we have socket listening on psm */
-	if (!(parent = l2cap_get_sock_listen(conn->src, psm))) {
+	parent = l2cap_get_sock_by_psm(BT_LISTEN, psm, conn->src);
+	if (!parent) {
 		result = L2CAP_CR_BAD_PSM;
-		goto resp;
+		goto sendresp;
 	}
 
-	write_lock(&list->lock);
-	bh_lock_sock(parent);
-
 	result = L2CAP_CR_NO_MEM;
 
-	/* Check if we already have channel with that dcid */
-	if (__l2cap_get_chan_by_dcid(list, scid))
-		goto unlock;
-
 	/* Check for backlog size */
 	if (parent->ack_backlog > parent->max_ack_backlog) {
 		BT_DBG("backlog full %d", parent->ack_backlog); 
-		goto unlock;
+		goto response;
 	}
 
-	if (!(sk = l2cap_sock_alloc(NULL, BTPROTO_L2CAP, GFP_ATOMIC)))
-		goto unlock;
+	sk = l2cap_sock_alloc(NULL, BTPROTO_L2CAP, GFP_ATOMIC);
+	if (!sk)
+		goto response;
 
-	l2cap_sock_init(sk, parent);
+	write_lock(&list->lock);
+
+	/* Check if we already have channel with that dcid */
+	if (__l2cap_get_chan_by_dcid(list, scid)) {
+		write_unlock(&list->lock);
+		sk->zapped = 1;
+		l2cap_sock_kill(sk);
+		goto response;
+	}
 
+	hci_conn_hold(conn->hcon);
+
+	l2cap_sock_init(sk, parent);
 	bacpy(&bluez_sk(sk)->src, conn->src);
 	bacpy(&bluez_sk(sk)->dst, conn->dst);
 	l2cap_pi(sk)->psm  = psm;
 	l2cap_pi(sk)->dcid = scid;
-	
-	hci_conn_hold(conn->hcon);
 
 	__l2cap_chan_add(conn, sk, parent);
 	dcid = l2cap_pi(sk)->scid;
@@ -1360,20 +1392,22 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd,
 	
 	if (l2cap_pi(sk)->link_mode & L2CAP_LM_ENCRYPT) {
 		if (!hci_conn_encrypt(conn->hcon))
-			goto unlock;
+			goto done;
 	} else if (l2cap_pi(sk)->link_mode & L2CAP_LM_AUTH) {
 		if (!hci_conn_auth(conn->hcon))
-			goto unlock;
+			goto done;
 	}
 
 	sk->state = BT_CONFIG;
 	result = status = 0;
 
-unlock:
-	bh_unlock_sock(parent);
+done:
 	write_unlock(&list->lock);
 
-resp:
+response:
+	bh_unlock_sock(parent);
+
+sendresp:
 	rsp.scid   = __cpu_to_le16(scid);
 	rsp.dcid   = __cpu_to_le16(dcid);
 	rsp.result = __cpu_to_le16(result);
@@ -1678,10 +1712,37 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, __u16 cid, struct
 	return 0;
 }
 
+static inline int l2cap_conless_channel(struct l2cap_conn *conn, __u16 psm, struct sk_buff *skb)
+{
+	struct sock *sk;
+
+	sk = l2cap_get_sock_by_psm(0, psm, conn->src);
+	if (!sk)
+		goto drop;
+
+	BT_DBG("sk %p, len %d", sk, skb->len);
+
+	if (sk->state != BT_BOUND && sk->state != BT_CONNECTED)
+		goto drop;
+
+	if (l2cap_pi(sk)->imtu < skb->len)
+		goto drop;
+
+	if (!sock_queue_rcv_skb(sk, skb))
+		goto done;
+
+drop:
+	kfree_skb(skb);
+
+done:
+	if (sk) bh_unlock_sock(sk);
+	return 0;
+}
+
 static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
 {
 	l2cap_hdr *lh = (l2cap_hdr *) skb->data;
-	__u16 cid, len;
+	__u16 cid, psm, len;
 
 	skb_pull(skb, L2CAP_HDR_SIZE);
 	cid = __le16_to_cpu(lh->cid);
@@ -1689,10 +1750,21 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
 
 	BT_DBG("len %d, cid 0x%4.4x", len, cid);
 
-	if (cid == 0x0001)
+	switch (cid) {
+	case 0x0001:
 		l2cap_sig_channel(conn, skb);
-	else	
+		break;
+
+	case 0x0002:
+		psm = get_unaligned((__u16 *) skb->data);
+		skb_pull(skb, 2);
+		l2cap_conless_channel(conn, psm, skb);
+		break;
+		
+	default:
 		l2cap_data_channel(conn, cid, skb);
+		break;
+	}
 }
 
 /* ------------ L2CAP interface with lower layer (HCI) ------------- */
@@ -1859,8 +1931,8 @@ static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, __u16
 	BT_DBG("conn %p len %d flags 0x%x", conn, skb->len, flags);
 
 	if (flags & ACL_START) {
-		int flen, tlen, size;
-		l2cap_hdr *lh;
+		l2cap_hdr *hdr;
+		int len;
 
 		if (conn->rx_len) {
 			BT_ERR("Unexpected start frame (len %d)", skb->len);
@@ -1869,30 +1941,28 @@ static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, __u16
 			conn->rx_len = 0;
 		}
 
-		if (skb->len < L2CAP_HDR_SIZE) {
+		if (skb->len < 2) {
 			BT_ERR("Frame is too small (len %d)", skb->len);
 			goto drop;
 		}
 
-		lh = (l2cap_hdr *)skb->data;
-		tlen = __le16_to_cpu(lh->len);
-		flen = skb->len - L2CAP_HDR_SIZE;
+		hdr = (l2cap_hdr *) skb->data;
+		len = __le16_to_cpu(hdr->len) + L2CAP_HDR_SIZE;
 
-		BT_DBG("Start: total len %d, frag len %d", tlen, flen);
+		BT_DBG("Start: total len %d, frag len %d", len, skb->len);
 
-		if (flen == tlen) {
+		if (len == skb->len) {
 			/* Complete frame received */
 			l2cap_recv_frame(conn, skb);
 			return 0;
 		}
 
 		/* Allocate skb for the complete frame (with header) */
-		size = L2CAP_HDR_SIZE + tlen;
-		if (!(conn->rx_skb = bluez_skb_alloc(size, GFP_ATOMIC)))
+		if (!(conn->rx_skb = bluez_skb_alloc(len, GFP_ATOMIC)))
 			goto drop;
 
 		memcpy(skb_put(conn->rx_skb, skb->len), skb->data, skb->len);
-		conn->rx_len = tlen - flen;
+		conn->rx_len = len - skb->len;
 	} else {
 		BT_DBG("Cont: frag len %d (expecting %d)", skb->len, conn->rx_len);
 
@@ -1932,7 +2002,7 @@ static int l2cap_sock_dump(char *buf, struct bluez_sock_list *list)
 	struct sock *sk;
 	char *ptr = buf;
 
-	write_lock(&list->lock);
+	read_lock_bh(&list->lock);
 
 	for (sk = list->head; sk; sk = sk->next) {
 		pi = l2cap_pi(sk);
@@ -1942,7 +2012,7 @@ static int l2cap_sock_dump(char *buf, struct bluez_sock_list *list)
 				pi->link_mode);
 	}
 
-	write_unlock(&list->lock);
+	read_unlock_bh(&list->lock);
 
 	ptr += sprintf(ptr, "\n");
 	return ptr - buf;
@@ -1973,38 +2043,38 @@ static int l2cap_read_proc(char *buf, char **start, off_t offset, int count, int
 }
 
 static struct proto_ops l2cap_sock_ops = {
-	.family =	PF_BLUETOOTH,
-	.release =	l2cap_sock_release,
-	.bind =		l2cap_sock_bind,
-	.connect =	l2cap_sock_connect,
-	.listen =	l2cap_sock_listen,
-	.accept =	l2cap_sock_accept,
-	.getname =	l2cap_sock_getname,
-	.sendmsg =	l2cap_sock_sendmsg,
-	.recvmsg =	bluez_sock_recvmsg,
-	.poll =		bluez_sock_poll,
-	.socketpair =	sock_no_socketpair,
-	.ioctl =	sock_no_ioctl,
-	.shutdown =	sock_no_shutdown,
-	.setsockopt =	l2cap_sock_setsockopt,
-	.getsockopt =	l2cap_sock_getsockopt,
-	.mmap =		sock_no_mmap
+	.family  =      PF_BLUETOOTH,
+	.release =      l2cap_sock_release,
+	.bind    =      l2cap_sock_bind,
+	.connect =      l2cap_sock_connect,
+	.listen  =      l2cap_sock_listen,
+	.accept  =      l2cap_sock_accept,
+	.getname =      l2cap_sock_getname,
+	.sendmsg =      l2cap_sock_sendmsg,
+	.recvmsg =      bluez_sock_recvmsg,
+	.poll    =      bluez_sock_poll,
+	.mmap    =      sock_no_mmap,
+	.socketpair =   sock_no_socketpair,
+	.ioctl      =   sock_no_ioctl,
+	.shutdown   =   l2cap_sock_shutdown,
+	.setsockopt =   l2cap_sock_setsockopt,
+	.getsockopt =   l2cap_sock_getsockopt
 };
 
 static struct net_proto_family l2cap_sock_family_ops = {
-	.family =	PF_BLUETOOTH,
-	.create =	l2cap_sock_create
+	.family =       PF_BLUETOOTH,
+	.create	=       l2cap_sock_create
 };
 
 static struct hci_proto l2cap_hci_proto = {
-	.name =		"L2CAP",
-	.id =		HCI_PROTO_L2CAP,
-	.connect_ind =	l2cap_connect_ind,
-	.connect_cfm =	l2cap_connect_cfm,
-	.disconn_ind =	l2cap_disconn_ind,
-	.recv_acldata =	l2cap_recv_acldata,
-	.auth_cfm =	l2cap_auth_cfm,
-	.encrypt_cfm =	l2cap_encrypt_cfm
+	.name =         "L2CAP",
+	.id   =         HCI_PROTO_L2CAP,
+	.connect_ind =  l2cap_connect_ind,
+	.connect_cfm =  l2cap_connect_cfm,
+	.disconn_ind =  l2cap_disconn_ind,
+	.auth_cfm    =  l2cap_auth_cfm,
+	.encrypt_cfm =  l2cap_encrypt_cfm,
+	.recv_acldata =	l2cap_recv_acldata
 };
 
 int __init l2cap_init(void)
diff --git a/net/bluetooth/lib.c b/net/bluetooth/lib.c
index 44b2bb2771e7..3fbcbd646d9f 100644
--- a/net/bluetooth/lib.c
+++ b/net/bluetooth/lib.c
@@ -105,7 +105,7 @@ int bterr(__u16 code)
 		return EACCES;
 
 	case 0x06:
-		return EINVAL;
+		return EBADE;
 
 	case 0x07:
 		return ENOMEM;
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
index eb0ef4a11766..129e77012728 100644
--- a/net/bluetooth/sco.c
+++ b/net/bluetooth/sco.c
@@ -27,7 +27,7 @@
  *
  * $Id: sco.c,v 1.3 2002/04/17 17:37:16 maxk Exp $
  */
-#define VERSION "0.2"
+#define VERSION "0.3"
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -67,16 +67,15 @@ static struct bluez_sock_list sco_sk_list = {
 	.lock = RW_LOCK_UNLOCKED
 };
 
-static inline int sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent);
+static void __sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent);
 static void sco_chan_del(struct sock *sk, int err);
-static inline struct sock * sco_chan_get(struct sco_conn *conn);
 
 static int  sco_conn_del(struct hci_conn *conn, int err);
 
 static void sco_sock_close(struct sock *sk);
 static void sco_sock_kill(struct sock *sk);
 
-/* ----- SCO timers ------ */
+/* ---- SCO timers ---- */
 static void sco_sock_timeout(unsigned long arg)
 {
 	struct sock *sk = (struct sock *) arg;
@@ -115,7 +114,7 @@ static void sco_sock_init_timer(struct sock *sk)
 	sk->timer.data = (unsigned long)sk;
 }
 
-/* -------- SCO connections --------- */
+/* ---- SCO connections ---- */
 static struct sco_conn *sco_conn_add(struct hci_conn *hcon, __u8 status)
 {
 	struct hci_dev *hdev = hcon->hdev;
@@ -150,6 +149,15 @@ static struct sco_conn *sco_conn_add(struct hci_conn *hcon, __u8 status)
 	return conn;
 }
 
+static inline struct sock *sco_chan_get(struct sco_conn *conn)
+{
+	struct sock *sk = NULL;
+	sco_conn_lock(conn);
+	sk = conn->sk;
+	sco_conn_unlock(conn);
+	return sk;
+}
+
 static int sco_conn_del(struct hci_conn *hcon, int err)
 {
 	struct sco_conn *conn;
@@ -176,6 +184,20 @@ static int sco_conn_del(struct hci_conn *hcon, int err)
 	return 0;
 }
 
+static inline int sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent)
+{
+	int err = 0;
+
+	sco_conn_lock(conn);
+	if (conn->sk) {
+		err = -EBUSY;
+	} else {
+		__sco_chan_add(conn, sk, parent);
+	}
+	sco_conn_unlock(conn);
+	return err;
+}
+
 int sco_connect(struct sock *sk)
 {
 	bdaddr_t *src = &bluez_sk(sk)->src;
@@ -462,23 +484,20 @@ static int sco_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_le
 		goto done;
 	}
 
-	write_lock(&sco_sk_list.lock);
-
+	write_lock_bh(&sco_sk_list.lock);
+	
 	if (bacmp(src, BDADDR_ANY) && __sco_get_sock_by_addr(src)) {
 		err = -EADDRINUSE;
-		goto unlock;
+	} else {
+		/* Save source address */
+		bacpy(&bluez_sk(sk)->src, &sa->sco_bdaddr);
+		sk->state = BT_BOUND;
 	}
-
-	/* Save source address */
-	bacpy(&bluez_sk(sk)->src, &sa->sco_bdaddr);
-	sk->state = BT_BOUND;
-
-unlock:
-	write_unlock(&sco_sk_list.lock);
+	
+	write_unlock_bh(&sco_sk_list.lock);
 
 done:
 	release_sock(sk);
-
 	return err;
 }
 
@@ -649,7 +668,7 @@ int sco_sock_setsockopt(struct socket *sock, int level, int optname, char *optva
 	default:
 		err = -ENOPROTOOPT;
 		break;
-	};
+	}
 
 	release_sock(sk);
 	return err;
@@ -703,7 +722,7 @@ int sco_sock_getsockopt(struct socket *sock, int level, int optname, char *optva
 	default:
 		err = -ENOPROTOOPT;
 		break;
-	};
+	}
 
 	release_sock(sk);
 	return err;
@@ -735,29 +754,6 @@ static void __sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *
 		bluez_accept_enqueue(parent, sk);
 }
 
-static inline int sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent)
-{
-	int err = 0;
-
-	sco_conn_lock(conn);
-	if (conn->sk) {
-		err = -EBUSY;
-	} else {
-		__sco_chan_add(conn, sk, parent);
-	}
-	sco_conn_unlock(conn);
-	return err;
-}
-
-static inline struct sock * sco_chan_get(struct sco_conn *conn)
-{
-	struct sock *sk = NULL;
-	sco_conn_lock(conn);
-	sk = conn->sk;
-	sco_conn_unlock(conn);
-	return sk;
-}
-
 /* Delete channel. 
  * Must be called on the locked socket. */
 static void sco_chan_del(struct sock *sk, int err)
@@ -895,7 +891,7 @@ static int sco_sock_dump(char *buf, struct bluez_sock_list *list)
 	struct sock *sk;
 	char *ptr = buf;
 
-	write_lock(&list->lock);
+	read_lock_bh(&list->lock);
 
 	for (sk = list->head; sk; sk = sk->next) {
 		pi = sco_pi(sk);
@@ -904,7 +900,7 @@ static int sco_sock_dump(char *buf, struct bluez_sock_list *list)
 				sk->state); 
 	}
 
-	write_unlock(&list->lock);
+	read_unlock_bh(&list->lock);
 
 	ptr += sprintf(ptr, "\n");
 
@@ -936,36 +932,36 @@ static int sco_read_proc(char *buf, char **start, off_t offset, int count, int *
 }
 
 static struct proto_ops sco_sock_ops = {
-	.family =	PF_BLUETOOTH,
-	.release =	sco_sock_release,
-	.bind =		sco_sock_bind,
-	.connect =	sco_sock_connect,
-	.listen =	sco_sock_listen,
-	.accept =	sco_sock_accept,
-	.getname =	sco_sock_getname,
-	.sendmsg =	sco_sock_sendmsg,
-	.recvmsg =	bluez_sock_recvmsg,
-	.poll =		bluez_sock_poll,
-	.socketpair =	sock_no_socketpair,
-	.ioctl =	sock_no_ioctl,
-	.shutdown =	sock_no_shutdown,
-	.setsockopt =	sco_sock_setsockopt,
-	.getsockopt =	sco_sock_getsockopt,
-	.mmap =		sock_no_mmap
+	.family  =      PF_BLUETOOTH,
+	.release =      sco_sock_release,
+	.bind    =     	sco_sock_bind,
+	.connect =      sco_sock_connect,
+	.listen  =      sco_sock_listen,
+	.accept  =      sco_sock_accept,
+	.getname =      sco_sock_getname,
+	.sendmsg =      sco_sock_sendmsg,
+	.recvmsg =      bluez_sock_recvmsg,
+	.poll    =      bluez_sock_poll,
+	.ioctl   =      sock_no_ioctl,
+	.mmap    =      sock_no_mmap,
+	.socketpair =   sock_no_socketpair,
+	.shutdown   =   sock_no_shutdown,
+	.setsockopt =   sco_sock_setsockopt,
+	.getsockopt =   sco_sock_getsockopt
 };
 
 static struct net_proto_family sco_sock_family_ops = {
-	.family =	PF_BLUETOOTH,
-	.create =	sco_sock_create
+	.family =       PF_BLUETOOTH,
+	.create =       sco_sock_create
 };
 
 static struct hci_proto sco_hci_proto = {
-	.name =		"SCO",
-	.id =		HCI_PROTO_SCO,
-	.connect_ind =	sco_connect_ind,
-	.connect_cfm =	sco_connect_cfm,
-	.disconn_ind =	sco_disconn_ind,
-	.recv_scodata =	sco_recv_scodata,
+	.name =         "SCO",
+	.id   =         HCI_PROTO_SCO,
+	.connect_ind =  sco_connect_ind,
+	.connect_cfm =  sco_connect_cfm,
+	.disconn_ind =  sco_disconn_ind,
+	.recv_scodata =	sco_recv_scodata
 };
 
 int __init sco_init(void)
-- 
2.30.9