diff options
| author | Johan Hedberg <johan.hedberg@nokia.com> | 2010-12-16 03:17:38 -0500 |
|---|---|---|
| committer | Gustavo F. Padovan <padovan@profusion.mobi> | 2011-02-07 22:40:04 -0500 |
| commit | eec8d2bcc841ae44edcde9660ff21144a2016053 (patch) | |
| tree | 32756650c2932b07b4c4fcd7184eadaed766e3b3 | |
| parent | 5add6af8fcbce269cac2457584c0ebfda055474a (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.h | 3 | ||||
| -rw-r--r-- | include/net/bluetooth/mgmt.h | 10 | ||||
| -rw-r--r-- | net/bluetooth/hci_core.c | 4 | ||||
| -rw-r--r-- | net/bluetooth/hci_event.c | 2 | ||||
| -rw-r--r-- | net/bluetooth/hci_sock.c | 6 | ||||
| -rw-r--r-- | 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 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); | |||
| 667 | void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data); | 667 | void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data); |
| 668 | 668 | ||
| 669 | /* ----- HCI Sockets ----- */ | 669 | /* ----- HCI Sockets ----- */ |
| 670 | void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb); | 670 | void 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 */ |
| 673 | int mgmt_control(struct sock *sk, struct msghdr *msg, size_t len); | 674 | 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 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 | ||
| 62 | struct mgmt_cp_set_powered { | ||
| 63 | __le16 index; | ||
| 64 | __u8 powered; | ||
| 65 | } __packed; | ||
| 66 | struct 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 |
| 62 | struct mgmt_ev_cmd_complete { | 72 | struct 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 */ |
| 88 | void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb) | 88 | void 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 | ||
| 35 | struct pending_cmd { | ||
| 36 | struct list_head list; | ||
| 37 | __u16 opcode; | ||
| 38 | int index; | ||
| 39 | void *cmd; | ||
| 40 | struct sock *sk; | ||
| 41 | }; | ||
| 42 | |||
| 43 | LIST_HEAD(cmd_list); | ||
| 44 | |||
| 35 | static int cmd_status(struct sock *sk, u16 cmd, u8 status) | 45 | static 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 | ||
| 233 | static void mgmt_pending_free(struct pending_cmd *cmd) | ||
| 234 | { | ||
| 235 | sock_put(cmd->sk); | ||
| 236 | kfree(cmd->cmd); | ||
| 237 | kfree(cmd); | ||
| 238 | } | ||
| 239 | |||
| 240 | static 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 | |||
| 268 | static 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 | |||
| 289 | static 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) | ||
