diff options
Diffstat (limited to 'net/bluetooth/mgmt.c')
-rw-r--r-- | net/bluetooth/mgmt.c | 124 |
1 files changed, 40 insertions, 84 deletions
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index b8554d429d88..c2457435a670 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c | |||
@@ -129,9 +129,6 @@ static const u16 mgmt_events[] = { | |||
129 | 129 | ||
130 | #define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000) | 130 | #define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000) |
131 | 131 | ||
132 | #define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \ | ||
133 | !test_bit(HCI_AUTO_OFF, &hdev->dev_flags)) | ||
134 | |||
135 | struct pending_cmd { | 132 | struct pending_cmd { |
136 | struct list_head list; | 133 | struct list_head list; |
137 | u16 opcode; | 134 | u16 opcode; |
@@ -1536,9 +1533,11 @@ static void set_discoverable_complete(struct hci_dev *hdev, u8 status) | |||
1536 | 1533 | ||
1537 | /* When the discoverable mode gets changed, make sure | 1534 | /* When the discoverable mode gets changed, make sure |
1538 | * that class of device has the limited discoverable | 1535 | * that class of device has the limited discoverable |
1539 | * bit correctly set. | 1536 | * bit correctly set. Also update page scan based on whitelist |
1537 | * entries. | ||
1540 | */ | 1538 | */ |
1541 | hci_req_init(&req, hdev); | 1539 | hci_req_init(&req, hdev); |
1540 | hci_update_page_scan(hdev, &req); | ||
1542 | update_class(&req); | 1541 | update_class(&req); |
1543 | hci_req_run(&req, NULL); | 1542 | hci_req_run(&req, NULL); |
1544 | 1543 | ||
@@ -1785,6 +1784,7 @@ static void set_connectable_complete(struct hci_dev *hdev, u8 status) | |||
1785 | 1784 | ||
1786 | if (conn_changed || discov_changed) { | 1785 | if (conn_changed || discov_changed) { |
1787 | new_settings(hdev, cmd->sk); | 1786 | new_settings(hdev, cmd->sk); |
1787 | hci_update_page_scan(hdev, NULL); | ||
1788 | if (discov_changed) | 1788 | if (discov_changed) |
1789 | mgmt_update_adv_data(hdev); | 1789 | mgmt_update_adv_data(hdev); |
1790 | hci_update_background_scan(hdev); | 1790 | hci_update_background_scan(hdev); |
@@ -1818,6 +1818,7 @@ static int set_connectable_update_settings(struct hci_dev *hdev, | |||
1818 | return err; | 1818 | return err; |
1819 | 1819 | ||
1820 | if (changed) { | 1820 | if (changed) { |
1821 | hci_update_page_scan(hdev, NULL); | ||
1821 | hci_update_background_scan(hdev); | 1822 | hci_update_background_scan(hdev); |
1822 | return new_settings(hdev, sk); | 1823 | return new_settings(hdev, sk); |
1823 | } | 1824 | } |
@@ -4381,27 +4382,6 @@ unlock: | |||
4381 | return err; | 4382 | return err; |
4382 | } | 4383 | } |
4383 | 4384 | ||
4384 | static void set_bredr_scan(struct hci_request *req) | ||
4385 | { | ||
4386 | struct hci_dev *hdev = req->hdev; | ||
4387 | u8 scan = 0; | ||
4388 | |||
4389 | /* Ensure that fast connectable is disabled. This function will | ||
4390 | * not do anything if the page scan parameters are already what | ||
4391 | * they should be. | ||
4392 | */ | ||
4393 | write_fast_connectable(req, false); | ||
4394 | |||
4395 | if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags) || | ||
4396 | !list_empty(&hdev->whitelist)) | ||
4397 | scan |= SCAN_PAGE; | ||
4398 | if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) | ||
4399 | scan |= SCAN_INQUIRY; | ||
4400 | |||
4401 | if (scan) | ||
4402 | hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan); | ||
4403 | } | ||
4404 | |||
4405 | static void set_bredr_complete(struct hci_dev *hdev, u8 status) | 4385 | static void set_bredr_complete(struct hci_dev *hdev, u8 status) |
4406 | { | 4386 | { |
4407 | struct pending_cmd *cmd; | 4387 | struct pending_cmd *cmd; |
@@ -4507,9 +4487,8 @@ static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) | |||
4507 | 4487 | ||
4508 | hci_req_init(&req, hdev); | 4488 | hci_req_init(&req, hdev); |
4509 | 4489 | ||
4510 | if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags) || | 4490 | write_fast_connectable(&req, false); |
4511 | !list_empty(&hdev->whitelist)) | 4491 | hci_update_page_scan(hdev, &req); |
4512 | set_bredr_scan(&req); | ||
4513 | 4492 | ||
4514 | /* Since only the advertising data flags will change, there | 4493 | /* Since only the advertising data flags will change, there |
4515 | * is no need to update the scan response data. | 4494 | * is no need to update the scan response data. |
@@ -5235,27 +5214,6 @@ unlock: | |||
5235 | return err; | 5214 | return err; |
5236 | } | 5215 | } |
5237 | 5216 | ||
5238 | /* Helper for Add/Remove Device commands */ | ||
5239 | static void update_page_scan(struct hci_dev *hdev, u8 scan) | ||
5240 | { | ||
5241 | if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) | ||
5242 | return; | ||
5243 | |||
5244 | if (!hdev_is_powered(hdev)) | ||
5245 | return; | ||
5246 | |||
5247 | /* If HCI_CONNECTABLE is set then Add/Remove Device should not | ||
5248 | * make any changes to page scanning. | ||
5249 | */ | ||
5250 | if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) | ||
5251 | return; | ||
5252 | |||
5253 | if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) | ||
5254 | scan |= SCAN_INQUIRY; | ||
5255 | |||
5256 | hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan); | ||
5257 | } | ||
5258 | |||
5259 | static void device_added(struct sock *sk, struct hci_dev *hdev, | 5217 | static void device_added(struct sock *sk, struct hci_dev *hdev, |
5260 | bdaddr_t *bdaddr, u8 type, u8 action) | 5218 | bdaddr_t *bdaddr, u8 type, u8 action) |
5261 | { | 5219 | { |
@@ -5291,8 +5249,6 @@ static int add_device(struct sock *sk, struct hci_dev *hdev, | |||
5291 | hci_dev_lock(hdev); | 5249 | hci_dev_lock(hdev); |
5292 | 5250 | ||
5293 | if (cp->addr.type == BDADDR_BREDR) { | 5251 | if (cp->addr.type == BDADDR_BREDR) { |
5294 | bool update_scan; | ||
5295 | |||
5296 | /* Only incoming connections action is supported for now */ | 5252 | /* Only incoming connections action is supported for now */ |
5297 | if (cp->action != 0x01) { | 5253 | if (cp->action != 0x01) { |
5298 | err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE, | 5254 | err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE, |
@@ -5301,15 +5257,12 @@ static int add_device(struct sock *sk, struct hci_dev *hdev, | |||
5301 | goto unlock; | 5257 | goto unlock; |
5302 | } | 5258 | } |
5303 | 5259 | ||
5304 | update_scan = list_empty(&hdev->whitelist); | ||
5305 | |||
5306 | err = hci_bdaddr_list_add(&hdev->whitelist, &cp->addr.bdaddr, | 5260 | err = hci_bdaddr_list_add(&hdev->whitelist, &cp->addr.bdaddr, |
5307 | cp->addr.type); | 5261 | cp->addr.type); |
5308 | if (err) | 5262 | if (err) |
5309 | goto unlock; | 5263 | goto unlock; |
5310 | 5264 | ||
5311 | if (update_scan) | 5265 | hci_update_page_scan(hdev, NULL); |
5312 | update_page_scan(hdev, SCAN_PAGE); | ||
5313 | 5266 | ||
5314 | goto added; | 5267 | goto added; |
5315 | } | 5268 | } |
@@ -5392,8 +5345,7 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev, | |||
5392 | goto unlock; | 5345 | goto unlock; |
5393 | } | 5346 | } |
5394 | 5347 | ||
5395 | if (list_empty(&hdev->whitelist)) | 5348 | hci_update_page_scan(hdev, NULL); |
5396 | update_page_scan(hdev, SCAN_DISABLED); | ||
5397 | 5349 | ||
5398 | device_removed(sk, hdev, &cp->addr.bdaddr, | 5350 | device_removed(sk, hdev, &cp->addr.bdaddr, |
5399 | cp->addr.type); | 5351 | cp->addr.type); |
@@ -5444,7 +5396,7 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev, | |||
5444 | kfree(b); | 5396 | kfree(b); |
5445 | } | 5397 | } |
5446 | 5398 | ||
5447 | update_page_scan(hdev, SCAN_DISABLED); | 5399 | hci_update_page_scan(hdev, NULL); |
5448 | 5400 | ||
5449 | list_for_each_entry_safe(p, tmp, &hdev->le_conn_params, list) { | 5401 | list_for_each_entry_safe(p, tmp, &hdev->le_conn_params, list) { |
5450 | if (p->auto_connect == HCI_AUTO_CONN_DISABLED) | 5402 | if (p->auto_connect == HCI_AUTO_CONN_DISABLED) |
@@ -5969,8 +5921,8 @@ static int powered_update_hci(struct hci_dev *hdev) | |||
5969 | sizeof(link_sec), &link_sec); | 5921 | sizeof(link_sec), &link_sec); |
5970 | 5922 | ||
5971 | if (lmp_bredr_capable(hdev)) { | 5923 | if (lmp_bredr_capable(hdev)) { |
5972 | if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) | 5924 | write_fast_connectable(&req, false); |
5973 | set_bredr_scan(&req); | 5925 | hci_update_page_scan(hdev, &req); |
5974 | update_class(&req); | 5926 | update_class(&req); |
5975 | update_name(&req); | 5927 | update_name(&req); |
5976 | update_eir(&req); | 5928 | update_eir(&req); |
@@ -6281,25 +6233,35 @@ static void unpair_device_rsp(struct pending_cmd *cmd, void *data) | |||
6281 | mgmt_pending_remove(cmd); | 6233 | mgmt_pending_remove(cmd); |
6282 | } | 6234 | } |
6283 | 6235 | ||
6236 | bool mgmt_powering_down(struct hci_dev *hdev) | ||
6237 | { | ||
6238 | struct pending_cmd *cmd; | ||
6239 | struct mgmt_mode *cp; | ||
6240 | |||
6241 | cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev); | ||
6242 | if (!cmd) | ||
6243 | return false; | ||
6244 | |||
6245 | cp = cmd->param; | ||
6246 | if (!cp->val) | ||
6247 | return true; | ||
6248 | |||
6249 | return false; | ||
6250 | } | ||
6251 | |||
6284 | void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, | 6252 | void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, |
6285 | u8 link_type, u8 addr_type, u8 reason, | 6253 | u8 link_type, u8 addr_type, u8 reason, |
6286 | bool mgmt_connected) | 6254 | bool mgmt_connected) |
6287 | { | 6255 | { |
6288 | struct mgmt_ev_device_disconnected ev; | 6256 | struct mgmt_ev_device_disconnected ev; |
6289 | struct pending_cmd *power_off; | ||
6290 | struct sock *sk = NULL; | 6257 | struct sock *sk = NULL; |
6291 | 6258 | ||
6292 | power_off = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev); | 6259 | /* The connection is still in hci_conn_hash so test for 1 |
6293 | if (power_off) { | 6260 | * instead of 0 to know if this is the last one. |
6294 | struct mgmt_mode *cp = power_off->param; | 6261 | */ |
6295 | 6262 | if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) { | |
6296 | /* The connection is still in hci_conn_hash so test for 1 | 6263 | cancel_delayed_work(&hdev->power_off); |
6297 | * instead of 0 to know if this is the last one. | 6264 | queue_work(hdev->req_workqueue, &hdev->power_off.work); |
6298 | */ | ||
6299 | if (!cp->val && hci_conn_count(hdev) == 1) { | ||
6300 | cancel_delayed_work(&hdev->power_off); | ||
6301 | queue_work(hdev->req_workqueue, &hdev->power_off.work); | ||
6302 | } | ||
6303 | } | 6265 | } |
6304 | 6266 | ||
6305 | if (!mgmt_connected) | 6267 | if (!mgmt_connected) |
@@ -6359,19 +6321,13 @@ void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, | |||
6359 | u8 addr_type, u8 status) | 6321 | u8 addr_type, u8 status) |
6360 | { | 6322 | { |
6361 | struct mgmt_ev_connect_failed ev; | 6323 | struct mgmt_ev_connect_failed ev; |
6362 | struct pending_cmd *power_off; | ||
6363 | |||
6364 | power_off = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev); | ||
6365 | if (power_off) { | ||
6366 | struct mgmt_mode *cp = power_off->param; | ||
6367 | 6324 | ||
6368 | /* The connection is still in hci_conn_hash so test for 1 | 6325 | /* The connection is still in hci_conn_hash so test for 1 |
6369 | * instead of 0 to know if this is the last one. | 6326 | * instead of 0 to know if this is the last one. |
6370 | */ | 6327 | */ |
6371 | if (!cp->val && hci_conn_count(hdev) == 1) { | 6328 | if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) { |
6372 | cancel_delayed_work(&hdev->power_off); | 6329 | cancel_delayed_work(&hdev->power_off); |
6373 | queue_work(hdev->req_workqueue, &hdev->power_off.work); | 6330 | queue_work(hdev->req_workqueue, &hdev->power_off.work); |
6374 | } | ||
6375 | } | 6331 | } |
6376 | 6332 | ||
6377 | bacpy(&ev.addr.bdaddr, bdaddr); | 6333 | bacpy(&ev.addr.bdaddr, bdaddr); |