aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohan Hedberg <johan.hedberg@nokia.com>2010-12-16 03:17:38 -0500
committerGustavo F. Padovan <padovan@profusion.mobi>2011-02-07 22:40:04 -0500
commiteec8d2bcc841ae44edcde9660ff21144a2016053 (patch)
tree32756650c2932b07b4c4fcd7184eadaed766e3b3
parent5add6af8fcbce269cac2457584c0ebfda055474a (diff)
Bluetooth: Add support for set_powered management command
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> Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
-rw-r--r--include/net/bluetooth/hci_core.h3
-rw-r--r--include/net/bluetooth/mgmt.h10
-rw-r--r--net/bluetooth/hci_core.c4
-rw-r--r--net/bluetooth/hci_event.c2
-rw-r--r--net/bluetooth/hci_sock.c6
-rw-r--r--net/bluetooth/mgmt.c200
6 files changed, 215 insertions, 10 deletions
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 32e11b37ef28..2d046e07a586 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -667,7 +667,8 @@ void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode);
667void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data); 667void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data);
668 668
669/* ----- HCI Sockets ----- */ 669/* ----- HCI Sockets ----- */
670void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb); 670void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb,
671 struct sock *skip_sk);
671 672
672/* Management interface */ 673/* Management interface */
673int mgmt_control(struct sock *sk, struct msghdr *msg, size_t len); 674int 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 0ac1520573ed..81ef78918b66 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -58,6 +58,16 @@ struct mgmt_rp_read_info {
58 __u16 hci_rev; 58 __u16 hci_rev;
59} __packed; 59} __packed;
60 60
61#define MGMT_OP_SET_POWERED 0x0005
62struct mgmt_cp_set_powered {
63 __le16 index;
64 __u8 powered;
65} __packed;
66struct mgmt_rp_set_powered {
67 __le16 index;
68 __u8 powered;
69} __packed;
70
61#define MGMT_EV_CMD_COMPLETE 0x0001 71#define MGMT_EV_CMD_COMPLETE 0x0001
62struct mgmt_ev_cmd_complete { 72struct mgmt_ev_cmd_complete {
63 __le16 opcode; 73 __le16 opcode;
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index c5a78e797bc2..dfc4ef90deca 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1377,7 +1377,7 @@ static int hci_send_frame(struct sk_buff *skb)
1377 /* Time stamp */ 1377 /* Time stamp */
1378 __net_timestamp(skb); 1378 __net_timestamp(skb);
1379 1379
1380 hci_send_to_sock(hdev, skb); 1380 hci_send_to_sock(hdev, skb, NULL);
1381 } 1381 }
1382 1382
1383 /* Get rid of skb owner, prior to sending to the driver. */ 1383 /* Get rid of skb owner, prior to sending to the driver. */
@@ -1767,7 +1767,7 @@ static void hci_rx_task(unsigned long arg)
1767 while ((skb = skb_dequeue(&hdev->rx_q))) { 1767 while ((skb = skb_dequeue(&hdev->rx_q))) {
1768 if (atomic_read(&hdev->promisc)) { 1768 if (atomic_read(&hdev->promisc)) {
1769 /* Send copy to the sockets */ 1769 /* Send copy to the sockets */
1770 hci_send_to_sock(hdev, skb); 1770 hci_send_to_sock(hdev, skb, NULL);
1771 } 1771 }
1772 1772
1773 if (test_bit(HCI_RAW, &hdev->flags)) { 1773 if (test_bit(HCI_RAW, &hdev->flags)) {
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index a290854fdaa6..d42fb35309b5 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -2083,6 +2083,6 @@ void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data)
2083 2083
2084 bt_cb(skb)->pkt_type = HCI_EVENT_PKT; 2084 bt_cb(skb)->pkt_type = HCI_EVENT_PKT;
2085 skb->dev = (void *) hdev; 2085 skb->dev = (void *) hdev;
2086 hci_send_to_sock(hdev, skb); 2086 hci_send_to_sock(hdev, skb, NULL);
2087 kfree_skb(skb); 2087 kfree_skb(skb);
2088} 2088}
diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c
index 29827c77f6ce..d50e96136608 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 = {
85}; 85};
86 86
87/* Send frame to RAW socket */ 87/* Send frame to RAW socket */
88void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb) 88void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb,
89 struct sock *skip_sk)
89{ 90{
90 struct sock *sk; 91 struct sock *sk;
91 struct hlist_node *node; 92 struct hlist_node *node;
@@ -97,6 +98,9 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb)
97 struct hci_filter *flt; 98 struct hci_filter *flt;
98 struct sk_buff *nskb; 99 struct sk_buff *nskb;
99 100
101 if (sk == skip_sk)
102 continue;
103
100 if (sk->sk_state != BT_BOUND || hci_pi(sk)->hdev != hdev) 104 if (sk->sk_state != BT_BOUND || hci_pi(sk)->hdev != hdev)
101 continue; 105 continue;
102 106
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index f746e19ebec0..b65b6ca08463 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -32,6 +32,16 @@
32#define MGMT_VERSION 0 32#define MGMT_VERSION 0
33#define MGMT_REVISION 1 33#define MGMT_REVISION 1
34 34
35struct pending_cmd {
36 struct list_head list;
37 __u16 opcode;
38 int index;
39 void *cmd;
40 struct sock *sk;
41};
42
43LIST_HEAD(cmd_list);
44
35static int cmd_status(struct sock *sk, u16 cmd, u8 status) 45static int cmd_status(struct sock *sk, u16 cmd, u8 status)
36{ 46{
37 struct sk_buff *skb; 47 struct sk_buff *skb;
@@ -220,6 +230,129 @@ static int read_controller_info(struct sock *sk, unsigned char *data, u16 len)
220 return 0; 230 return 0;
221} 231}
222 232
233static void mgmt_pending_free(struct pending_cmd *cmd)
234{
235 sock_put(cmd->sk);
236 kfree(cmd->cmd);
237 kfree(cmd);
238}
239
240static int mgmt_pending_add(struct sock *sk, u16 opcode, int index,
241 void *data, u16 len)
242{
243 struct pending_cmd *cmd;
244
245 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
246 if (!cmd)
247 return -ENOMEM;
248
249 cmd->opcode = opcode;
250 cmd->index = index;
251
252 cmd->cmd = kmalloc(len, GFP_ATOMIC);
253 if (!cmd->cmd) {
254 kfree(cmd);
255 return -ENOMEM;
256 }
257
258 memcpy(cmd->cmd, data, len);
259
260 cmd->sk = sk;
261 sock_hold(sk);
262
263 list_add(&cmd->list, &cmd_list);
264
265 return 0;
266}
267
268static void mgmt_pending_foreach(u16 opcode, int index,
269 void (*cb)(struct pending_cmd *cmd, void *data),
270 void *data)
271{
272 struct list_head *p, *n;
273
274 list_for_each_safe(p, n, &cmd_list) {
275 struct pending_cmd *cmd;
276
277 cmd = list_entry(p, struct pending_cmd, list);
278
279 if (cmd->opcode != opcode)
280 continue;
281
282 if (index >= 0 && cmd->index != index)
283 continue;
284
285 cb(cmd, data);
286 }
287}
288
289static struct pending_cmd *mgmt_pending_find(u16 opcode, int index)
290{
291 struct list_head *p;
292
293 list_for_each(p, &cmd_list) {
294 struct pending_cmd *cmd;
295
296 cmd = list_entry(p, struct pending_cmd, list);
297
298 if (cmd->opcode != opcode)
299 continue;
300
301 if (index >= 0 && cmd->index != index)