cfg80211: fix alignment problem in scan request
authorJohannes Berg <johannes@sipsolutions.net>
Fri, 7 Aug 2009 15:54:07 +0000 (17:54 +0200)
committerJohn W. Linville <linville@tuxdriver.com>
Fri, 14 Aug 2009 13:13:44 +0000 (09:13 -0400)
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: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
include/net/cfg80211.h
net/mac80211/ieee80211_i.h
net/mac80211/main.c
net/mac80211/scan.c
net/wireless/nl80211.c
net/wireless/scan.c
net/wireless/sme.c

index de7d116acc3d5796708e03887e514f579e127efe..d5756c9fe3d3df807954e82796636c63d5b65ca3 100644 (file)
@@ -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];
 };
 
 /**
index 99433222bc5cc7512ca9f214df19ac9b5ee2c0d5..d6bd7dd7796057b581936bccd4559009a3aba0cb 100644 (file)
@@ -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;
index 0c4f8e122ed67c0ae24421072a3d3e4342a3962b..b03fd84777fa5d12b526ade7cc81d5c60eeb0bf1 100644 (file)
@@ -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);
 
index 244f53f3c8b48395e7ca350575f796955609bf26..e091cbc3434f9049a76c3a33d76bc5cffca2f7ea 100644 (file)
@@ -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;
index b3d5c1df08dd318a6a9c6fb44f47ea0a4db8ea21..667a87d307da8dd7e140df2cb03d4cfa18c9fda4 100644 (file)
@@ -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)
index 1bcb1312bd949a539e2efc0b66d37729a52261c9..e6c1f11595da05ec2e87976475e693bbd89d4022 100644 (file)
@@ -612,8 +612,8 @@ int cfg80211_wext_siwscan(struct net_device *dev,
 
        creq->wiphy = wiphy;
        creq->dev = dev;
-       creq->ssids = (void *)(creq + 1);
-       creq->channels = (void *)(creq->ssids + 1);
+       /* SSIDs come after channels */
+       creq->ssids = (void *)&creq->channels[n_channels];
        creq->n_channels = n_channels;
        creq->n_ssids = 1;
 
index 104b33e34d22bc0f9a2e71b80d2300a148eb5857..8e2ef54ea714c076f42668f5d84259c9f56e28dd 100644 (file)
@@ -65,7 +65,6 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev)
        if (!request)
                return -ENOMEM;
 
-       request->channels = (void *)((char *)request + sizeof(*request));
        if (wdev->conn->params.channel)
                request->channels[0] = wdev->conn->params.channel;
        else {
@@ -82,7 +81,7 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev)
                }
        }
        request->n_channels = n_channels;
-       request->ssids = (void *)(request->channels + n_channels);
+       request->ssids = (void *)&request->channels[n_channels];
        request->n_ssids = 1;
 
        memcpy(request->ssids[0].ssid, wdev->conn->params.ssid,