All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 01/11] Bluetooth: Implement automatic setup procedure for local adapters
@ 2011-01-04 10:08 johan.hedberg
  2011-01-04 10:08 ` [PATCH 02/11] Bluetooth: Add support for management powered event johan.hedberg
                   ` (9 more replies)
  0 siblings, 10 replies; 13+ messages in thread
From: johan.hedberg @ 2011-01-04 10:08 UTC (permalink / raw)
  To: linux-bluetooth

From: Johan Hedberg <johan.hedberg@nokia.com>

This patch implements automatic initialization of basic information
about newly registered Bluetooth adapters. E.g. the address and features
are always needed so it makes sense for the kernel to automatically
power on adapters and read this information. A new HCI_SETUP flag is
added to track this state.

In order to not consume unnecessary amounts of power if there isn't a
user space available that could switch the adapter back off, a timer is
added to do this automatically as long as no Bluetooth user space seems
to be present. A new HCI_AUTO_OFF flag is added that user space needs to
clear to avoid the automatic power off.

Additionally, the management interface index_added event is moved to the
end of the HCI_SETUP stage so a user space supporting the managment
inteface has all the necessary information available for fetching when
it gets notified of a new adapter. The HCI_DEV_REG event is kept in the
same place as before since existing HCI raw socket based user space
versions depend on seeing the kernels initialization sequence
(hci_init_req) to determine when the adapter is ready for use.

Signed-off-by: Johan Hedberg <johan.hedberg@nokia.com>
---
 include/net/bluetooth/hci.h      |    3 ++
 include/net/bluetooth/hci_core.h |    6 +++
 net/bluetooth/hci_core.c         |   64 ++++++++++++++++++++++++++++++++++++-
 net/bluetooth/mgmt.c             |    8 +++++
 4 files changed, 79 insertions(+), 2 deletions(-)

diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 29a7a8c..6469d67 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -76,6 +76,9 @@ enum {
 	HCI_INQUIRY,
 
 	HCI_RAW,
+
+	HCI_SETUP,
+	HCI_AUTO_OFF,
 };
 
 /* HCI ioctl defines */
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index a29feb0..dfbb325 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -114,6 +114,10 @@ struct hci_dev {
 
 	struct workqueue_struct	*workqueue;
 
+	struct work_struct	power_on;
+	struct work_struct	power_off;
+	struct timer_list	off_timer;
+
 	struct tasklet_struct	cmd_task;
 	struct tasklet_struct	rx_task;
 	struct tasklet_struct	tx_task;
@@ -436,6 +440,8 @@ int hci_inquiry(void __user *arg);
 struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr);
 int hci_blacklist_clear(struct hci_dev *hdev);
 
+void hci_del_off_timer(struct hci_dev *hdev);
+
 void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb);
 
 int hci_recv_frame(struct sk_buff *skb);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 8b602d8..d5a315c 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -50,6 +50,8 @@
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
 
+#define AUTO_OFF_TIMEOUT 2000
+
 static void hci_cmd_task(unsigned long arg);
 static void hci_rx_task(unsigned long arg);
 static void hci_tx_task(unsigned long arg);
@@ -794,6 +796,7 @@ int hci_get_dev_list(void __user *arg)
 	list_for_each(p, &hci_dev_list) {
 		struct hci_dev *hdev;
 		hdev = list_entry(p, struct hci_dev, list);
+		hci_del_off_timer(hdev);
 		(dr + n)->dev_id  = hdev->id;
 		(dr + n)->dev_opt = hdev->flags;
 		if (++n >= dev_num)
@@ -823,6 +826,8 @@ int hci_get_dev_info(void __user *arg)
 	if (!hdev)
 		return -ENODEV;
 
+	hci_del_off_timer(hdev);
+
 	strcpy(di.name, hdev->name);
 	di.bdaddr   = hdev->bdaddr;
 	di.type     = (hdev->bus & 0x0f) | (hdev->dev_type << 4);
@@ -891,6 +896,51 @@ void hci_free_dev(struct hci_dev *hdev)
 }
 EXPORT_SYMBOL(hci_free_dev);
 
+static void hci_power_on(struct work_struct *work)
+{
+	struct hci_dev *hdev = container_of(work, struct hci_dev, power_on);
+
+	BT_DBG("%s", hdev->name);
+
+	if (hci_dev_open(hdev->id) < 0)
+		return;
+
+	if (test_bit(HCI_AUTO_OFF, &hdev->flags))
+		mod_timer(&hdev->off_timer,
+				jiffies + msecs_to_jiffies(AUTO_OFF_TIMEOUT));
+
+	if (test_and_clear_bit(HCI_SETUP, &hdev->flags))
+		mgmt_index_added(hdev->id);
+}
+
+static void hci_power_off(struct work_struct *work)
+{
+	struct hci_dev *hdev = container_of(work, struct hci_dev, power_off);
+
+	BT_DBG("%s", hdev->name);
+
+	hci_dev_close(hdev->id);
+}
+
+static void hci_auto_off(unsigned long data)
+{
+	struct hci_dev *hdev = (struct hci_dev *) data;
+
+	BT_DBG("%s", hdev->name);
+
+	clear_bit(HCI_AUTO_OFF, &hdev->flags);
+
+	queue_work(hdev->workqueue, &hdev->power_off);
+}
+
+void hci_del_off_timer(struct hci_dev *hdev)
+{
+	BT_DBG("%s", hdev->name);
+
+	clear_bit(HCI_AUTO_OFF, &hdev->flags);
+	del_timer(&hdev->off_timer);
+}
+
 /* Register HCI device */
 int hci_register_dev(struct hci_dev *hdev)
 {
@@ -948,6 +998,10 @@ int hci_register_dev(struct hci_dev *hdev)
 
 	INIT_LIST_HEAD(&hdev->blacklist);
 
+	INIT_WORK(&hdev->power_on, hci_power_on);
+	INIT_WORK(&hdev->power_off, hci_power_off);
+	setup_timer(&hdev->off_timer, hci_auto_off, (unsigned long) hdev);
+
 	memset(&hdev->stat, 0, sizeof(struct hci_dev_stats));
 
 	atomic_set(&hdev->promisc, 0);
@@ -969,7 +1023,10 @@ int hci_register_dev(struct hci_dev *hdev)
 		}
 	}
 
-	mgmt_index_added(hdev->id);
+	set_bit(HCI_AUTO_OFF, &hdev->flags);
+	set_bit(HCI_SETUP, &hdev->flags);
+	queue_work(hdev->workqueue, &hdev->power_on);
+
 	hci_notify(hdev, HCI_DEV_REG);
 
 	return id;
@@ -999,7 +1056,10 @@ int hci_unregister_dev(struct hci_dev *hdev)
 	for (i = 0; i < NUM_REASSEMBLY; i++)
 		kfree_skb(hdev->reassembly[i]);
 
-	mgmt_index_removed(hdev->id);
+	if (!test_bit(HCI_INIT, &hdev->flags) &&
+					!test_bit(HCI_SETUP, &hdev->flags))
+		mgmt_index_removed(hdev->id);
+
 	hci_notify(hdev, HCI_DEV_UNREG);
 
 	if (hdev->rfkill) {
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index f827fd9..2a88b35 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -127,6 +127,12 @@ static int read_index_list(struct sock *sk)
 	i = 0;
 	list_for_each(p, &hci_dev_list) {
 		struct hci_dev *d = list_entry(p, struct hci_dev, list);
+
+		hci_del_off_timer(d);
+
+		if (test_bit(HCI_SETUP, &d->flags))
+			continue;
+
 		put_unaligned_le16(d->id, &rp->index[i++]);
 		BT_DBG("Added hci%u", d->id);
 	}
@@ -178,6 +184,8 @@ static int read_controller_info(struct sock *sk, unsigned char *data, u16 len)
 		return cmd_status(sk, MGMT_OP_READ_INFO, ENODEV);
 	}
 
+	hci_del_off_timer(hdev);
+
 	hci_dev_lock_bh(hdev);
 
 	put_unaligned_le16(hdev->id, &rp->index);
-- 
1.7.2.3


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 02/11] Bluetooth: Add support for management powered event
  2011-01-04 10:08 [PATCH 01/11] Bluetooth: Implement automatic setup procedure for local adapters johan.hedberg
@ 2011-01-04 10:08 ` johan.hedberg
  2011-01-04 10:08 ` [PATCH 03/11] Bluetooth: Add support for set_powered management command johan.hedberg
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 13+ messages in thread
From: johan.hedberg @ 2011-01-04 10:08 UTC (permalink / raw)
  To: linux-bluetooth

From: Johan Hedberg <johan.hedberg@nokia.com>

This patch adds support for the powered event that's used to indicate to
userspace when the powered state of a local adapter changes.

Signed-off-by: Johan Hedberg <johan.hedberg@nokia.com>
---
 include/net/bluetooth/hci_core.h |    1 +
 include/net/bluetooth/mgmt.h     |    6 ++++++
 net/bluetooth/hci_core.c         |    4 ++++
 net/bluetooth/mgmt.c             |   10 ++++++++++
 4 files changed, 21 insertions(+), 0 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index dfbb325..6449ff8 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -671,6 +671,7 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb);
 int mgmt_control(struct sock *sk, struct msghdr *msg, size_t len);
 int mgmt_index_added(u16 index);
 int mgmt_index_removed(u16 index);
+int mgmt_powered(u16 index, u8 powered);
 
 /* HCI info for socket */
 #define hci_pi(sk) ((struct hci_pinfo *) sk)
diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index ca29c13..0ac1520 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -85,3 +85,9 @@ struct mgmt_ev_index_added {
 struct mgmt_ev_index_removed {
 	__le16 index;
 } __packed;
+
+#define MGMT_EV_POWERED			0x0006
+struct mgmt_ev_powered {
+	__le16 index;
+	__u8 powered;
+} __packed;
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index d5a315c..36b08a4 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -535,6 +535,8 @@ int hci_dev_open(__u16 dev)
 		hci_dev_hold(hdev);
 		set_bit(HCI_UP, &hdev->flags);
 		hci_notify(hdev, HCI_DEV_UP);
+		if (!test_bit(HCI_SETUP, &hdev->flags))
+			mgmt_powered(hdev->id, 1);
 	} else {
 		/* Init failed, cleanup */
 		tasklet_kill(&hdev->rx_task);
@@ -616,6 +618,8 @@ static int hci_dev_do_close(struct hci_dev *hdev)
 	 * and no tasks are scheduled. */
 	hdev->close(hdev);
 
+	mgmt_powered(hdev->id, 0);
+
 	/* Clear flags */
 	hdev->flags = 0;
 
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 2a88b35..b7aeb7c 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -314,3 +314,13 @@ int mgmt_index_removed(u16 index)
 
 	return mgmt_event(MGMT_EV_INDEX_REMOVED, &ev, sizeof(ev));
 }
