@@ -3004,7 +3004,11 @@ static int nl80211_start_periodic(struct sk_buff *skb,
struct cfg80211_periodic_request *request;
struct cfg80211_registered_device *rdev;
struct net_device *dev;
- int err;
+ struct ieee80211_channel *channel;
+ struct nlattr *attr;
+ struct wiphy *wiphy;
+ int err, tmp, n_channels, i;
+ enum ieee80211_band band;
printk("nl80211_start_periodic\n");
@@ -3029,7 +3033,24 @@ static int nl80211_start_periodic(struct sk_buff *skb,
goto out;
}
- request = kzalloc(sizeof(*request), GFP_KERNEL);
+ wiphy = &rdev->wiphy;
+
+ if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
+ n_channels = validate_scan_freqs(
+ info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]);
+ if (!n_channels)
+ return -EINVAL;
+ } else {
+ n_channels = 0;
+
+ for (band = 0; band < IEEE80211_NUM_BANDS; band++)
+ if (wiphy->bands[band])
+ n_channels += wiphy->bands[band]->n_channels;
+ }
+
+ request = kzalloc(sizeof(*request)
+ + sizeof(channel) * n_channels,
+ GFP_KERNEL);
if (!request) {
err = -ENOMEM;
goto out;
@@ -3040,8 +3061,56 @@ static int nl80211_start_periodic(struct sk_buff *skb,
rdev->periodic_req = request;
+ i = 0;
+ if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
+ /* user specified, bail out if channel not found */
+ nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_FREQUENCIES], tmp) {
+ struct ieee80211_channel *chan;
+
+ chan = ieee80211_get_channel(wiphy, nla_get_u32(attr));
+
+ if (!chan) {
+ err = -EINVAL;
+ goto out_free;
+ }
+
+ /* ignore disabled channels */
+ if (chan->flags & IEEE80211_CHAN_DISABLED)
+ continue;
+
+ request->channels[i] = chan;
+ i++;
+ }
+ } else {
+ /* all channels */
+ for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+ int j;
+ if (!wiphy->bands[band])
+ continue;
+ for (j = 0; j < wiphy->bands[band]->n_channels; j++) {
+ struct ieee80211_channel *chan;
+
+ chan = &wiphy->bands[band]->channels[j];
+
+ if (chan->flags & IEEE80211_CHAN_DISABLED)
+ continue;
+
+ request->channels[i] = chan;
+ i++;
+ }
+ }
+ }
+
+ if (!i) {
+ err = -EINVAL;
+ goto out_free;
+ }
+
+ request->n_channels = i;
+
err = rdev->ops->periodic_start(&rdev->wiphy, dev, request);
if (err) {
+out_free:
kfree(request);
rdev->periodic_req = NULL;
goto out;