diff options
| author | Johan Hedberg <johan.hedberg@nokia.com> | 2010-12-29 09:00:25 -0500 |
|---|---|---|
| committer | Gustavo F. Padovan <padovan@profusion.mobi> | 2011-02-07 22:40:04 -0500 |
| commit | 73f22f62388795c0f6b4f3f97bda7a64f9681aac (patch) | |
| tree | 5e85471cd9411a9f21cd2f7bb722be196a23f7c7 | |
| parent | eec8d2bcc841ae44edcde9660ff21144a2016053 (diff) | |
Bluetooth: Add support for set_discoverable management command
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>
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
| -rw-r--r-- | include/net/bluetooth/hci_core.h | 1 | ||||
| -rw-r--r-- | include/net/bluetooth/mgmt.h | 16 | ||||
| -rw-r--r-- | net/bluetooth/hci_event.c | 5 | ||||
| -rw-r--r-- | 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 2d046e07a586..ee5ec4f17a15 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h | |||
| @@ -675,6 +675,7 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t len); | |||
| 675 | int mgmt_index_added(u16 index); | 675 | int mgmt_index_added(u16 index); |
| 676 | int mgmt_index_removed(u16 index); | 676 | int mgmt_index_removed(u16 index); |
| 677 | int mgmt_powered(u16 index, u8 powered); | 677 | int mgmt_powered(u16 index, u8 powered); |
| 678 | int mgmt_discoverable(u16 index, u8 discoverable); | ||
| 678 | 679 | ||
| 679 | /* HCI info for socket */ | 680 | /* HCI info for socket */ |
| 680 | #define hci_pi(sk) ((struct hci_pinfo *) sk) | 681 | #define hci_pi(sk) ((struct hci_pinfo *) sk) |
diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 81ef78918b66..434dbcf28b6e 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h | |||
| @@ -68,6 +68,16 @@ struct mgmt_rp_set_powered { | |||
| 68 | __u8 powered; | 68 | __u8 powered; |
| 69 | } __packed; | 69 | } __packed; |
| 70 | 70 | ||
| 71 | #define MGMT_OP_SET_DISCOVERABLE 0x0006 | ||
| 72 | struct mgmt_cp_set_discoverable { | ||
| 73 | __le16 index; | ||
| 74 | __u8 discoverable; | ||
| 75 | } __packed; | ||
| 76 | struct mgmt_rp_set_discoverable { | ||
| 77 | __le16 index; | ||
| 78 | __u8 discoverable; | ||
| 79 | } __packed; | ||
| 80 | |||
| 71 | #define MGMT_EV_CMD_COMPLETE 0x0001 | 81 | #define MGMT_EV_CMD_COMPLETE 0x0001 |
| 72 | struct mgmt_ev_cmd_complete { | 82 | struct mgmt_ev_cmd_complete { |
| 73 | __le16 opcode; | 83 | __le16 opcode; |
| @@ -101,3 +111,9 @@ struct mgmt_ev_powered { | |||
| 101 | __le16 index; | 111 | __le16 index; |
| 102 | __u8 powered; | 112 | __u8 powered; |
| 103 | } __packed; | 113 | } __packed; |
| 114 | |||
| 115 | #define MGMT_EV_DISCOVERABLE 0x0007 | ||
| 116 | struct mgmt_ev_discoverable { | ||
| 117 | __le16 index; | ||
| 118 | __u8 discoverable; | ||
| 119 | } __packed; | ||
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index d42fb35309b5..f55004af0558 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) | |||
| 278 | clear_bit(HCI_PSCAN, &hdev->flags); | 278 | clear_bit(HCI_PSCAN, &hdev->flags); |
| 279 | clear_bit(HCI_ISCAN, &hdev->flags); | 279 | clear_bit(HCI_ISCAN, &hdev->flags); |
| 280 | 280 | ||
| 281 | if (param & SCAN_INQUIRY) | 281 | if (param & SCAN_INQUIRY) { |
| 282 | set_bit(HCI_ISCAN, &hdev->flags); | 282 | set_bit(HCI_ISCAN, &hdev->flags); |
| 283 | mgmt_discoverable(hdev->id, 1); | ||
| 284 | } else | ||
| 285 | mgmt_discoverable(hdev->id, 0); | ||
| 283 | 286 | ||
| 284 | if (param & SCAN_PAGE) | 287 | if (param & SCAN_PAGE) |
| 285 | set_bit(HCI_PSCAN, &hdev->flags); | 288 | set_bit(HCI_PSCAN, &hdev->flags); |
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index b65b6ca08463..5fa3034fe79f 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c | |||
| @@ -307,6 +307,18 @@ static struct pending_cmd *mgmt_pending_find(u16 opcode, int index) | |||
| 307 | return NULL; | 307 | return NULL; |
| 308 | } | 308 | } |
| 309 | 309 | ||
| 310 | static void mgmt_pending_remove(u16 opcode, int index) | ||
| 311 | { | ||
| 312 | struct pending_cmd *cmd; | ||
| 313 | |||
| 314 | cmd = mgmt_pending_find(opcode, index); | ||
| 315 | if (cmd == NULL) | ||
| 316 | return; | ||
| 317 | |||
| 318 | list_del(&cmd->list); | ||
| 319 | mgmt_pending_free(cmd); | ||
| 320 | } | ||
| 321 | |||
| 310 | static int set_powered(struct sock *sk, unsigned char *data, u16 len) | 322 | static int set_powered(struct sock *sk, unsigned char *data, u16 len) |
| 311 | { | 323 | { |
| 312 | struct mgmt_cp_set_powered *cp; | 324 | struct mgmt_cp_set_powered *cp; |
| @@ -353,6 +365,63 @@ failed: | |||
| 353 | return ret; | 365 | return ret; |
| 354 | } | 366 | } |
| 355 | 367 | ||
| 368 | static int set_discoverable(struct sock *sk, unsigned char *data, u16 len) | ||
| 369 | { | ||
| 370 | struct mgmt_cp_set_discoverable *cp; | ||
| 371 | struct hci_dev *hdev; | ||
| 372 | u16 dev_id; | ||
| 373 | u8 scan; | ||
| 374 | int err; | ||
| 375 | |||
| 376 | cp = (void *) data; | ||
| 377 | dev_id = get_unaligned_le16(&cp->index); | ||
| 378 | |||
| 379 | BT_DBG("request for hci%u", dev_id); | ||
| 380 | |||
| 381 | hdev = hci_dev_get(dev_id); | ||
| 382 | if (!hdev) | ||
| 383 | return cmd_status(sk, MGMT_OP_SET_DISCOVERABLE, ENODEV); | ||
| 384 | |||
| 385 | hci_dev_lock_bh(hdev); | ||
| 386 | |||
| 387 | if (!test_bit(HCI_UP, &hdev->flags)) { | ||
| 388 | err = cmd_status(sk, MGMT_OP_SET_DISCOVERABLE, ENETDOWN); | ||
| 389 | goto failed; | ||
| 390 | } | ||
| 391 | |||
| 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); | ||
| 396 | goto failed; | ||
| 397 | } | ||
| 398 | |||
| 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); | ||
| 402 | goto failed; | ||
| 403 | } | ||
| 404 | |||
| 405 | err = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, dev_id, data, len); | ||
| 406 | if (err < 0) | ||
| 407 | goto failed; | ||
| 408 | |||
| 409 | scan = SCAN_PAGE; | ||
| 410 | |||
| 411 | if (cp->discoverable) | ||
| 412 | scan |= SCAN_INQUIRY; | ||
| 413 | |||
| 414 | err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan); | ||
| 415 | if (err < 0) | ||
| 416 | mgmt_pending_remove(MGMT_OP_SET_DISCOVERABLE, dev_id); | ||
| 417 | |||
| 418 | failed: | ||
| 419 | hci_dev_unlock_bh(hdev); | ||
| 420 | hci_dev_put(hdev); | ||
| 421 | |||
| 422 | return err; | ||
| 423 | } | ||
| 424 | |||
| 356 | int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) | 425 | int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) |
| 357 | { | 426 | { |
| 358 | unsigned char *buf; | 427 | unsigned char *buf; |
| @@ -396,6 +465,9 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) | |||
| 396 | case MGMT_OP_SET_POWERED: | 465 | case MGMT_OP_SET_POWERED: |
| 397 | err = set_powered(sk, buf + sizeof(*hdr), len); | 466 | err = set_powered(sk, buf + sizeof(*hdr), len); |
| 398 | break; | 467 | break; |
| 468 | case MGMT_OP_SET_DISCOVERABLE: | ||
| 469 | err = set_discoverable(sk, buf + sizeof(*hdr), len); | ||
| 470 | break; | ||
| 399 | default: | 471 | default: |
| 400 | BT_DBG("Unknown op %u", opcode); | 472 | BT_DBG("Unknown op %u", opcode); |
| 401 | err = cmd_status(sk, opcode, 0x01); | 473 | err = cmd_status(sk, opcode, 0x01); |
| @@ -453,8 +525,8 @@ int mgmt_index_removed(u16 index) | |||
| 453 | return mgmt_event(MGMT_EV_INDEX_REMOVED, &ev, sizeof(ev), NULL); | 525 | return mgmt_event(MGMT_EV_INDEX_REMOVED, &ev, sizeof(ev), NULL); |
| 454 | } | 526 | } |
| 455 | 527 | ||
| 456 | struct powered_lookup { | 528 | struct cmd_lookup { |
| 457 | u8 powered; | 529 | u8 value; |
| 458 | struct sock *sk; | 530 | struct sock *sk; |
| 459 | }; | 531 | }; |
| 460 | 532 | ||
| @@ -465,9 +537,9 @@ static void power_rsp(struct pending_cmd *cmd, void *data) | |||
| 465 | struct mgmt_rp_set_powered *rp; | 537 | struct mgmt_rp_set_powered *rp; |
| 466 | struct mgmt_cp_set_powered *cp = cmd->cmd; | 538 | struct mgmt_cp_set_powered *cp = cmd->cmd; |
| 467 | struct sk_buff *skb; | 539 | struct sk_buff *skb; |
| 468 | struct powered_lookup *match = data; | 540 | struct cmd_lookup *match = data; |
| 469 | 541 | ||
| 470 | if (cp->powered != match->powered) | 542 | if (cp->powered != match->value) |
| 471 | return; | 543 | return; |
| 472 | 544 | ||
| 473 | skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + sizeof(*rp), GFP_ATOMIC); | 545 | skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + sizeof(*rp), GFP_ATOMIC); |
| @@ -501,7 +573,7 @@ static void power_rsp(struct pending_cmd *cmd, void *data) | |||
| 501 | int mgmt_powered(u16 index, u8 powered) | 573 | int mgmt_powered(u16 index, u8 powered) |
| 502 | { | 574 | { |