+
+int mgmt_powered(u16 index, u8 powered)
+{
+	struct mgmt_ev_powered ev;
+
+	put_unaligned_le16(index, &ev.index);
+	ev.powered = powered;
+
+	return mgmt_event(MGMT_EV_POWERED, &ev, sizeof(ev));
+}
-- 
1.7.2.3


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 03/11] Bluetooth: Add support for set_powered management command
  2011-01-04 10:08 [PATCH 01/11] Bluetooth: Implement automatic setup procedure for local adapters johan.hedberg
  2011-01-04 10:08 ` [PATCH 02/11] Bluetooth: Add support for management powered event johan.hedberg
@ 2011-01-04 10:08 ` johan.hedberg
  2011-01-04 10:08 ` [PATCH 04/11] Bluetooth: Add support for set_discoverable " johan.hedberg
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 13+ messages in thread
From: johan.hedberg @ 2011-01-04 10:08 UTC (permalink / raw)
  To: linux-bluetooth

From: Johan Hedberg <johan.hedberg@nokia.com>

This patch adds a set_powered command to the management interface
through which the powered state of local adapters can be controlled.

Signed-off-by: Johan Hedberg <johan.hedberg@nokia.com>
---
 include/net/bluetooth/hci_core.h |    3 +-
 include/net/bluetooth/mgmt.h     |   10 ++
 net/bluetooth/hci_core.c         |    4 +-
 net/bluetooth/hci_event.c        |    2 +-
 net/bluetooth/hci_sock.c         |    6 +-
 net/bluetooth/mgmt.c             |  200 +++++++++++++++++++++++++++++++++++++-
 6 files changed, 215 insertions(+), 10 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 6449ff8..b6078ba 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -665,7 +665,8 @@ void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode);
 void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data);
 
 /* ----- HCI Sockets ----- */
-void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb);
+void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb,
+							struct sock *skip_sk);
 
 /* Management interface */
 int mgmt_control(struct sock *sk, struct msghdr *msg, size_t len);
diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index 0ac1520..81ef789 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -58,6 +58,16 @@ struct mgmt_rp_read_info {
 	__u16 hci_rev;
 } __packed;
 
+#define MGMT_OP_SET_POWERED		0x0005
+struct mgmt_cp_set_powered {
+	__le16 index;
+	__u8 powered;
+} __packed;
+struct mgmt_rp_set_powered {
+	__le16 index;
+	__u8 powered;
+} __packed;
+
 #define MGMT_EV_CMD_COMPLETE		0x0001
 struct mgmt_ev_cmd_complete {
 	__le16 opcode;
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 36b08a4..de40a8a 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1373,7 +1373,7 @@ static int hci_send_frame(struct sk_buff *skb)
 		/* Time stamp */
 		__net_timestamp(skb);
 
-		hci_send_to_sock(hdev, skb);
+		hci_send_to_sock(hdev, skb, NULL);
 	}
 
 	/* Get rid of skb owner, prior to sending to the driver. */
@@ -1760,7 +1760,7 @@ static void hci_rx_task(unsigned long arg)
 	while ((skb = skb_dequeue(&hdev->rx_q))) {
 		if (atomic_read(&hdev->promisc)) {
 			/* Send copy to the sockets */
-			hci_send_to_sock(hdev, skb);
+			hci_send_to_sock(hdev, skb, NULL);
 		}
 
 		if (test_bit(HCI_RAW, &hdev->flags)) {
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 3810017..b19b061 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -2082,6 +2082,6 @@ void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data)
 
 	bt_cb(skb)->pkt_type = HCI_EVENT_PKT;
 	skb->dev = (void *) hdev;
-	hci_send_to_sock(hdev, skb);
+	hci_send_to_sock(hdev, skb, NULL);
 	kfree_skb(skb);
 }
diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c
index 29827c7..d50e961 100644
--- a/net/bluetooth/hci_sock.c
+++ b/net/bluetooth/hci_sock.c
@@ -85,7 +85,8 @@ static struct bt_sock_list hci_sk_list = {
 };
 
 /* Send frame to RAW socket */
-void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb)
+void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb,
+							struct sock *skip_sk)
 {
 	struct sock *sk;
 	struct hlist_node *node;
@@ -97,6 +98,9 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb)
 		struct hci_filter *flt;
 		struct sk_buff *nskb;
 
+		if (sk == skip_sk)
+			continue;
+
 		if (sk->sk_state != BT_BOUND || hci_pi(sk)->hdev != hdev)
 			continue;
 
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index b7aeb7c..046696b 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -32,6 +32,16 @@
 #define MGMT_VERSION	0
 #define MGMT_REVISION	1
 
+struct pending_cmd {
+	struct list_head list;
+	__u16 opcode;
+	int index;
+	void *cmd;
+	struct sock *sk;
+};
+
+LIST_HEAD(cmd_list);
+
 static int cmd_status(struct sock *sk, u16 cmd, u8 status)
 {
 	struct sk_buff *skb;
@@ -218,6 +228,129 @@ static int read_controller_info(struct sock *sk, unsigned char *data, u16 len)
 	return 0;
 }
 
+static void mgmt_pending_free(struct pending_cmd *cmd)
+{
+	sock_put(cmd->sk);
+	kfree(cmd->cmd);
+	kfree(cmd);
+}
+
+static int mgmt_pending_add(struct sock *sk, u16 opcode, int index,
+							void *data, u16 len)
+{
+	struct pending_cmd *cmd;
+
+	cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
+	if (!cmd)
+		return -ENOMEM;
+
+	cmd->opcode = opcode;
+	cmd->index = index;
+
+	cmd->cmd = kmalloc(len, GFP_ATOMIC);
+	if (!cmd->cmd) {
+		kfree(cmd);
+		return -ENOMEM;
+	}
+
+	memcpy(cmd->cmd, data, len);
+
+	cmd->sk = sk;
+	sock_hold(sk);
+
+	list_add(&cmd->list, &cmd_list);
+
+	return 0;
+}
+
+static void mgmt_pending_foreach(u16 opcode, int index,
+				void (*cb)(struct pending_cmd *cmd, void *data),
+				void *data)
+{
+	struct list_head *p, *n;
+
+	list_for_each_safe(p, n, &cmd_list) {
+		struct pending_cmd *cmd;
+
+		cmd = list_entry(p, struct pending_cmd, list);
+
+		if (cmd->opcode != opcode)
+			continue;
+
+		if (index >= 0 && cmd->index != index)
+			continue;
+
+		cb(cmd, data);
+	}
+}
+
+static struct pending_cmd *mgmt_pending_find(u16 opcode, int index)
+{
+	struct list_head *p;
+
+	list_for_each(p, &cmd_list) {
+		struct pending_cmd *cmd;
+
+		cmd = list_entry(p, struct pending_cmd, list);
+
+		if (cmd->opcode != opcode)
+			continue;
+
+		if (index >= 0 && cmd->index != index)
+			continue;
+
+		return cmd;
+	}
+
+	return NULL;
+}
+
+static int set_powered(struct sock *sk, unsigned char *data, u16 len)
+{
+	struct mgmt_cp_set_powered *cp;
+	struct hci_dev *hdev;
+	u16 dev_id;
+	int ret, up;
+
+	cp = (void *) data;
+	dev_id = get_unaligned_le16(&cp->index);
+
+	BT_DBG("request for hci%u", dev_id);
+
+	hdev = hci_dev_get(dev_id);
+	if (!hdev)
+		return cmd_status(sk, MGMT_OP_SET_POWERED, ENODEV);
+
+	hci_dev_lock_bh(hdev);
+
+	up = test_bit(HCI_UP, &hdev->flags);
+	if ((cp->powered && up) || (!cp->powered && !up)) {
+		ret = cmd_status(sk, MGMT_OP_SET_POWERED, EALREADY);
+		goto failed;
+	}
+
+	if (mgmt_pending_find(MGMT_OP_SET_POWERED, dev_id)) {
+		ret = cmd_status(sk, MGMT_OP_SET_POWERED, EBUSY);
+		goto failed;
+	}
+
+	ret = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, dev_id, data, len);
+	if (ret < 0)
+		goto failed;
+
+	if (cp->powered)
+		queue_work(hdev->workqueue, &hdev->power_on);
+	else
+		queue_work(hdev->workqueue, &hdev->power_off);
+
+	ret = 0;
+
+failed:
+	hci_dev_unlock_bh(hdev);
+	hci_dev_put(hdev);
+	return ret;
+}
+
 int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
 {
 	unsigned char *buf;
@@ -258,6 +391,9 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
 	case MGMT_OP_READ_INFO:
 		err = read_controller_info(sk, buf + sizeof(*hdr), len);
 		break;
+	case MGMT_OP_SET_POWERED:
+		err = set_powered(sk, buf + sizeof(*hdr), len);
+		break;
 	default:
 		BT_DBG("Unknown op %u", opcode);
 		err = cmd_status(sk, opcode, 0x01);
@@ -274,7 +410,7 @@ done:
 	return err;
 }
 
-static int mgmt_event(u16 event, void *data, u16 data_len)
+static int mgmt_event(u16 event, void *data, u16 data_len, struct sock *skip_sk)
 {
 	struct sk_buff *skb;
 	struct mgmt_hdr *hdr;
@@ -291,7 +427,7 @@ static int mgmt_event(u16 event, void *data, u16 data_len)
 
 	memcpy(skb_put(skb, data_len), data, data_len);
 
-	hci_send_to_sock(NULL, skb);
+	hci_send_to_sock(NULL, skb, skip_sk);
 	kfree_skb(skb);
 
 	return 0;
@@ -303,7 +439,7 @@ int mgmt_index_added(u16 index)
 
 	put_unaligned_le16(index, &ev.index);
 
-	return mgmt_event(MGMT_EV_INDEX_ADDED, &ev, sizeof(ev));
+	return mgmt_event(MGMT_EV_INDEX_ADDED, &ev, sizeof(ev), NULL);
 }
 
 int mgmt_index_removed(u16 index)
@@ -312,15 +448,69 @@ int mgmt_index_removed(u16 index)
 
 	put_unaligned_le16(index, &ev.index);
 
-	return mgmt_event(MGMT_EV_INDEX_REMOVED, &ev, sizeof(ev));
+	return mgmt_event(MGMT_EV_INDEX_REMOVED, &ev, sizeof(ev), NULL);
+}
+
+struct powered_lookup {
+	u8 powered;
+	struct sock *sk;
+};
+
+static void power_rsp(struct pending_cmd *cmd, void *data)
+{
+	struct mgmt_hdr *hdr;
+	struct mgmt_ev_cmd_complete *ev;
+	struct mgmt_rp_set_powered *rp;
+	struct mgmt_cp_set_powered *cp = cmd->cmd;
+	struct sk_buff *skb;
+	struct powered_lookup *match = data;
+
+	if (cp->powered != match->powered)
+		return;
+
+	skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + sizeof(*rp), GFP_ATOMIC);
+	if (!skb)
+		return;
+
+	hdr = (void *) skb_put(skb, sizeof(*hdr));
+	hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
+	hdr->len = cpu_to_le16(sizeof(*ev) + sizeof(*rp));
+
+	ev = (void *) skb_put(skb, sizeof(*ev));
+	put_unaligned_le16(cmd->opcode, &ev->opcode);
+
+	rp = (void *) skb_put(skb, sizeof(*rp));
+	put_unaligned_le16(cmd->index, &rp->index);
+	rp->powered = cp->powered;
+
+	if (sock_queue_rcv_skb(cmd->sk, skb) < 0)
+		kfree_skb(skb);
+
+	list_del(&cmd->list);
+
+	if (match->sk == NULL) {
+		match->sk = cmd->sk;
+		sock_hold(match->sk);
+	}
+
+	mgmt_pending_free(cmd);
 }
 
 int mgmt_powered(u16 index, u8 powered)
 {
 	struct mgmt_ev_powered ev;
+	struct powered_lookup match = { powered, NULL };
+	int ret;
 
 	put_unaligned_le16(index, &ev.index);
 	ev.powered = powered;
 
-	return mgmt_event(MGMT_EV_POWERED, &ev, sizeof(ev));
+	mgmt_pending_foreach(MGMT_OP_SET_POWERED, index, power_rsp, &match);
+
+	ret = mgmt_event(MGMT_EV_POWERED, &ev, sizeof(ev), match.sk);
+
+	if (match.sk)
+		sock_put(match.sk);
+
+	return ret;
 }
-- 
1.7.2.3


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 04/11] Bluetooth: Add support for set_discoverable management command
  2011-01-04 10:08 [PATCH 01/11] Bluetooth: Implement automatic setup procedure for local adapters johan.hedberg
  2011-01-04 10:08 ` [PATCH 02/11] Bluetooth: Add support for management powered event johan.hedberg
  2011-01-04 10:08 ` [PATCH 03/11] Bluetooth: Add support for set_powered management command johan.hedberg
@ 2011-01-04 10:08 ` johan.hedberg
  2011-01-04 10:08 ` [PATCH 05/11] Bluetooth: Add set_connectable " johan.hedberg
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 13+ messages in thread
From: johan.hedberg @ 2011-01-04 10:08 UTC (permalink / raw)
  To: linux-bluetooth

From: Johan Hedberg <johan.hedberg@nokia.com>

This patch adds a set_discoverable command to the management interface
as well as the corresponding event. The command is used to control the
discoverable state of adapters.

Signed-off-by: Johan Hedberg <johan.hedberg@nokia.com>
---
 include/net/bluetooth/hci_core.h |    1 +
 include/net/bluetooth/mgmt.h     |   16 ++++
 net/bluetooth/hci_event.c        |    5 +-
 net/bluetooth/mgmt.c             |  142 ++++++++++++++++++++++++++++++++++++--
 4 files changed, 158 insertions(+), 6 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index b6078ba..2b7c31f 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -673,6 +673,7 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t len);
 int mgmt_index_added(u16 index);
 int mgmt_index_removed(u16 index);
 int mgmt_powered(u16 index, u8 powered);
+int mgmt_discoverable(u16 index, u8 discoverable);
 
 /* HCI info for socket */
 #define hci_pi(sk) ((struct hci_pinfo *) sk)
diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index 81ef789..434dbcf 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -68,6 +68,16 @@ struct mgmt_rp_set_powered {
 	__u8 powered;
 } __packed;
 
+#define MGMT_OP_SET_DISCOVERABLE	0x0006
+struct mgmt_cp_set_discoverable {
+	__le16 index;
+	__u8 discoverable;
+} __packed;
+struct mgmt_rp_set_discoverable {
+	__le16 index;
+	__u8 discoverable;
+} __packed;
+
 #define MGMT_EV_CMD_COMPLETE		0x0001
 struct mgmt_ev_cmd_complete {
 	__le16 opcode;
@@ -101,3 +111,9 @@ struct mgmt_ev_powered {
 	__le16 index;
 	__u8 powered;
 } __packed;
+
+#define MGMT_EV_DISCOVERABLE		0x0007
+struct mgmt_ev_discoverable {
+	__le16 index;
+	__u8 discoverable;
+} __packed;
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index b19b061..f47ceb1 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -278,8 +278,11 @@ static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb)
 		clear_bit(HCI_PSCAN, &hdev->flags);
 		clear_bit(HCI_ISCAN, &hdev->flags);
 
-		if (param & SCAN_INQUIRY)
+		if (param & SCAN_INQUIRY) {
 			set_bit(HCI_ISCAN, &hdev->flags);
+			mgmt_discoverable(hdev->id, 1);
+		} else
+			mgmt_discoverable(hdev->id, 0);
 
 		if (param & SCAN_PAGE)
 			set_bit(HCI_PSCAN, &hdev->flags);
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 046696b..e7c2fa3 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -305,6 +305,18 @@ static struct pending_cmd *mgmt_pending_find(u16 opcode, int index)
 	return NULL;
 }
 
+static void mgmt_pending_remove(u16 opcode, int index)
+{
+	struct pending_cmd *cmd;
+
+	cmd = mgmt_pending_find(opcode, index);
+	if (cmd == NULL)
+		return;
+
+	list_del(&cmd->list);
+	mgmt_pending_free(cmd);
+}
+
 static int set_powered(struct sock *sk, unsigned char *data, u16 len)
 {
 	struct mgmt_cp_set_powered *cp;
@@ -351,6 +363,63 @@ failed:
 	return ret;
 }
 
+static int set_discoverable(struct sock *sk, unsigned char *data, u16 len)
+{
+	struct mgmt_cp_set_discoverable *cp;
+	struct hci_dev *hdev;
+	u16 dev_id;
+	u8 scan;
+	int err;
+
+	cp = (void *) data;
+	dev_id = get_unaligned_le16(&cp->index);
+
+	BT_DBG("request for hci%u", dev_id);
+
+	hdev = hci_dev_get(dev_id);
+	if (!hdev)
+		return cmd_status(sk, MGMT_OP_SET_DISCOVERABLE, ENODEV);
+
+	hci_dev_lock_bh(hdev);
+
+	if (!test_bit(HCI_UP, &hdev->flags)) {
+		err = cmd_status(sk, MGMT_OP_SET_DISCOVERABLE, ENETDOWN);
+		goto failed;
+	}
+
+	if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, dev_id) ||
+			mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, dev_id) ||
+			hci_sent_cmd_data(hdev, HCI_OP_WRITE_SCAN_ENABLE)) {
+		err = cmd_status(sk, MGMT_OP_SET_DISCOVERABLE, EBUSY);
+		goto failed;
+	}
+
+	if (cp->discoverable == test_bit(HCI_ISCAN, &hdev->flags) &&
+					test_bit(HCI_PSCAN, &hdev->flags)) {
+		err = cmd_status(sk, MGMT_OP_SET_DISCOVERABLE, EALREADY);
+		goto failed;
+	}
+
+	err = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, dev_id, data, len);
+	if (err < 0)
+		goto failed;
+
+	scan = SCAN_PAGE;
+
+	if (cp->discoverable)
+		scan |= SCAN_INQUIRY;
+
+	err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
+	if (err < 0)
+		mgmt_pending_remove(MGMT_OP_SET_DISCOVERABLE, dev_id);
+
+failed:
+	hci_dev_unlock_bh(hdev);
+	hci_dev_put(hdev);
+
+	return err;
+}
+
 int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
 {
 	unsigned char *buf;
@@ -394,6 +463,9 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
 	case MGMT_OP_SET_POWERED:
 		err = set_powered(sk, buf + sizeof(*hdr), len);
 		break;
+	case MGMT_OP_SET_DISCOVERABLE:
+		err = set_discoverable(sk, buf + sizeof(*hdr), len);
+		break;
 	default:
 		BT_DBG("Unknown op %u", opcode);
 		err = cmd_status(sk, opcode, 0x01);
@@ -451,8 +523,8 @@ int mgmt_index_removed(u16 index)
 	return mgmt_event(MGMT_EV_INDEX_REMOVED, &ev, sizeof(ev), NULL);
 }
 
-struct powered_lookup {
-	u8 powered;
+struct cmd_lookup {
+	u8 value;
 	struct sock *sk;
 };
 
@@ -463,9 +535,9 @@ static void power_rsp(struct pending_cmd *cmd, void *data)
 	struct mgmt_rp_set_powered *rp;
 	struct mgmt_cp_set_powered *cp = cmd->cmd;
 	struct sk_buff *skb;
-	struct powered_lookup *match = data;
+	struct cmd_lookup *match = data;
 
-	if (cp->powered != match->powered)
+	if (cp->powered != match->value)
 		return;
 
 	skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + sizeof(*rp), GFP_ATOMIC);
@@ -499,7 +571,7 @@ static void power_rsp(struct pending_cmd *cmd, void *data)
 int mgmt_powered(u16 index, u8 powered)
 {
 	struct mgmt_ev_powered ev;
-	struct powered_lookup match = { powered, NULL };
+	struct cmd_lookup match = { powered, NULL };
 	int ret;
 
 	put_unaligned_le16(index, &ev.index);
@@ -514,3 +586,63 @@ int mgmt_powered(u16 index, u8 powered)
 
 	return ret;
 }
+
+static void discoverable_rsp(struct pending_cmd *cmd, void *data)
+{
+	struct mgmt_cp_set_discoverable *cp = cmd->cmd;
+	struct cmd_lookup *match = data;
+	struct sk_buff *skb;
+	struct mgmt_hdr *hdr;
+	struct mgmt_ev_cmd_complete *ev;
+	struct mgmt_rp_set_discoverable *rp;
+
+	if (cp->discoverable != match->value)
+		return;
+
+	skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + sizeof(*rp), GFP_ATOMIC);
+	if (!skb)
+		return;
+
+	hdr = (void *) skb_put(skb, sizeof(*hdr));
+	hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
+	hdr->len = cpu_to_le16(sizeof(*ev) + sizeof(*rp));
+
+	ev = (void *) skb_put(skb, sizeof(*ev));
+	put_unaligned_le16(MGMT_OP_SET_DISCOVERABLE, &ev->opcode);
+
+	rp = (void *) skb_put(skb, sizeof(*rp));
+	put_unaligned_le16(cmd->index, &rp->index);
+	rp->discoverable = cp->discoverable;
+
+	if (sock_queue_rcv_skb(cmd->sk, skb) < 0)
+		kfree_skb(skb);
+
+	list_del(&cmd->list);
+
+	if (match->sk == NULL) {
+		match->sk = cmd->sk;
+		sock_hold(match->sk);
+	}
+
+	mgmt_pending_free(cmd);
+}
+
+int mgmt_discoverable(u16 index, u8 discoverable)
+{
+	struct mgmt_ev_discoverable ev;
+	struct cmd_lookup match = { discoverable, NULL };
+	int ret;
+
+	put_unaligned_le16(index, &ev.index);
+	ev.discoverable = discoverable;
+
+	mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index,
+						discoverable_rsp, &match);
+
+	ret = mgmt_event(MGMT_EV_DISCOVERABLE, &ev, sizeof(ev), match.sk);
+
+	if (match.sk)
+		sock_put(match.sk);
+
+	return ret;
+}
-- 
1.7.2.3


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 05/11] Bluetooth: Add set_connectable management command
  2011-01-04 10:08 [PATCH 01/11] Bluetooth: Implement automatic setup procedure for local adapters johan.hedberg
                   ` (2 preceding siblings ...)
  2011-01-04 10:08 ` [PATCH 04/11] Bluetooth: Add support for set_discoverable " johan.hedberg
@ 2011-01-04 10:08 ` johan.hedberg
  2011-01-04 10:08 ` [PATCH 06/11] Bluetooth: Unify mode related management messages to a single struct johan.hedberg
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 13+ messages in thread
From: johan.hedberg @ 2011-01-04 10:08 UTC (permalink / raw)
  To: linux-bluetooth

From: Johan Hedberg <johan.hedberg@nokia.com>

This patch adds a set_connectable command as well as a corresponding
event to the management interface. It's mainly useful for setting an
adapter as connectable from a non-initialized state as well as setting
an already initialized adapter as non-connectable (mostly useful for
qualification purposes).

Signed-off-by: Johan Hedberg <johan.hedberg@nokia.com>
---
 include/net/bluetooth/hci_core.h |    1 +
 include/net/bluetooth/mgmt.h     |   17 +++++
 net/bluetooth/hci_event.c        |   16 ++++--
 net/bluetooth/mgmt.c             |  122 +++++++++++++++++++++++++++++++++++++-
 4 files changed, 149 insertions(+), 7 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 2b7c31f..8d800d9 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -674,6 +674,7 @@ int mgmt_index_added(u16 index);
 int mgmt_index_removed(u16 index);
 int mgmt_powered(u16 index, u8 powered);
 int mgmt_discoverable(u16 index, u8 discoverable);
+int mgmt_connectable(u16 index, u8 connectable);
 
 /* HCI info for socket */
 #define hci_pi(sk) ((struct hci_pinfo *) sk)
diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index 434dbcf..008acf5 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -47,6 +47,7 @@ struct mgmt_rp_read_info {
 	__le16 index;
 	__u8 type;
 	__u8 powered;
+	__u8 connectable;
 	__u8 discoverable;
 	__u8 pairable;
 	__u8 sec_mode;
@@ -78,6 +79,16 @@ struct mgmt_rp_set_discoverable {
 	__u8 discoverable;
 } __packed;
 
+#define MGMT_OP_SET_CONNECTABLE		0x0007
+struct mgmt_cp_set_connectable {
+	__le16 index;
+	__u8 connectable;
+} __packed;
+struct mgmt_rp_set_connectable {
+	__le16 index;
+	__u8 connectable;
+} __packed;
+
 #define MGMT_EV_CMD_COMPLETE		0x0001
 struct mgmt_ev_cmd_complete {
 	__le16 opcode;
@@ -117,3 +128,9 @@ struct mgmt_ev_discoverable {
 	__le16 index;
 	__u8 discoverable;
 } __packed;
+
+#define MGMT_EV_CONNECTABLE		0x0008
+struct mgmt_ev_connectable {
+	__le16 index;
+	__u8 connectable;
+} __packed;
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index f47ceb1..319f954 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -274,18 +274,24 @@ static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb)
 
 	if (!status) {
 		__u8 param = *((__u8 *) sent);
+		int old_pscan, old_iscan;
 
-		clear_bit(HCI_PSCAN, &hdev->flags);
-		clear_bit(HCI_ISCAN, &hdev->flags);
+		old_pscan = test_and_clear_bit(HCI_PSCAN, &hdev->flags);
+		old_iscan = test_and_clear_bit(HCI_ISCAN, &hdev->flags);
 
 		if (param & SCAN_INQUIRY) {
 			set_bit(HCI_ISCAN, &hdev->flags);
-			mgmt_discoverable(hdev->id, 1);
-		} else
+			if (!old_iscan)
+				mgmt_discoverable(hdev->id, 1);
+		} else if (old_iscan)
 			mgmt_discoverable(hdev->id, 0);
 
-		if (param & SCAN_PAGE)
+		if (param & SCAN_PAGE) {
 			set_bit(HCI_PSCAN, &hdev->flags);
+			if (!old_pscan)
+				mgmt_connectable(hdev->id, 1);
+		} else if (old_pscan)
+			mgmt_connectable(hdev->id, 0);
 	}
 
 	hci_req_complete(hdev, HCI_OP_WRITE_SCAN_ENABLE, status);
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index e7c2fa3..d3ec5d8 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -202,6 +202,7 @@ static int read_controller_info(struct sock *sk, unsigned char *data, u16 len)
 	rp->type = hdev->dev_type;
 
 	rp->powered = test_bit(HCI_UP, &hdev->flags);
+	rp->connectable = test_bit(HCI_PSCAN, &hdev->flags);
 	rp->discoverable = test_bit(HCI_ISCAN, &hdev->flags);
 	rp->pairable = test_bit(HCI_PSCAN, &hdev->flags);
 
@@ -388,8 +389,7 @@ static int set_discoverable(struct sock *sk, unsigned char *data, u16 len)
 	}
 
 	if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, dev_id) ||
-			mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, dev_id) ||
-			hci_sent_cmd_data(hdev, HCI_OP_WRITE_SCAN_ENABLE)) {
+			mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, dev_id)) {
 		err = cmd_status(sk, MGMT_OP_SET_DISCOVERABLE, EBUSY);
 		goto failed;
 	}
@@ -420,6 +420,61 @@ failed:
 	return err;
 }
 
+static int set_connectable(struct sock *sk, unsigned char *data, u16 len)
+{
+	struct mgmt_cp_set_connectable *cp;
+	struct hci_dev *hdev;
+	u16 dev_id;
+	u8 scan;
+	int err;
+
+	cp = (void *) data;
+	dev_id = get_unaligned_le16(&cp->index);
+
+	BT_DBG("request for hci%u", dev_id);
+
+	hdev = hci_dev_get(dev_id);
+	if (!hdev)
+		return cmd_status(sk, MGMT_OP_SET_CONNECTABLE, ENODEV);
+
+	hci_dev_lock_bh(hdev);
+
+	if (!test_bit(HCI_UP, &hdev->flags)) {
+		err = cmd_status(sk, MGMT_OP_SET_CONNECTABLE, ENETDOWN);
+		goto failed;
+	}
+
+	if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, dev_id) ||
+			mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, dev_id)) {
+		err = cmd_status(sk, MGMT_OP_SET_CONNECTABLE, EBUSY);
+		goto failed;
+	}
+
+	if (cp->connectable == test_bit(HCI_PSCAN, &hdev->flags)) {
+		err = cmd_status(sk, MGMT_OP_SET_CONNECTABLE, EALREADY);
+		goto failed;
+	}
+
+	err = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, dev_id, data, len);
+	if (err < 0)
+		goto failed;
+
+	if (cp->connectable)
+		scan = SCAN_PAGE;
+	else
+		scan = 0;
+
+	err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
+	if (err < 0)
+		mgmt_pending_remove(MGMT_OP_SET_CONNECTABLE, dev_id);
+
+failed:
+	hci_dev_unlock_bh(hdev);
+	hci_dev_put(hdev);
+
+	return err;
+}
+
 int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
 {
 	unsigned char *buf;
@@ -466,6 +521,9 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
 	case MGMT_OP_SET_DISCOVERABLE:
 		err = set_discoverable(sk, buf + sizeof(*hdr), len);
 		break;
+	case MGMT_OP_SET_CONNECTABLE:
+		err = set_connectable(sk, buf + sizeof(*hdr), len);
+		break;
 	default:
 		BT_DBG("Unknown op %u", opcode);
 		err = cmd_status(sk, opcode, 0x01);
@@ -646,3 +704,63 @@ int mgmt_discoverable(u16 index, u8 discoverable)
 
 	return ret;
 }
+
+static void connectable_rsp(struct pending_cmd *cmd, void *data)
+{
+	struct mgmt_cp_set_connectable *cp = cmd->cmd;
+	struct cmd_lookup *match = data;
+	struct sk_buff *skb;
+	struct mgmt_hdr *hdr;
+	struct mgmt_ev_cmd_complete *ev;
+	struct mgmt_rp_set_connectable *rp;
+
+	if (cp->connectable != match->value)
+		return;
+
+	skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + sizeof(*rp), GFP_ATOMIC);
+	if (!skb)
+		return;
+
+	hdr = (void *) skb_put(skb, sizeof(*hdr));
+	hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
+	hdr->len = cpu_to_le16(sizeof(*ev) + sizeof(*rp));
+
+	ev = (void *) skb_put(skb, sizeof(*ev));
+	put_unaligned_le16(MGMT_OP_SET_CONNECTABLE, &ev->opcode);
+
+	rp = (void *) skb_put(skb, sizeof(*rp));
+	put_unaligned_le16(cmd->index, &rp->index);
+	rp->connectable = cp->connectable;
+
+	if (sock_queue_rcv_skb(cmd->sk, skb) < 0)
+		kfree_skb(skb);
+
+	list_del(&cmd->list);
+
+	if (match->sk == NULL) {
+		match->sk = cmd->sk;
+		sock_hold(match->sk);
+	}
+
+	mgmt_pending_free(cmd);
+}
+
+int mgmt_connectable(u16 index, u8 connectable)
+{
+	struct mgmt_ev_connectable ev;
+	struct cmd_lookup match = { connectable, NULL };
+	int ret;
+
+	put_unaligned_le16(index, &ev.index);
+	ev.connectable = connectable;
+
+	mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index,
+						connectable_rsp, &match);
+
+	ret = mgmt_event(MGMT_EV_CONNECTABLE, &ev, sizeof(ev), match.sk);
+
+	if (match.sk)
+		sock_put(match.sk);
+
+	return ret;
+}
-- 
1.7.2.3


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 06/11] Bluetooth: Unify mode related management messages to a single struct
  2011-01-04 10:08 [PATCH 01/11] Bluetooth: Implement automatic setup procedure for local adapters johan.hedberg
                   ` (3 preceding siblings ...)
  2011-01-04 10:08 ` [PATCH 05/11] Bluetooth: Add set_connectable " johan.hedberg
@ 2011-01-04 10:08 ` johan.hedberg
  2011-01-04 10:08 ` [PATCH 07/11] Bluetooth: Add flag to track managment controlled adapters johan.hedberg
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 13+ messages in thread
From: johan.hedberg @ 2011-01-04 10:08 UTC (permalink / raw)
  To: linux-bluetooth

From: Johan Hedberg <johan.hedberg@nokia.com>

The powered, connectable and discoverable messages all have the same
format. By using a single struct for all of them a lot of code can be
simplified and reused.

Signed-off-by: Johan Hedberg <johan.hedberg@nokia.com>
---
 include/net/bluetooth/mgmt.h |   39 +-----------
 net/bluetooth/mgmt.c         |  137 +++++++++---------------------------------
 2 files changed, 32 insertions(+), 144 deletions(-)

diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index 008acf5..f61fd67 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -59,35 +59,16 @@ struct mgmt_rp_read_info {
 	__u16 hci_rev;
 } __packed;
 
-#define MGMT_OP_SET_POWERED		0x0005
-struct mgmt_cp_set_powered {
+struct mgmt_mode {
 	__le16 index;
-	__u8 powered;
-} __packed;
-struct mgmt_rp_set_powered {
-	__le16 index;
-	__u8 powered;
+	__u8 val;
 } __packed;
 
+#define MGMT_OP_SET_POWERED		0x0005
+
 #define MGMT_OP_SET_DISCOVERABLE	0x0006
-struct mgmt_cp_set_discoverable {
-	__le16 index;
-	__u8 discoverable;
-} __packed;
-struct mgmt_rp_set_discoverable {
-	__le16 index;
-	__u8 discoverable;
-} __packed;
 
 #define MGMT_OP_SET_CONNECTABLE		0x0007
-struct mgmt_cp_set_connectable {
-	__le16 index;
-	__u8 connectable;
-} __packed;
-struct mgmt_rp_set_connectable {
-	__le16 index;
-	__u8 connectable;
-} __packed;
 
 #define MGMT_EV_CMD_COMPLETE		0x0001
 struct mgmt_ev_cmd_complete {
@@ -118,19 +99,7 @@ struct mgmt_ev_index_removed {
 } __packed;
 
 #define MGMT_EV_POWERED			0x0006
-struct mgmt_ev_powered {
-	__le16 index;
-	__u8 powered;
-} __packed;
 
 #define MGMT_EV_DISCOVERABLE		0x0007
-struct mgmt_ev_discoverable {
-	__le16 index;
-	__u8 discoverable;
-} __packed;
 
 #define MGMT_EV_CONNECTABLE		0x0008
-struct mgmt_ev_connectable {
-	__le16 index;
-	__u8 connectable;
-} __packed;
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index d3ec5d8..36a3e1c 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -320,7 +320,7 @@ static void mgmt_pending_remove(u16 opcode, int index)
 
 static int set_powered(struct sock *sk, unsigned char *data, u16 len)
 {
-	struct mgmt_cp_set_powered *cp;
+	struct mgmt_mode *cp;
 	struct hci_dev *hdev;
 	u16 dev_id;
 	int ret, up;
@@ -337,7 +337,7 @@ static int set_powered(struct sock *sk, unsigned char *data, u16 len)
 	hci_dev_lock_bh(hdev);
 
 	up = test_bit(HCI_UP, &hdev->flags);
-	if ((cp->powered && up) || (!cp->powered && !up)) {
+	if ((cp->val && up) || (!cp->val && !up)) {
 		ret = cmd_status(sk, MGMT_OP_SET_POWERED, EALREADY);
 		goto failed;
 	}
@@ -351,7 +351,7 @@ static int set_powered(struct sock *sk, unsigned char *data, u16 len)
 	if (ret < 0)
 		goto failed;
 
-	if (cp->powered)
+	if (cp->val)
 		queue_work(hdev->workqueue, &hdev->power_on);
 	else
 		queue_work(hdev->workqueue, &hdev->power_off);
@@ -366,7 +366,7 @@ failed:
 
 static int set_discoverable(struct sock *sk, unsigned char *data, u16 len)
 {
-	struct mgmt_cp_set_discoverable *cp;
+	struct mgmt_mode *cp;
 	struct hci_dev *hdev;
 	u16 dev_id;
 	u8 scan;
@@ -394,7 +394,7 @@ static int set_discoverable(struct sock *sk, unsigned char *data, u16 len)
 		goto failed;
 	}
 
-	if (cp->discoverable == test_bit(HCI_ISCAN, &hdev->flags) &&
+	if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
 					test_bit(HCI_PSCAN, &hdev->flags)) {
 		err = cmd_status(sk, MGMT_OP_SET_DISCOVERABLE, EALREADY);
 		goto failed;
@@ -406,7 +406,7 @@ static int set_discoverable(struct sock *sk, unsigned char *data, u16 len)
 
 	scan = SCAN_PAGE;
 
-	if (cp->discoverable)
+	if (cp->val)
 		scan |= SCAN_INQUIRY;
 
 	err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
@@ -422,7 +422,7 @@ failed:
 
 static int set_connectable(struct sock *sk, unsigned char *data, u16 len)
 {
-	struct mgmt_cp_set_connectable *cp;
+	struct mgmt_mode *cp;
 	struct hci_dev *hdev;
 	u16 dev_id;
 	u8 scan;
@@ -450,7 +450,7 @@ static int set_connectable(struct sock *sk, unsigned char *data, u16 len)
 		goto failed;
 	}
 
-	if (cp->connectable == test_bit(HCI_PSCAN, &hdev->flags)) {
+	if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
 		err = cmd_status(sk, MGMT_OP_SET_CONNECTABLE, EALREADY);
 		goto failed;
 	}
@@ -459,7 +459,7 @@ static int set_connectable(struct sock *sk, unsigned char *data, u16 len)
 	if (err < 0)
 		goto failed;
 
-	if (cp->connectable)
+	if (cp->val)
 		scan = SCAN_PAGE;
 	else
 		scan = 0;
@@ -582,20 +582,20 @@ int mgmt_index_removed(u16 index)
 }
 
 struct cmd_lookup {
-	u8 value;
+	u8 val;
 	struct sock *sk;
 };
 
-static void power_rsp(struct pending_cmd *cmd, void *data)
+static void mode_rsp(struct pending_cmd *cmd, void *data)
 {
 	struct mgmt_hdr *hdr;
 	struct mgmt_ev_cmd_complete *ev;
-	struct mgmt_rp_set_powered *rp;
-	struct mgmt_cp_set_powered *cp = cmd->cmd;
+	struct mgmt_mode *rp;
+	struct mgmt_mode *cp = cmd->cmd;
 	struct sk_buff *skb;
 	struct cmd_lookup *match = data;
 
-	if (cp->powered != match->value)
+	if (cp->val != match->val)
 		return;
 
 	skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + sizeof(*rp), GFP_ATOMIC);
@@ -611,7 +611,7 @@ static void power_rsp(struct pending_cmd *cmd, void *data)
 
 	rp = (void *) skb_put(skb, sizeof(*rp));
 	put_unaligned_le16(cmd->index, &rp->index);
-	rp->powered = cp->powered;
+	rp->val = cp->val;
 
 	if (sock_queue_rcv_skb(cmd->sk, skb) < 0)
 		kfree_skb(skb);
@@ -628,14 +628,14 @@ static void power_rsp(struct pending_cmd *cmd, void *data)
 
 int mgmt_powered(u16 index, u8 powered)
 {
-	struct mgmt_ev_powered ev;
+	struct mgmt_mode ev;
 	struct cmd_lookup match = { powered, NULL };
 	int ret;
 
-	put_unaligned_le16(index, &ev.index);
-	ev.powered = powered;
+	mgmt_pending_foreach(MGMT_OP_SET_POWERED, index, mode_rsp, &match);
 
-	mgmt_pending_foreach(MGMT_OP_SET_POWERED, index, power_rsp, &match);
+	put_unaligned_le16(index, &ev.index);
+	ev.val = powered;
 
 	ret = mgmt_event(MGMT_EV_POWERED, &ev, sizeof(ev), match.sk);
 
@@ -645,57 +645,17 @@ int mgmt_powered(u16 index, u8 powered)
 	return ret;
 }
 
-static void discoverable_rsp(struct pending_cmd *cmd, void *data)
-{
-	struct mgmt_cp_set_discoverable *cp = cmd->cmd;
-	struct cmd_lookup *match = data;
-	struct sk_buff *skb;
-	struct mgmt_hdr *hdr;
-	struct mgmt_ev_cmd_complete *ev;
-	struct mgmt_rp_set_discoverable *rp;
-
-	if (cp->discoverable != match->value)
-		return;
-
-	skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + sizeof(*rp), GFP_ATOMIC);
-	if (!skb)
-		return;
-
-	hdr = (void *) skb_put(skb, sizeof(*hdr));
-	hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
-	hdr->len = cpu_to_le16(sizeof(*ev) + sizeof(*rp));
-
-	ev = (void *) skb_put(skb, sizeof(*ev));
-	put_unaligned_le16(MGMT_OP_SET_DISCOVERABLE, &ev->opcode);
-
-	rp = (void *) skb_put(skb, sizeof(*rp));
-	put_unaligned_le16(cmd->index, &rp->index);
-	rp->discoverable = cp->discoverable;
-
-	if (sock_queue_rcv_skb(cmd->sk, skb) < 0)
-		kfree_skb(skb);
-
-	list_del(&cmd->list);
-
-	if (match->sk == NULL) {
-		match->sk = cmd->sk;
-		sock_hold(match->sk);
-	}
-
-	mgmt_pending_free(cmd);
-}
-
 int mgmt_discoverable(u16 index, u8 discoverable)
 {
-	struct mgmt_ev_discoverable ev;
+	struct mgmt_mode ev;
 	struct cmd_lookup match = { discoverable, NULL };
 	int ret;
 
-	put_unaligned_le16(index, &ev.index);
-	ev.discoverable = discoverable;
-
 	mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index,
-						discoverable_rsp, &match);
+							mode_rsp, &match);
+
+	put_unaligned_le16(index, &ev.index);
+	ev.val = discoverable;
 
 	ret = mgmt_event(MGMT_EV_DISCOVERABLE, &ev, sizeof(ev), match.sk);
 
@@ -705,57 +665,16 @@ int mgmt_discoverable(u16 index, u8 discoverable)
 	return ret;
 }
 
-static void connectable_rsp(struct pending_cmd *cmd, void *data)
-{
-	struct mgmt_cp_set_connectable *cp = cmd->cmd;
-	struct cmd_lookup *match = data;
-	struct sk_buff *skb;
-	struct mgmt_hdr *hdr;
-	struct mgmt_ev_cmd_complete *ev;
-	struct mgmt_rp_set_connectable *rp;
-
-	if (cp->connectable != match->value)
-		return;
-
-	skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + sizeof(*rp), GFP_ATOMIC);
-	if (!skb)
-		return;
-
-	hdr = (void *) skb_put(skb, sizeof(*hdr));
-	hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
-	hdr->len = cpu_to_le16(sizeof(*ev) + sizeof(*rp));
-
-	ev = (void *) skb_put(skb, sizeof(*ev));
-	put_unaligned_le16(MGMT_OP_SET_CONNECTABLE, &ev->opcode);
-
-	rp = (void *) skb_put(skb, sizeof(*rp));
-	put_unaligned_le16(cmd->index, &rp->index);
-	rp->connectable = cp->connectable;
-
-	if (sock_queue_rcv_skb(cmd->sk, skb) < 0)
-		kfree_skb(skb);
-
-	list_del(&cmd->list);
-
-	if (match->sk == NULL) {
-		match->sk = cmd->sk;
-		sock_hold(match->sk);
-	}
-
-	mgmt_pending_free(cmd);
-}
-
 int mgmt_connectable(u16 index, u8 connectable)
 {
-	struct mgmt_ev_connectable ev;
+	struct mgmt_mode ev;
 	struct cmd_lookup match = { connectable, NULL };
 	int ret;
 
-	put_unaligned_le16(index, &ev.index);
-	ev.connectable = connectable;
+	mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index, mode_rsp, &match);
 
-	mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index,
-						connectable_rsp, &match);
+	put_unaligned_le16(index, &ev.index);
+	ev.val = connectable;
 
 	ret = mgmt_event(MGMT_EV_CONNECTABLE, &ev, sizeof(ev), match.sk);
 
-- 
1.7.2.3


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 07/11] Bluetooth: Add flag to track managment controlled adapters
  2011-01-04 10:08 [PATCH 01/11] Bluetooth: Implement automatic setup procedure for local adapters johan.hedberg
                   ` (4 preceding siblings ...)
  2011-01-04 10:08 ` [PATCH 06/11] Bluetooth: Unify mode related management messages to a single struct johan.hedberg
@ 2011-01-04 10:08 ` johan.hedberg
  2011-01-04 10:08 ` [PATCH 08/11] Bluetooth: Implement set_pairable managment command johan.hedberg
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 13+ messages in thread
From: johan.hedberg @ 2011-01-04 10:08 UTC (permalink / raw)
  To: linux-bluetooth

From: Johan Hedberg <johan.hedberg@nokia.com>

This patch adds a HCI_MGMT flag to track adapters which are under the
control of the management interface. This is needed to make sure that
new kernels will work with old user space versions. I.e. behaviour which
could break old user space versions (but is needed by the management
interface) should not be exhibited when the HCI_MGMT flag is not set.

Signed-off-by: Johan Hedberg <johan.hedberg@nokia.com>
---
 include/net/bluetooth/hci.h |    1 +
 net/bluetooth/mgmt.c        |    4 ++++
 2 files changed, 5 insertions(+), 0 deletions(-)

diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 6469d67..a34f638 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -79,6 +79,7 @@ enum {
 
 	HCI_SETUP,
 	HCI_AUTO_OFF,
+	HCI_MGMT,
 };
 
 /* HCI ioctl defines */
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 36a3e1c..9d82da9 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -140,6 +140,8 @@ static int read_index_list(struct sock *sk)
 
 		hci_del_off_timer(d);
 
+		set_bit(HCI_MGMT, &d->flags);
+
 		if (test_bit(HCI_SETUP, &d->flags))
 			continue;
 
@@ -198,6 +200,8 @@ static int read_controller_info(struct sock *sk, unsigned char *data, u16 len)
 
 	hci_dev_lock_bh(hdev);
 
+	set_bit(HCI_MGMT, &hdev->flags);
+
 	put_unaligned_le16(hdev->id, &rp->index);
 	rp->type = hdev->dev_type;
 
-- 
1.7.2.3


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 08/11] Bluetooth: Implement set_pairable managment command
  2011-01-04 10:08 [PATCH 01/11] Bluetooth: Implement automatic setup procedure for local adapters johan.hedberg
                   ` (5 preceding siblings ...)
  2011-01-04 10:08 ` [PATCH 07/11] Bluetooth: Add flag to track managment controlled adapters johan.hedberg
@ 2011-01-04 10:08 ` johan.hedberg
  2011-01-04 10:08 ` [PATCH 09/11] Bluetooth: Fix leaking blacklist when unregistering a hci device johan.hedberg
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 13+ messages in thread
From: johan.hedberg @ 2011-01-04 10:08 UTC (permalink / raw)
  To: linux-bluetooth

From: Johan Hedberg <johan.hedberg@nokia.com>

This patch implements a new set_pairable management command to control
the pairable state of local adapters. The state is represented using a
new HCI_PAIRABLE flag in the hci_dev struct.

For backwards compatibility with older user space versions the
HCI_PAIRABLE flag gets automatically set when the existence of an
adapter is reported to user space through legacy methods and the
HCI_MGMT flag is not set.

Signed-off-by: Johan Hedberg <johan.hedberg@nokia.com>
---
 include/net/bluetooth/hci.h  |    1 +
 include/net/bluetooth/mgmt.h |    4 +
 net/bluetooth/hci_core.c     |   10 +++
 net/bluetooth/mgmt.c         |  138 ++++++++++++++++++++++++++++-------------
 4 files changed, 109 insertions(+), 44 deletions(-)

diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index a34f638..2b370ba 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -80,6 +80,7 @@ enum {
 	HCI_SETUP,
 	HCI_AUTO_OFF,
 	HCI_MGMT,
+	HCI_PAIRABLE,
 };
 
 /* HCI ioctl defines */
diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index f61fd67..a554802 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -70,6 +70,8 @@ struct mgmt_mode {
 
 #define MGMT_OP_SET_CONNECTABLE		0x0007
 
+#define MGMT_OP_SET_PAIRABLE		0x0008
+
 #define MGMT_EV_CMD_COMPLETE		0x0001
 struct mgmt_ev_cmd_complete {
 	__le16 opcode;
@@ -103,3 +105,5 @@ struct mgmt_ev_index_removed {
 #define MGMT_EV_DISCOVERABLE		0x0007
 
 #define MGMT_EV_CONNECTABLE		0x0008
+
+#define MGMT_EV_PAIRABLE		0x0009
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index de40a8a..c03e6c9 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -799,10 +799,17 @@ int hci_get_dev_list(void __user *arg)
 	read_lock_bh(&hci_dev_list_lock);
 	list_for_each(p, &hci_dev_list) {
 		struct hci_dev *hdev;
+
 		hdev = list_entry(p, struct hci_dev, list);
+
 		hci_del_off_timer(hdev);
+
+		if (!test_bit(HCI_MGMT, &hdev->flags))
+			set_bit(HCI_PAIRABLE, &hdev->flags);
+
 		(dr + n)->dev_id  = hdev->id;
 		(dr + n)->dev_opt = hdev->flags;
+
 		if (++n >= dev_num)
 			break;
 	}
@@ -832,6 +839,9 @@ int hci_get_dev_info(void __user *arg)
 
 	hci_del_off_timer(hdev);
 
+	if (!test_bit(HCI_MGMT, &hdev->flags))
+		set_bit(HCI_PAIRABLE, &hdev->flags);
+
 	strcpy(di.name, hdev->name);
 	di.bdaddr   = hdev->bdaddr;
 	di.type     = (hdev->bus & 0x0f) | (hdev->dev_type << 4);
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 9d82da9..04d8ad2 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -479,6 +479,96 @@ failed:
 	return err;
 }
 
+static int mgmt_event(u16 event, void *data, u16 data_len, struct sock *skip_sk)
+{
+	struct sk_buff *skb;
+	struct mgmt_hdr *hdr;
+
+	skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
+	if (!skb)
+		return -ENOMEM;
+
+	bt_cb(skb)->channel = HCI_CHANNEL_CONTROL;
+
+	hdr = (void *) skb_put(skb, sizeof(*hdr));
+	hdr->opcode = cpu_to_le16(event);
+	hdr->len = cpu_to_le16(data_len);
+
+	memcpy(skb_put(skb, data_len), data, data_len);
+
+	hci_send_to_sock(NULL, skb, skip_sk);
+	kfree_skb(skb);
+
+	return 0;
+}
+
+static int send_mode_rsp(struct sock *sk, u16 opcode, u16 index, u8 val)
+{
+	struct mgmt_hdr *hdr;
+	struct mgmt_ev_cmd_complete *ev;
+	struct mgmt_mode *rp;
+	struct sk_buff *skb;
+
+	skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + sizeof(*rp), GFP_ATOMIC);
+	if (!skb)
+		return -ENOMEM;
+
+	hdr = (void *) skb_put(skb, sizeof(*hdr));
+	hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
+	hdr->len = cpu_to_le16(sizeof(*ev) + sizeof(*rp));
+
+	ev = (void *) skb_put(skb, sizeof(*ev));
+	put_unaligned_le16(opcode, &ev->opcode);
+
+	rp = (void *) skb_put(skb, sizeof(*rp));
+	put_unaligned_le16(index, &rp->index);
+	rp->val = val;
+
+	if (sock_queue_rcv_skb(sk, skb) < 0)
+		kfree_skb(skb);
+
+	return 0;
+}
+
+static int set_pairable(struct sock *sk, unsigned char *data, u16 len)
+{
+	struct mgmt_mode *cp, ev;
+	struct hci_dev *hdev;
+	u16 dev_id;
+	int err;
+
+	cp = (void *) data;
+	dev_id = get_unaligned_le16(&cp->index);
+
+	BT_DBG("request for hci%u", dev_id);
+
+	hdev = hci_dev_get(dev_id);
+	if (!hdev)
+		return cmd_status(sk, MGMT_OP_SET_PAIRABLE, ENODEV);
+
+	hci_dev_lock_bh(hdev);
+
+	if (cp->val)
+		set_bit(HCI_PAIRABLE, &hdev->flags);
+	else
+		clear_bit(HCI_PAIRABLE, &hdev->flags);
+
+	err = send_mode_rsp(sk, MGMT_OP_SET_PAIRABLE, dev_id, cp->val);
+	if (err < 0)
+		goto failed;
+
+	put_unaligned_le16(dev_id, &ev.index);
+	ev.val = cp->val;
+
+	err = mgmt_event(MGMT_EV_PAIRABLE, &ev, sizeof(ev), sk);
+
+failed:
+	hci_dev_unlock_bh(hdev);
+	hci_dev_put(hdev);
+
+	return err;
+}
+
 int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
 {
 	unsigned char *buf;
@@ -528,6 +618,9 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
 	case MGMT_OP_SET_CONNECTABLE:
 		err = set_connectable(sk, buf + sizeof(*hdr), len);
 		break;
+	case MGMT_OP_SET_PAIRABLE:
+		err = set_pairable(sk, buf + sizeof(*hdr), len);
+		break;
 	default:
 		BT_DBG("Unknown op %u", opcode);
 		err = cmd_status(sk, opcode, 0x01);
@@ -544,29 +637,6 @@ done:
 	return err;
 }
 
-static int mgmt_event(u16 event, void *data, u16 data_len, struct sock *skip_sk)
-{
-	struct sk_buff *skb;
-	struct mgmt_hdr *hdr;
-
-	skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
-	if (!skb)
-		return -ENOMEM;
-
-	bt_cb(skb)->channel = HCI_CHANNEL_CONTROL;
-
-	hdr = (void *) skb_put(skb, sizeof(*hdr));
-	hdr->opcode = cpu_to_le16(event);
-	hdr->len = cpu_to_le16(data_len);
-
-	memcpy(skb_put(skb, data_len), data, data_len);
-
-	hci_send_to_sock(NULL, skb, skip_sk);
-	kfree_skb(skb);
-
-	return 0;
-}
-
 int mgmt_index_added(u16 index)
 {
 	struct mgmt_ev_index_added ev;
@@ -592,33 +662,13 @@ struct cmd_lookup {
 
 static void mode_rsp(struct pending_cmd *cmd, void *data)
 {
-	struct mgmt_hdr *hdr;
-	struct mgmt_ev_cmd_complete *ev;
-	struct mgmt_mode *rp;
 	struct mgmt_mode *cp = cmd->cmd;
-	struct sk_buff *skb;
 	struct cmd_lookup *match = data;
 
 	if (cp->val != match->val)
 		return;
 
-	skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + sizeof(*rp), GFP_ATOMIC);
-	if (!skb)
-		return;
-
-	hdr = (void *) skb_put(skb, sizeof(*hdr));
-	hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
-	hdr->len = cpu_to_le16(sizeof(*ev) + sizeof(*rp));
-
-	ev = (void *) skb_put(skb, sizeof(*ev));
-	put_unaligned_le16(cmd->opcode, &ev->opcode);
-
-	rp = (void *) skb_put(skb, sizeof(*rp));
-	put_unaligned_le16(cmd->index, &rp->index);
-	rp->val = cp->val;
-
-	if (sock_queue_rcv_skb(cmd->sk, skb) < 0)
-		kfree_skb(skb);
+	send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
 
 	list_del(&cmd->list);
 
-- 
1.7.2.3


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 09/11] Bluetooth: Fix leaking blacklist when unregistering a hci device
  2011-01-04 10:08 [PATCH 01/11] Bluetooth: Implement automatic setup procedure for local adapters johan.hedberg
                   ` (6 preceding siblings ...)
  2011-01-04 10:08 ` [PATCH 08/11] Bluetooth: Implement set_pairable managment command johan.hedberg
@ 2011-01-04 10:08 ` johan.hedberg
  2011-01-17 18:25   ` Gustavo F. Padovan
  2011-01-04 10:08 ` [PATCH 10/11] Bluetooth: Implement UUID handling through the management interface johan.hedberg
  2011-01-04 10:08 ` [PATCH 11/11] Bluetooth: Implement debugfs support for listing UUIDs johan.hedberg
  9 siblings, 1 reply; 13+ messages in thread
From: johan.hedberg @ 2011-01-04 10:08 UTC (permalink / raw)
  To: linux-bluetooth

From: Johan Hedberg <johan.hedberg@nokia.com>

The blacklist should be freed before the hci device gets unregistered.

Signed-off-by: Johan Hedberg <johan.hedberg@nokia.com>
---
 net/bluetooth/hci_core.c |    4 ++++
 1 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index c03e6c9..f01dcea 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1085,6 +1085,10 @@ int hci_unregister_dev(struct hci_dev *hdev)
 
 	destroy_workqueue(hdev->workqueue);
 
+	hci_dev_lock_bh(hdev);
+	hci_blacklist_clear(hdev);
+	hci_dev_unlock_bh(hdev);
+
 	__hci_dev_put(hdev);
 
 	return 0;
-- 
1.7.2.3


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 10/11] Bluetooth: Implement UUID handling through the management interface
  2011-01-04 10:08 [PATCH 01/11] Bluetooth: Implement automatic setup procedure for local adapters johan.hedberg
                   ` (7 preceding siblings ...)
  2011-01-04 10:08 ` [PATCH 09/11] Bluetooth: Fix leaking blacklist when unregistering a hci device johan.hedberg
@ 2011-01-04 10:08 ` johan.hedberg
  2011-01-25  9:12   ` [PATCH 10/11 v2] " johan.hedberg
  2011-01-04 10:08 ` [PATCH 11/11] Bluetooth: Implement debugfs support for listing UUIDs johan.hedberg
  9 siblings, 1 reply; 13+ messages in thread
