diff options
Diffstat (limited to 'net')
| -rw-r--r-- | net/bluetooth/hci_core.c | 21 | ||||
| -rw-r--r-- | net/bluetooth/hci_request.c | 100 | ||||
| -rw-r--r-- | net/bluetooth/hci_request.h | 2 | ||||
| -rw-r--r-- | net/bluetooth/mgmt.c | 136 |
4 files changed, 126 insertions, 133 deletions
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 484c75f3332c..eac3f6fa1272 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c | |||
| @@ -1399,10 +1399,10 @@ static int hci_dev_do_open(struct hci_dev *hdev) | |||
| 1399 | !hci_dev_test_flag(hdev, HCI_CONFIG) && | 1399 | !hci_dev_test_flag(hdev, HCI_CONFIG) && |
| 1400 | !hci_dev_test_flag(hdev, HCI_UNCONFIGURED) && | 1400 | !hci_dev_test_flag(hdev, HCI_UNCONFIGURED) && |
| 1401 | !hci_dev_test_flag(hdev, HCI_USER_CHANNEL) && | 1401 | !hci_dev_test_flag(hdev, HCI_USER_CHANNEL) && |
| 1402 | hci_dev_test_flag(hdev, HCI_MGMT) && | ||
| 1402 | hdev->dev_type == HCI_BREDR) { | 1403 | hdev->dev_type == HCI_BREDR) { |
| 1403 | hci_dev_lock(hdev); | 1404 | ret = __hci_req_hci_power_on(hdev); |
| 1404 | mgmt_powered(hdev, 1); | 1405 | mgmt_power_on(hdev, ret); |
| 1405 | hci_dev_unlock(hdev); | ||
| 1406 | } | 1406 | } |
| 1407 | } else { | 1407 | } else { |
| 1408 | /* Init failed, cleanup */ | 1408 | /* Init failed, cleanup */ |
| @@ -1559,8 +1559,9 @@ int hci_dev_do_close(struct hci_dev *hdev) | |||
| 1559 | 1559 | ||
| 1560 | auto_off = hci_dev_test_and_clear_flag(hdev, HCI_AUTO_OFF); | 1560 | auto_off = hci_dev_test_and_clear_flag(hdev, HCI_AUTO_OFF); |
| 1561 | 1561 | ||
| 1562 | if (!auto_off && hdev->dev_type == HCI_BREDR) | 1562 | if (!auto_off && hdev->dev_type == HCI_BREDR && |
| 1563 | mgmt_powered(hdev, 0); | 1563 | hci_dev_test_flag(hdev, HCI_MGMT)) |
| 1564 | __mgmt_power_off(hdev); | ||
| 1564 | 1565 | ||
| 1565 | hci_inquiry_cache_flush(hdev); | 1566 | hci_inquiry_cache_flush(hdev); |
| 1566 | hci_pend_le_actions_clear(hdev); | 1567 | hci_pend_le_actions_clear(hdev); |
| @@ -2013,6 +2014,16 @@ static void hci_power_on(struct work_struct *work) | |||
| 2013 | 2014 | ||
| 2014 | BT_DBG("%s", hdev->name); | 2015 | BT_DBG("%s", hdev->name); |
| 2015 | 2016 | ||
| 2017 | if (test_bit(HCI_UP, &hdev->flags) && | ||
| 2018 | hci_dev_test_flag(hdev, HCI_MGMT) && | ||
| 2019 | hci_dev_test_and_clear_flag(hdev, HCI_AUTO_OFF)) { | ||
| 2020 | hci_req_sync_lock(hdev); | ||
| 2021 | err = __hci_req_hci_power_on(hdev); | ||
| 2022 | hci_req_sync_unlock(hdev); | ||
| 2023 | mgmt_power_on(hdev, err); | ||
| 2024 | return; | ||
| 2025 | } | ||
| 2026 | |||
| 2016 | err = hci_dev_do_open(hdev); | 2027 | err = hci_dev_do_open(hdev); |
| 2017 | if (err < 0) { | 2028 | if (err < 0) { |
| 2018 | hci_dev_lock(hdev); | 2029 | hci_dev_lock(hdev); |
diff --git a/net/bluetooth/hci_request.c b/net/bluetooth/hci_request.c index 0abd83ddd4fb..7cc24f1448bd 100644 --- a/net/bluetooth/hci_request.c +++ b/net/bluetooth/hci_request.c | |||
| @@ -2181,6 +2181,106 @@ static void discov_off(struct work_struct *work) | |||
| 2181 | mgmt_new_settings(hdev); | 2181 | mgmt_new_settings(hdev); |
| 2182 | } | 2182 | } |
| 2183 | 2183 | ||
| 2184 | static int powered_update_hci(struct hci_request *req, unsigned long opt) | ||
| 2185 | { | ||
| 2186 | struct hci_dev *hdev = req->hdev; | ||
| 2187 | struct adv_info *adv_instance; | ||
| 2188 | u8 link_sec; | ||
| 2189 | |||
| 2190 | hci_dev_lock(hdev); | ||
| 2191 | |||
| 2192 | if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED) && | ||
| 2193 | !lmp_host_ssp_capable(hdev)) { | ||
| 2194 | u8 mode = 0x01; | ||
| 2195 | |||
| 2196 | hci_req_add(req, HCI_OP_WRITE_SSP_MODE, sizeof(mode), &mode); | ||
| 2197 | |||
| 2198 | if (bredr_sc_enabled(hdev) && !lmp_host_sc_capable(hdev)) { | ||
| 2199 | u8 support = 0x01; | ||
| 2200 | |||
| 2201 | hci_req_add(req, HCI_OP_WRITE_SC_SUPPORT, | ||
| 2202 | sizeof(support), &support); | ||
| 2203 | } | ||
| 2204 | } | ||
| 2205 | |||
| 2206 | if (hci_dev_test_flag(hdev, HCI_LE_ENABLED) && | ||
| 2207 | lmp_bredr_capable(hdev)) { | ||
| 2208 | struct hci_cp_write_le_host_supported cp; | ||
| 2209 | |||
| 2210 | cp.le = 0x01; | ||
| 2211 | cp.simul = 0x00; | ||
| 2212 | |||
| 2213 | /* Check first if we already have the right | ||
| 2214 | * host state (host features set) | ||
| 2215 | */ | ||
| 2216 | if (cp.le != lmp_host_le_capable(hdev) || | ||
| 2217 | cp.simul != lmp_host_le_br_capable(hdev)) | ||
| 2218 | hci_req_add(req, HCI_OP_WRITE_LE_HOST_SUPPORTED, | ||
| 2219 | sizeof(cp), &cp); | ||
| 2220 | } | ||
| 2221 | |||
| 2222 | if (lmp_le_capable(hdev)) { | ||
| 2223 | /* Make sure the controller has a good default for | ||
| 2224 | * advertising data. This also applies to the case | ||
| 2225 | * where BR/EDR was toggled during the AUTO_OFF phase. | ||
| 2226 | */ | ||
| 2227 | if (hci_dev_test_flag(hdev, HCI_LE_ENABLED) && | ||
| 2228 | (hci_dev_test_flag(hdev, HCI_ADVERTISING) || | ||
| 2229 | !hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE))) { | ||
| 2230 | __hci_req_update_adv_data(req, HCI_ADV_CURRENT); | ||
| 2231 | __hci_req_update_scan_rsp_data(req, HCI_ADV_CURRENT); | ||
| 2232 | } | ||
| 2233 | |||
| 2234 | if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) && | ||
| 2235 | hdev->cur_adv_instance == 0x00 && | ||
| 2236 | !list_empty(&hdev->adv_instances)) { | ||
| 2237 | adv_instance = list_first_entry(&hdev->adv_instances, | ||
| 2238 | struct adv_info, list); | ||
| 2239 | hdev->cur_adv_instance = adv_instance->instance; | ||
| 2240 | } | ||
| 2241 | |||
| 2242 | if (hci_dev_test_flag(hdev, HCI_ADVERTISING)) | ||
| 2243 | __hci_req_enable_advertising(req); | ||
| 2244 | else if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) && | ||
| 2245 | hdev->cur_adv_instance) | ||
| 2246 | __hci_req_schedule_adv_instance(req, | ||
| 2247 | hdev->cur_adv_instance, | ||
| 2248 | true); | ||
| 2249 | } | ||
| 2250 | |||
| 2251 | link_sec = hci_dev_test_flag(hdev, HCI_LINK_SECURITY); | ||
| 2252 | if (link_sec != test_bit(HCI_AUTH, &hdev->flags)) | ||
| 2253 | hci_req_add(req, HCI_OP_WRITE_AUTH_ENABLE, | ||
| 2254 | sizeof(link_sec), &link_sec); | ||
| 2255 | |||
| 2256 | if (lmp_bredr_capable(hdev)) { | ||
| 2257 | if (hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE)) | ||
| 2258 | __hci_req_write_fast_connectable(req, true); | ||
| 2259 | else | ||
| 2260 | __hci_req_write_fast_connectable(req, false); | ||
| 2261 | __hci_req_update_scan(req); | ||
| 2262 | __hci_req_update_class(req); | ||
| 2263 | __hci_req_update_name(req); | ||
| 2264 | __hci_req_update_eir(req); | ||
| 2265 | } | ||
| 2266 | |||
| 2267 | hci_dev_unlock(hdev); | ||
| 2268 | return 0; | ||
| 2269 | } | ||
| 2270 | |||
| 2271 | int __hci_req_hci_power_on(struct hci_dev *hdev) | ||
| 2272 | { | ||
| 2273 | /* Register the available SMP channels (BR/EDR and LE) only when | ||
| 2274 | * successfully powering on the controller. This late | ||
| 2275 | * registration is required so that LE SMP can clearly decide if | ||
| 2276 | * the public address or static address is used. | ||
| 2277 | */ | ||
| 2278 | smp_register(hdev); | ||
| 2279 | |||
| 2280 | return __hci_req_sync(hdev, powered_update_hci, 0, HCI_CMD_TIMEOUT, | ||
| 2281 | NULL); | ||
| 2282 | } | ||
| 2283 | |||
| 2184 | void hci_request_setup(struct hci_dev *hdev) | 2284 | void hci_request_setup(struct hci_dev *hdev) |
| 2185 | { | 2285 | { |
| 2186 | INIT_WORK(&hdev->discov_update, discov_update); | 2286 | INIT_WORK(&hdev->discov_update, discov_update); |
diff --git a/net/bluetooth/hci_request.h b/net/bluetooth/hci_request.h index d3dd24deca74..a24d3b55094c 100644 --- a/net/bluetooth/hci_request.h +++ b/net/bluetooth/hci_request.h | |||
| @@ -55,6 +55,8 @@ void hci_req_sync_cancel(struct hci_dev *hdev, int err); | |||
| 55 | struct sk_buff *hci_prepare_cmd(struct hci_dev *hdev, u16 opcode, u32 plen, | 55 | struct sk_buff *hci_prepare_cmd(struct hci_dev *hdev, u16 opcode, u32 plen, |
| 56 | const void *param); | 56 | const void *param); |
| 57 | 57 | ||
| 58 | int __hci_req_hci_power_on(struct hci_dev *hdev); | ||
| 59 | |||
| 58 | void __hci_req_write_fast_connectable(struct hci_request *req, bool enable); | 60 | void __hci_req_write_fast_connectable(struct hci_request *req, bool enable); |
| 59 | void __hci_req_update_name(struct hci_request *req); | 61 | void __hci_req_update_name(struct hci_request *req); |
| 60 | void __hci_req_update_eir(struct hci_request *req); | 62 | void __hci_req_update_eir(struct hci_request *req); |
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 0a7e6f4de383..468402ad933c 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c | |||
| @@ -961,17 +961,6 @@ static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data, | |||
| 961 | goto failed; | 961 | goto failed; |
| 962 | } | 962 | } |
| 963 | 963 | ||
| 964 | if (hci_dev_test_and_clear_flag(hdev, HCI_AUTO_OFF)) { | ||
| 965 | cancel_delayed_work(&hdev->power_off); | ||
| 966 | |||
| 967 | if (cp->val) { | ||
| 968 | mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, | ||
| 969 | data, len); | ||
| 970 | err = mgmt_powered(hdev, 1); | ||
| 971 | goto failed; | ||
| 972 | } | ||
| 973 | } | ||
| 974 | |||
| 975 | if (!!cp->val == hdev_is_powered(hdev)) { | 964 | if (!!cp->val == hdev_is_powered(hdev)) { |
| 976 | err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev); | 965 | err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev); |
| 977 | goto failed; | 966 | goto failed; |
| @@ -6434,139 +6423,33 @@ static void restart_le_actions(struct hci_dev *hdev) | |||
| 6434 | } | 6423 | } |
| 6435 | } | 6424 | } |
| 6436 | 6425 | ||
| 6437 | static void powered_complete(struct hci_dev *hdev, u8 status, u16 opcode) | 6426 | void mgmt_power_on(struct hci_dev *hdev, int err) |
| 6438 | { | 6427 | { |
| 6439 | struct cmd_lookup match = { NULL, hdev }; | 6428 | struct cmd_lookup match = { NULL, hdev }; |
| 6440 | 6429 | ||
| 6441 | BT_DBG("status 0x%02x", status); | 6430 | BT_DBG("err %d", err); |
| 6442 | 6431 | ||
| 6443 | if (!status) { | 6432 | hci_dev_lock(hdev); |
| 6433 | |||
| 6434 | if (!err) { | ||
| 6444 | restart_le_actions(hdev); | 6435 | restart_le_actions(hdev); |
| 6445 | hci_update_background_scan(hdev); | 6436 | hci_update_background_scan(hdev); |
| 6446 | } | 6437 | } |
| 6447 | 6438 | ||
| 6448 | hci_dev_lock(hdev); | ||
| 6449 | |||
| 6450 | mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match); | 6439 | mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match); |
| 6451 | 6440 | ||
| 6452 | new_settings(hdev, match.sk); | 6441 | new_settings(hdev, match.sk); |
| 6453 | 6442 | ||
| 6454 | hci_dev_unlock(hdev); | ||
| 6455 | |||
| 6456 | if (match.sk) | 6443 | if (match.sk) |
| 6457 | sock_put(match.sk); | 6444 | sock_put(match.sk); |
| 6458 | } | ||
| 6459 | 6445 | ||
| 6460 | static int powered_update_hci(struct hci_dev *hdev) | 6446 | hci_dev_unlock(hdev); |
| 6461 | { | ||
| 6462 | struct hci_request req; | ||
| 6463 | struct adv_info *adv_instance; | ||
| 6464 | u8 link_sec; | ||
| 6465 | |||
| 6466 | hci_req_init(&req, hdev); | ||
| 6467 | |||
| 6468 | if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED) && | ||
| 6469 | !lmp_host_ssp_capable(hdev)) { | ||
| 6470 | u8 mode = 0x01; | ||
| 6471 | |||
| 6472 | hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, sizeof(mode), &mode); | ||
| 6473 | |||
| 6474 | if (bredr_sc_enabled(hdev) && !lmp_host_sc_capable(hdev)) { | ||
| 6475 | u8 support = 0x01; | ||
| 6476 | |||
| 6477 | hci_req_add(&req, HCI_OP_WRITE_SC_SUPPORT, | ||
| 6478 | sizeof(support), &support); | ||
| 6479 | } | ||
| 6480 | } | ||
| 6481 | |||
| 6482 | if (hci_dev_test_flag(hdev, HCI_LE_ENABLED) && | ||
| 6483 | lmp_bredr_capable(hdev)) { | ||
| 6484 | struct hci_cp_write_le_host_supported cp; | ||
| 6485 | |||
| 6486 | cp.le = 0x01; | ||
| 6487 | cp.simul = 0x00; | ||
| 6488 | |||
| 6489 | /* Check first if we already have the right | ||
| 6490 | * host state (host features set) | ||
| 6491 | */ | ||
| 6492 | if (cp.le != lmp_host_le_capable(hdev) || | ||
| 6493 | cp.simul != lmp_host_le_br_capable(hdev)) | ||
| 6494 | hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, | ||
| 6495 | sizeof(cp), &cp); | ||
| 6496 | } | ||
| 6497 | |||
| 6498 | if (lmp_le_capable(hdev)) { | ||
| 6499 | /* Make sure the controller has a good default for | ||
| 6500 | * advertising data. This also applies to the case | ||
| 6501 | * where BR/EDR was toggled during the AUTO_OFF phase. | ||
| 6502 | */ | ||
| 6503 | if (hci_dev_test_flag(hdev, HCI_LE_ENABLED) && | ||
| 6504 | (hci_dev_test_flag(hdev, HCI_ADVERTISING) || | ||
| 6505 | !hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE))) { | ||
| 6506 | __hci_req_update_adv_data(&req, HCI_ADV_CURRENT); | ||
| 6507 | __hci_req_update_scan_rsp_data(&req, HCI_ADV_CURRENT); | ||
| 6508 | } | ||
| 6509 | |||
| 6510 | if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) && | ||
| 6511 | hdev->cur_adv_instance == 0x00 && | ||
| 6512 | !list_empty(&hdev->adv_instances)) { | ||
| 6513 | adv_instance = list_first_entry(&hdev->adv_instances, | ||
| 6514 | struct adv_info, list); | ||
| 6515 | hdev->cur_adv_instance = adv_instance->instance; | ||
| 6516 | } | ||
| 6517 | |||
| 6518 | if (hci_dev_test_flag(hdev, HCI_ADVERTISING)) | ||
| 6519 | __hci_req_enable_advertising(&req); | ||
| 6520 | else if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) && | ||
| 6521 | hdev->cur_adv_instance) | ||
| 6522 | __hci_req_schedule_adv_instance(&req, | ||
| 6523 | hdev->cur_adv_instance, | ||
| 6524 | true); | ||
| 6525 | } | ||
| 6526 | |||
| 6527 | link_sec = hci_dev_test_flag(hdev, HCI_LINK_SECURITY); | ||
| 6528 | if (link_sec != test_bit(HCI_AUTH, &hdev->flags)) | ||
| 6529 | hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE, | ||
| 6530 | sizeof(link_sec), &link_sec); | ||
| 6531 | |||
| 6532 | if (lmp_bredr_capable(hdev)) { | ||
| 6533 | if (hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE)) | ||
| 6534 | __hci_req_write_fast_connectable(&req, true); | ||
| 6535 | else | ||
| 6536 | __hci_req_write_fast_connectable(&req, false); | ||
| 6537 | __hci_req_update_scan(&req); | ||
| 6538 | __hci_req_update_class(&req); | ||
| 6539 | __hci_req_update_name(&req); | ||
| 6540 | __hci_req_update_eir(&req); | ||
| 6541 | } | ||
| 6542 | |||
| 6543 | return hci_req_run(&req, powered_complete); | ||
| 6544 | } | 6447 | } |
| 6545 | 6448 | ||
| 6546 | int mgmt_powered(struct hci_dev *hdev, u8 powered) | 6449 | void __mgmt_power_off(struct hci_dev *hdev) |
| 6547 | { | 6450 | { |
| 6548 | struct cmd_lookup match = { NULL, hdev }; | 6451 | struct cmd_lookup match = { NULL, hdev }; |
| 6549 | u8 status, zero_cod[] = { 0, 0, 0 }; | 6452 | u8 status, zero_cod[] = { 0, 0, 0 }; |
| 6550 | int err; | ||
| 6551 | |||
| 6552 | if (!hci_dev_test_flag(hdev, HCI_MGMT)) | ||
| 6553 | return 0; | ||
| 6554 | |||
| 6555 | if (powered) { | ||
| 6556 | /* Register the available SMP channels (BR/EDR and LE) only | ||
| 6557 | * when successfully powering on the controller. This late | ||
| 6558 | * registration is required so that LE SMP can clearly | ||
| 6559 | * decide if the public address or static address is used. | ||
| 6560 | */ | ||
| 6561 | smp_register(hdev); | ||
| 6562 | |||
| 6563 | if (powered_update_hci(hdev) == 0) | ||
| 6564 | return 0; | ||
| 6565 | |||
| 6566 | mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, | ||
| 6567 | &match); | ||
| 6568 | goto new_settings; | ||
| 6569 | } | ||
| 6570 | 6453 | ||
| 6571 | mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match); | 6454 | mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match); |
| 6572 | 6455 | ||
| @@ -6588,13 +6471,10 @@ int mgmt_powered(struct hci_dev *hdev, u8 powered) | |||
| 6588 | mgmt_generic_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, | 6471 | mgmt_generic_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, |
| 6589 | zero_cod, sizeof(zero_cod), NULL); | 6472 | zero_cod, sizeof(zero_cod), NULL); |
| 6590 | 6473 | ||
| 6591 | new_settings: | 6474 | new_settings(hdev, match.sk); |
| 6592 | err = new_settings(hdev, match.sk); | ||
| 6593 | 6475 | ||
| 6594 | if (match.sk) | 6476 | if (match.sk) |
| 6595 | sock_put(match.sk); | 6477 | sock_put(match.sk); |
| 6596 | |||
| 6597 | return err; | ||
| 6598 | } | 6478 | } |
| 6599 | 6479 | ||
| 6600 | void mgmt_set_powered_failed(struct hci_dev *hdev, int err) | 6480 | void mgmt_set_powered_failed(struct hci_dev *hdev, int err) |
