diff mbox series

[BlueZ,v2] mesh: Fix segfault caused by re-enabling of HCI controller

Message ID 20200515174156.11958-1-inga.stotland@intel.com (mailing list archive)
State Accepted
Headers show
Series [BlueZ,v2] mesh: Fix segfault caused by re-enabling of HCI controller | expand

Commit Message

Stotland, Inga May 15, 2020, 5:41 p.m. UTC
This fixes the crash that occurs when a controller used by bluetooth-meshd
is removed and then added back again.

Also, correctly restart scanning when the controller is re-enabled.

Backtrace:
0x00005618e754d040 in ?? ()
0x00005618e6e12d9a in io_ready_callback () at mesh/mesh.c:174
0x00005618e6e3d2c8 in l_queue_foreach () at ell/queue.c:441
0x00005618e6e37927 in request_complete () at src/shared/mgmt.c:261
---
 mesh/mesh-io-generic.c | 135 ++++++++++++++++++++++++-----------------
 mesh/mesh.c            |   9 ++-
 2 files changed, 87 insertions(+), 57 deletions(-)

Comments

Brian Gix May 17, 2020, 3:27 p.m. UTC | #1
Patch Applied
On Fri, 2020-05-15 at 10:41 -0700, Inga Stotland wrote:
> This fixes the crash that occurs when a controller used by bluetooth-meshd
> is removed and then added back again.
> 
> Also, correctly restart scanning when the controller is re-enabled.
> 
> Backtrace:
> 0x00005618e754d040 in ?? ()
> 0x00005618e6e12d9a in io_ready_callback () at mesh/mesh.c:174
> 0x00005618e6e3d2c8 in l_queue_foreach () at ell/queue.c:441
> 0x00005618e6e37927 in request_complete () at src/shared/mgmt.c:261
> ---
>  mesh/mesh-io-generic.c | 135 ++++++++++++++++++++++++-----------------
>  mesh/mesh.c            |   9 ++-
>  2 files changed, 87 insertions(+), 57 deletions(-)
> 
> diff --git a/mesh/mesh-io-generic.c b/mesh/mesh-io-generic.c
> index 2efd32f12..3ad130567 100644
> --- a/mesh/mesh-io-generic.c
> +++ b/mesh/mesh-io-generic.c
> @@ -287,10 +287,86 @@ static void configure_hci(struct mesh_io_private *io)
>  				sizeof(cmd), hci_generic_callback, NULL, NULL);
>  }
>  
> +static void scan_enable_rsp(const void *buf, uint8_t size,
> +							void *user_data)
> +{
> +	uint8_t status = *((uint8_t *) buf);
> +
> +	if (status)
> +		l_error("LE Scan enable failed (0x%02x)", status);
> +}
> +
> +static void set_recv_scan_enable(const void *buf, uint8_t size,
> +							void *user_data)
> +{
> +	struct mesh_io_private *pvt = user_data;
> +	struct bt_hci_cmd_le_set_scan_enable cmd;
> +
> +	cmd.enable = 0x01;	/* Enable scanning */
> +	cmd.filter_dup = 0x00;	/* Report duplicates */
> +	bt_hci_send(pvt->hci, BT_HCI_CMD_LE_SET_SCAN_ENABLE,
> +			&cmd, sizeof(cmd), scan_enable_rsp, pvt, NULL);
> +}
> +
> +static void scan_disable_rsp(const void *buf, uint8_t size,
> +							void *user_data)
> +{
> +	struct bt_hci_cmd_le_set_scan_parameters cmd;
> +	struct mesh_io_private *pvt = user_data;
> +	uint8_t status = *((uint8_t *) buf);
> +
> +	if (status)
> +		l_error("LE Scan disable failed (0x%02x)", status);
> +
> +	cmd.type = pvt->active ? 0x01 : 0x00;	/* Passive/Active scanning */
> +	cmd.interval = L_CPU_TO_LE16(0x0010);	/* 10 ms */
> +	cmd.window = L_CPU_TO_LE16(0x0010);	/* 10 ms */
> +	cmd.own_addr_type = 0x01;		/* ADDR_TYPE_RANDOM */
> +	cmd.filter_policy = 0x00;		/* Accept all */
> +
> +	bt_hci_send(pvt->hci, BT_HCI_CMD_LE_SET_SCAN_PARAMETERS,
> +			&cmd, sizeof(cmd),
> +			set_recv_scan_enable, pvt, NULL);
> +}
> +
> +static bool find_active(const void *a, const void *b)
> +{
> +	const struct pvt_rx_reg *rx_reg = a;
> +
> +	/* Mesh specific AD types do *not* require active scanning,
> +	 * so do not turn on Active Scanning on their account.
> +	 */
> +	if (rx_reg->filter[0] < MESH_AD_TYPE_PROVISION ||
> +			rx_reg->filter[0] > MESH_AD_TYPE_BEACON)
> +		return true;
> +
> +	return false;
> +}
> +
> +static void restart_scan(struct mesh_io_private *pvt)
> +{
> +	struct bt_hci_cmd_le_set_scan_enable cmd;
> +
> +	if (l_queue_isempty(pvt->rx_regs))
> +		return;
> +
> +	pvt->active = l_queue_find(pvt->rx_regs, find_active, NULL);
> +	cmd.enable = 0x00;	/* Disable scanning */
> +	cmd.filter_dup = 0x00;	/* Report duplicates */
> +	bt_hci_send(pvt->hci, BT_HCI_CMD_LE_SET_SCAN_ENABLE,
> +				&cmd, sizeof(cmd), scan_disable_rsp, pvt, NULL);
> +}
> +
>  static void hci_init(void *user_data)
>  {
>  	struct mesh_io *io = user_data;
>  	bool result = true;
> +	bool restarted = false;
> +
> +	if (io->pvt->hci) {
> +		restarted = true;
> +		bt_hci_unref(io->pvt->hci);
> +	}
>  
>  	io->pvt->hci = bt_hci_new_user_channel(io->pvt->index);
>  	if (!io->pvt->hci) {
> @@ -306,6 +382,9 @@ static void hci_init(void *user_data)
>  						event_callback, io, NULL);
>  
>  		l_debug("Started mesh on hci %u", io->pvt->index);
> +
> +		if (restarted)
> +			restart_scan(io->pvt);
>  	}
>  
>  	if (io->pvt->ready_callback)
> @@ -713,62 +792,6 @@ static bool find_by_filter(const void *a, const void *b)
>  	return !memcmp(rx_reg->filter, filter, rx_reg->len);
>  }
>  
> -static void scan_enable_rsp(const void *buf, uint8_t size,
> -							void *user_data)
> -{
> -	uint8_t status = *((uint8_t *) buf);
> -
> -	if (status)
> -		l_error("LE Scan enable failed (0x%02x)", status);
> -}
> -
> -static void set_recv_scan_enable(const void *buf, uint8_t size,
> -							void *user_data)
> -{
> -	struct mesh_io_private *pvt = user_data;
> -	struct bt_hci_cmd_le_set_scan_enable cmd;
> -
> -	cmd.enable = 0x01;	/* Enable scanning */
> -	cmd.filter_dup = 0x00;	/* Report duplicates */
> -	bt_hci_send(pvt->hci, BT_HCI_CMD_LE_SET_SCAN_ENABLE,
> -			&cmd, sizeof(cmd), scan_enable_rsp, pvt, NULL);
> -}
> -
> -static void scan_disable_rsp(const void *buf, uint8_t size,
> -							void *user_data)
> -{
> -	struct bt_hci_cmd_le_set_scan_parameters cmd;
> -	struct mesh_io_private *pvt = user_data;
> -	uint8_t status = *((uint8_t *) buf);
> -
> -	if (status)
> -		l_error("LE Scan disable failed (0x%02x)", status);
> -
> -	cmd.type = pvt->active ? 0x01 : 0x00;	/* Passive/Active scanning */
> -	cmd.interval = L_CPU_TO_LE16(0x0010);	/* 10 ms */
> -	cmd.window = L_CPU_TO_LE16(0x0010);	/* 10 ms */
> -	cmd.own_addr_type = 0x01;		/* ADDR_TYPE_RANDOM */
> -	cmd.filter_policy = 0x00;		/* Accept all */
> -
> -	bt_hci_send(pvt->hci, BT_HCI_CMD_LE_SET_SCAN_PARAMETERS,
> -			&cmd, sizeof(cmd),
> -			set_recv_scan_enable, pvt, NULL);
> -}
> -
> -static bool find_active(const void *a, const void *b)
> -{
> -	const struct pvt_rx_reg *rx_reg = a;
> -
> -	/* Mesh specific AD types do *not* require active scanning,
> -	 * so do not turn on Active Scanning on their account.
> -	 */
> -	if (rx_reg->filter[0] < MESH_AD_TYPE_PROVISION ||
> -			rx_reg->filter[0] > MESH_AD_TYPE_BEACON)
> -		return true;
> -
> -	return false;
> -}
> -
>  static bool recv_register(struct mesh_io *io, const uint8_t *filter,
>  			uint8_t len, mesh_io_recv_func_t cb, void *user_data)
>  {
> diff --git a/mesh/mesh.c b/mesh/mesh.c
> index 890a3aa8f..0a8ea970d 100644
> --- a/mesh/mesh.c
> +++ b/mesh/mesh.c
> @@ -66,6 +66,7 @@ struct bt_mesh {
>  	uint16_t req_index;
>  	uint8_t friend_queue_sz;
>  	uint8_t max_filters;
> +	bool initialized;
>  };
>  
>  struct join_data{
> @@ -91,7 +92,8 @@ static struct bt_mesh mesh = {
>  	.lpn_support = false,
>  	.proxy_support = false,
>  	.crpl = DEFAULT_CRPL,
> -	.friend_queue_sz = DEFAULT_FRIEND_QUEUE_SZ
> +	.friend_queue_sz = DEFAULT_FRIEND_QUEUE_SZ,
> +	.initialized = false
>  };
>  
>  /* We allow only one outstanding Join request */
> @@ -168,6 +170,11 @@ static void io_ready_callback(void *user_data, bool result)
>  {
>  	struct mesh_init_request *req = user_data;
>  
> +	if (mesh.initialized)
> +		return;
> +
> +	mesh.initialized = true;
> +
>  	if (result)
>  		node_attach_io_all(mesh.io);
>
diff mbox series

Patch

diff --git a/mesh/mesh-io-generic.c b/mesh/mesh-io-generic.c
index 2efd32f12..3ad130567 100644
--- a/mesh/mesh-io-generic.c
+++ b/mesh/mesh-io-generic.c
@@ -287,10 +287,86 @@  static void configure_hci(struct mesh_io_private *io)
 				sizeof(cmd), hci_generic_callback, NULL, NULL);
 }
 
+static void scan_enable_rsp(const void *buf, uint8_t size,
+							void *user_data)
+{
+	uint8_t status = *((uint8_t *) buf);
+
+	if (status)
+		l_error("LE Scan enable failed (0x%02x)", status);
+}
+
+static void set_recv_scan_enable(const void *buf, uint8_t size,
+							void *user_data)
+{
+	struct mesh_io_private *pvt = user_data;
+	struct bt_hci_cmd_le_set_scan_enable cmd;
+
+	cmd.enable = 0x01;	/* Enable scanning */
+	cmd.filter_dup = 0x00;	/* Report duplicates */
+	bt_hci_send(pvt->hci, BT_HCI_CMD_LE_SET_SCAN_ENABLE,
+			&cmd, sizeof(cmd), scan_enable_rsp, pvt, NULL);
+}
+
+static void scan_disable_rsp(const void *buf, uint8_t size,
+							void *user_data)
+{
+	struct bt_hci_cmd_le_set_scan_parameters cmd;
+	struct mesh_io_private *pvt = user_data;
+	uint8_t status = *((uint8_t *) buf);
+
+	if (status)
+		l_error("LE Scan disable failed (0x%02x)", status);
+
+	cmd.type = pvt->active ? 0x01 : 0x00;	/* Passive/Active scanning */
+	cmd.interval = L_CPU_TO_LE16(0x0010);	/* 10 ms */
+	cmd.window = L_CPU_TO_LE16(0x0010);	/* 10 ms */
+	cmd.own_addr_type = 0x01;		/* ADDR_TYPE_RANDOM */
+	cmd.filter_policy = 0x00;		/* Accept all */
+
+	bt_hci_send(pvt->hci, BT_HCI_CMD_LE_SET_SCAN_PARAMETERS,
+			&cmd, sizeof(cmd),
+			set_recv_scan_enable, pvt, NULL);
+}
+
+static bool find_active(const void *a, const void *b)
+{
+	const struct pvt_rx_reg *rx_reg = a;
+
+	/* Mesh specific AD types do *not* require active scanning,
+	 * so do not turn on Active Scanning on their account.
+	 */
+	if (rx_reg->filter[0] < MESH_AD_TYPE_PROVISION ||
+			rx_reg->filter[0] > MESH_AD_TYPE_BEACON)
+		return true;
+
+	return false;
+}
+
+static void restart_scan(struct mesh_io_private *pvt)
+{
+	struct bt_hci_cmd_le_set_scan_enable cmd;
+
+	if (l_queue_isempty(pvt->rx_regs))
+		return;
+
+	pvt->active = l_queue_find(pvt->rx_regs, find_active, NULL);
+	cmd.enable = 0x00;	/* Disable scanning */
+	cmd.filter_dup = 0x00;	/* Report duplicates */
+	bt_hci_send(pvt->hci, BT_HCI_CMD_LE_SET_SCAN_ENABLE,
+				&cmd, sizeof(cmd), scan_disable_rsp, pvt, NULL);
+}
+
 static void hci_init(void *user_data)
 {
 	struct mesh_io *io = user_data;
 	bool result = true;
+	bool restarted = false;
+
+	if (io->pvt->hci) {
+		restarted = true;
+		bt_hci_unref(io->pvt->hci);
+	}
 
 	io->pvt->hci = bt_hci_new_user_channel(io->pvt->index);
 	if (!io->pvt->hci) {
@@ -306,6 +382,9 @@  static void hci_init(void *user_data)
 						event_callback, io, NULL);
 
 		l_debug("Started mesh on hci %u", io->pvt->index);
+
+		if (restarted)
+			restart_scan(io->pvt);
 	}
 
 	if (io->pvt->ready_callback)
@@ -713,62 +792,6 @@  static bool find_by_filter(const void *a, const void *b)
 	return !memcmp(rx_reg->filter, filter, rx_reg->len);
 }
 