From: johan.hedberg @ 2011-01-04 10:08 UTC (permalink / raw)
  To: linux-bluetooth

From: Johan Hedberg <johan.hedberg@nokia.com>

This patch adds methods to the management interface for userspace to
notify the kernel of which services have been registered for specific
adapters. This information is needed for setting the appropriate Class
of Device value as well as the Extended Inquiry Response value. This
patch doesn't actually implement setting of these values but just
provides the storage of the UUIDs so the needed functionality can be
built on top of it.

Signed-off-by: Johan Hedberg <johan.hedberg@nokia.com>
---
 include/net/bluetooth/hci_core.h |   10 +++
 include/net/bluetooth/mgmt.h     |   12 ++++
 net/bluetooth/hci_core.c         |   19 ++++++
 net/bluetooth/mgmt.c             |  120 ++++++++++++++++++++++++++++++++++++++
 4 files changed, 161 insertions(+), 0 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 8d800d9..3008f33 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -66,6 +66,12 @@ struct bdaddr_list {
 	struct list_head list;
 	bdaddr_t bdaddr;
 };
+
+struct bt_uuid {
+	struct list_head list;
+	u8 uuid[16];
+};
+
 #define NUM_REASSEMBLY 4
 struct hci_dev {
 	struct list_head list;
@@ -139,6 +145,8 @@ struct hci_dev {
 	struct hci_conn_hash	conn_hash;
 	struct list_head	blacklist;
 
+	struct list_head	uuids;
+
 	struct hci_dev_stats	stat;
 
 	struct sk_buff_head	driver_init;
@@ -440,6 +448,8 @@ int hci_inquiry(void __user *arg);
 struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr);
 int hci_blacklist_clear(struct hci_dev *hdev);
 
+int hci_uuids_clear(struct hci_dev *hdev);
+
 void hci_del_off_timer(struct hci_dev *hdev);
 
 void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb);
diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index a554802..c118ad3 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -72,6 +72,18 @@ struct mgmt_mode {
 
 #define MGMT_OP_SET_PAIRABLE		0x0008
 
+#define MGMT_OP_ADD_UUID		0x0009
+struct mgmt_cp_add_uuid {
+	__le16 index;
+	__u8 uuid[16];
+} __packed;
+
+#define MGMT_OP_REMOVE_UUID		0x000A
+struct mgmt_cp_remove_uuid {
+	__le16 index;
+	__u8 uuid[16];
+} __packed;
+
 #define MGMT_EV_CMD_COMPLETE		0x0001
 struct mgmt_ev_cmd_complete {
 	__le16 opcode;
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index f01dcea..49590c6 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -955,6 +955,22 @@ void hci_del_off_timer(struct hci_dev *hdev)
 	del_timer(&hdev->off_timer);
 }
 
+int hci_uuids_clear(struct hci_dev *hdev)
+{
+	struct list_head *p, *n;
+
+	list_for_each_safe(p, n, &hdev->uuids) {
+		struct bt_uuid *uuid;
+
+		uuid = list_entry(p, struct bt_uuid, list);
+
+		list_del(p);
+		kfree(uuid);
+	}
+
+	return 0;
+}
+
 /* Register HCI device */
 int hci_register_dev(struct hci_dev *hdev)
 {
@@ -1012,6 +1028,8 @@ int hci_register_dev(struct hci_dev *hdev)
 
 	INIT_LIST_HEAD(&hdev->blacklist);
 
+	INIT_LIST_HEAD(&hdev->uuids);
+
 	INIT_WORK(&hdev->power_on, hci_power_on);
 	INIT_WORK(&hdev->power_off, hci_power_off);
 	setup_timer(&hdev->off_timer, hci_auto_off, (unsigned long) hdev);
@@ -1087,6 +1105,7 @@ int hci_unregister_dev(struct hci_dev *hdev)
 
 	hci_dev_lock_bh(hdev);
 	hci_blacklist_clear(hdev);
+	hci_uuids_clear(hdev);
 	hci_dev_unlock_bh(hdev);
 
 	__hci_dev_put(hdev);
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 04d8ad2..e6d7104 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -569,6 +569,120 @@ failed:
 	return err;
 }
 
+static int uuid_rsp(struct sock *sk, u16 opcode, u16 index)
+{
+	struct mgmt_hdr *hdr;
+	struct mgmt_ev_cmd_complete *ev;
+	struct sk_buff *skb;
+
+	skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + sizeof(index), GFP_ATOMIC);
+	if (!skb)
+		return -ENOMEM;
+
+	hdr = (void *) skb_put(skb, sizeof(*hdr));
+	hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
+	hdr->len = cpu_to_le16(sizeof(*ev) + sizeof(index));
+
+	ev = (void *) skb_put(skb, sizeof(*ev));
+	put_unaligned_le16(opcode, &ev->opcode);
+
+	put_unaligned_le16(index, skb_put(skb, sizeof(index)));
+
+	if (sock_queue_rcv_skb(sk, skb) < 0)
+		kfree_skb(skb);
+
+	return 0;
+}
+
+static int add_uuid(struct sock *sk, unsigned char *data, u16 len)
+{
+	struct mgmt_cp_add_uuid *cp;
+	struct hci_dev *hdev;
+	struct bt_uuid *uuid;
+	u16 dev_id;
+	int err;
+
+	cp = (void *) data;
+	dev_id = get_unaligned_le16(&cp->index);
+
+	BT_DBG("request for hci%u", dev_id);
+
+	hdev = hci_dev_get(dev_id);
+	if (!hdev)
+		return cmd_status(sk, MGMT_OP_ADD_UUID, ENODEV);
+
+	hci_dev_lock_bh(hdev);
+
+	uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
+	if (!uuid) {
+		err = -ENOMEM;
+		goto failed;
+	}
+
+	memcpy(uuid->uuid, cp->uuid, 16);
+
+	list_add(&uuid->list, &hdev->uuids);
+
+	err = uuid_rsp(sk, MGMT_OP_ADD_UUID, dev_id);
+
+failed:
+	hci_dev_unlock_bh(hdev);
+	hci_dev_put(hdev);
+
+	return err;
+}
+
+static int remove_uuid(struct sock *sk, unsigned char *data, u16 len)
+{
+	struct list_head *p, *n;
+	struct mgmt_cp_add_uuid *cp;
+	struct hci_dev *hdev;
+	u8 bt_uuid_any[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+	u16 dev_id;
+	int err, found;
+
+	cp = (void *) data;
+	dev_id = get_unaligned_le16(&cp->index);
+
+	BT_DBG("request for hci%u", dev_id);
+
+	hdev = hci_dev_get(dev_id);
+	if (!hdev)
+		return cmd_status(sk, MGMT_OP_REMOVE_UUID, ENODEV);
+
+	hci_dev_lock_bh(hdev);
+
+	if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
+		err = hci_uuids_clear(hdev);
+		goto unlock;
+	}
+
+	found = 0;
+
+	list_for_each_safe(p, n, &hdev->uuids) {
+		struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
+
+		if (memcmp(match->uuid, cp->uuid, 16) != 0)
+			continue;
+
+		list_del(&match->list);
+		found++;
+	}
+
+	if (found == 0) {
+		cmd_status(sk, MGMT_OP_REMOVE_UUID, ENOENT);
+		goto unlock;
+	}
+
+	err = uuid_rsp(sk, MGMT_OP_REMOVE_UUID, dev_id);
+
+unlock:
+	hci_dev_unlock_bh(hdev);
+	hci_dev_put(hdev);
+
+	return err;
+}
+
 int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
 {
 	unsigned char *buf;
@@ -621,6 +735,12 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
 	case MGMT_OP_SET_PAIRABLE:
 		err = set_pairable(sk, buf + sizeof(*hdr), len);
 		break;
+	case MGMT_OP_ADD_UUID:
+		err = add_uuid(sk, buf + sizeof(*hdr), len);
+		break;
+	case MGMT_OP_REMOVE_UUID:
+		err = remove_uuid(sk, buf + sizeof(*hdr), len);
+		break;
 	default:
 		BT_DBG("Unknown op %u", opcode);
 		err = cmd_status(sk, opcode, 0x01);
-- 
1.7.2.3


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 11/11] Bluetooth: Implement debugfs support for listing UUIDs
  2011-01-04 10:08 [PATCH 01/11] Bluetooth: Implement automatic setup procedure for local adapters johan.hedberg
                   ` (8 preceding siblings ...)
  2011-01-04 10:08 ` [PATCH 10/11] Bluetooth: Implement UUID handling through the management interface johan.hedberg
