Re: [PATCH v6 4/4] Bluetooth: Add directed advertising support through connect()

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Johan,

> When we're in peripheral mode (HCI_ADVERTISING flag is set) the most
> natural mapping of connect() is to perform directed advertising to the
> peer device.
> 
> This patch does the necessary changes to enable directed advertising and
> keeps the hci_conn state as BT_CONNECT in a similar way as is done for
> central or BR/EDR connection initiation.
> 
> Signed-off-by: Johan Hedberg <johan.hedberg@xxxxxxxxx>
> ---
> include/net/bluetooth/hci.h |  1 +
> net/bluetooth/hci_conn.c    | 77 ++++++++++++++++++++++++++++++++++++++++-----
> net/bluetooth/hci_event.c   | 19 +++++++++--
> 3 files changed, 87 insertions(+), 10 deletions(-)
> 
> diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
> index be150cf8cd43..4261a67682c0 100644
> --- a/include/net/bluetooth/hci.h
> +++ b/include/net/bluetooth/hci.h
> @@ -367,6 +367,7 @@ enum {
> #define HCI_ERROR_REMOTE_POWER_OFF	0x15
> #define HCI_ERROR_LOCAL_HOST_TERM	0x16
> #define HCI_ERROR_PAIRING_NOT_ALLOWED	0x18
> +#define HCI_ERROR_ADVERTISING_TIMEOUT	0x3c
> 
> /* Flow control modes */
> #define HCI_FLOW_CTL_MODE_PACKET_BASED	0x00
> diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
> index 129c22a85ccf..b2500f48b373 100644
> --- a/net/bluetooth/hci_conn.c
> +++ b/net/bluetooth/hci_conn.c
> @@ -367,9 +367,23 @@ static void le_conn_timeout(struct work_struct *work)
> {
> 	struct hci_conn *conn = container_of(work, struct hci_conn,
> 					     le_conn_timeout.work);
> +	struct hci_dev *hdev = conn->hdev;
> 
> 	BT_DBG("");
> 
> +	/* We could end up here due to having done directed advertising,
> +	 * so clean up the state if necessary. This should however only
> +	 * happen with broken hardware or if low duty cycle was used
> +	 * (which doesn't have a timeout of its own).
> +	 */
> +	if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
> +		u8 enable = 0x00;
> +		hci_send_cmd(hdev, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable),
> +			     &enable);
> +		hci_le_conn_failed(conn, HCI_ERROR_ADVERTISING_TIMEOUT);
> +		return;
> +	}
> +
> 	hci_le_create_connection_cancel(conn);
> }
> 
> @@ -549,6 +563,11 @@ void hci_le_conn_failed(struct hci_conn *conn, u8 status)
> 	 * favor of connection establishment, we should restart it.
> 	 */
> 	hci_update_background_scan(hdev);
> +
> +	/* Re-enable advertising in case this was a failed connection
> +	 * attempt as a peripheral.
> +	 */
> +	mgmt_reenable_advertising(hdev);
> }
> 
> static void create_le_conn_complete(struct hci_dev *hdev, u8 status)
> @@ -609,6 +628,45 @@ static void hci_req_add_le_create_conn(struct hci_request *req,
> 	conn->state = BT_CONNECT;
> }
> 
> +static void hci_req_directed_advertising(struct hci_request *req,
> +					 struct hci_conn *conn)
> +{
> +	struct hci_dev *hdev = req->hdev;
> +	struct hci_cp_le_set_adv_param cp;
> +	u8 own_addr_type;
> +	u8 enable;
> +
> +	enable = 0x00;
> +	hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
> +
> +	/* Clear the HCI_ADVERTISING bit temporarily so that the
> +	 * hci_update_random_address knows that it's safe to go ahead
> +	 * and write a new random address. The flag will be set back on
> +	 * as soon as the SET_ADV_ENABLE HCI command completes.
> +	 */
> +	clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
> +
> +	/* Set require_privacy to false so that the remote device has a
> +	 * chance of identifying us.
> +	 */
> +	if (hci_update_random_address(req, false, &own_addr_type) < 0)
> +		return;
> +
> +	memset(&cp, 0, sizeof(cp));
> +	cp.type = 0x01;

please use LE_ADV_DIRECT_IND here.

> +	cp.own_address_type = own_addr_type;
> +	cp.direct_addr_type = conn->dst_type;
> +	bacpy(&cp.direct_addr, &conn->dst);
> +	cp.channel_map = hdev->le_adv_channel_map;
> +
> +	hci_req_add(req, HCI_OP_LE_SET_ADV_PARAM, sizeof(cp), &cp);
> +
> +	enable = 0x01;
> +	hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
> +
> +	conn->state = BT_CONNECT;
> +}
> +
> struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
> 				u8 dst_type, u8 sec_level, u8 auth_type)
> {
> @@ -618,9 +676,6 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
> 	struct hci_request req;
> 	int err;
> 
> -	if (test_bit(HCI_ADVERTISING, &hdev->flags))
> -		return ERR_PTR(-ENOTSUPP);
> -
> 	/* Some devices send ATT messages as soon as the physical link is
> 	 * established. To be able to handle these ATT messages, the user-
> 	 * space first establishes the connection and then starts the pairing
> @@ -668,13 +723,20 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
> 		return ERR_PTR(-ENOMEM);
> 
> 	conn->dst_type = dst_type;
> -
> -	conn->out = true;
> -	conn->link_mode |= HCI_LM_MASTER;
> 	conn->sec_level = BT_SECURITY_LOW;
> 	conn->pending_sec_level = sec_level;
> 	conn->auth_type = auth_type;
> 
> +	hci_req_init(&req, hdev);
> +
> +	if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
> +		hci_req_directed_advertising(&req, conn);
> +		goto create_conn;
> +	}
> +
> +	conn->out = true;
> +	conn->link_mode |= HCI_LM_MASTER;
> +
> 	params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type);
> 	if (params) {
> 		conn->le_conn_min_interval = params->conn_min_interval;
> @@ -684,8 +746,6 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
> 		conn->le_conn_max_interval = hdev->le_conn_max_interval;
> 	}
> 
> -	hci_req_init(&req, hdev);
> -
> 	/* If controller is scanning, we stop it since some controllers are
> 	 * not able to scan and connect at the same time. Also set the
> 	 * HCI_LE_SCAN_INTERRUPTED flag so that the command complete
> @@ -699,6 +759,7 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
> 
> 	hci_req_add_le_create_conn(&req, conn);
> 
> +create_conn:
> 	err = hci_req_run(&req, create_le_conn_complete);
> 	if (err) {
> 		hci_conn_del(conn);
> diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
> index 224eecfc0ecd..c91eeff68324 100644
> --- a/net/bluetooth/hci_event.c
> +++ b/net/bluetooth/hci_event.c
> @@ -991,10 +991,25 @@ static void hci_cc_le_set_adv_enable(struct hci_dev *hdev, struct sk_buff *skb)
> 	if (!sent)
> 		return;
> 
> +	if (status)
> +		return;
> +
> 	hci_dev_lock(hdev);
> 
> -	if (!status)
> -		mgmt_advertising(hdev, *sent);
> +	/* If we're doing connection initation as peripheral. Set a
> +	 * timeout in case something goes wrong.
> +	 */
> +	if (*sent) {
> +		struct hci_conn *conn;
> +
> +		conn = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT);
> +		if (conn)
> +			queue_delayed_work(hdev->workqueue,
> +					   &conn->le_conn_timeout,
> +					   HCI_LE_CONN_TIMEOUT);
> +	}
> +
> +	mgmt_advertising(hdev, *sent);
> 
> 	hci_dev_unlock(hdev);
> }

Regards

Marcel

--
To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Bluez Devel]     [Linux Wireless Networking]     [Linux Wireless Personal Area Networking]     [Linux ATH6KL]     [Linux USB Devel]     [Linux Media Drivers]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux