From b1a8014471b01dd862de9f91bbbff1296afac42d Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 28 Sep 2013 15:25:39 +0200 Subject: Bluetooth: revert: "Bluetooth: Add missing reset_resume dev_pm_ops" Many btusb devices have 2 modes, a hid mode and a bluetooth hci mode. These devices default to hid mode for BIOS use. This means that after having been reset they will revert to HID mode, and are no longer usable as a HCI. Therefor it is a very bad idea to just blindly make reset_resume point to the regular resume handler. Note that the btusb driver has no clue how to switch these devices from hid to hci mode, this is done in userspace through udev rules, so the proper way to deal with this is to not have a reset-resume handler and instead let the usb-system re-enumerate the device, and re-run the udev rules. I must also note, that the commit message for the commit causing this problem has a very weak motivation for the change: "Add missing reset_resume dev_pm_ops. Missing reset_resume results in the following message after power management device test. This change sets reset_resume to btusb_resume(). [ 2506.936134] btusb 1-1.5:1.0: no reset_resume for driver btusb? [ 2506.936137] btusb 1-1.5:1.1: no reset_resume for driver btusb?" Making a change solely to silence a warning while also changing important behavior (normal resume handling versus re-enumeration) requires a commit message with a proper explanation why it is safe to do so, which clearly lacks here, and unsurprisingly it turns out to not be safe to make this change. Reverting the commit in question fixes bt no longer working on my Dell E6430 after a suspend/resume, and I believe it likely also fixes the following bugs: https://bugzilla.redhat.com/show_bug.cgi?id=988481 https://bugzilla.redhat.com/show_bug.cgi?id=1010649 https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1213239 This reverts commit 502f769662978a2fe99d0caed5e53e3006107381. Cc: Shuah Khan Cc: Gustavo Padovan Cc: stable@vger.kernel.org Signed-off-by: Hans de Goede Signed-off-by: Gustavo Padovan --- drivers/bluetooth/btusb.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index f3dfc0a88fd..d593c99121c 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -1628,7 +1628,6 @@ static struct usb_driver btusb_driver = { #ifdef CONFIG_PM .suspend = btusb_suspend, .resume = btusb_resume, - .reset_resume = btusb_resume, #endif .id_table = btusb_table, .supports_autosuspend = 1, -- cgit v1.2.3-18-g5258 From fe1811438a2a229e93beaefa69481d72652795e5 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 7 Oct 2013 16:27:55 -0700 Subject: cfg80211: fix nl80211.h documentation for DFS enum states The names are prefixed incorrectly on the documentation. Signed-off-by: Luis R. Rodriguez [also remove spurious blank line] Signed-off-by: Johannes Berg --- include/uapi/linux/nl80211.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index fde2c021b26..a58ea652cc2 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -3860,13 +3860,12 @@ enum nl80211_radar_event { * * Channel states used by the DFS code. * - * @IEEE80211_DFS_USABLE: The channel can be used, but channel availability + * @NL80211_DFS_USABLE: The channel can be used, but channel availability * check (CAC) must be performed before using it for AP or IBSS. - * @IEEE80211_DFS_UNAVAILABLE: A radar has been detected on this channel, it + * @NL80211_DFS_UNAVAILABLE: A radar has been detected on this channel, it * is therefore marked as not available. - * @IEEE80211_DFS_AVAILABLE: The channel has been CAC checked and is available. + * @NL80211_DFS_AVAILABLE: The channel has been CAC checked and is available. */ - enum nl80211_dfs_state { NL80211_DFS_USABLE, NL80211_DFS_UNAVAILABLE, -- cgit v1.2.3-18-g5258 From 789fd03331aa1ec45cb58168e2d82525c97c7351 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Fri, 4 Oct 2013 18:07:24 -0700 Subject: cfg80211: rename regulatory_hint_11d() to regulatory_hint_country_ie() It is incorrect to refer to this as 11d as 802.11d was just a proposed amendment, 802.11d was merged to the standard so use proper terminology. Signed-off-by: Luis R. Rodriguez Signed-off-by: Johannes Berg --- include/uapi/linux/nl80211.h | 2 +- net/wireless/reg.c | 4 ++-- net/wireless/reg.h | 4 ++-- net/wireless/sme.c | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index a58ea652cc2..8c0417c222c 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -988,7 +988,7 @@ enum nl80211_commands { * to query the CRDA to retrieve one regulatory domain. This attribute can * also be used by userspace to query the kernel for the currently set * regulatory domain. We chose an alpha2 as that is also used by the - * IEEE-802.11d country information element to identify a country. + * IEEE-802.11 country information element to identify a country. * Users can also simply ask the wireless core to set regulatory domain * to a specific alpha2. * @NL80211_ATTR_REG_RULES: a nested array of regulatory domain regulatory diff --git a/net/wireless/reg.c b/net/wireless/reg.c index d62cb1e9147..8fbe664fdcf 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -1699,8 +1699,8 @@ int regulatory_hint(struct wiphy *wiphy, const char *alpha2) } EXPORT_SYMBOL(regulatory_hint); -void regulatory_hint_11d(struct wiphy *wiphy, enum ieee80211_band band, - const u8 *country_ie, u8 country_ie_len) +void regulatory_hint_country_ie(struct wiphy *wiphy, enum ieee80211_band band, + const u8 *country_ie, u8 country_ie_len) { char alpha2[2]; enum environment_cap env = ENVIRON_ANY; diff --git a/net/wireless/reg.h b/net/wireless/reg.h index af2d5f8a5d8..9677e3c13da 100644 --- a/net/wireless/reg.h +++ b/net/wireless/reg.h @@ -58,7 +58,7 @@ int regulatory_hint_found_beacon(struct wiphy *wiphy, gfp_t gfp); /** - * regulatory_hint_11d - hints a country IE as a regulatory domain + * regulatory_hint_country_ie - hints a country IE as a regulatory domain * @wiphy: the wireless device giving the hint (used only for reporting * conflicts) * @band: the band on which the country IE was received on. This determines @@ -78,7 +78,7 @@ int regulatory_hint_found_beacon(struct wiphy *wiphy, * not observed. For this reason if a triplet is seen with channel * information for a band the BSS is not present in it will be ignored. */ -void regulatory_hint_11d(struct wiphy *wiphy, +void regulatory_hint_country_ie(struct wiphy *wiphy, enum ieee80211_band band, const u8 *country_ie, u8 country_ie_len); diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 20e86a95dc4..65f800890d7 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -682,8 +682,8 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, * - country_ie + 2, the start of the country ie data, and * - and country_ie[1] which is the IE length */ - regulatory_hint_11d(wdev->wiphy, bss->channel->band, - country_ie + 2, country_ie[1]); + regulatory_hint_country_ie(wdev->wiphy, bss->channel->band, + country_ie + 2, country_ie[1]); kfree(country_ie); } -- cgit v1.2.3-18-g5258 From c01fc9ada926aaad907989ca2eba40c2a2a73afe Mon Sep 17 00:00:00 2001 From: Sunil Dutt Date: Wed, 9 Oct 2013 20:45:21 +0530 Subject: cfg80211: pass station supported channel and oper class info The information of the peer's supported channels and supported operating classes are required for the driver to perform TDLS off channel operations. This commit enhances the function nl80211_(new)set_station to pass this information of the peer to the driver. Signed-off-by: Sunil Dutt [return errors for malformed tuples] Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 8 ++++++++ include/uapi/linux/nl80211.h | 9 +++++++++ net/wireless/nl80211.c | 46 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 45f6bf59110..5db5fe24eff 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -744,6 +744,10 @@ enum station_parameters_apply_mask { * @capability: station capability * @ext_capab: extended capabilities of the station * @ext_capab_len: number of extended capabilities + * @supported_channels: supported channels in IEEE 802.11 format + * @supported_channels_len: number of supported channels + * @supported_oper_classes: supported oper classes in IEEE 802.11 format + * @supported_oper_classes_len: number of supported operating classes */ struct station_parameters { const u8 *supported_rates; @@ -763,6 +767,10 @@ struct station_parameters { u16 capability; const u8 *ext_capab; u8 ext_capab_len; + const u8 *supported_channels; + u8 supported_channels_len; + const u8 *supported_oper_classes; + u8 supported_oper_classes_len; }; /** diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 8c0417c222c..f2aef2a7a57 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -1496,6 +1496,11 @@ enum nl80211_commands { * @NL80211_ATTR_RXMGMT_FLAGS: flags for nl80211_send_mgmt(), u32. * As specified in the &enum nl80211_rxmgmt_flags. * + * @NL80211_ATTR_STA_SUPPORTED_CHANNELS: array of supported channels. + * + * @NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES: array of supported + * supported operating classes. + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -1806,6 +1811,10 @@ enum nl80211_attrs { NL80211_ATTR_RXMGMT_FLAGS, + NL80211_ATTR_STA_SUPPORTED_CHANNELS, + + NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 2838206ddad..460638ac2d7 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -354,6 +354,8 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { [NL80211_ATTR_CSA_IES] = { .type = NLA_NESTED }, [NL80211_ATTR_CSA_C_OFF_BEACON] = { .type = NLA_U16 }, [NL80211_ATTR_CSA_C_OFF_PRESP] = { .type = NLA_U16 }, + [NL80211_ATTR_STA_SUPPORTED_CHANNELS] = { .type = NLA_BINARY }, + [NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES] = { .type = NLA_BINARY }, }; /* policy for the key attributes */ @@ -3896,9 +3898,45 @@ static int nl80211_parse_sta_wme(struct genl_info *info, return 0; } +static int nl80211_parse_sta_channel_info(struct genl_info *info, + struct station_parameters *params) +{ + if (info->attrs[NL80211_ATTR_STA_SUPPORTED_CHANNELS]) { + params->supported_channels = + nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_CHANNELS]); + params->supported_channels_len = + nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_CHANNELS]); + /* + * Need to include at least one (first channel, number of + * channels) tuple for each subband, and must have proper + * tuples for the rest of the data as well. + */ + if (params->supported_channels_len < 2) + return -EINVAL; + if (params->supported_channels_len % 2) + return -EINVAL; + } + + if (info->attrs[NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES]) { + params->supported_oper_classes = + nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES]); + params->supported_oper_classes_len = + nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES]); + /* + * The value of the Length field of the Supported Operating + * Classes element is between 2 and 253. + */ + if (params->supported_oper_classes_len < 2 || + params->supported_oper_classes_len > 253) + return -EINVAL; + } + return 0; +} + static int nl80211_set_station_tdls(struct genl_info *info, struct station_parameters *params) { + int err; /* Dummy STA entry gets updated once the peer capabilities are known */ if (info->attrs[NL80211_ATTR_PEER_AID]) params->aid = nla_get_u16(info->attrs[NL80211_ATTR_PEER_AID]); @@ -3909,6 +3947,10 @@ static int nl80211_set_station_tdls(struct genl_info *info, params->vht_capa = nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]); + err = nl80211_parse_sta_channel_info(info, params); + if (err) + return err; + return nl80211_parse_sta_wme(info, params); } @@ -4089,6 +4131,10 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) return -EINVAL; } + err = nl80211_parse_sta_channel_info(info, ¶ms); + if (err) + return err; + err = nl80211_parse_sta_wme(info, ¶ms); if (err) return err; -- cgit v1.2.3-18-g5258 From cea85247f8725fcad1ac7533ce5b32dace506cfc Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 2 Oct 2013 18:33:09 -0700 Subject: cfg80211: enable regulatory hints for strict custom settings If we have a wiphy with an ISO3166-alpha2 regulatory domain programmed with the strict flag set we wait until the wiphy gets its wiphy->regd programmed before allowing regulatory domains hints other than country IE hints from processing on the wiphy. The existing check however discards the possibility of custom regulatory domains having also used the strict flag and these will not have the wiphy->regd set. Custom strict regulatory domains never set the wiphy->regd though as such currently all regulatory hints other than country IE hints are being ignored on these wiphys. All custom strict regulatory domains set the wiphy with the WIPHY_FLAG_CUSTOM_REGULATORY and use wiphy_apply_custom_regulatory(). Enhance the check for the strict ISO3166-alpha2 regulatory domain case by exempting the WIPHY_FLAG_CUSTOM_REGULATORY case. This will enable other regulatory hints to be processed now for these strict custom regulatory domains. Cc: smihir@qti.qualcomm.com Cc: tushnimb@qca.qualcomm.com Signed-off-by: Luis R. Rodriguez Signed-off-by: Johannes Berg --- net/wireless/reg.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 8fbe664fdcf..37c2a63d069 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -997,6 +997,7 @@ static bool ignore_reg_update(struct wiphy *wiphy, */ if (wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY && !wiphy->regd && initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE && + !(wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY) && !is_world_regdom(lr->alpha2)) { REG_DBG_PRINT("Ignoring regulatory request %s since the driver requires its own regulatory domain to be set first\n", reg_initiator_name(initiator)); -- cgit v1.2.3-18-g5258 From fa1fb9cb1c734204018d2b4e6f38c4a9b4146612 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 2 Oct 2013 18:33:10 -0700 Subject: cfg80211: simplify strict custom alpha2 regdomain check This makes it easier to read. Cc: smihir@qti.qualcomm.com Cc: tushnimb@qca.qualcomm.com Signed-off-by: Luis R. Rodriguez Signed-off-by: Johannes Berg --- net/wireless/reg.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 37c2a63d069..edb2ba4e2a1 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -972,6 +972,13 @@ static bool reg_dev_ignore_cell_hint(struct wiphy *wiphy) } #endif +static bool wiphy_strict_alpha2_regd(struct wiphy *wiphy) +{ + if (wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY && + !(wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY)) + return true; + return false; +} static bool ignore_reg_update(struct wiphy *wiphy, enum nl80211_reg_initiator initiator) @@ -995,9 +1002,8 @@ static bool ignore_reg_update(struct wiphy *wiphy, * wiphy->regd will be set once the device has its own * desired regulatory domain set */ - if (wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY && !wiphy->regd && + if (wiphy_strict_alpha2_regd(wiphy) && !wiphy->regd && initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE && - !(wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY) && !is_world_regdom(lr->alpha2)) { REG_DBG_PRINT("Ignoring regulatory request %s since the driver requires its own regulatory domain to be set first\n", reg_initiator_name(initiator)); -- cgit v1.2.3-18-g5258 From 7ec7c4a9a686c608315739ab6a2b0527a240883c Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Thu, 10 Oct 2013 09:55:20 +0200 Subject: mac80211: port CCMP to cryptoapi's CCM driver Use the generic CCM aead chaining mode driver rather than a local implementation that sits right on top of the core AES cipher. This allows the use of accelerated implementations of either CCM as a whole or the CTR mode which it encapsulates. Signed-off-by: Ard Biesheuvel Signed-off-by: Johannes Berg --- net/mac80211/Kconfig | 1 + net/mac80211/aes_ccm.c | 169 ++++++++++++++++--------------------------------- net/mac80211/aes_ccm.h | 14 ++-- net/mac80211/key.h | 2 +- net/mac80211/wpa.c | 44 ++++++------- 5 files changed, 84 insertions(+), 146 deletions(-) diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index 62535fe9f57..dc31ec3db40 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig @@ -4,6 +4,7 @@ config MAC80211 select CRYPTO select CRYPTO_ARC4 select CRYPTO_AES + select CRYPTO_CCM select CRC32 select AVERAGE ---help--- diff --git a/net/mac80211/aes_ccm.c b/net/mac80211/aes_ccm.c index be7614b9ed2..7c7df475a40 100644 --- a/net/mac80211/aes_ccm.c +++ b/net/mac80211/aes_ccm.c @@ -2,6 +2,8 @@ * Copyright 2003-2004, Instant802 Networks, Inc. * Copyright 2005-2006, Devicescape Software, Inc. * + * Rewrite: Copyright (C) 2013 Linaro Ltd + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. @@ -17,134 +19,75 @@ #include "key.h" #include "aes_ccm.h" -static void aes_ccm_prepare(struct crypto_cipher *tfm, u8 *scratch, u8 *a) +void ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad, + u8 *data, size_t data_len, u8 *mic) { - int i; - u8 *b_0, *aad, *b, *s_0; - - b_0 = scratch + 3 * AES_BLOCK_SIZE; - aad = scratch + 4 * AES_BLOCK_SIZE; - b = scratch; - s_0 = scratch + AES_BLOCK_SIZE; - - crypto_cipher_encrypt_one(tfm, b, b_0); + struct scatterlist assoc, pt, ct[2]; + struct { + struct aead_request req; + u8 priv[crypto_aead_reqsize(tfm)]; + } aead_req; - /* Extra Authenticate-only data (always two AES blocks) */ - for (i = 0; i < AES_BLOCK_SIZE; i++) - aad[i] ^= b[i]; - crypto_cipher_encrypt_one(tfm, b, aad); + memset(&aead_req, 0, sizeof(aead_req)); - aad += AES_BLOCK_SIZE; + sg_init_one(&pt, data, data_len); + sg_init_one(&assoc, &aad[2], be16_to_cpup((__be16 *)aad)); + sg_init_table(ct, 2); + sg_set_buf(&ct[0], data, data_len); + sg_set_buf(&ct[1], mic, IEEE80211_CCMP_MIC_LEN); - for (i = 0; i < AES_BLOCK_SIZE; i++) - aad[i] ^= b[i]; - crypto_cipher_encrypt_one(tfm, a, aad); + aead_request_set_tfm(&aead_req.req, tfm); + aead_request_set_assoc(&aead_req.req, &assoc, assoc.length); + aead_request_set_crypt(&aead_req.req, &pt, ct, data_len, b_0); - /* Mask out bits from auth-only-b_0 */ - b_0[0] &= 0x07; - - /* S_0 is used to encrypt T (= MIC) */ - b_0[14] = 0; - b_0[15] = 0; - crypto_cipher_encrypt_one(tfm, s_0, b_0); + crypto_aead_encrypt(&aead_req.req); } - -void ieee80211_aes_ccm_encrypt(struct crypto_cipher *tfm, u8 *scratch, - u8 *data, size_t data_len, - u8 *cdata, u8 *mic) +int ieee80211_aes_ccm_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad, + u8 *data, size_t data_len, u8 *mic) { - int i, j, last_len, num_blocks; - u8 *pos, *cpos, *b, *s_0, *e, *b_0; - - b = scratch; - s_0 = scratch + AES_BLOCK_SIZE; - e = scratch + 2 * AES_BLOCK_SIZE; - b_0 = scratch + 3 * AES_BLOCK_SIZE; - - num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_SIZE); - last_len = data_len % AES_BLOCK_SIZE; - aes_ccm_prepare(tfm, scratch, b); - - /* Process payload blocks */ - pos = data; - cpos = cdata; - for (j = 1; j <= num_blocks; j++) { - int blen = (j == num_blocks && last_len) ? - last_len : AES_BLOCK_SIZE; - - /* Authentication followed by encryption */ - for (i = 0; i < blen; i++) - b[i] ^= pos[i]; - crypto_cipher_encrypt_one(tfm, b, b); - - b_0[14] = (j >> 8) & 0xff; - b_0[15] = j & 0xff; - crypto_cipher_encrypt_one(tfm, e, b_0); - for (i = 0; i < blen; i++) - *cpos++ = *pos++ ^ e[i]; - } - - for (i = 0; i < IEEE80211_CCMP_MIC_LEN; i++) - mic[i] = b[i] ^ s_0[i]; + struct scatterlist assoc, pt, ct[2]; + struct { + struct aead_request req; + u8 priv[crypto_aead_reqsize(tfm)]; + } aead_req; + + memset(&aead_req, 0, sizeof(aead_req)); + + sg_init_one(&pt, data, data_len); + sg_init_one(&assoc, &aad[2], be16_to_cpup((__be16 *)aad)); + sg_init_table(ct, 2); + sg_set_buf(&ct[0], data, data_len); + sg_set_buf(&ct[1], mic, IEEE80211_CCMP_MIC_LEN); + + aead_request_set_tfm(&aead_req.req, tfm); + aead_request_set_assoc(&aead_req.req, &assoc, assoc.length); + aead_request_set_crypt(&aead_req.req, ct, &pt, + data_len + IEEE80211_CCMP_MIC_LEN, b_0); + + return crypto_aead_decrypt(&aead_req.req); } - -int ieee80211_aes_ccm_decrypt(struct crypto_cipher *tfm, u8 *scratch, - u8 *cdata, size_t data_len, u8 *mic, u8 *data) +struct crypto_aead *ieee80211_aes_key_setup_encrypt(const u8 key[]) { - int i, j, last_len, num_blocks; - u8 *pos, *cpos, *b, *s_0, *a, *b_0; - - b = scratch; - s_0 = scratch + AES_BLOCK_SIZE; - a = scratch + 2 * AES_BLOCK_SIZE; - b_0 = scratch + 3 * AES_BLOCK_SIZE; - - num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_SIZE); - last_len = data_len % AES_BLOCK_SIZE; - aes_ccm_prepare(tfm, scratch, a); - - /* Process payload blocks */ - cpos = cdata; - pos = data; - for (j = 1; j <= num_blocks; j++) { - int blen = (j == num_blocks && last_len) ? - last_len : AES_BLOCK_SIZE; - - /* Decryption followed by authentication */ - b_0[14] = (j >> 8) & 0xff; - b_0[15] = j & 0xff; - crypto_cipher_encrypt_one(tfm, b, b_0); - for (i = 0; i < blen; i++) { - *pos = *cpos++ ^ b[i]; - a[i] ^= *pos++; - } - crypto_cipher_encrypt_one(tfm, a, a); - } - - for (i = 0; i < IEEE80211_CCMP_MIC_LEN; i++) { - if ((mic[i] ^ s_0[i]) != a[i]) - return -1; - } - - return 0; -} + struct crypto_aead *tfm; + int err; + tfm = crypto_alloc_aead("ccm(aes)", 0, CRYPTO_ALG_ASYNC); + if (IS_ERR(tfm)) + return tfm; -struct crypto_cipher *ieee80211_aes_key_setup_encrypt(const u8 key[]) -{ - struct crypto_cipher *tfm; + err = crypto_aead_setkey(tfm, key, WLAN_KEY_LEN_CCMP); + if (!err) + err = crypto_aead_setauthsize(tfm, IEEE80211_CCMP_MIC_LEN); + if (!err) + return tfm; - tfm = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC); - if (!IS_ERR(tfm)) - crypto_cipher_setkey(tfm, key, WLAN_KEY_LEN_CCMP); - - return tfm; + crypto_free_aead(tfm); + return ERR_PTR(err); } - -void ieee80211_aes_key_free(struct crypto_cipher *tfm) +void ieee80211_aes_key_free(struct crypto_aead *tfm) { - crypto_free_cipher(tfm); + crypto_free_aead(tfm); } diff --git a/net/mac80211/aes_ccm.h b/net/mac80211/aes_ccm.h index 5b7d744e237..2c7ab1948a2 100644 --- a/net/mac80211/aes_ccm.h +++ b/net/mac80211/aes_ccm.h @@ -12,13 +12,11 @@ #include -struct crypto_cipher *ieee80211_aes_key_setup_encrypt(const u8 key[]); -void ieee80211_aes_ccm_encrypt(struct crypto_cipher *tfm, u8 *scratch, - u8 *data, size_t data_len, - u8 *cdata, u8 *mic); -int ieee80211_aes_ccm_decrypt(struct crypto_cipher *tfm, u8 *scratch, - u8 *cdata, size_t data_len, - u8 *mic, u8 *data); -void ieee80211_aes_key_free(struct crypto_cipher *tfm); +struct crypto_aead *ieee80211_aes_key_setup_encrypt(const u8 key[]); +void ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad, + u8 *data, size_t data_len, u8 *mic); +int ieee80211_aes_ccm_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad, + u8 *data, size_t data_len, u8 *mic); +void ieee80211_aes_key_free(struct crypto_aead *tfm); #endif /* AES_CCM_H */ diff --git a/net/mac80211/key.h b/net/mac80211/key.h index 036d57e76a5..aaae0ed3700 100644 --- a/net/mac80211/key.h +++ b/net/mac80211/key.h @@ -83,7 +83,7 @@ struct ieee80211_key { * Management frames. */ u8 rx_pn[IEEE80211_NUM_TIDS + 1][IEEE80211_CCMP_PN_LEN]; - struct crypto_cipher *tfm; + struct crypto_aead *tfm; u32 replays; /* dot11RSNAStatsCCMPReplays */ } ccmp; struct { diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index c9edfcb7a13..d6572822076 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -301,22 +301,16 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx) } -static void ccmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *scratch, +static void ccmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *b_0, u8 *aad, int encrypted) { __le16 mask_fc; int a4_included, mgmt; u8 qos_tid; - u8 *b_0, *aad; - u16 data_len, len_a; + u16 len_a; unsigned int hdrlen; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - memset(scratch, 0, 6 * AES_BLOCK_SIZE); - - b_0 = scratch + 3 * AES_BLOCK_SIZE; - aad = scratch + 4 * AES_BLOCK_SIZE; - /* * Mask FC: zero subtype b4 b5 b6 (if not mgmt) * Retry, PwrMgt, MoreData; set Protected @@ -338,20 +332,21 @@ static void ccmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *scratch, else qos_tid = 0; - data_len = skb->len - hdrlen - IEEE80211_CCMP_HDR_LEN; - if (encrypted) - data_len -= IEEE80211_CCMP_MIC_LEN; + /* In CCM, the initial vectors (IV) used for CTR mode encryption and CBC + * mode authentication are not allowed to collide, yet both are derived + * from this vector b_0. We only set L := 1 here to indicate that the + * data size can be represented in (L+1) bytes. The CCM layer will take + * care of storing the data length in the top (L+1) bytes and setting + * and clearing the other bits as is required to derive the two IVs. + */ + b_0[0] = 0x1; - /* First block, b_0 */ - b_0[0] = 0x59; /* flags: Adata: 1, M: 011, L: 001 */ /* Nonce: Nonce Flags | A2 | PN * Nonce Flags: Priority (b0..b3) | Management (b4) | Reserved (b5..b7) */ b_0[1] = qos_tid | (mgmt << 4); memcpy(&b_0[2], hdr->addr2, ETH_ALEN); memcpy(&b_0[8], pn, IEEE80211_CCMP_PN_LEN); - /* l(m) */ - put_unaligned_be16(data_len, &b_0[14]); /* AAD (extra authenticate-only data) / masked 802.11 header * FC | A1 | A2 | A3 | SC | [A4] | [QC] */ @@ -407,7 +402,8 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) u8 *pos; u8 pn[6]; u64 pn64; - u8 scratch[6 * AES_BLOCK_SIZE]; + u8 aad[2 * AES_BLOCK_SIZE]; + u8 b_0[AES_BLOCK_SIZE]; if (info->control.hw_key && !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV) && @@ -460,9 +456,9 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) return 0; pos += IEEE80211_CCMP_HDR_LEN; - ccmp_special_blocks(skb, pn, scratch, 0); - ieee80211_aes_ccm_encrypt(key->u.ccmp.tfm, scratch, pos, len, - pos, skb_put(skb, IEEE80211_CCMP_MIC_LEN)); + ccmp_special_blocks(skb, pn, b_0, aad, 0); + ieee80211_aes_ccm_encrypt(key->u.ccmp.tfm, b_0, aad, pos, len, + skb_put(skb, IEEE80211_CCMP_MIC_LEN)); return 0; } @@ -525,16 +521,16 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx) } if (!(status->flag & RX_FLAG_DECRYPTED)) { - u8 scratch[6 * AES_BLOCK_SIZE]; + u8 aad[2 * AES_BLOCK_SIZE]; + u8 b_0[AES_BLOCK_SIZE]; /* hardware didn't decrypt/verify MIC */ - ccmp_special_blocks(skb, pn, scratch, 1); + ccmp_special_blocks(skb, pn, b_0, aad, 1); if (ieee80211_aes_ccm_decrypt( - key->u.ccmp.tfm, scratch, + key->u.ccmp.tfm, b_0, aad, skb->data + hdrlen + IEEE80211_CCMP_HDR_LEN, data_len, - skb->data + skb->len - IEEE80211_CCMP_MIC_LEN, - skb->data + hdrlen + IEEE80211_CCMP_HDR_LEN)) + skb->data + skb->len - IEEE80211_CCMP_MIC_LEN)) return RX_DROP_UNUSABLE; } -- cgit v1.2.3-18-g5258 From 8d6083fe0ab6ffbe486b5d537922fba68e872568 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 14 Oct 2013 16:38:45 -0700 Subject: Bluetooth: Fix minor coding style issue in set_connectable() There is a minor coding style violation and so just fix it. No actual logic has changed. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 861e389f4b4..c071708aac2 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1264,14 +1264,13 @@ static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data, if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) && cp->val != test_bit(HCI_PSCAN, &hdev->flags)) { - if (cp->val) { scan = SCAN_PAGE; } else { scan = 0; if (test_bit(HCI_ISCAN, &hdev->flags) && - hdev->discov_timeout > 0) + hdev->discov_timeout > 0) cancel_delayed_work(&hdev->discov_off); } -- cgit v1.2.3-18-g5258 From b1e73124104d0c4c6c9a073afea07ff0b73d5787 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 15 Oct 2013 06:33:51 -0700 Subject: Bluetooth: Use hci_request for discoverable timeout handling When the discoverable timeout triggers and it is time to turn inquiry scan back off, use the HCI request framework to do it. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 7add9c96e32..c53f7f9c630 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1789,6 +1789,7 @@ static void hci_power_off(struct work_struct *work) static void hci_discov_off(struct work_struct *work) { struct hci_dev *hdev; + struct hci_request req; u8 scan = SCAN_PAGE; hdev = container_of(work, struct hci_dev, discov_off.work); @@ -1797,7 +1798,9 @@ static void hci_discov_off(struct work_struct *work) hci_dev_lock(hdev); - hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, sizeof(scan), &scan); + hci_req_init(&req, hdev); + hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, sizeof(scan), &scan); + hci_req_run(&req, NULL); hdev->discov_timeout = 0; -- cgit v1.2.3-18-g5258 From 441ad2d04123eecb06d7c14948a0e7b07bf75aa5 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 15 Oct 2013 06:33:52 -0700 Subject: Bluetooth: Update advertising data based on management commands Magically updating the advertising data when some random command enables advertising in the controller is not really a good idea. It also caused a bit of complicated code with the exported hci_udpate_ad function that is shared from many places. This patch consolidates the advertising data update into the management core. It also makes sure that when powering on with LE enabled or later on enabling LE the controller has a good default for advertising data. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 2 - net/bluetooth/hci_core.c | 87 +-------------------------- net/bluetooth/hci_event.c | 8 --- net/bluetooth/mgmt.c | 126 +++++++++++++++++++++++++++++++++++---- 4 files changed, 116 insertions(+), 107 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 4e208420d84..4a186ec9913 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1183,8 +1183,6 @@ struct hci_sec_filter { #define hci_req_lock(d) mutex_lock(&d->req_lock) #define hci_req_unlock(d) mutex_unlock(&d->req_lock) -void hci_update_ad(struct hci_request *req); - void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, u16 latency, u16 to_multiplier); void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8], diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index c53f7f9c630..a49ca486962 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -685,10 +685,8 @@ static void hci_init3_req(struct hci_request *req, unsigned long opt) if (hdev->commands[5] & 0x10) hci_setup_link_policy(req); - if (lmp_le_capable(hdev)) { + if (lmp_le_capable(hdev)) hci_set_le_support(req); - hci_update_ad(req); - } /* Read features beyond page 1 if available */ for (p = 2; p < HCI_MAX_PAGES && p <= hdev->max_page; p++) { @@ -1127,89 +1125,6 @@ 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_ADVERTISING, &hdev->dev_flags)) - flags |= LE_AD_GENERAL; - - if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) { - 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; - } else { - flags |= LE_AD_NO_BREDR; - } - - 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; -} - -void hci_update_ad(struct hci_request *req) -{ - struct hci_dev *hdev = req->hdev; - struct hci_cp_le_set_adv_data cp; - u8 len; - - if (!lmp_le_capable(hdev)) - return; - - 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) - return; - - memcpy(hdev->adv_data, cp.data, sizeof(cp.data)); - hdev->adv_data_len = len; - - cp.length = len; - - hci_req_add(req, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp); -} - static int hci_dev_do_open(struct hci_dev *hdev) { int ret = 0; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 5391469ff1a..7b133f0e0c3 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -939,14 +939,6 @@ static void hci_cc_le_set_adv_enable(struct hci_dev *hdev, struct sk_buff *skb) clear_bit(HCI_ADVERTISING, &hdev->dev_flags); } - if (*sent && !test_bit(HCI_INIT, &hdev->flags)) { - struct hci_request req; - - hci_req_init(&req, hdev); - hci_update_ad(&req); - hci_req_run(&req, NULL); - } - hci_dev_unlock(hdev); } diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index c071708aac2..285d571eee6 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -536,6 +536,89 @@ static u8 *create_uuid128_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len) return ptr; } +static u8 create_ad(struct hci_dev *hdev, u8 *ptr) +{ + u8 ad_len = 0, flags = 0; + size_t name_len; + + if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) + flags |= LE_AD_GENERAL; + + if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) { + 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; + } else { + flags |= LE_AD_NO_BREDR; + } + + 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; +} + +static void update_ad(struct hci_request *req) +{ + struct hci_dev *hdev = req->hdev; + struct hci_cp_le_set_adv_data cp; + u8 len; + + if (!lmp_le_capable(hdev)) + return; + + 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) + return; + + memcpy(hdev->adv_data, cp.data, sizeof(cp.data)); + hdev->adv_data_len = len; + + cp.length = len; + + hci_req_add(req, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp); +} + static void create_eir(struct hci_dev *hdev, u8 *data) { u8 *ptr = data; @@ -1555,6 +1638,23 @@ static void le_enable_complete(struct hci_dev *hdev, u8 status) if (match.sk) sock_put(match.sk); + + /* Make sure the controller has a good default for + * advertising data. Restrict the update to when LE + * has actually been enabled. During power on, the + * update in powered_update_hci will take care of it. + */ + if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) { + struct hci_request req; + + hci_dev_lock(hdev); + + hci_req_init(&req, hdev); + update_ad(&req); + hci_req_run(&req, NULL); + + hci_dev_unlock(hdev); + } } static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) @@ -1622,18 +1722,18 @@ static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) goto unlock; } + hci_req_init(&req, hdev); + memset(&hci_cp, 0, sizeof(hci_cp)); if (val) { hci_cp.le = val; hci_cp.simul = lmp_le_br_capable(hdev); + } else { + if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) + disable_advertising(&req); } - hci_req_init(&req, hdev); - - if (test_bit(HCI_ADVERTISING, &hdev->dev_flags) && !val) - disable_advertising(&req); - hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp), &hci_cp); @@ -2772,7 +2872,7 @@ static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data, } if (lmp_le_capable(hdev)) - hci_update_ad(&req); + update_ad(&req); err = hci_req_run(&req, set_name_complete); if (err < 0) @@ -3724,7 +3824,7 @@ static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) goto unlock; } - /* We need to flip the bit already here so that hci_update_ad + /* We need to flip the bit already here so that update_ad * generates the correct flags. */ set_bit(HCI_BREDR_ENABLED, &hdev->dev_flags); @@ -3734,7 +3834,7 @@ static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) set_bredr_scan(&req); - hci_update_ad(&req); + update_ad(&req); err = hci_req_run(&req, set_bredr_complete); if (err < 0) @@ -4035,9 +4135,6 @@ static int powered_update_hci(struct hci_dev *hdev) cp.simul != lmp_host_le_br_capable(hdev)) hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(cp), &cp); - - /* In case BR/EDR was toggled during the AUTO_OFF phase */ - hci_update_ad(&req); } if (lmp_le_capable(hdev)) { @@ -4046,6 +4143,13 @@ static int powered_update_hci(struct hci_dev *hdev) hci_req_add(&req, HCI_OP_LE_SET_RANDOM_ADDR, 6, &hdev->static_addr); + /* Make sure the controller has a good default for + * advertising data. This also applies to the case + * where BR/EDR was toggled during the AUTO_OFF phase. + */ + if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) + update_ad(&req); + if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) enable_advertising(&req); } -- cgit v1.2.3-18-g5258 From 6acd7db41dc2b6bc91b930edf21fbfd8654cbb68 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 15 Oct 2013 06:33:53 -0700 Subject: Bluetooth: Introduce flag for limited discoverable mode Add a new flag that can be set when in limited discoverable mode. This flag will cause the limited discoverable bit in the class of device value to bet set. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci.h | 1 + net/bluetooth/mgmt.c | 3 +++ 2 files changed, 4 insertions(+) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index b096f5f7378..f4650a8c119 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -125,6 +125,7 @@ enum { HCI_ADVERTISING, HCI_CONNECTABLE, HCI_DISCOVERABLE, + HCI_LIMITED_DISCOVERABLE, HCI_LINK_SECURITY, HCI_PERIODIC_INQ, HCI_FAST_CONNECTABLE, diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 285d571eee6..d5eaa28bfd5 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -724,6 +724,9 @@ static void update_class(struct hci_request *req) cod[1] = hdev->major_class; cod[2] = get_service_classes(hdev); + if (test_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags)) + cod[1] |= 0x20; + if (memcmp(cod, hdev->dev_class, 3) == 0) return; -- cgit v1.2.3-18-g5258 From 86a7564573a7de9e01aa9a2e26faa993d8f962ac Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 15 Oct 2013 06:33:54 -0700 Subject: Bluetooth: Make mgmt_discoverable() return void The return value of mgmt_discoverable() function is not used and so just change it to return void. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 2 +- net/bluetooth/mgmt.c | 22 ++++++++-------------- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 4a186ec9913..783c70cf305 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1100,7 +1100,7 @@ void mgmt_index_added(struct hci_dev *hdev); void mgmt_index_removed(struct hci_dev *hdev); void mgmt_set_powered_failed(struct hci_dev *hdev, int err); int mgmt_powered(struct hci_dev *hdev, u8 powered); -int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable); +void mgmt_discoverable(struct hci_dev *hdev, u8 discoverable); int mgmt_connectable(struct hci_dev *hdev, u8 connectable); int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status); int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index d5eaa28bfd5..62c53126992 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -4227,30 +4227,24 @@ void mgmt_set_powered_failed(struct hci_dev *hdev, int err) mgmt_pending_remove(cmd); } -int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable) +void mgmt_discoverable(struct hci_dev *hdev, u8 discoverable) { - bool changed = false; - int err = 0; + bool changed; /* Nothing needed here if there's a pending command since that * commands request completion callback takes care of everything * necessary. */ if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev)) - return 0; + return; - if (discoverable) { - if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) - changed = true; - } else { - if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) - changed = true; - } + if (discoverable) + changed = !test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags); + else + changed = test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags); if (changed) - err = new_settings(hdev, NULL); - - return err; + new_settings(hdev, NULL); } int mgmt_connectable(struct hci_dev *hdev, u8 connectable) -- cgit v1.2.3-18-g5258 From a330916c4f29898b93708b6bec8f59f7a7956f41 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 15 Oct 2013 06:33:55 -0700 Subject: Bluetooth: Make mgmt_connectable() return void The return value of mgmt_connectable() function is not used and so just change it to return void. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 2 +- net/bluetooth/mgmt.c | 22 ++++++++-------------- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 783c70cf305..997d43d1996 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1101,7 +1101,7 @@ void mgmt_index_removed(struct hci_dev *hdev); void mgmt_set_powered_failed(struct hci_dev *hdev, int err); int mgmt_powered(struct hci_dev *hdev, u8 powered); void mgmt_discoverable(struct hci_dev *hdev, u8 discoverable); -int mgmt_connectable(struct hci_dev *hdev, u8 connectable); +void mgmt_connectable(struct hci_dev *hdev, u8 connectable); int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status); int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, bool persistent); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 62c53126992..9ffca590566 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -4247,30 +4247,24 @@ void mgmt_discoverable(struct hci_dev *hdev, u8 discoverable) new_settings(hdev, NULL); } -int mgmt_connectable(struct hci_dev *hdev, u8 connectable) +void mgmt_connectable(struct hci_dev *hdev, u8 connectable) { - bool changed = false; - int err = 0; + bool changed; /* Nothing needed here if there's a pending command since that * commands request completion callback takes care of everything * necessary. */ if (mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) - return 0; + return; - if (connectable) { - if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags)) - changed = true; - } else { - if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags)) - changed = true; - } + if (connectable) + changed = !test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags); + else + changed = test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags); if (changed) - err = new_settings(hdev, NULL); - - return err; + new_settings(hdev, NULL); } int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status) -- cgit v1.2.3-18-g5258 From 4796e8af60ee7d2922386ef9fd4389d21e2c1665 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 15 Oct 2013 06:33:56 -0700 Subject: Bluetooth: Make mgmt_write_scan_failed() return void The return value of mgmt_write_scan_failed() function is not used and so just change it to return void. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 2 +- net/bluetooth/mgmt.c | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 997d43d1996..da21a8d2b4a 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1102,7 +1102,7 @@ void mgmt_set_powered_failed(struct hci_dev *hdev, int err); int mgmt_powered(struct hci_dev *hdev, u8 powered); void mgmt_discoverable(struct hci_dev *hdev, u8 discoverable); void mgmt_connectable(struct hci_dev *hdev, u8 connectable); -int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status); +void mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status); int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, bool persistent); void mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 9ffca590566..12d1cb02c2a 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -4267,7 +4267,7 @@ void mgmt_connectable(struct hci_dev *hdev, u8 connectable) new_settings(hdev, NULL); } -int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status) +void mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status) { u8 mgmt_err = mgmt_status(status); @@ -4278,8 +4278,6 @@ int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status) if (scan & SCAN_INQUIRY) mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, cmd_status_rsp, &mgmt_err); - - return 0; } int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, -- cgit v1.2.3-18-g5258 From 970ba5242d86ea281a263231639e935f6386e49d Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 15 Oct 2013 06:33:57 -0700 Subject: Bluetooth: Update class of device after changing discoverable mode When the discoverable mode gets changed, ensure that the class of device value has the correct limited discoverable bit value set. Since the class of device HCI command will only be send to the controller when the value changes, it is safe to just always trigger the update. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 12d1cb02c2a..6db23934ac9 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1025,6 +1025,7 @@ static void set_discoverable_complete(struct hci_dev *hdev, u8 status) { struct pending_cmd *cmd; struct mgmt_mode *cp; + struct hci_request req; bool changed; BT_DBG("status 0x%02x", status); @@ -1054,6 +1055,14 @@ static void set_discoverable_complete(struct hci_dev *hdev, u8 status) if (changed) new_settings(hdev, cmd->sk); + /* When the discoverable mode gets changed, make sure + * that class of device has the limited discoverable + * bit correctly set. + */ + hci_req_init(&req, hdev); + update_class(&req); + hci_req_run(&req, NULL); + remove_cmd: mgmt_pending_remove(cmd); -- cgit v1.2.3-18-g5258 From d4462a07de025dec0f5242743f4d687a39b78bd5 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 15 Oct 2013 08:11:02 -0700 Subject: Bluetooth: Move arming of discoverable timeout to complete handler The discoverable timeout is currently armed from hci_event.c and causes some side effects when using HCI commands instead of the management interface. To make this clear, only arm the discoverable timeout from the management command complete handler. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_event.c | 5 ----- net/bluetooth/mgmt.c | 11 +++++++++-- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 7b133f0e0c3..071c0df118d 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -310,11 +310,6 @@ static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb) set_bit(HCI_ISCAN, &hdev->flags); if (!old_iscan) mgmt_discoverable(hdev, 1); - if (hdev->discov_timeout > 0) { - int to = msecs_to_jiffies(hdev->discov_timeout * 1000); - queue_delayed_work(hdev->workqueue, &hdev->discov_off, - to); - } } else if (old_iscan) mgmt_discoverable(hdev, 0); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 6db23934ac9..686bda76fca 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1043,12 +1043,19 @@ static void set_discoverable_complete(struct hci_dev *hdev, u8 status) } cp = cmd->param; - if (cp->val) + if (cp->val) { changed = !test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags); - else + + if (hdev->discov_timeout > 0) { + int to = msecs_to_jiffies(hdev->discov_timeout * 1000); + queue_delayed_work(hdev->workqueue, &hdev->discov_off, + to); + } + } else { changed = test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags); + } send_settings_rsp(cmd->sk, MGMT_OP_SET_DISCOVERABLE, hdev); -- cgit v1.2.3-18-g5258 From 36261547c9699c6bc746b1db9508aaeb68faa7c9 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 15 Oct 2013 08:28:51 -0700 Subject: Bluetooth: Simplify the code for re-arming discoverable timeout When only the discoverable timeout gets updated, just cancel the current timeout, store the new timeout value. If the new timeout is valid, then arm the discoverable timeout again. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 686bda76fca..1d608ca0b0e 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1143,15 +1143,13 @@ static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data, } if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) { - if (hdev->discov_timeout > 0) { - cancel_delayed_work(&hdev->discov_off); - hdev->discov_timeout = 0; - } + cancel_delayed_work(&hdev->discov_off); + hdev->discov_timeout = timeout; - if (cp->val && timeout > 0) { - hdev->discov_timeout = timeout; + if (cp->val && hdev->discov_timeout > 0) { + int to = msecs_to_jiffies(hdev->discov_timeout * 1000); queue_delayed_work(hdev->workqueue, &hdev->discov_off, - msecs_to_jiffies(hdev->discov_timeout * 1000)); + to); } err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev); -- cgit v1.2.3-18-g5258 From 3d5053127fc51b11f10a2cc3ad638736f2fa814c Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 15 Oct 2013 08:34:15 -0700 Subject: Bluetooth: Add HCI command structure for writing current IAC LAP This patch just adds the HCI command structure for configuring the current IAC LAP setting. The length of the command is variable and supports more than two IAC. However since there is only general discoverable and limited discoverable modes, this can be limited to two possible IACs. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index f4650a8c119..8b8c3e2ddb0 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -824,6 +824,12 @@ struct hci_rp_read_num_supported_iac { #define HCI_OP_READ_CURRENT_IAC_LAP 0x0c39 +#define HCI_OP_WRITE_CURRENT_IAC_LAP 0x0c3a +struct hci_cp_write_current_iac_lap { + __u8 num_iac; + __u8 iac_lap[6]; +} __packed; + #define HCI_OP_WRITE_INQUIRY_MODE 0x0c45 #define HCI_MAX_EIR_LENGTH 240 -- cgit v1.2.3-18-g5258 From 310a3d4854d71c0a565c9f7705749e78f6113c4c Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 15 Oct 2013 09:13:39 -0700 Subject: Bluetooth: Add support for entering limited discoverable mode The limited discoverable mode should be used when a device is only discoverable for a certain amount of time and after that it returns back into being non-discoverable. This adds another option to the set discoverable management command to clearly distinguish limited discoverable from general discoverable mode. While the general discoverable mode can be set with a specific timeout or as permanent setting, the limited discoverable mode requires a timeout. The timeout is flexible and the kernel will not enforce any specific limitations. That GAP part of this is required by userspace to enforce according to the Bluetooth core specification. Devices in limited discoverable mode can still be found by the general discovery procedure. It is mandatory that a device sets both GIAC and LIAC when entering limited discoverable mode. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 8 ++++++ net/bluetooth/mgmt.c | 67 ++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 65 insertions(+), 10 deletions(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index a49ca486962..7a3d17990b4 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1282,6 +1282,7 @@ static int hci_dev_do_close(struct hci_dev *hdev) cancel_delayed_work(&hdev->discov_off); hdev->discov_timeout = 0; clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags); + clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags); } if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) @@ -1717,6 +1718,13 @@ static void hci_discov_off(struct work_struct *work) hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, sizeof(scan), &scan); hci_req_run(&req, NULL); + /* When discoverable timeout triggers, then just make sure + * the limited discoverable flag is cleared. Even in the case + * of a timeout triggered from general discoverable, it is + * safe to unconditionally clear the flag. + */ + clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags); + hdev->discov_timeout = 0; hci_dev_unlock(hdev); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 1d608ca0b0e..c70094014d4 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1039,6 +1039,7 @@ static void set_discoverable_complete(struct hci_dev *hdev, u8 status) if (status) { u8 mgmt_err = mgmt_status(status); cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err); + clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags); goto remove_cmd; } @@ -1094,12 +1095,17 @@ static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data, return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE, status); - if (cp->val != 0x00 && cp->val != 0x01) + if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02) return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE, MGMT_STATUS_INVALID_PARAMS); timeout = __le16_to_cpu(cp->timeout); - if (!cp->val && timeout > 0) + + /* Disabling discoverable requires that no timeout is set, + * and enabling limited discoverable requires a timeout. + */ + if ((cp->val == 0x00 && timeout > 0) || + (cp->val == 0x02 && timeout == 0)) return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE, MGMT_STATUS_INVALID_PARAMS); @@ -1127,6 +1133,10 @@ static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data, if (!hdev_is_powered(hdev)) { bool changed = false; + /* Setting limited discoverable when powered off is + * not a valid operation since it requires a timeout + * and so no need to check HCI_LIMITED_DISCOVERABLE. + */ if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) { change_bit(HCI_DISCOVERABLE, &hdev->dev_flags); changed = true; @@ -1142,7 +1152,13 @@ static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data, goto failed; } - if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) { + /* If the current mode is the same, then just update the timeout + * value with the new value. And if only the timeout gets updated, + * then no need for any HCI transactions. + */ + if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags) && + (cp->val == 0x02) == test_bit(HCI_LIMITED_DISCOVERABLE, + &hdev->dev_flags)) { cancel_delayed_work(&hdev->discov_off); hdev->discov_timeout = timeout; @@ -1162,24 +1178,55 @@ static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data, goto failed; } + /* Cancel any potential discoverable timeout that might be + * still active and store new timeout value. The arming of + * the timeout happens in the complete handler. + */ + cancel_delayed_work(&hdev->discov_off); + hdev->discov_timeout = timeout; + hci_req_init(&req, hdev); scan = SCAN_PAGE; - if (cp->val) + if (cp->val) { + struct hci_cp_write_current_iac_lap hci_cp; + + if (cp->val == 0x02) { + /* Limited discoverable mode */ + set_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags); + + hci_cp.num_iac = 2; + hci_cp.iac_lap[0] = 0x00; /* LIAC */ + hci_cp.iac_lap[1] = 0x8b; + hci_cp.iac_lap[2] = 0x9e; + hci_cp.iac_lap[3] = 0x33; /* GIAC */ + hci_cp.iac_lap[4] = 0x8b; + hci_cp.iac_lap[5] = 0x9e; + } else { + /* General discoverable mode */ + clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags); + + hci_cp.num_iac = 1; + hci_cp.iac_lap[0] = 0x33; /* GIAC */ + hci_cp.iac_lap[1] = 0x8b; + hci_cp.iac_lap[2] = 0x9e; + } + + hci_req_add(&req, HCI_OP_WRITE_CURRENT_IAC_LAP, + (hci_cp.num_iac * 3) + 1, &hci_cp); + scan |= SCAN_INQUIRY; - else - cancel_delayed_work(&hdev->discov_off); + } else { + clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags); + } - hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan); + hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, sizeof(scan), &scan); err = hci_req_run(&req, set_discoverable_complete); if (err < 0) mgmt_pending_remove(cmd); - if (cp->val) - hdev->discov_timeout = timeout; - failed: hci_dev_unlock(hdev); return err; -- cgit v1.2.3-18-g5258 From dc4a5ee2a3282a1044b164979609b4bfab43900b Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 15 Oct 2013 10:15:57 -0700 Subject: Bluetooth: Make mgmt_new_link_key() return void The return value of mgmt_new_link_key() function is not used and so just change it to return void. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 4 ++-- net/bluetooth/mgmt.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index da21a8d2b4a..cf6be04336a 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1103,8 +1103,8 @@ int mgmt_powered(struct hci_dev *hdev, u8 powered); void mgmt_discoverable(struct hci_dev *hdev, u8 discoverable); void mgmt_connectable(struct hci_dev *hdev, u8 connectable); void mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status); -int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, - bool persistent); +void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, + bool persistent); void mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type, u32 flags, u8 *name, u8 name_len, u8 *dev_class); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index c70094014d4..6fb302e04cd 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -4341,8 +4341,8 @@ void mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status) cmd_status_rsp, &mgmt_err); } -int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, - bool persistent) +void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, + bool persistent) { struct mgmt_ev_new_link_key ev; @@ -4355,7 +4355,7 @@ int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE); ev.key.pin_len = key->pin_len; - return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL); + mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL); } int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent) -- cgit v1.2.3-18-g5258 From 9493399108a186492bb828417a43ff37d9ae48fa Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 15 Oct 2013 10:26:39 -0700 Subject: Bluetooth: Move eir_append_data() function into mgmt.c The eir_append_data() function is only used from mgmt.c and so instead of having a public function move it to the location where it is used. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 11 ----------- net/bluetooth/mgmt.c | 11 +++++++++++ 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index cf6be04336a..42591a41baf 100644 --- a/include/net/bluetooth/h