@ 2011-01-04 10:08 ` johan.hedberg
  9 siblings, 0 replies; 13+ messages in thread
From: johan.hedberg @ 2011-01-04 10:08 UTC (permalink / raw)
  To: linux-bluetooth

From: Johan Hedberg <johan.hedberg@nokia.com>

This patch adds a debugfs entry to list the UUIDs that have been
registered through the management interface.

Signed-off-by: Johan Hedberg <johan.hedberg@nokia.com>
---
 net/bluetooth/hci_sysfs.c |   52 +++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 52 insertions(+), 0 deletions(-)

diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c
index 5fce3d6..23471dd 100644
--- a/net/bluetooth/hci_sysfs.c
+++ b/net/bluetooth/hci_sysfs.c
@@ -461,6 +461,56 @@ static const struct file_operations blacklist_fops = {
 	.llseek		= seq_lseek,
 	.release	= single_release,
 };
+
+static void print_bt_uuid(struct seq_file *f, u8 *uuid)
+{
+	u32 data0, data4;
+	u16 data1, data2, data3, data5;
+
+	memcpy(&data0, &uuid[0], 4);
+	memcpy(&data1, &uuid[4], 2);
+	memcpy(&data2, &uuid[6], 2);
+	memcpy(&data3, &uuid[8], 2);
+	memcpy(&data4, &uuid[10], 4);
+	memcpy(&data5, &uuid[14], 2);
+
+	seq_printf(f, "%.8x-%.4x-%.4x-%.4x-%.8x%.4x\n",
+				ntohl(data0), ntohs(data1), ntohs(data2),
+				ntohs(data3), ntohl(data4), ntohs(data5));
+}
+
+static int uuids_show(struct seq_file *f, void *p)
+{
+	struct hci_dev *hdev = f->private;
+	struct list_head *l;
+
+	hci_dev_lock_bh(hdev);
+
+	list_for_each(l, &hdev->uuids) {
+		struct bt_uuid *uuid;
+
+		uuid = list_entry(l, struct bt_uuid, list);
+
+		print_bt_uuid(f, uuid->uuid);
+	}
+
+	hci_dev_unlock_bh(hdev);
+
+	return 0;
+}
+
+static int uuids_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, uuids_show, inode->i_private);
+}
+
+static const struct file_operations uuids_fops = {
+	.open		= uuids_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
 int hci_register_sysfs(struct hci_dev *hdev)
 {
 	struct device *dev = &hdev->dev;
@@ -493,6 +543,8 @@ int hci_register_sysfs(struct hci_dev *hdev)
 	debugfs_create_file("blacklist", 0444, hdev->debugfs,
 						hdev, &blacklist_fops);
 
+	debugfs_create_file("uuids", 0444, hdev->debugfs, hdev, &uuids_fops);
+
 	return 0;
 }
 
-- 
1.7.2.3


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH 09/11] Bluetooth: Fix leaking blacklist when unregistering a hci device
  2011-01-04 10:08 ` [PATCH 09/11] Bluetooth: Fix leaking blacklist when unregistering a hci device johan.hedberg
