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

Commit 5ba63533 authored by Johannes Berg's avatar Johannes Berg Committed by John W. Linville
Browse files

cfg80211: fix alignment problem in scan request



The memory layout for scan requests was rather wrong,
we put the scan SSIDs before the channels which could
lead to the channel pointers being unaligned in memory.
It turns out that using a pointer to the channel array
isn't necessary anyway since we can embed a zero-length
array into the struct.

Signed-off-by: default avatarJohannes Berg <johannes@sipsolutions.net>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent ad5351db
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -559,7 +559,6 @@ struct cfg80211_ssid {
struct cfg80211_scan_request {
	struct cfg80211_ssid *ssids;
	int n_ssids;
	struct ieee80211_channel **channels;
	u32 n_channels;
	const u8 *ie;
	size_t ie_len;
@@ -568,6 +567,9 @@ struct cfg80211_scan_request {
	struct wiphy *wiphy;
	struct net_device *dev;
	bool aborted;

	/* keep last */
	struct ieee80211_channel *channels[0];
};

/**
+1 −1
Original line number Diff line number Diff line
@@ -715,7 +715,7 @@ struct ieee80211_local {
	struct mutex scan_mtx;
	unsigned long scanning;
	struct cfg80211_ssid scan_ssid;
	struct cfg80211_scan_request int_scan_req;
	struct cfg80211_scan_request *int_scan_req;
	struct cfg80211_scan_request *scan_req;
	struct ieee80211_channel *scan_channel;
	const u8 *orig_ies;
+8 −8
Original line number Diff line number Diff line
@@ -765,9 +765,9 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
		supp_ht = supp_ht || sband->ht_cap.ht_supported;
	}

	local->int_scan_req.n_channels = channels;
	local->int_scan_req.channels = kzalloc(sizeof(void *) * channels, GFP_KERNEL);
	if (!local->int_scan_req.channels)
	local->int_scan_req = kzalloc(sizeof(*local->int_scan_req) +
				      sizeof(void *) * channels, GFP_KERNEL);
	if (!local->int_scan_req)
		return -ENOMEM;

	/* if low-level driver supports AP, we also support VLAN */
@@ -882,13 +882,13 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)

	/* alloc internal scan request */
	i = 0;
	local->int_scan_req.ssids = &local->scan_ssid;
	local->int_scan_req.n_ssids = 1;
	local->int_scan_req->ssids = &local->scan_ssid;
	local->int_scan_req->n_ssids = 1;
	for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
		if (!hw->wiphy->bands[band])
			continue;
		for (j = 0; j < hw->wiphy->bands[band]->n_channels; j++) {
			local->int_scan_req.channels[i] =
			local->int_scan_req->channels[i] =
				&hw->wiphy->bands[band]->channels[j];
			i++;
		}
@@ -920,7 +920,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
 fail_workqueue:
	wiphy_unregister(local->hw.wiphy);
 fail_wiphy_register:
	kfree(local->int_scan_req.channels);
	kfree(local->int_scan_req->channels);
	return result;
}
EXPORT_SYMBOL(ieee80211_register_hw);
@@ -962,7 +962,7 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
	wiphy_unregister(local->hw.wiphy);
	ieee80211_wep_free(local);
	ieee80211_led_exit(local);
	kfree(local->int_scan_req.channels);
	kfree(local->int_scan_req);
}
EXPORT_SYMBOL(ieee80211_unregister_hw);

+5 −5
Original line number Diff line number Diff line
@@ -277,7 +277,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
	if (test_bit(SCAN_HW_SCANNING, &local->scanning))
		ieee80211_restore_scan_ies(local);

	if (local->scan_req != &local->int_scan_req)
	if (local->scan_req != local->int_scan_req)
		cfg80211_scan_done(local->scan_req, aborted);
	local->scan_req = NULL;

@@ -423,7 +423,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
	local->scan_req = req;
	local->scan_sdata = sdata;

	if (req != &local->int_scan_req &&
	if (req != local->int_scan_req &&
	    sdata->vif.type == NL80211_IFTYPE_STATION &&
	    !list_empty(&ifmgd->work_list)) {
		/* actually wait for the work it's doing to finish/time out */
@@ -743,10 +743,10 @@ int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata,
	if (local->scan_req)
		goto unlock;

	memcpy(local->int_scan_req.ssids[0].ssid, ssid, IEEE80211_MAX_SSID_LEN);
	local->int_scan_req.ssids[0].ssid_len = ssid_len;
	memcpy(local->int_scan_req->ssids[0].ssid, ssid, IEEE80211_MAX_SSID_LEN);
	local->int_scan_req->ssids[0].ssid_len = ssid_len;

	ret = __ieee80211_start_scan(sdata, &sdata->local->int_scan_req);
	ret = __ieee80211_start_scan(sdata, sdata->local->int_scan_req);
 unlock:
	mutex_unlock(&local->scan_mtx);
	return ret;
+1 −2
Original line number Diff line number Diff line
@@ -3002,10 +3002,9 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
		goto out;
	}

	request->channels = (void *)((char *)request + sizeof(*request));
	request->n_channels = n_channels;
	if (n_ssids)
		request->ssids = (void *)(request->channels + n_channels);
		request->ssids = (void *)&request->channels[n_channels];
	request->n_ssids = n_ssids;
	if (ie_len) {
		if (request->ssids)
Loading