diff options
author | David S. Miller <davem@davemloft.net> | 2014-12-16 23:16:48 +0300 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-12-16 23:16:48 +0300 |
commit | c9f2c3d36c10717159caae4b66410f74ce45d30c (patch) | |
tree | b691f572aecdefc2366380c3215a45dc2e91f3ad /net/bluetooth/mgmt.c | |
parent | 6539c44d08ac2eea693b6163135169b9c8c18bb1 (diff) | |
parent | 9a1dce3a059111a7289680f4b8c0ec4f8736b6ee (diff) | |
download | linux-c9f2c3d36c10717159caae4b66410f74ce45d30c.tar.xz |
Merge tag 'master-2014-12-15' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless
John W. Linville says:
====================
pull request: wireless 2014-12-16
Please pull this batch of fixes intended for the 3.19 stream!
For the Bluetooth bits, Johan says:
"The patches consist of:
- Coccinelle warning fix
- hci_dev_lock/unlock fixes
- Fixes for pending mgmt command handling
- Fixes for properly following the force_lesc_support switch
- Fix for a Microsoft branded Broadcom adapter
- New device id for Atheros AR3012
- Fix for BR/EDR Secure Connections enabling"
Along with that...
Brian Norris avoids leaking some kernel memory contents via printk in brcmsmac.
Julia Lawall corrects some misspellings in a few drivers.
Larry Finger gives us one more rtlwifi fix to correct a porting oversight.
Wei Yongjun fixes a sparse warning in rtlwifi.
Please let me know if there are problems!
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/bluetooth/mgmt.c')
-rw-r--r-- | net/bluetooth/mgmt.c | 85 |
1 files changed, 60 insertions, 25 deletions
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 7384f1161336..06c2e652e4b6 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2199,12 +2199,14 @@ static void le_enable_complete(struct hci_dev *hdev, u8 status) { struct cmd_lookup match = { NULL, hdev }; + hci_dev_lock(hdev); + if (status) { u8 mgmt_err = mgmt_status(status); mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp, &mgmt_err); - return; + goto unlock; } mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match); @@ -2222,17 +2224,16 @@ static void le_enable_complete(struct hci_dev *hdev, u8 status) if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) { struct hci_request req; - hci_dev_lock(hdev); - hci_req_init(&req, hdev); update_adv_data(&req); update_scan_rsp_data(&req); hci_req_run(&req, NULL); hci_update_background_scan(hdev); - - hci_dev_unlock(hdev); } + +unlock: + hci_dev_unlock(hdev); } static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) @@ -3114,14 +3115,13 @@ static void pairing_complete(struct pending_cmd *cmd, u8 status) conn->disconn_cfm_cb = NULL; hci_conn_drop(conn); - hci_conn_put(conn); - - mgmt_pending_remove(cmd); /* The device is paired so there is no need to remove * its connection parameters anymore. */ clear_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags); + + hci_conn_put(conn); } void mgmt_smp_complete(struct hci_conn *conn, bool complete) @@ -3130,8 +3130,10 @@ void mgmt_smp_complete(struct hci_conn *conn, bool complete) struct pending_cmd *cmd; cmd = find_pairing(conn); - if (cmd) + if (cmd) { cmd->cmd_complete(cmd, status); + mgmt_pending_remove(cmd); + } } static void pairing_complete_cb(struct hci_conn *conn, u8 status) @@ -3141,10 +3143,13 @@ static void pairing_complete_cb(struct hci_conn *conn, u8 status) BT_DBG("status %u", status); cmd = find_pairing(conn); - if (!cmd) + if (!cmd) { BT_DBG("Unable to find a pending command"); - else - cmd->cmd_complete(cmd, mgmt_status(status)); + return; + } + + cmd->cmd_complete(cmd, mgmt_status(status)); + mgmt_pending_remove(cmd); } static void le_pairing_complete_cb(struct hci_conn *conn, u8 status) @@ -3157,10 +3162,13 @@ static void le_pairing_complete_cb(struct hci_conn *conn, u8 status) return; cmd = find_pairing(conn); - if (!cmd) + if (!cmd) { BT_DBG("Unable to find a pending command"); - else - cmd->cmd_complete(cmd, mgmt_status(status)); + return; + } + + cmd->cmd_complete(cmd, mgmt_status(status)); + mgmt_pending_remove(cmd); } static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data, @@ -3274,8 +3282,10 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data, cmd->user_data = hci_conn_get(conn); if ((conn->state == BT_CONNECTED || conn->state == BT_CONFIG) && - hci_conn_security(conn, sec_level, auth_type, true)) - pairing_complete(cmd, 0); + hci_conn_security(conn, sec_level, auth_type, true)) { + cmd->cmd_complete(cmd, 0); + mgmt_pending_remove(cmd); + } err = 0; @@ -3317,7 +3327,8 @@ static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data, goto unlock; } - pairing_complete(cmd, MGMT_STATUS_CANCELLED); + cmd->cmd_complete(cmd, MGMT_STATUS_CANCELLED); + mgmt_pending_remove(cmd); err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0, addr, sizeof(*addr)); @@ -3791,7 +3802,7 @@ static bool trigger_discovery(struct hci_request *req, u8 *status) /* All active scans will be done with either a resolvable * private address (when privacy feature has been enabled) - * or unresolvable private address. + * or non-resolvable private address. */ err = hci_update_random_address(req, true, &own_addr_type); if (err < 0) { @@ -4279,12 +4290,14 @@ static void set_advertising_complete(struct hci_dev *hdev, u8 status) { struct cmd_lookup match = { NULL, hdev }; + hci_dev_lock(hdev); + if (status) { u8 mgmt_err = mgmt_status(status); mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, cmd_status_rsp, &mgmt_err); - return; + goto unlock; } if (test_bit(HCI_LE_ADV, &hdev->dev_flags)) @@ -4299,6 +4312,9 @@ static void set_advertising_complete(struct hci_dev *hdev, u8 status) if (match.sk) sock_put(match.sk); + +unlock: + hci_dev_unlock(hdev); } static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data, @@ -6081,6 +6097,11 @@ static int powered_update_hci(struct hci_dev *hdev) hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, 1, &ssp); } + if (bredr_sc_enabled(hdev) && !lmp_host_sc_capable(hdev)) { + u8 sc = 0x01; + hci_req_add(&req, HCI_OP_WRITE_SC_SUPPORT, sizeof(sc), &sc); + } + if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags) && lmp_bredr_capable(hdev)) { struct hci_cp_write_le_host_supported cp; @@ -6130,8 +6151,7 @@ static int powered_update_hci(struct hci_dev *hdev) int mgmt_powered(struct hci_dev *hdev, u8 powered) { struct cmd_lookup match = { NULL, hdev }; - u8 status_not_powered = MGMT_STATUS_NOT_POWERED; - u8 zero_cod[] = { 0, 0, 0 }; + u8 status, zero_cod[] = { 0, 0, 0 }; int err; if (!test_bit(HCI_MGMT, &hdev->dev_flags)) @@ -6147,7 +6167,20 @@ int mgmt_powered(struct hci_dev *hdev, u8 powered) } mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match); - mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status_not_powered); + + /* If the power off is because of hdev unregistration let + * use the appropriate INVALID_INDEX status. Otherwise use + * NOT_POWERED. We cover both scenarios here since later in + * mgmt_index_removed() any hci_conn callbacks will have already + * been triggered, potentially causing misleading DISCONNECTED + * status responses. + */ + if (test_bit(HCI_UNREGISTER, &hdev->dev_flags)) + status = MGMT_STATUS_INVALID_INDEX; + else + status = MGMT_STATUS_NOT_POWERED; + + mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status); if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0) mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, @@ -6681,8 +6714,10 @@ void mgmt_auth_failed(struct hci_conn *conn, u8 hci_status) mgmt_event(MGMT_EV_AUTH_FAILED, conn->hdev, &ev, sizeof(ev), cmd ? cmd->sk : NULL); - if (cmd) - pairing_complete(cmd, status); + if (cmd) { + cmd->cmd_complete(cmd, status); + mgmt_pending_remove(cmd); + } } void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status) |