2 BlueZ - Bluetooth protocol stack for Linux
3 Copyright (C) 2010 Nokia Corporation
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License version 2 as
7 published by the Free Software Foundation;
9 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
10 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
11 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
12 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
13 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
19 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
20 SOFTWARE IS DISCLAIMED.
23 /* Bluetooth HCI Management interface */
25 #include <asm/uaccess.h>
26 #include <asm/unaligned.h>
28 #include <net/bluetooth/bluetooth.h>
29 #include <net/bluetooth/hci_core.h>
30 #include <net/bluetooth/mgmt.h>
32 #define MGMT_VERSION 0
33 #define MGMT_REVISION 1
36 struct list_head list;
45 static int cmd_status(struct sock *sk, u16 cmd, u8 status)
49 struct mgmt_ev_cmd_status *ev;
51 BT_DBG("sock %p", sk);
53 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
57 hdr = (void *) skb_put(skb, sizeof(*hdr));
59 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
60 hdr->len = cpu_to_le16(sizeof(*ev));
62 ev = (void *) skb_put(skb, sizeof(*ev));
64 put_unaligned_le16(cmd, &ev->opcode);
66 if (sock_queue_rcv_skb(sk, skb) < 0)
72 static int read_version(struct sock *sk)
76 struct mgmt_ev_cmd_complete *ev;
77 struct mgmt_rp_read_version *rp;
79 BT_DBG("sock %p", sk);
81 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + sizeof(*rp), GFP_ATOMIC);
85 hdr = (void *) skb_put(skb, sizeof(*hdr));
86 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
87 hdr->len = cpu_to_le16(sizeof(*ev) + sizeof(*rp));
89 ev = (void *) skb_put(skb, sizeof(*ev));
90 put_unaligned_le16(MGMT_OP_READ_VERSION, &ev->opcode);
92 rp = (void *) skb_put(skb, sizeof(*rp));
93 rp->version = MGMT_VERSION;
94 put_unaligned_le16(MGMT_REVISION, &rp->revision);
96 if (sock_queue_rcv_skb(sk, skb) < 0)
102 static int read_index_list(struct sock *sk)
105 struct mgmt_hdr *hdr;
106 struct mgmt_ev_cmd_complete *ev;
107 struct mgmt_rp_read_index_list *rp;
113 BT_DBG("sock %p", sk);
115 read_lock(&hci_dev_list_lock);
118 list_for_each(p, &hci_dev_list) {
122 body_len = sizeof(*ev) + sizeof(*rp) + (2 * count);
123 skb = alloc_skb(sizeof(*hdr) + body_len, GFP_ATOMIC);
125 read_unlock(&hci_dev_list_lock);
129 hdr = (void *) skb_put(skb, sizeof(*hdr));
130 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
131 hdr->len = cpu_to_le16(body_len);
133 ev = (void *) skb_put(skb, sizeof(*ev));
134 put_unaligned_le16(MGMT_OP_READ_INDEX_LIST, &ev->opcode);
136 rp = (void *) skb_put(skb, sizeof(*rp) + (2 * count));
137 put_unaligned_le16(count, &rp->num_controllers);
140 list_for_each(p, &hci_dev_list) {
141 struct hci_dev *d = list_entry(p, struct hci_dev, list);
143 hci_del_off_timer(d);
145 if (test_bit(HCI_SETUP, &d->flags))
148 put_unaligned_le16(d->id, &rp->index[i++]);
149 BT_DBG("Added hci%u", d->id);
152 read_unlock(&hci_dev_list_lock);
154 if (sock_queue_rcv_skb(sk, skb) < 0)
160 static int read_controller_info(struct sock *sk, unsigned char *data, u16 len)
163 struct mgmt_hdr *hdr;
164 struct mgmt_ev_cmd_complete *ev;
165 struct mgmt_rp_read_info *rp;
166 struct mgmt_cp_read_info *cp;
167 struct hci_dev *hdev;
170 BT_DBG("sock %p", sk);
173 return cmd_status(sk, MGMT_OP_READ_INFO, EINVAL);
175 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + sizeof(*rp), GFP_ATOMIC);
179 hdr = (void *) skb_put(skb, sizeof(*hdr));
180 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
181 hdr->len = cpu_to_le16(sizeof(*ev) + sizeof(*rp));
183 ev = (void *) skb_put(skb, sizeof(*ev));
184 put_unaligned_le16(MGMT_OP_READ_INFO, &ev->opcode);
186 rp = (void *) skb_put(skb, sizeof(*rp));
189 dev_id = get_unaligned_le16(&cp->index);
191 BT_DBG("request for hci%u", dev_id);
193 hdev = hci_dev_get(dev_id);
196 return cmd_status(sk, MGMT_OP_READ_INFO, ENODEV);
199 hci_del_off_timer(hdev);
201 hci_dev_lock_bh(hdev);
203 put_unaligned_le16(hdev->id, &rp->index);
204 rp->type = hdev->dev_type;
206 rp->powered = test_bit(HCI_UP, &hdev->flags);
207 rp->discoverable = test_bit(HCI_ISCAN, &hdev->flags);
208 rp->pairable = test_bit(HCI_PSCAN, &hdev->flags);
210 if (test_bit(HCI_AUTH, &hdev->flags))
212 else if (hdev->ssp_mode > 0)
217 bacpy(&rp->bdaddr, &hdev->bdaddr);
218 memcpy(rp->features, hdev->features, 8);
219 memcpy(rp->dev_class, hdev->dev_class, 3);
220 put_unaligned_le16(hdev->manufacturer, &rp->manufacturer);
221 rp->hci_ver = hdev->hci_ver;
222 put_unaligned_le16(hdev->hci_rev, &rp->hci_rev);
224 hci_dev_unlock_bh(hdev);
227 if (sock_queue_rcv_skb(sk, skb) < 0)
233 static void mgmt_pending_free(struct pending_cmd *cmd)
240 static int mgmt_pending_add(struct sock *sk, u16 opcode, int index,
243 struct pending_cmd *cmd;
245 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
249 cmd->opcode = opcode;
252 cmd->cmd = kmalloc(len, GFP_ATOMIC);
258 memcpy(cmd->cmd, data, len);
263 list_add(&cmd->list, &cmd_list);
268 static void mgmt_pending_foreach(u16 opcode, int index,
269 void (*cb)(struct pending_cmd *cmd, void *data),
272 struct list_head *p, *n;
274 list_for_each_safe(p, n, &cmd_list) {
275 struct pending_cmd *cmd;
277 cmd = list_entry(p, struct pending_cmd, list);
279 if (cmd->opcode != opcode)
282 if (index >= 0 && cmd->index != index)
289 static struct pending_cmd *mgmt_pending_find(u16 opcode, int index)
293 list_for_each(p, &cmd_list) {
294 struct pending_cmd *cmd;
296 cmd = list_entry(p, struct pending_cmd, list);
298 if (cmd->opcode != opcode)
301 if (index >= 0 && cmd->index != index)
310 static void mgmt_pending_remove(u16 opcode, int index)
312 struct pending_cmd *cmd;
314 cmd = mgmt_pending_find(opcode, index);
318 list_del(&cmd->list);
319 mgmt_pending_free(cmd);
322 static int set_powered(struct sock *sk, unsigned char *data, u16 len)
324 struct mgmt_cp_set_powered *cp;
325 struct hci_dev *hdev;
330 dev_id = get_unaligned_le16(&cp->index);
332 BT_DBG("request for hci%u", dev_id);
334 hdev = hci_dev_get(dev_id);
336 return cmd_status(sk, MGMT_OP_SET_POWERED, ENODEV);
338 hci_dev_lock_bh(hdev);
340 up = test_bit(HCI_UP, &hdev->flags);
341 if ((cp->powered && up) || (!cp->powered && !up)) {
342 ret = cmd_status(sk, MGMT_OP_SET_POWERED, EALREADY);
346 if (mgmt_pending_find(MGMT_OP_SET_POWERED, dev_id)) {
347 ret = cmd_status(sk, MGMT_OP_SET_POWERED, EBUSY);
351 ret = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, dev_id, data, len);
356 queue_work(hdev->workqueue, &hdev->power_on);
358 queue_work(hdev->workqueue, &hdev->power_off);
363 hci_dev_unlock_bh(hdev);
368 static int set_discoverable(struct sock *sk, unsigned char *data, u16 len)
370 struct mgmt_cp_set_discoverable *cp;
371 struct hci_dev *hdev;
377 dev_id = get_unaligned_le16(&cp->index);
379 BT_DBG("request for hci%u", dev_id);
381 hdev = hci_dev_get(dev_id);
383 return cmd_status(sk, MGMT_OP_SET_DISCOVERABLE, ENODEV);
385 hci_dev_lock_bh(hdev);
387 if (!test_bit(HCI_UP, &hdev->flags)) {
388 err = cmd_status(sk, MGMT_OP_SET_DISCOVERABLE, ENETDOWN);
392 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, dev_id) ||
393 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, dev_id) ||
394 hci_sent_cmd_data(hdev, HCI_OP_WRITE_SCAN_ENABLE)) {
395 err = cmd_status(sk, MGMT_OP_SET_DISCOVERABLE, EBUSY);
399 if (cp->discoverable == test_bit(HCI_ISCAN, &hdev->flags) &&
400 test_bit(HCI_PSCAN, &hdev->flags)) {
401 err = cmd_status(sk, MGMT_OP_SET_DISCOVERABLE, EALREADY);
405 err = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, dev_id, data, len);
411 if (cp->discoverable)
412 scan |= SCAN_INQUIRY;
414 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
416 mgmt_pending_remove(MGMT_OP_SET_DISCOVERABLE, dev_id);
419 hci_dev_unlock_bh(hdev);
425 int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
428 struct mgmt_hdr *hdr;
432 BT_DBG("got %zu bytes", msglen);
434 if (msglen < sizeof(*hdr))
437 buf = kmalloc(msglen, GFP_ATOMIC);
441 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
446 hdr = (struct mgmt_hdr *) buf;
447 opcode = get_unaligned_le16(&hdr->opcode);
448 len = get_unaligned_le16(&hdr->len);
450 if (len != msglen - sizeof(*hdr)) {
456 case MGMT_OP_READ_VERSION:
457 err = read_version(sk);
459 case MGMT_OP_READ_INDEX_LIST:
460 err = read_index_list(sk);
462 case MGMT_OP_READ_INFO:
463 err = read_controller_info(sk, buf + sizeof(*hdr), len);
465 case MGMT_OP_SET_POWERED:
466 err = set_powered(sk, buf + sizeof(*hdr), len);
468 case MGMT_OP_SET_DISCOVERABLE:
469 err = set_discoverable(sk, buf + sizeof(*hdr), len);
472 BT_DBG("Unknown op %u", opcode);
473 err = cmd_status(sk, opcode, 0x01);
487 static int mgmt_event(u16 event, void *data, u16 data_len, struct sock *skip_sk)
490 struct mgmt_hdr *hdr;
492 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
496 bt_cb(skb)->channel = HCI_CHANNEL_CONTROL;
498 hdr = (void *) skb_put(skb, sizeof(*hdr));
499 hdr->opcode = cpu_to_le16(event);
500 hdr->len = cpu_to_le16(data_len);
502 memcpy(skb_put(skb, data_len), data, data_len);
504 hci_send_to_sock(NULL, skb, skip_sk);
510 int mgmt_index_added(u16 index)
512 struct mgmt_ev_index_added ev;
514 put_unaligned_le16(index, &ev.index);
516 return mgmt_event(MGMT_EV_INDEX_ADDED, &ev, sizeof(ev), NULL);
519 int mgmt_index_removed(u16 index)
521 struct mgmt_ev_index_added ev;
523 put_unaligned_le16(index, &ev.index);
525 return mgmt_event(MGMT_EV_INDEX_REMOVED, &ev, sizeof(ev), NULL);
533 static void power_rsp(struct pending_cmd *cmd, void *data)
535 struct mgmt_hdr *hdr;
536 struct mgmt_ev_cmd_complete *ev;
537 struct mgmt_rp_set_powered *rp;
538 struct mgmt_cp_set_powered *cp = cmd->cmd;
540 struct cmd_lookup *match = data;
542 if (cp->powered != match->value)
545 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + sizeof(*rp), GFP_ATOMIC);
549 hdr = (void *) skb_put(skb, sizeof(*hdr));
550 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
551 hdr->len = cpu_to_le16(sizeof(*ev) + sizeof(*rp));
553 ev = (void *) skb_put(skb, sizeof(*ev));
554 put_unaligned_le16(cmd->opcode, &ev->opcode);
556 rp = (void *) skb_put(skb, sizeof(*rp));
557 put_unaligned_le16(cmd->index, &rp->index);
558 rp->powered = cp->powered;
560 if (sock_queue_rcv_skb(cmd->sk, skb) < 0)
563 list_del(&cmd->list);
565 if (match->sk == NULL) {
567 sock_hold(match->sk);
570 mgmt_pending_free(cmd);
573 int mgmt_powered(u16 index, u8 powered)
575 struct mgmt_ev_powered ev;
576 struct cmd_lookup match = { powered, NULL };
579 put_unaligned_le16(index, &ev.index);
580 ev.powered = powered;
582 mgmt_pending_foreach(MGMT_OP_SET_POWERED, index, power_rsp, &match);
584 ret = mgmt_event(MGMT_EV_POWERED, &ev, sizeof(ev), match.sk);
592 static void discoverable_rsp(struct pending_cmd *cmd, void *data)
594 struct mgmt_cp_set_discoverable *cp = cmd->cmd;
595 struct cmd_lookup *match = data;
597 struct mgmt_hdr *hdr;
598 struct mgmt_ev_cmd_complete *ev;
599 struct mgmt_rp_set_discoverable *rp;
601 if (cp->discoverable != match->value)
604 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + sizeof(*rp), GFP_ATOMIC);
608 hdr = (void *) skb_put(skb, sizeof(*hdr));
609 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
610 hdr->len = cpu_to_le16(sizeof(*ev) + sizeof(*rp));
612 ev = (void *) skb_put(skb, sizeof(*ev));
613 put_unaligned_le16(MGMT_OP_SET_DISCOVERABLE, &ev->opcode);
615 rp = (void *) skb_put(skb, sizeof(*rp));
616 put_unaligned_le16(cmd->index, &rp->index);
617 rp->discoverable = cp->discoverable;
619 if (sock_queue_rcv_skb(cmd->sk, skb) < 0)
622 list_del(&cmd->list);
624 if (match->sk == NULL) {
626 sock_hold(match->sk);
629 mgmt_pending_free(cmd);
632 int mgmt_discoverable(u16 index, u8 discoverable)
634 struct mgmt_ev_discoverable ev;
635 struct cmd_lookup match = { discoverable, NULL };
638 put_unaligned_le16(index, &ev.index);
639 ev.discoverable = discoverable;
641 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index,
642 discoverable_rsp, &match);
644 ret = mgmt_event(MGMT_EV_DISCOVERABLE, &ev, sizeof(ev), match.sk);