aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohan Hedberg <johan.hedberg@intel.com>2012-11-07 19:23:00 -0500
committerGustavo Padovan <gustavo.padovan@collabora.co.uk>2012-11-18 20:03:01 -0500
commit3f0f524bafcd2025c12e215f13207c7be0a13bf9 (patch)
tree0938ee73420e34e3753f344d3a3e8927db57f672
parentbbaf444a89dd7dd7effd8ed2f4e4ec64da3cc1da (diff)
Bluetooth: Add support for setting LE advertising data
This patch adds support for setting basing LE advertising data. The three elements supported for now are the advertising flags, the TX power and the friendly name. Signed-off-by: Johan Hedberg <johan.hedberg@intel.com> Acked-by: Marcel Holtmann <marcel@holtmann.org> Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
-rw-r--r--include/net/bluetooth/hci.h15
-rw-r--r--include/net/bluetooth/hci_core.h4
-rw-r--r--net/bluetooth/hci_core.c94
-rw-r--r--net/bluetooth/hci_event.c11
4 files changed, 123 insertions, 1 deletions
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 344fea0a7244..7306078e547c 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -338,6 +338,13 @@ enum {
338#define EIR_SSP_RAND_R 0x0F /* Simple Pairing Randomizer R */ 338#define EIR_SSP_RAND_R 0x0F /* Simple Pairing Randomizer R */
339#define EIR_DEVICE_ID 0x10 /* device ID */ 339#define EIR_DEVICE_ID 0x10 /* device ID */
340 340
341/* Low Energy Advertising Flags */
342#define LE_AD_LIMITED 0x01 /* Limited Discoverable */
343#define LE_AD_GENERAL 0x02 /* General Discoverable */
344#define LE_AD_NO_BREDR 0x04 /* BR/EDR not supported */
345#define LE_AD_SIM_LE_BREDR_CTRL 0x08 /* Simultaneous LE & BR/EDR Controller */
346#define LE_AD_SIM_LE_BREDR_HOST 0x10 /* Simultaneous LE & BR/EDR Host */
347
341/* ----- HCI Commands ---- */ 348/* ----- HCI Commands ---- */
342#define HCI_OP_NOP 0x0000 349#define HCI_OP_NOP 0x0000
343 350
@@ -942,6 +949,14 @@ struct hci_rp_le_read_adv_tx_power {
942 __s8 tx_power; 949 __s8 tx_power;
943} __packed; 950} __packed;
944 951
952#define HCI_MAX_AD_LENGTH 31
953
954#define HCI_OP_LE_SET_ADV_DATA 0x2008
955struct hci_cp_le_set_adv_data {
956 __u8 length;
957 __u8 data[HCI_MAX_AD_LENGTH];
958} __packed;
959
945#define HCI_OP_LE_SET_SCAN_PARAM 0x200b 960#define HCI_OP_LE_SET_SCAN_PARAM 0x200b
946struct hci_cp_le_set_scan_param { 961struct hci_cp_le_set_scan_param {
947 __u8 type; 962 __u8 type;
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index ce6dbeb6dfb6..ef5b85dac3f7 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -279,6 +279,8 @@ struct hci_dev {
279 struct le_scan_params le_scan_params; 279 struct le_scan_params le_scan_params;
280 280
281 __s8 adv_tx_power; 281 __s8 adv_tx_power;
282 __u8 adv_data[HCI_MAX_AD_LENGTH];
283 __u8 adv_data_len;
282 284
283 int (*open)(struct hci_dev *hdev); 285 int (*open)(struct hci_dev *hdev);
284 int (*close)(struct hci_dev *hdev); 286 int (*close)(struct hci_dev *hdev);
@@ -734,6 +736,8 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash,
734 u8 *randomizer); 736 u8 *randomizer);
735int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr); 737int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr);
736 738
739int hci_update_ad(struct hci_dev *hdev);
740
737void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb); 741void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb);
738 742
739int hci_recv_frame(struct sk_buff *skb); 743int hci_recv_frame(struct sk_buff *skb);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 9713a2917ddc..e3a49db9cfcb 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -594,6 +594,99 @@ done:
594 return err; 594 return err;
595} 595}
596 596
597static u8 create_ad(struct hci_dev *hdev, u8 *ptr)
598{
599 u8 ad_len = 0, flags = 0;
600 size_t name_len;
601
602 if (test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags))
603 flags |= LE_AD_GENERAL;
604
605 if (!lmp_bredr_capable(hdev))
606 flags |= LE_AD_NO_BREDR;
607
608 if (lmp_le_br_capable(hdev))
609 flags |= LE_AD_SIM_LE_BREDR_CTRL;
610
611 if (lmp_host_le_br_capable(hdev))
612 flags |= LE_AD_SIM_LE_BREDR_HOST;
613
614 if (flags) {
615 BT_DBG("adv flags 0x%02x", flags);
616
617 ptr[0] = 2;
618 ptr[1] = EIR_FLAGS;
619 ptr[2] = flags;
620
621 ad_len += 3;
622 ptr += 3;
623 }
624
625 if (hdev->adv_tx_power != HCI_TX_POWER_INVALID) {
626 ptr[0] = 2;
627 ptr[1] = EIR_TX_POWER;
628 ptr[2] = (u8) hdev->adv_tx_power;
629
630 ad_len += 3;
631 ptr += 3;
632 }
633
634 name_len = strlen(hdev->dev_name);
635 if (name_len > 0) {
636 size_t max_len = HCI_MAX_AD_LENGTH - ad_len - 2;
637
638 if (name_len > max_len) {
639 name_len = max_len;
640 ptr[1] = EIR_NAME_SHORT;
641 } else
642 ptr[1] = EIR_NAME_COMPLETE;
643
644 ptr[0] = name_len + 1;
645
646 memcpy(ptr + 2, hdev->dev_name, name_len);
647
648 ad_len += (name_len + 2);
649 ptr += (name_len + 2);
650 }
651
652 return ad_len;
653}
654
655int hci_update_ad(struct hci_dev *hdev)
656{
657 struct hci_cp_le_set_adv_data cp;
658 u8 len;
659 int err;
660
661 hci_dev_lock(hdev);
662
663 if (!lmp_le_capable(hdev)) {
664 err = -EINVAL;
665 goto unlock;
666 }
667
668 memset(&cp, 0, sizeof(cp));
669
670 len = create_ad(hdev, cp.data);
671
672 if (hdev->adv_data_len == len &&
673 memcmp(cp.data, hdev->adv_data, len) == 0) {
674 err = 0;
675 goto unlock;
676 }
677
678 memcpy(hdev->adv_data, cp.data, sizeof(cp.data));
679 hdev->adv_data_len = len;
680
681 cp.length = len;
682 err = hci_send_cmd(hdev, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp);
683
684unlock:
685 hci_dev_unlock(hdev);
686
687 return err;
688}
689
597/* ---- HCI ioctl helpers ---- */ 690/* ---- HCI ioctl helpers ---- */
598 691
599int hci_dev_open(__u16 dev) 692int hci_dev_open(__u16 dev)
@@ -651,6 +744,7 @@ int hci_dev_open(__u16 dev)
651 hci_dev_hold(hdev); 744 hci_dev_hold(hdev);
652 set_bit(HCI_UP, &hdev->flags); 745 set_bit(HCI_UP, &hdev->flags);
653 hci_notify(hdev, HCI_DEV_UP); 746 hci_notify(hdev, HCI_DEV_UP);
747 hci_update_ad(hdev);
654 if (!test_bit(HCI_SETUP, &hdev->dev_flags) && 748 if (!test_bit(HCI_SETUP, &hdev->dev_flags) &&
655 mgmt_valid_hdev(hdev)) { 749 mgmt_valid_hdev(hdev)) {
656 hci_dev_lock(hdev); 750 hci_dev_lock(hdev);
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 09c65712e8cc..7caea1af557b 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -204,6 +204,9 @@ static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb)
204 hdev->discovery.state = DISCOVERY_STOPPED; 204 hdev->discovery.state = DISCOVERY_STOPPED;
205 hdev->inq_tx_power = HCI_TX_POWER_INVALID; 205 hdev->inq_tx_power = HCI_TX_POWER_INVALID;
206 hdev->adv_tx_power = HCI_TX_POWER_INVALID; 206 hdev->adv_tx_power = HCI_TX_POWER_INVALID;
207
208 memset(hdev->adv_data, 0, sizeof(hdev->adv_data));
209 hdev->adv_data_len = 0;
207} 210}
208 211
209static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb) 212static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb)
@@ -226,6 +229,9 @@ static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb)
226 229
227 hci_dev_unlock(hdev); 230 hci_dev_unlock(hdev);
228 231
232 if (!status && !test_bit(HCI_INIT, &hdev->flags))
233 hci_update_ad(hdev);
234
229 hci_req_complete(hdev, HCI_OP_WRITE_LOCAL_NAME, status); 235 hci_req_complete(hdev, HCI_OP_WRITE_LOCAL_NAME, status);
230} 236}
231 237
@@ -1091,8 +1097,11 @@ static void hci_cc_le_read_adv_tx_power(struct hci_dev *hdev,
1091 1097
1092 BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); 1098 BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
1093 1099
1094 if (!rp->status) 1100 if (!rp->status) {
1095 hdev->adv_tx_power = rp->tx_power; 1101 hdev->adv_tx_power = rp->tx_power;
1102 if (!test_bit(HCI_INIT, &hdev->flags))
1103 hci_update_ad(hdev);
1104 }
1096 1105
1097 hci_req_complete(hdev, HCI_OP_LE_READ_ADV_TX_POWER, rp->status); 1106 hci_req_complete(hdev, HCI_OP_LE_READ_ADV_TX_POWER, rp->status);
1098} 1107}