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

Commit 3209e061 authored by Andres Salomon's avatar Andres Salomon Committed by John W. Linville
Browse files

libertas: ensure we clean up a scan request properly



Commit 2e30168b ("libertas: terminate scan when stopping interface")
adds cleanup code to lbs_eth_stop to call cfg80211_scan_done if there's
an outstanding cfg80211_scan_request.  However, it assumes that the
scan request was allocated via the cfg80211 stack.  Libertas has
its own internal allocation method, kept track of with
priv->internal_scan.  This doesn't set scan_req->wiphy, amongst other
things, which results in hitting a BUG() when we call cfg80211_scan_done
on the request.

This provides a function to take care of the low-level scan_req cleanup
details.  We simply call that to deal with finishing up scan requests.

The bug we were hitting was:

[  964.321495] kernel BUG at net/wireless/core.h:87!
[  964.329970] Unable to handle kernel NULL pointer dereference at virtual address 00000000
[  964.341963] pgd = dcf80000
...
[  964.849998] 9fe0: 00000000 beb417b8 4018e280 401e822c 60000010 00000004 00000000 00000000
[  964.865007] [<c003104c>] (__bug+0x1c/0x28) from [<c0384ffc>] (cfg80211_scan_done+0x54/0x6c)
[  964.895324] [<c0384ffc>] (cfg80211_scan_done+0x54/0x6c) from [<bf028bac>] (lbs_eth_stop+0x10c/0x188 [libertas])
[  964.895324] [<bf028bac>] (lbs_eth_stop+0x10c/0x188 [libertas]) from [<c03002a0>] (__dev_close_many+0x94/0xc4)
[  964.918995] [<c03002a0>] (__dev_close_many+0x94/0xc4) from [<c030037c>] (dev_close_many+0x78/0xe0)

Signed-off-by: default avatarAndres Salomon <dilinger@queued.net>
Acked-by: default avatarDan Williams <dcbw@redhat.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 93348928
Loading
Loading
Loading
Loading
+17 −8
Original line number Diff line number Diff line
@@ -728,15 +728,9 @@ static void lbs_scan_worker(struct work_struct *work)
		le16_to_cpu(scan_cmd->hdr.size),
		lbs_ret_scan, 0);

	if (priv->scan_channel >= priv->scan_req->n_channels) {
	if (priv->scan_channel >= priv->scan_req->n_channels)
		/* Mark scan done */
		if (priv->internal_scan)
			kfree(priv->scan_req);
		else
			cfg80211_scan_done(priv->scan_req, false);

		priv->scan_req = NULL;
	}
		lbs_scan_done(priv);

	/* Restart network */
	if (carrier)
@@ -774,6 +768,21 @@ static void _internal_start_scan(struct lbs_private *priv, bool internal,
	lbs_deb_leave(LBS_DEB_CFG80211);
}

/*
 * Clean up priv->scan_req.  Should be used to handle the allocation details.
 */
void lbs_scan_done(struct lbs_private *priv)
{
	WARN_ON(!priv->scan_req);

	if (priv->internal_scan)
		kfree(priv->scan_req);
	else
		cfg80211_scan_done(priv->scan_req, false);

	priv->scan_req = NULL;
}

static int lbs_cfg_scan(struct wiphy *wiphy,
	struct net_device *dev,
	struct cfg80211_scan_request *request)
+1 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@ int lbs_reg_notifier(struct wiphy *wiphy,
void lbs_send_disconnect_notification(struct lbs_private *priv);
void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event);

void lbs_scan_done(struct lbs_private *priv);
void lbs_scan_deinit(struct lbs_private *priv);
int lbs_disconnect(struct lbs_private *priv, u16 reason);

+2 −4
Original line number Diff line number Diff line
@@ -255,10 +255,8 @@ static int lbs_eth_stop(struct net_device *dev)

	lbs_update_mcast(priv);
	cancel_delayed_work_sync(&priv->scan_work);
	if (priv->scan_req) {
		cfg80211_scan_done(priv->scan_req, false);
		priv->scan_req = NULL;
	}
	if (priv->scan_req)
		lbs_scan_done(priv);

	netif_carrier_off(priv->dev);