Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a736abc1 authored by Szymon Janc's avatar Szymon Janc Committed by Johan Hedberg
Browse files

Bluetooth: Fix invalid response for 'Start Discovery' command



According to Management Interface API 'Start Discovery' command should
generate a Command Complete event on failure. Currently kernel is
sending Command Status on early errors. This results in userspace
ignoring such event due to invalid size.

bluetoothd[28499]: src/adapter.c:trigger_start_discovery()
bluetoothd[28499]: src/adapter.c:cancel_passive_scanning()
bluetoothd[28499]: src/adapter.c:start_discovery_timeout()
bluetoothd[28499]: src/adapter.c:start_discovery_complete() status 0x0a
bluetoothd[28499]: Wrong size of start discovery return parameters

Reported-by: default avatarJukka Taimisto <jtt@codenomicon.com>
Signed-off-by: default avatarSzymon Janc <szymon.janc@tieto.com>
Signed-off-by: default avatarJohan Hedberg <johan.hedberg@intel.com>
parent 845472e8
Loading
Loading
Loading
Loading
+35 −21
Original line number Diff line number Diff line
@@ -3727,20 +3727,23 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev,
	hci_dev_lock(hdev);

	if (!hdev_is_powered(hdev)) {
		err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
				 MGMT_STATUS_NOT_POWERED);
		err = cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY,
				   MGMT_STATUS_NOT_POWERED,
				   &cp->type, sizeof(cp->type));
		goto failed;
	}

	if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
		err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
				 MGMT_STATUS_BUSY);
		err = cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY,
				   MGMT_STATUS_BUSY, &cp->type,
				   sizeof(cp->type));
		goto failed;
	}

	if (hdev->discovery.state != DISCOVERY_STOPPED) {
		err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
				 MGMT_STATUS_BUSY);
		err = cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY,
				   MGMT_STATUS_BUSY, &cp->type,
				   sizeof(cp->type));
		goto failed;
	}

@@ -3758,15 +3761,18 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev,
	case DISCOV_TYPE_BREDR:
		status = mgmt_bredr_support(hdev);
		if (status) {
			err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
					 status);
			err = cmd_complete(sk, hdev->id,
					   MGMT_OP_START_DISCOVERY, status,
					   &cp->type, sizeof(cp->type));
			mgmt_pending_remove(cmd);
			goto failed;
		}

		if (test_bit(HCI_INQUIRY, &hdev->flags)) {
			err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
					 MGMT_STATUS_BUSY);
			err = cmd_complete(sk, hdev->id,
					   MGMT_OP_START_DISCOVERY,
					   MGMT_STATUS_BUSY, &cp->type,
					   sizeof(cp->type));
			mgmt_pending_remove(cmd);
			goto failed;
		}
@@ -3783,16 +3789,19 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev,
	case DISCOV_TYPE_INTERLEAVED:
		status = mgmt_le_support(hdev);
		if (status) {
			err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
					 status);
			err = cmd_complete(sk, hdev->id,
					   MGMT_OP_START_DISCOVERY, status,
					   &cp->type, sizeof(cp->type));
			mgmt_pending_remove(cmd);
			goto failed;
		}

		if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
		    !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
			err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
					 MGMT_STATUS_NOT_SUPPORTED);
			err = cmd_complete(sk, hdev->id,
					   MGMT_OP_START_DISCOVERY,
					   MGMT_STATUS_NOT_SUPPORTED,
					   &cp->type, sizeof(cp->type));
			mgmt_pending_remove(cmd);
			goto failed;
		}
@@ -3804,9 +3813,11 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev,
			 */
			if (hci_conn_hash_lookup_state(hdev, LE_LINK,
						       BT_CONNECT)) {
				err = cmd_status(sk, hdev->id,
				err = cmd_complete(sk, hdev->id,
						   MGMT_OP_START_DISCOVERY,
						 MGMT_STATUS_REJECTED);
						   MGMT_STATUS_REJECTED,
						   &cp->type,
						   sizeof(cp->type));
				mgmt_pending_remove(cmd);
				goto failed;
			}
@@ -3829,8 +3840,10 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev,
		 */
		err = hci_update_random_address(&req, true, &own_addr_type);
		if (err < 0) {
			err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
					 MGMT_STATUS_FAILED);
			err = cmd_complete(sk, hdev->id,
					   MGMT_OP_START_DISCOVERY,
					   MGMT_STATUS_FAILED,
					   &cp->type, sizeof(cp->type));
			mgmt_pending_remove(cmd);
			goto failed;
		}
@@ -3850,8 +3863,9 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev,
		break;

	default:
		err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
				 MGMT_STATUS_INVALID_PARAMS);
		err = cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY,
				   MGMT_STATUS_INVALID_PARAMS,
				   &cp->type, sizeof(cp->type));
		mgmt_pending_remove(cmd);
		goto failed;
	}