From 0857dd3bed62d8f905f61a399d1ed76464b5270f Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 19 Dec 2014 13:40:20 +0200 Subject: Bluetooth: Split hci_request helpers to hci_request.[ch] None of the hci_request related things in net/bluetooth/hci_core.h are needed anywhere outside of the core bluetooth module. This patch creates a new net/bluetooth/hci_request.c file with its corresponding h-file and moves the functionality there from hci_core.c and hci_core.h. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_request.c | 397 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 397 insertions(+) create mode 100644 net/bluetooth/hci_request.c (limited to 'net/bluetooth/hci_request.c') diff --git a/net/bluetooth/hci_request.c b/net/bluetooth/hci_request.c new file mode 100644 index 000000000000..eba83a2a6556 --- /dev/null +++ b/net/bluetooth/hci_request.c @@ -0,0 +1,397 @@ +/* + BlueZ - Bluetooth protocol stack for Linux + + Copyright (C) 2014 Intel Corporation + + 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; + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. + IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY + CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, + COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS + SOFTWARE IS DISCLAIMED. +*/ + +#include +#include + +#include "smp.h" +#include "hci_request.h" + +void hci_req_init(struct hci_request *req, struct hci_dev *hdev) +{ + skb_queue_head_init(&req->cmd_q); + req->hdev = hdev; + req->err = 0; +} + +int hci_req_run(struct hci_request *req, hci_req_complete_t complete) +{ + struct hci_dev *hdev = req->hdev; + struct sk_buff *skb; + unsigned long flags; + + BT_DBG("length %u", skb_queue_len(&req->cmd_q)); + + /* If an error occurred during request building, remove all HCI + * commands queued on the HCI request queue. + */ + if (req->err) { + skb_queue_purge(&req->cmd_q); + return req->err; + } + + /* Do not allow empty requests */ + if (skb_queue_empty(&req->cmd_q)) + return -ENODATA; + + skb = skb_peek_tail(&req->cmd_q); + bt_cb(skb)->req.complete = complete; + + spin_lock_irqsave(&hdev->cmd_q.lock, flags); + skb_queue_splice_tail(&req->cmd_q, &hdev->cmd_q); + spin_unlock_irqrestore(&hdev->cmd_q.lock, flags); + + queue_work(hdev->workqueue, &hdev->cmd_work); + + return 0; +} + +struct sk_buff *hci_prepare_cmd(struct hci_dev *hdev, u16 opcode, u32 plen, + const void *param) +{ + int len = HCI_COMMAND_HDR_SIZE + plen; + struct hci_command_hdr *hdr; + struct sk_buff *skb; + + skb = bt_skb_alloc(len, GFP_ATOMIC); + if (!skb) + return NULL; + + hdr = (struct hci_command_hdr *) skb_put(skb, HCI_COMMAND_HDR_SIZE); + hdr->opcode = cpu_to_le16(opcode); + hdr->plen = plen; + + if (plen) + memcpy(skb_put(skb, plen), param, plen); + + BT_DBG("skb len %d", skb->len); + + bt_cb(skb)->pkt_type = HCI_COMMAND_PKT; + bt_cb(skb)->opcode = opcode; + + return skb; +} + +/* Queue a command to an asynchronous HCI request */ +void hci_req_add_ev(struct hci_request *req, u16 opcode, u32 plen, + const void *param, u8 event) +{ + struct hci_dev *hdev = req->hdev; + struct sk_buff *skb; + + BT_DBG("%s opcode 0x%4.4x plen %d", hdev->name, opcode, plen); + + /* If an error occurred during request building, there is no point in + * queueing the HCI command. We can simply return. + */ + if (req->err) + return; + + skb = hci_prepare_cmd(hdev, opcode, plen, param); + if (!skb) { + BT_ERR("%s no memory for command (opcode 0x%4.4x)", + hdev->name, opcode); + req->err = -ENOMEM; + return; + } + + if (skb_queue_empty(&req->cmd_q)) + bt_cb(skb)->req.start = true; + + bt_cb(skb)->req.event = event; + + skb_queue_tail(&req->cmd_q, skb); +} + +void hci_req_add(struct hci_request *req, u16 opcode, u32 plen, + const void *param) +{ + hci_req_add_ev(req, opcode, plen, param, 0); +} + +void hci_req_add_le_scan_disable(struct hci_request *req) +{ + struct hci_cp_le_set_scan_enable cp; + + memset(&cp, 0, sizeof(cp)); + cp.enable = LE_SCAN_DISABLE; + hci_req_add(req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp); +} + +static void add_to_white_list(struct hci_request *req, + struct hci_conn_params *params) +{ + struct hci_cp_le_add_to_white_list cp; + + cp.bdaddr_type = params->addr_type; + bacpy(&cp.bdaddr, ¶ms->addr); + + hci_req_add(req, HCI_OP_LE_ADD_TO_WHITE_LIST, sizeof(cp), &cp); +} + +static u8 update_white_list(struct hci_request *req) +{ + struct hci_dev *hdev = req->hdev; + struct hci_conn_params *params; + struct bdaddr_list *b; + uint8_t white_list_entries = 0; + + /* Go through the current white list programmed into the + * controller one by one and check if that address is still + * in the list of pending connections or list of devices to + * report. If not present in either list, then queue the + * command to remove it from the controller. + */ + list_for_each_entry(b, &hdev->le_white_list, list) { + struct hci_cp_le_del_from_white_list cp; + + if (hci_pend_le_action_lookup(&hdev->pend_le_conns, + &b->bdaddr, b->bdaddr_type) || + hci_pend_le_action_lookup(&hdev->pend_le_reports, + &b->bdaddr, b->bdaddr_type)) { + white_list_entries++; + continue; + } + + cp.bdaddr_type = b->bdaddr_type; + bacpy(&cp.bdaddr, &b->bdaddr); + + hci_req_add(req, HCI_OP_LE_DEL_FROM_WHITE_LIST, + sizeof(cp), &cp); + } + + /* Since all no longer valid white list entries have been + * removed, walk through the list of pending connections + * and ensure that any new device gets programmed into + * the controller. + * + * If the list of the devices is larger than the list of + * available white list entries in the controller, then + * just abort and return filer policy value to not use the + * white list. + */ + list_for_each_entry(params, &hdev->pend_le_conns, action) { + if (hci_bdaddr_list_lookup(&hdev->le_white_list, + ¶ms->addr, params->addr_type)) + continue; + + if (white_list_entries >= hdev->le_white_list_size) { + /* Select filter policy to accept all advertising */ + return 0x00; + } + + if (hci_find_irk_by_addr(hdev, ¶ms->addr, + params->addr_type)) { + /* White list can not be used with RPAs */ + return 0x00; + } + + white_list_entries++; + add_to_white_list(req, params); + } + + /* After adding all new pending connections, walk through + * the list of pending reports and also add these to the + * white list if there is still space. + */ + list_for_each_entry(params, &hdev->pend_le_reports, action) { + if (hci_bdaddr_list_lookup(&hdev->le_white_list, + ¶ms->addr, params->addr_type)) + continue; + + if (white_list_entries >= hdev->le_white_list_size) { + /* Select filter policy to accept all advertising */ + return 0x00; + } + + if (hci_find_irk_by_addr(hdev, ¶ms->addr, + params->addr_type)) { + /* White list can not be used with RPAs */ + return 0x00; + } + + white_list_entries++; + add_to_white_list(req, params); + } + + /* Select filter policy to use white list */ + return 0x01; +} + +void hci_req_add_le_passive_scan(struct hci_request *req) +{ + struct hci_cp_le_set_scan_param param_cp; + struct hci_cp_le_set_scan_enable enable_cp; + struct hci_dev *hdev = req->hdev; + u8 own_addr_type; + u8 filter_policy; + + /* Set require_privacy to false since no SCAN_REQ are send + * during passive scanning. Not using an non-resolvable address + * here is important so that peer devices using direct + * advertising with our address will be correctly reported + * by the controller. + */ + if (hci_update_random_address(req, false, &own_addr_type)) + return; + + /* Adding or removing entries from the white list must + * happen before enabling scanning. The controller does + * not allow white list modification while scanning. + */ + filter_policy = update_white_list(req); + + /* When the controller is using random resolvable addresses and + * with that having LE privacy enabled, then controllers with + * Extended Scanner Filter Policies support can now enable support + * for handling directed advertising. + * + * So instead of using filter polices 0x00 (no whitelist) + * and 0x01 (whitelist enabled) use the new filter policies + * 0x02 (no whitelist) and 0x03 (whitelist enabled). + */ + if (test_bit(HCI_PRIVACY, &hdev->dev_flags) && + (hdev->le_features[0] & HCI_LE_EXT_SCAN_POLICY)) + filter_policy |= 0x02; + + memset(¶m_cp, 0, sizeof(param_cp)); + param_cp.type = LE_SCAN_PASSIVE; + param_cp.interval = cpu_to_le16(hdev->le_scan_interval); + param_cp.window = cpu_to_le16(hdev->le_scan_window); + param_cp.own_address_type = own_addr_type; + param_cp.filter_policy = filter_policy; + hci_req_add(req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp), + ¶m_cp); + + memset(&enable_cp, 0, sizeof(enable_cp)); + enable_cp.enable = LE_SCAN_ENABLE; + enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE; + hci_req_add(req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp), + &enable_cp); +} + +static void set_random_addr(struct hci_request *req, bdaddr_t *rpa) +{ + struct hci_dev *hdev = req->hdev; + + /* If we're advertising or initiating an LE connection we can't + * go ahead and change the random address at this time. This is + * because the eventual initiator address used for the + * subsequently created connection will be undefined (some + * controllers use the new address and others the one we had + * when the operation started). + * + * In this kind of scenario skip the update and let the random + * address be updated at the next cycle. + */ + if (test_bit(HCI_LE_ADV, &hdev->dev_flags) || + hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT)) { + BT_DBG("Deferring random address update"); + set_bit(HCI_RPA_EXPIRED, &hdev->dev_flags); + return; + } + + hci_req_add(req, HCI_OP_LE_SET_RANDOM_ADDR, 6, rpa); +} + +int hci_update_random_address(struct hci_request *req, bool require_privacy, + u8 *own_addr_type) +{ + struct hci_dev *hdev = req->hdev; + int err; + + /* If privacy is enabled use a resolvable private address. If + * current RPA has expired or there is something else than + * the current RPA in use, then generate a new one. + */ + if (test_bit(HCI_PRIVACY, &hdev->dev_flags)) { + int to; + + *own_addr_type = ADDR_LE_DEV_RANDOM; + + if (!test_and_clear_bit(HCI_RPA_EXPIRED, &hdev->dev_flags) && + !bacmp(&hdev->random_addr, &hdev->rpa)) + return 0; + + err = smp_generate_rpa(hdev, hdev->irk, &hdev->rpa); + if (err < 0) { + BT_ERR("%s failed to generate new RPA", hdev->name); + return err; + } + + set_random_addr(req, &hdev->rpa); + + to = msecs_to_jiffies(hdev->rpa_timeout * 1000); + queue_delayed_work(hdev->workqueue, &hdev->rpa_expired, to); + + return 0; + } + + /* In case of required privacy without resolvable private address, + * use an non-resolvable private address. This is useful for active + * scanning and non-connectable advertising. + */ + if (require_privacy) { + bdaddr_t nrpa; + + while (true) { + /* The non-resolvable private address is generated + * from random six bytes with the two most significant + * bits cleared. + */ + get_random_bytes(&nrpa, 6); + nrpa.b[5] &= 0x3f; + + /* The non-resolvable private address shall not be + * equal to the public address. + */ + if (bacmp(&hdev->bdaddr, &nrpa)) + break; + } + + *own_addr_type = ADDR_LE_DEV_RANDOM; + set_random_addr(req, &nrpa); + return 0; + } + + /* If forcing static address is in use or there is no public + * address use the static address as random address (but skip + * the HCI command if the current random address is already the + * static one. + */ + if (test_bit(HCI_FORCE_STATIC_ADDR, &hdev->dbg_flags) || + !bacmp(&hdev->bdaddr, BDADDR_ANY)) { + *own_addr_type = ADDR_LE_DEV_RANDOM; + if (bacmp(&hdev->static_addr, &hdev->random_addr)) + hci_req_add(req, HCI_OP_LE_SET_RANDOM_ADDR, 6, + &hdev->static_addr); + return 0; + } + + /* Neither privacy nor static address is being used so use a + * public address. + */ + *own_addr_type = ADDR_LE_DEV_PUBLIC; + + return 0; +} -- cgit v1.2.3 From 2cf22218b00f46f93b39a9355b830e9e8e4fd077 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 19 Dec 2014 22:26:00 +0200 Subject: Bluetooth: Add hci_request support for hci_update_background_scan Many places using hci_update_background_scan() try to synchronize whatever they're doing with the help of hci_request callbacks. However, since the hci_update_background_scan() function hasn't so far accepted a hci_request pointer any commands triggered by it have been left out by the synchronization. This patch modifies the API in a similar way as was done for hci_update_page_scan, i.e. there's a variant that takes a hci_request and another one that takes a hci_dev. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 2 - net/bluetooth/hci_core.c | 89 ------------------------------------- net/bluetooth/hci_request.c | 96 ++++++++++++++++++++++++++++++++++++++++ net/bluetooth/hci_request.h | 3 ++ net/bluetooth/mgmt.c | 12 ++--- 5 files changed, 105 insertions(+), 97 deletions(-) (limited to 'net/bluetooth/hci_request.c') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 93066f70f8ab..8eccdf029500 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -930,8 +930,6 @@ struct hci_conn_params *hci_pend_le_action_lookup(struct list_head *list, bdaddr_t *addr, u8 addr_type); -void hci_update_background_scan(struct hci_dev *hdev); - void hci_uuids_clear(struct hci_dev *hdev); void hci_link_keys_clear(struct hci_dev *hdev); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 2cfaaa6acb04..def6fba01b45 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -5312,95 +5312,6 @@ static void hci_cmd_work(struct work_struct *work) } } -static void update_background_scan_complete(struct hci_dev *hdev, u8 status) -{ - if (status) - BT_DBG("HCI request failed to update background scanning: " - "status 0x%2.2x", status); -} - -/* This function controls the background scanning based on hdev->pend_le_conns - * list. If there are pending LE connection we start the background scanning, - * otherwise we stop it. - * - * This function requires the caller holds hdev->lock. - */ -void hci_update_background_scan(struct hci_dev *hdev) -{ - struct hci_request req; - struct hci_conn *conn; - int err; - - if (!test_bit(HCI_UP, &hdev->flags) || - test_bit(HCI_INIT, &hdev->flags) || - test_bit(HCI_SETUP, &hdev->dev_flags) || - test_bit(HCI_CONFIG, &hdev->dev_flags) || - test_bit(HCI_AUTO_OFF, &hdev->dev_flags) || - test_bit(HCI_UNREGISTER, &hdev->dev_flags)) - return; - - /* No point in doing scanning if LE support hasn't been enabled */ - if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) - return; - - /* If discovery is active don't interfere with it */ - if (hdev->discovery.state != DISCOVERY_STOPPED) - return; - - /* Reset RSSI and UUID filters when starting background scanning - * since these filters are meant for service discovery only. - * - * The Start Discovery and Start Service Discovery operations - * ensure to set proper values for RSSI threshold and UUID - * filter list. So it is safe to just reset them here. - */ - hci_discovery_filter_clear(hdev); - - hci_req_init(&req, hdev); - - if (list_empty(&hdev->pend_le_conns) && - list_empty(&hdev->pend_le_reports)) { - /* If there is no pending LE connections or devices - * to be scanned for, we should stop the background - * scanning. - */ - - /* If controller is not scanning we are done. */ - if (!test_bit(HCI_LE_SCAN, &hdev->dev_flags)) - return; - - hci_req_add_le_scan_disable(&req); - - BT_DBG("%s stopping background scanning", hdev->name); - } else { - /* If there is at least one pending LE connection, we should - * keep the background scan running. - */ - - /* If controller is connecting, we should not start scanning - * since some controllers are not able to scan and connect at - * the same time. - */ - conn = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT); - if (conn) - return; - - /* If controller is currently scanning, we stop it to ensure we - * don't miss any advertising (due to duplicates filter). - */ - if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) - hci_req_add_le_scan_disable(&req); - - hci_req_add_le_passive_scan(&req); - - BT_DBG("%s starting background scanning", hdev->name); - } - - err = hci_req_run(&req, update_background_scan_complete); - if (err) - BT_ERR("Failed to run HCI request: err %d", err); -} - static bool disconnected_whitelist_entries(struct hci_dev *hdev) { struct bdaddr_list *b; diff --git a/net/bluetooth/hci_request.c b/net/bluetooth/hci_request.c index eba83a2a6556..e49f682f1550 100644 --- a/net/bluetooth/hci_request.c +++ b/net/bluetooth/hci_request.c @@ -395,3 +395,99 @@ int hci_update_random_address(struct hci_request *req, bool require_privacy, return 0; } + +/* This function controls the background scanning based on hdev->pend_le_conns + * list. If there are pending LE connection we start the background scanning, + * otherwise we stop it. + * + * This function requires the caller holds hdev->lock. + */ +void __hci_update_background_scan(struct hci_request *req) +{ + struct hci_dev *hdev = req->hdev; + struct hci_conn *conn; + + if (!test_bit(HCI_UP, &hdev->flags) || + test_bit(HCI_INIT, &hdev->flags) || + test_bit(HCI_SETUP, &hdev->dev_flags) || + test_bit(HCI_CONFIG, &hdev->dev_flags) || + test_bit(HCI_AUTO_OFF, &hdev->dev_flags) || + test_bit(HCI_UNREGISTER, &hdev->dev_flags)) + return; + + /* No point in doing scanning if LE support hasn't been enabled */ + if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) + return; + + /* If discovery is active don't interfere with it */ + if (hdev->discovery.state != DISCOVERY_STOPPED) + return; + + /* Reset RSSI and UUID filters when starting background scanning + * since these filters are meant for service discovery only. + * + * The Start Discovery and Start Service Discovery operations + * ensure to set proper values for RSSI threshold and UUID + * filter list. So it is safe to just reset them here. + */ + hci_discovery_filter_clear(hdev); + + if (list_empty(&hdev->pend_le_conns) && + list_empty(&hdev->pend_le_reports)) { + /* If there is no pending LE connections or devices + * to be scanned for, we should stop the background + * scanning. + */ + + /* If controller is not scanning we are done. */ + if (!test_bit(HCI_LE_SCAN, &hdev->dev_flags)) + return; + + hci_req_add_le_scan_disable(req); + + BT_DBG("%s stopping background scanning", hdev->name); + } else { + /* If there is at least one pending LE connection, we should + * keep the background scan running. + */ + + /* If controller is connecting, we should not start scanning + * since some controllers are not able to scan and connect at + * the same time. + */ + conn = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT); + if (conn) + return; + + /* If controller is currently scanning, we stop it to ensure we + * don't miss any advertising (due to duplicates filter). + */ + if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) + hci_req_add_le_scan_disable(req); + + hci_req_add_le_passive_scan(req); + + BT_DBG("%s starting background scanning", hdev->name); + } +} + +static void update_background_scan_complete(struct hci_dev *hdev, u8 status) +{ + if (status) + BT_DBG("HCI request failed to update background scanning: " + "status 0x%2.2x", status); +} + +void hci_update_background_scan(struct hci_dev *hdev) +{ + int err; + struct hci_request req; + + hci_req_init(&req, hdev); + + __hci_update_background_scan(&req); + + err = hci_req_run(&req, update_background_scan_complete); + if (err && err != -ENODATA) + BT_ERR("Failed to run HCI request: err %d", err); +} diff --git a/net/bluetooth/hci_request.h b/net/bluetooth/hci_request.h index 1793a46fea65..adf074d33544 100644 --- a/net/bluetooth/hci_request.h +++ b/net/bluetooth/hci_request.h @@ -49,3 +49,6 @@ void __hci_update_page_scan(struct hci_request *req); int hci_update_random_address(struct hci_request *req, bool require_privacy, u8 *own_addr_type); + +void hci_update_background_scan(struct hci_dev *hdev); +void __hci_update_background_scan(struct hci_request *req); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 95473e966703..3afe1e175eb8 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2228,9 +2228,8 @@ static void le_enable_complete(struct hci_dev *hdev, u8 status) hci_req_init(&req, hdev); update_adv_data(&req); update_scan_rsp_data(&req); + __hci_update_background_scan(&req); hci_req_run(&req, NULL); - - hci_update_background_scan(hdev); } unlock: @@ -6038,8 +6037,9 @@ void mgmt_index_removed(struct hci_dev *hdev) } /* This function requires the caller holds hdev->lock */ -static void restart_le_actions(struct hci_dev *hdev) +static void restart_le_actions(struct hci_request *req) { + struct hci_dev *hdev = req->hdev; struct hci_conn_params *p; list_for_each_entry(p, &hdev->le_conn_params, list) { @@ -6061,7 +6061,7 @@ static void restart_le_actions(struct hci_dev *hdev) } } - hci_update_background_scan(hdev); + __hci_update_background_scan(req); } static void powered_complete(struct hci_dev *hdev, u8 status) @@ -6072,8 +6072,6 @@ static void powered_complete(struct hci_dev *hdev, u8 status) hci_dev_lock(hdev); - restart_le_actions(hdev); - mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match); new_settings(hdev, match.sk); @@ -6131,6 +6129,8 @@ static int powered_update_hci(struct hci_dev *hdev) if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) enable_advertising(&req); + + restart_le_actions(&req); } link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags); -- cgit v1.2.3 From 405a26110a735b88963875459efe63f4d274f49d Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 19 Dec 2014 23:18:22 +0200 Subject: Bluetooth: Move hci_update_page_scan to hci_request.c This is a left-over from the patch that created hci_request.c. The hci_update_page_scan functions should have been moved from hci_core.c there. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 56 --------------------------------------------- net/bluetooth/hci_request.c | 56 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 56 deletions(-) (limited to 'net/bluetooth/hci_request.c') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index ee2096c7ec2c..9790a0108e69 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -5253,59 +5253,3 @@ static void hci_cmd_work(struct work_struct *work) } } } - -static bool disconnected_whitelist_entries(struct hci_dev *hdev) -{ - struct bdaddr_list *b; - - list_for_each_entry(b, &hdev->whitelist, list) { - struct hci_conn *conn; - - conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &b->bdaddr); - if (!conn) - return true; - - if (conn->state != BT_CONNECTED && conn->state != BT_CONFIG) - return true; - } - - return false; -} - -void __hci_update_page_scan(struct hci_request *req) -{ - struct hci_dev *hdev = req->hdev; - u8 scan; - - if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) - return; - - if (!hdev_is_powered(hdev)) - return; - - if (mgmt_powering_down(hdev)) - return; - - if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags) || - disconnected_whitelist_entries(hdev)) - scan = SCAN_PAGE; - else - scan = SCAN_DISABLED; - - if (test_bit(HCI_PSCAN, &hdev->flags) == !!(scan & SCAN_PAGE)) - return; - - if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) - scan |= SCAN_INQUIRY; - - hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan); -} - -void hci_update_page_scan(struct hci_dev *hdev) -{ - struct hci_request req; - - hci_req_init(&req, hdev); - __hci_update_page_scan(&req); - hci_req_run(&req, NULL); -} diff --git a/net/bluetooth/hci_request.c b/net/bluetooth/hci_request.c index e49f682f1550..5e64ea70a106 100644 --- a/net/bluetooth/hci_request.c +++ b/net/bluetooth/hci_request.c @@ -396,6 +396,62 @@ int hci_update_random_address(struct hci_request *req, bool require_privacy, return 0; } +static bool disconnected_whitelist_entries(struct hci_dev *hdev) +{ + struct bdaddr_list *b; + + list_for_each_entry(b, &hdev->whitelist, list) { + struct hci_conn *conn; + + conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &b->bdaddr); + if (!conn) + return true; + + if (conn->state != BT_CONNECTED && conn->state != BT_CONFIG) + return true; + } + + return false; +} + +void __hci_update_page_scan(struct hci_request *req) +{ + struct hci_dev *hdev = req->hdev; + u8 scan; + + if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) + return; + + if (!hdev_is_powered(hdev)) + return; + + if (mgmt_powering_down(hdev)) + return; + + if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags) || + disconnected_whitelist_entries(hdev)) + scan = SCAN_PAGE; + else + scan = SCAN_DISABLED; + + if (test_bit(HCI_PSCAN, &hdev->flags) == !!(scan & SCAN_PAGE)) + return; + + if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) + scan |= SCAN_INQUIRY; + + hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan); +} + +void hci_update_page_scan(struct hci_dev *hdev) +{ + struct hci_request req; + + hci_req_init(&req, hdev); + __hci_update_page_scan(&req); + hci_req_run(&req, NULL); +} + /* This function controls the background scanning based on hdev->pend_le_conns * list. If there are pending LE connection we start the background scanning, * otherwise we stop it. -- cgit v1.2.3 From 50b5b952b7c2bf2c75c257a62a6c456a0bbfdfa3 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 19 Dec 2014 23:05:35 +0100 Subject: Bluetooth: Support static address when BR/EDR has been disabled Every BR/EDR/LE dual-mode controller requires to have a public address and so far that has become the identity address and own address. The only way to change that behavior was with a force_static_address debugfs option. However the host can actually disable the BR/EDR part of a dual-mode controller and turn into a single mode LE controller. In that case it makes perfect sense for a host to use a chosen static address instead of the public address. So if the host disables BR/EDR and configures a static address, then that static address is used as identity address and own address. If the host does not configure a static address, then the public address is used as before. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 8 +++++++- net/bluetooth/hci_request.c | 8 +++++++- 2 files changed, 14 insertions(+), 2 deletions(-) (limited to 'net/bluetooth/hci_request.c') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 9790a0108e69..91dca121dbb6 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3852,12 +3852,18 @@ static void le_scan_disable_work(struct work_struct *work) * * For debugging purposes it is possible to force controllers with a * public address to use the static random address instead. + * + * In case BR/EDR has been disabled on a dual-mode controller and + * userspace has configured a static address, then that address + * becomes the identity address instead of the public BR/EDR address. */ void hci_copy_identity_address(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *bdaddr_type) { if (test_bit(HCI_FORCE_STATIC_ADDR, &hdev->dbg_flags) || - !bacmp(&hdev->bdaddr, BDADDR_ANY)) { + !bacmp(&hdev->bdaddr, BDADDR_ANY) || + (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) && + bacmp(&hdev->static_addr, BDADDR_ANY))) { bacpy(bdaddr, &hdev->static_addr); *bdaddr_type = ADDR_LE_DEV_RANDOM; } else { diff --git a/net/bluetooth/hci_request.c b/net/bluetooth/hci_request.c index 5e64ea70a106..324c6418b17c 100644 --- a/net/bluetooth/hci_request.c +++ b/net/bluetooth/hci_request.c @@ -378,9 +378,15 @@ int hci_update_random_address(struct hci_request *req, bool require_privacy, * address use the static address as random address (but skip * the HCI command if the current random address is already the * static one. + * + * In case BR/EDR has been disabled on a dual-mode controller + * and a static address has been configured, then use that + * address instead of the public BR/EDR address. */ if (test_bit(HCI_FORCE_STATIC_ADDR, &hdev->dbg_flags) || - !bacmp(&hdev->bdaddr, BDADDR_ANY)) { + !bacmp(&hdev->bdaddr, BDADDR_ANY) || + (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) && + bacmp(&hdev->static_addr, BDADDR_ANY))) { *own_addr_type = ADDR_LE_DEV_RANDOM; if (bacmp(&hdev->static_addr, &hdev->random_addr)) hci_req_add(req, HCI_OP_LE_SET_RANDOM_ADDR, 6, -- cgit v1.2.3 From 1904a853fae40ee61bed7c231fc5bd2158984441 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 11 Jan 2015 13:50:44 -0800 Subject: Bluetooth: Add opcode parameter to hci_req_complete_t callback When hci_req_run() calls its provided complete function and one of the HCI commands in the sequence fails, then provide the opcode of failing command. In case of success HCI_OP_NOP is provided since all commands completed. This patch fixes the prototype of hci_req_complete_t and all its users. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/bluetooth.h | 2 +- net/bluetooth/hci_conn.c | 2 +- net/bluetooth/hci_core.c | 9 ++++---- net/bluetooth/hci_request.c | 3 ++- net/bluetooth/mgmt.c | 44 ++++++++++++++++++++++----------------- 5 files changed, 34 insertions(+), 26 deletions(-) (limited to 'net/bluetooth/hci_request.c') diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index 58695ffeb138..e00455aab18c 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -273,7 +273,7 @@ struct l2cap_ctrl { struct hci_dev; -typedef void (*hci_req_complete_t)(struct hci_dev *hdev, u8 status); +typedef void (*hci_req_complete_t)(struct hci_dev *hdev, u8 status, u16 opcode); struct hci_req_ctrl { bool start; diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 75240aaca101..2e724e0b75b9 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -633,7 +633,7 @@ void hci_le_conn_failed(struct hci_conn *conn, u8 status) mgmt_reenable_advertising(hdev); } -static void create_le_conn_complete(struct hci_dev *hdev, u8 status) +static void create_le_conn_complete(struct hci_dev *hdev, u8 status, u16 opcode) { struct hci_conn *conn; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index bc5486ea5411..ba0d1fdccbd9 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -141,7 +141,7 @@ static const struct file_operations dut_mode_fops = { /* ---- HCI requests ---- */ -static void hci_req_sync_complete(struct hci_dev *hdev, u8 result) +static void hci_req_sync_complete(struct hci_dev *hdev, u8 result, u16 opcode) { BT_DBG("%s result 0x%2.2x", hdev->name, result); @@ -2754,7 +2754,7 @@ void hci_conn_params_clear_all(struct hci_dev *hdev) BT_DBG("All LE connection parameters were removed"); } -static void inquiry_complete(struct hci_dev *hdev, u8 status) +static void inquiry_complete(struct hci_dev *hdev, u8 status, u16 opcode) { if (status) { BT_ERR("Failed to start inquiry: status %d", status); @@ -2766,7 +2766,8 @@ static void inquiry_complete(struct hci_dev *hdev, u8 status) } } -static void le_scan_disable_work_complete(struct hci_dev *hdev, u8 status) +static void le_scan_disable_work_complete(struct hci_dev *hdev, u8 status, + u16 opcode) { /* General inquiry access code (GIAC) */ u8 lap[3] = { 0x33, 0x8b, 0x9e }; @@ -4159,7 +4160,7 @@ void hci_req_cmd_complete(struct hci_dev *hdev, u16 opcode, u8 status) call_complete: if (req_complete) - req_complete(hdev, status); + req_complete(hdev, status, status ? opcode : HCI_OP_NOP); } static void hci_rx_work(struct work_struct *work) diff --git a/net/bluetooth/hci_request.c b/net/bluetooth/hci_request.c index 324c6418b17c..b59f92c6df0c 100644 --- a/net/bluetooth/hci_request.c +++ b/net/bluetooth/hci_request.c @@ -533,7 +533,8 @@ void __hci_update_background_scan(struct hci_request *req) } } -static void update_background_scan_complete(struct hci_dev *hdev, u8 status) +static void update_background_scan_complete(struct hci_dev *hdev, u8 status, + u16 opcode) { if (status) BT_DBG("HCI request failed to update background scanning: " diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 6b3f5537e441..e531da805923 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1251,7 +1251,7 @@ static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev) sizeof(settings)); } -static void clean_up_hci_complete(struct hci_dev *hdev, u8 status) +static void clean_up_hci_complete(struct hci_dev *hdev, u8 status, u16 opcode) { BT_DBG("%s status 0x%02x", hdev->name, status); @@ -1518,7 +1518,8 @@ static u8 mgmt_le_support(struct hci_dev *hdev) return MGMT_STATUS_SUCCESS; } -static void set_discoverable_complete(struct hci_dev *hdev, u8 status) +static void set_discoverable_complete(struct hci_dev *hdev, u8 status, + u16 opcode) { struct pending_cmd *cmd; struct mgmt_mode *cp; @@ -1777,7 +1778,8 @@ static void write_fast_connectable(struct hci_request *req, bool enable) hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type); } -static void set_connectable_complete(struct hci_dev *hdev, u8 status) +static void set_connectable_complete(struct hci_dev *hdev, u8 status, + u16 opcode) { struct pending_cmd *cmd; struct mgmt_mode *cp; @@ -2195,7 +2197,7 @@ unlock: return err; } -static void le_enable_complete(struct hci_dev *hdev, u8 status) +static void le_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode) { struct cmd_lookup match = { NULL, hdev }; @@ -2385,7 +2387,7 @@ unlock: hci_dev_unlock(hdev); } -static void add_uuid_complete(struct hci_dev *hdev, u8 status) +static void add_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode) { BT_DBG("status 0x%02x", status); @@ -2464,7 +2466,7 @@ static bool enable_service_cache(struct hci_dev *hdev) return false; } -static void remove_uuid_complete(struct hci_dev *hdev, u8 status) +static void remove_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode) { BT_DBG("status 0x%02x", status); @@ -2549,7 +2551,7 @@ unlock: return err; } -static void set_class_complete(struct hci_dev *hdev, u8 status) +static void set_class_complete(struct hci_dev *hdev, u8 status, u16 opcode) { BT_DBG("status 0x%02x", status); @@ -3483,7 +3485,7 @@ static void update_name(struct hci_request *req) hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp); } -static void set_name_complete(struct hci_dev *hdev, u8 status) +static void set_name_complete(struct hci_dev *hdev, u8 status, u16 opcode) { struct mgmt_cp_set_local_name *cp; struct pending_cmd *cmd; @@ -3834,7 +3836,8 @@ static bool trigger_discovery(struct hci_request *req, u8 *status) return true; } -static void start_discovery_complete(struct hci_dev *hdev, u8 status) +static void start_discovery_complete(struct hci_dev *hdev, u8 status, + u16 opcode) { struct pending_cmd *cmd; unsigned long timeout; @@ -4063,7 +4066,7 @@ failed: return err; } -static void stop_discovery_complete(struct hci_dev *hdev, u8 status) +static void stop_discovery_complete(struct hci_dev *hdev, u8 status, u16 opcode) { struct pending_cmd *cmd; @@ -4289,7 +4292,8 @@ static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data, return err; } -static void set_advertising_complete(struct hci_dev *hdev, u8 status) +static void set_advertising_complete(struct hci_dev *hdev, u8 status, + u16 opcode) { struct cmd_lookup match = { NULL, hdev }; @@ -4496,7 +4500,8 @@ static int set_scan_params(struct sock *sk, struct hci_dev *hdev, return err; } -static void fast_connectable_complete(struct hci_dev *hdev, u8 status) +static void fast_connectable_complete(struct hci_dev *hdev, u8 status, + u16 opcode) { struct pending_cmd *cmd; @@ -4594,7 +4599,7 @@ unlock: return err; } -static void set_bredr_complete(struct hci_dev *hdev, u8 status) +static void set_bredr_complete(struct hci_dev *hdev, u8 status, u16 opcode) { struct pending_cmd *cmd; @@ -5119,7 +5124,8 @@ static int conn_info_cmd_complete(struct pending_cmd *cmd, u8 status) return err; } -static void conn_info_refresh_complete(struct hci_dev *hdev, u8 hci_status) +static void conn_info_refresh_complete(struct hci_dev *hdev, u8 hci_status, + u16 opcode) { struct hci_cp_read_rssi *cp; struct pending_cmd *cmd; @@ -5326,7 +5332,7 @@ complete: return err; } -static void get_clock_info_complete(struct hci_dev *hdev, u8 status) +static void get_clock_info_complete(struct hci_dev *hdev, u8 status, u16 opcode) { struct hci_cp_read_clock *hci_cp; struct pending_cmd *cmd; @@ -5504,7 +5510,7 @@ static void device_added(struct sock *sk, struct hci_dev *hdev, mgmt_event(MGMT_EV_DEVICE_ADDED, hdev, &ev, sizeof(ev), sk); } -static void add_device_complete(struct hci_dev *hdev, u8 status) +static void add_device_complete(struct hci_dev *hdev, u8 status, u16 opcode) { struct pending_cmd *cmd; @@ -5627,7 +5633,7 @@ static void device_removed(struct sock *sk, struct hci_dev *hdev, mgmt_event(MGMT_EV_DEVICE_REMOVED, hdev, &ev, sizeof(ev), sk); } -static void remove_device_complete(struct hci_dev *hdev, u8 status) +static void remove_device_complete(struct hci_dev *hdev, u8 status, u16 opcode) { struct pending_cmd *cmd; @@ -6205,7 +6211,7 @@ static void restart_le_actions(struct hci_request *req) __hci_update_background_scan(req); } -static void powered_complete(struct hci_dev *hdev, u8 status) +static void powered_complete(struct hci_dev *hdev, u8 status, u16 opcode) { struct cmd_lookup match = { NULL, hdev }; @@ -7316,7 +7322,7 @@ void mgmt_discovering(struct hci_dev *hdev, u8 discovering) mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL); } -static void adv_enable_complete(struct hci_dev *hdev, u8 status) +static void adv_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode) { BT_DBG("%s status %u", hdev->name, status); } -- cgit v1.2.3