@ 2011-01-17 18:25   ` Gustavo F. Padovan
  0 siblings, 0 replies; 13+ messages in thread
From: Gustavo F. Padovan @ 2011-01-17 18:25 UTC (permalink / raw)
  To: johan.hedberg; +Cc: linux-bluetooth

Hi Johan,

* johan.hedberg@gmail.com <johan.hedberg@gmail.com> [2011-01-04 12:08:50 +0200]:

> From: Johan Hedberg <johan.hedberg@nokia.com>
> 
> The blacklist should be freed before the hci device gets unregistered.
> 
> Signed-off-by: Johan Hedberg <johan.hedberg@nokia.com>
> ---
>  net/bluetooth/hci_core.c |    4 ++++
>  1 files changed, 4 insertions(+), 0 deletions(-)

This one is applied. Thanks.

-- 
Gustavo F. Padovan
http://profusion.mobi

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH 10/11 v2] Bluetooth: Implement UUID handling through the management interface
  2011-01-04 10:08 ` [PATCH 10/11] Bluetooth: Implement UUID handling through the management interface johan.hedberg
@ 2011-01-25  9:12   ` johan.hedberg
  0 siblings, 0 replies; 13+ messages in thread
From: johan.hedberg @ 2011-01-25  9:12 UTC (permalink / raw)
  To: linux-bluetooth

From: Johan Hedberg <johan.hedberg@nokia.com>

This patch adds methods to the management interface for userspace to
notify the kernel of which services have been registered for specific
adapters. This information is needed for setting the appropriate Class
of Device value as well as the Extended Inquiry Response value. This
patch doesn't actually implement setting of these values but just
provides the storage of the UUIDs so the needed functionality can be
built on top of it.

Signed-off-by: Johan Hedberg <johan.hedberg@nokia.com>
---
v2: Fix compiler warning due to potentially uninitialized variable.

 include/net/bluetooth/hci_core.h |   10 +++
 include/net/bluetooth/mgmt.h     |   12 ++++
 net/bluetooth/hci_core.c         |   19 ++++++
 net/bluetooth/mgmt.c             |  120 ++++++++++++++++++++++++++++++++++++++
 4 files changed, 161 insertions(+), 0 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index ba3dbe3..8ee0b8b 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -66,6 +66,12 @@ struct bdaddr_list {
 	struct list_head list;
 	bdaddr_t bdaddr;
 };
+
+struct bt_uuid {
+	struct list_head list;
+	u8 uuid[16];
+};
+
 #define NUM_REASSEMBLY 4
 struct hci_dev {
 	struct list_head list;
@@ -139,6 +145,8 @@ struct hci_dev {
 	struct hci_conn_hash	conn_hash;
 	struct list_head	blacklist;
 
+	struct list_head	uuids;
+
 	struct hci_dev_stats	stat;
 
 	struct sk_buff_head	driver_init;
@@ -441,6 +449,8 @@ int hci_inquiry(void __user *arg);
 struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr);
 int hci_blacklist_clear(struct hci_dev *hdev);
 
+int hci_uuids_clear(struct hci_dev *hdev);
+
 void hci_del_off_timer(struct hci_dev *hdev);
 
 void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb);
diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index a554802..c118ad3 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -72,6 +72,18 @@ struct mgmt_mode {
 
 #define MGMT_OP_SET_PAIRABLE		0x0008
 
+#define MGMT_OP_ADD_UUID		0x0009
+struct mgmt_cp_add_uuid {
+	__le16 index;
+	__u8 uuid[16];
+} __packed;
+
+#define MGMT_OP_REMOVE_UUID		0x000A
+struct mgmt_cp_remove_uuid {
+	__le16 index;
+	__u8 uuid[16];
+} __packed;
+
 #define MGMT_EV_CMD_COMPLETE		0x0001
 struct mgmt_ev_cmd_complete {
 	__le16 opcode;
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 13eb5a8..b99248d 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -955,6 +955,22 @@ void hci_del_off_timer(struct hci_dev *hdev)
 	del_timer(&hdev->off_timer);
 }
 
+int hci_uuids_clear(struct hci_dev *hdev)
+{
+	struct list_head *p, *n;
+
+	list_for_each_safe(p, n, &hdev->uuids) {
+		struct bt_uuid *uuid;
+
+		uuid = list_entry(p, struct bt_uuid, list);
+
+		list_del(p);
+		kfree(uuid);
+	}
+
+	return 0;
+}
+
 /* Register HCI device */
 int hci_register_dev(struct hci_dev *hdev)
 {
@@ -1012,6 +1028,8 @@ int hci_register_dev(struct hci_dev *hdev)
 
 	INIT_LIST_HEAD(&hdev->blacklist);
 
+	INIT_LIST_HEAD(&hdev->uuids);
+
 	INIT_WORK(&hdev->power_on, hci_power_on);
 	INIT_WORK(&hdev->power_off, hci_power_off);
 	setup_timer(&hdev->off_timer, hci_auto_off, (unsigned long) hdev);
@@ -1087,6 +1105,7 @@ int hci_unregister_dev(struct hci_dev *hdev)
 
 	hci_dev_lock_bh(hdev);
 	hci_blacklist_clear(hdev);
+	hci_uuids_clear(hdev);
 	hci_dev_unlock_bh(hdev);
 
 	__hci_dev_put(hdev);
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index d107350..0854c2f 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -571,6 +571,120 @@ failed:
 	return err;
 }
 
+static int uuid_rsp(struct sock *sk, u16 opcode, u16 index)
+{
+	struct mgmt_hdr *hdr;
+	struct mgmt_ev_cmd_complete *ev;
+	struct sk_buff *skb;
+
+	skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + sizeof(index), GFP_ATOMIC);
+	if (!skb)
+		return -ENOMEM;
+
+	hdr = (void *) skb_put(skb, sizeof(*hdr));
+	hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
+	hdr->len = cpu_to_le16(sizeof(*ev) + sizeof(index));
+
+	ev = (void *) skb_put(skb, sizeof(*ev));
+	put_unaligned_le16(opcode, &ev->opcode);
+
+	put_unaligned_le16(index, skb_put(skb, sizeof(index)));
+
+	if (sock_queue_rcv_skb(sk, skb) < 0)
+		kfree_skb(skb);
+
+	return 0;
+}
+
+static int add_uuid(struct sock *sk, unsigned char *data, u16 len)
+{
+	struct mgmt_cp_add_uuid *cp;
+	struct hci_dev *hdev;
+	struct bt_uuid *uuid;
+	u16 dev_id;
+	int err;
+
+	cp = (void *) data;
+	dev_id = get_unaligned_le16(&cp->index);
+
+	BT_DBG("request for hci%u", dev_id);
+
+	hdev = hci_dev_get(dev_id);
+	if (!hdev)
+		return cmd_status(sk, MGMT_OP_ADD_UUID, ENODEV);
+
+	hci_dev_lock_bh(hdev);
+
+	uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
+	if (!uuid) {
+		err = -ENOMEM;
+		goto failed;
+	}
+
+	memcpy(uuid->uuid, cp->uuid, 16);
+
+	list_add(&uuid->list, &hdev->uuids);
+
+	err = uuid_rsp(sk, MGMT_OP_ADD_UUID, dev_id);
+
+failed:
+	hci_dev_unlock_bh(hdev);
+	hci_dev_put(hdev);
+
+	return err;
+}
+
+static int remove_uuid(struct sock *sk, unsigned char *data, u16 len)
+{
+	struct list_head *p, *n;
+	struct mgmt_cp_add_uuid *cp;
+	struct hci_dev *hdev;
+	u8 bt_uuid_any[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+	u16 dev_id;
+	int err, found;
+
+	cp = (void *) data;
+	dev_id = get_unaligned_le16(&cp->index);
+
+	BT_DBG("request for hci%u", dev_id);
+
+	hdev = hci_dev_get(dev_id);
+	if (!hdev)
+		return cmd_status(sk, MGMT_OP_REMOVE_UUID, ENODEV);
+
+	hci_dev_lock_bh(hdev);
+
+	if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
+		err = hci_uuids_clear(hdev);
+		goto unlock;
+	}
+
+	found = 0;
+
+	list_for_each_safe(p, n, &hdev->uuids) {
+		struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
+
+		if (memcmp(match->uuid, cp->uuid, 16) != 0)
+			continue;
+
+		list_del(&match->list);
+		found++;
+	}
+
+	if (found == 0) {
+		err = cmd_status(sk, MGMT_OP_REMOVE_UUID, ENOENT);
+		goto unlock;
+	}
+
+	err = uuid_rsp(sk, MGMT_OP_REMOVE_UUID, dev_id);
+
+unlock:
+	hci_dev_unlock_bh(hdev);
+	hci_dev_put(hdev);
+
+	return err;
+}
+
 int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
 {
 	unsigned char *buf;
@@ -623,6 +737,12 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
 	case MGMT_OP_SET_PAIRABLE:
 		err = set_pairable(sk, buf + sizeof(*hdr), len);
 		break;
+	case MGMT_OP_ADD_UUID:
+		err = add_uuid(sk, buf + sizeof(*hdr), len);
+		break;
+	case MGMT_OP_REMOVE_UUID:
+		err = remove_uuid(sk, buf + sizeof(*hdr), len);
+		break;
 	default:
 		BT_DBG("Unknown op %u", opcode);
 		err = cmd_status(sk, opcode, 0x01);
-- 
1.7.2.3


^ permalink raw reply related	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2011-01-25  9:12 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-01-04 10:08 [PATCH 01/11] Bluetooth: Implement automatic setup procedure for local adapters johan.hedberg
2011-01-04 10:08 ` [PATCH 02/11] Bluetooth: Add support for management powered event johan.hedberg
2011-01-04 10:08 ` [PATCH 03/11] Bluetooth: Add support for set_powered management command johan.hedberg
2011-01-04 10:08 ` [PATCH 04/11] Bluetooth: Add support for set_discoverable " johan.hedberg
2011-01-04 10:08 ` [PATCH 05/11] Bluetooth: Add set_connectable " johan.hedberg
2011-01-04 10:08 ` [PATCH 06/11] Bluetooth: Unify mode related management messages to a single struct johan.hedberg
2011-01-04 10:08 ` [PATCH 07/11] Bluetooth: Add flag to track managment controlled adapters johan.hedberg
2011-01-04 10:08 ` [PATCH 08/11] Bluetooth: Implement set_pairable managment command johan.hedberg
2011-01-04 10:08 ` [PATCH 09/11] Bluetooth: Fix leaking blacklist when unregistering a hci device johan.hedberg
2011-01-17 18:25   ` Gustavo F. Padovan
2011-01-04 10:08 ` [PATCH 10/11] Bluetooth: Implement UUID handling through the management interface johan.hedberg
2011-01-25  9:12   ` [PATCH 10/11 v2] " johan.hedberg
2011-01-04 10:08 ` [PATCH 11/11] Bluetooth: Implement debugfs support for listing UUIDs johan.hedberg

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.