-static void scan_enable_rsp(const void *buf, uint8_t size,
-							void *user_data)
-{
-	uint8_t status = *((uint8_t *) buf);
-
-	if (status)
-		l_error("LE Scan enable failed (0x%02x)", status);
-}
-
-static void set_recv_scan_enable(const void *buf, uint8_t size,
-							void *user_data)
-{
-	struct mesh_io_private *pvt = user_data;
-	struct bt_hci_cmd_le_set_scan_enable cmd;
-
-	cmd.enable = 0x01;	/* Enable scanning */
-	cmd.filter_dup = 0x00;	/* Report duplicates */
-	bt_hci_send(pvt->hci, BT_HCI_CMD_LE_SET_SCAN_ENABLE,
-			&cmd, sizeof(cmd), scan_enable_rsp, pvt, NULL);
-}
-
-static void scan_disable_rsp(const void *buf, uint8_t size,
-							void *user_data)
-{
-	struct bt_hci_cmd_le_set_scan_parameters cmd;
-	struct mesh_io_private *pvt = user_data;
-	uint8_t status = *((uint8_t *) buf);
-
-	if (status)
-		l_error("LE Scan disable failed (0x%02x)", status);
-
-	cmd.type = pvt->active ? 0x01 : 0x00;	/* Passive/Active scanning */
-	cmd.interval = L_CPU_TO_LE16(0x0010);	/* 10 ms */
-	cmd.window = L_CPU_TO_LE16(0x0010);	/* 10 ms */
-	cmd.own_addr_type = 0x01;		/* ADDR_TYPE_RANDOM */
-	cmd.filter_policy = 0x00;		/* Accept all */
-
-	bt_hci_send(pvt->hci, BT_HCI_CMD_LE_SET_SCAN_PARAMETERS,
-			&cmd, sizeof(cmd),
-			set_recv_scan_enable, pvt, NULL);
-}
-
-static bool find_active(const void *a, const void *b)
-{
-	const struct pvt_rx_reg *rx_reg = a;
-
-	/* Mesh specific AD types do *not* require active scanning,
-	 * so do not turn on Active Scanning on their account.
-	 */
-	if (rx_reg->filter[0] < MESH_AD_TYPE_PROVISION ||
-			rx_reg->filter[0] > MESH_AD_TYPE_BEACON)
-		return true;
-
-	return false;
-}
-
 static bool recv_register(struct mesh_io *io, const uint8_t *filter,
 			uint8_t len, mesh_io_recv_func_t cb, void *user_data)
 {
diff --git a/mesh/mesh.c b/mesh/mesh.c
index 890a3aa8f..0a8ea970d 100644
--- a/mesh/mesh.c
+++ b/mesh/mesh.c
@@ -66,6 +66,7 @@  struct bt_mesh {
 	uint16_t req_index;
 	uint8_t friend_queue_sz;
 	uint8_t max_filters;
+	bool initialized;
 };
 
 struct join_data{
@@ -91,7 +92,8 @@  static struct bt_mesh mesh = {
 	.lpn_support = false,
 	.proxy_support = false,
 	.crpl = DEFAULT_CRPL,
-	.friend_queue_sz = DEFAULT_FRIEND_QUEUE_SZ
+	.friend_queue_sz = DEFAULT_FRIEND_QUEUE_SZ,
+	.initialized = false
 };
 
 /* We allow only one outstanding Join request */
@@ -168,6 +170,11 @@  static void io_ready_callback(void *user_data, bool result)
 {
 	struct mesh_init_request *req = user_data;
 
+	if (mesh.initialized)
+		return;
+
+	mesh.initialized = true;
+
 	if (result)
 		node_attach_io_all(mesh.io);