diff options
author | Johan Hedberg <johan.hedberg@intel.com> | 2012-11-08 01:23:00 +0100 |
---|---|---|
committer | Gustavo Padovan <gustavo.padovan@collabora.co.uk> | 2012-11-18 23:03:01 -0200 |
commit | 3f0f524bafcd2025c12e215f13207c7be0a13bf9 (patch) | |
tree | 0938ee73420e34e3753f344d3a3e8927db57f672 /net/bluetooth/hci_core.c | |
parent | bbaf444a89dd7dd7effd8ed2f4e4ec64da3cc1da (diff) | |
download | kernel_goldelico_gta04-3f0f524bafcd2025c12e215f13207c7be0a13bf9.zip kernel_goldelico_gta04-3f0f524bafcd2025c12e215f13207c7be0a13bf9.tar.gz kernel_goldelico_gta04-3f0f524bafcd2025c12e215f13207c7be0a13bf9.tar.bz2 |
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>
Diffstat (limited to 'net/bluetooth/hci_core.c')
-rw-r--r-- | net/bluetooth/hci_core.c | 94 |
1 files changed, 94 insertions, 0 deletions
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 9713a29..e3a49db 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -594,6 +594,99 @@ done: return err; } +static u8 create_ad(struct hci_dev *hdev, u8 *ptr) +{ + u8 ad_len = 0, flags = 0; + size_t name_len; + + if (test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags)) + flags |= LE_AD_GENERAL; + + if (!lmp_bredr_capable(hdev)) + flags |= LE_AD_NO_BREDR; + + if (lmp_le_br_capable(hdev)) + flags |= LE_AD_SIM_LE_BREDR_CTRL; + + if (lmp_host_le_br_capable(hdev)) + flags |= LE_AD_SIM_LE_BREDR_HOST; + + if (flags) { + BT_DBG("adv flags 0x%02x", flags); + + ptr[0] = 2; + ptr[1] = EIR_FLAGS; + ptr[2] = flags; + + ad_len += 3; + ptr += 3; + } + + if (hdev->adv_tx_power != HCI_TX_POWER_INVALID) { + ptr[0] = 2; + ptr[1] = EIR_TX_POWER; + ptr[2] = (u8) hdev->adv_tx_power; + + ad_len += 3; + ptr += 3; + } + + name_len = strlen(hdev->dev_name); + if (name_len > 0) { + size_t max_len = HCI_MAX_AD_LENGTH - ad_len - 2; + + if (name_len > max_len) { + name_len = max_len; + ptr[1] = EIR_NAME_SHORT; + } else + ptr[1] = EIR_NAME_COMPLETE; + + ptr[0] = name_len + 1; + + memcpy(ptr + 2, hdev->dev_name, name_len); + + ad_len += (name_len + 2); + ptr += (name_len + 2); + } + + return ad_len; +} + +int hci_update_ad(struct hci_dev *hdev) +{ + struct hci_cp_le_set_adv_data cp; + u8 len; + int err; + + hci_dev_lock(hdev); + + if (!lmp_le_capable(hdev)) { + err = -EINVAL; + goto unlock; + } + + memset(&cp, 0, sizeof(cp)); + + len = create_ad(hdev, cp.data); + + if (hdev->adv_data_len == len && + memcmp(cp.data, hdev->adv_data, len) == 0) { + err = 0; + goto unlock; + } + + memcpy(hdev->adv_data, cp.data, sizeof(cp.data)); + hdev->adv_data_len = len; + + cp.length = len; + err = hci_send_cmd(hdev, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp); + +unlock: + hci_dev_unlock(hdev); + + return err; +} + /* ---- HCI ioctl helpers ---- */ int hci_dev_open(__u16 dev) @@ -651,6 +744,7 @@ int hci_dev_open(__u16 dev) hci_dev_hold(hdev); set_bit(HCI_UP, &hdev->flags); hci_notify(hdev, HCI_DEV_UP); + hci_update_ad(hdev); if (!test_bit(HCI_SETUP, &hdev->dev_flags) && mgmt_valid_hdev(hdev)) { hci_dev_lock(hdev); |