diff options
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r-- | net/wireless/nl80211.c | 106 |
1 files changed, 37 insertions, 69 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 0cd548267d4..eddab097435 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -408,6 +408,9 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->wiphy_idx); NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy)); + NLA_PUT_U32(msg, NL80211_ATTR_GENERATION, + cfg80211_rdev_list_generation); + NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_RETRY_SHORT, dev->wiphy.retry_short); NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_RETRY_LONG, @@ -701,15 +704,8 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; - struct ieee80211_channel *chan; - struct ieee80211_sta_ht_cap *ht_cap; u32 freq; - if (!rdev->ops->set_channel) { - result = -EOPNOTSUPP; - goto bad_res; - } - result = -EINVAL; if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { @@ -723,42 +719,12 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) } freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); - chan = ieee80211_get_channel(&rdev->wiphy, freq); - /* Primary channel not allowed */ - if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) - goto bad_res; - - if (channel_type == NL80211_CHAN_HT40MINUS && - (chan->flags & IEEE80211_CHAN_NO_HT40MINUS)) - goto bad_res; - else if (channel_type == NL80211_CHAN_HT40PLUS && - (chan->flags & IEEE80211_CHAN_NO_HT40PLUS)) - goto bad_res; - - /* - * At this point we know if that if HT40 was requested - * we are allowed to use it and the extension channel - * exists. - */ - - ht_cap = &rdev->wiphy.bands[chan->band]->ht_cap; - - /* no HT capabilities or intolerant */ - if (channel_type != NL80211_CHAN_NO_HT) { - if (!ht_cap->ht_supported) - goto bad_res; - if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) || - (ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT)) - goto bad_res; - } - - result = rdev->ops->set_channel(&rdev->wiphy, chan, - channel_type); + mutex_lock(&rdev->devlist_mtx); + result = rdev_set_freq(rdev, NULL, freq, channel_type); + mutex_unlock(&rdev->devlist_mtx); if (result) goto bad_res; - - rdev->channel = chan; } changed = 0; @@ -862,6 +828,11 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags, NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, dev->name); NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, dev->ieee80211_ptr->iftype); + + NLA_PUT_U32(msg, NL80211_ATTR_GENERATION, + rdev->devlist_generation ^ + (cfg80211_rdev_list_generation << 2)); + return genlmsg_end(msg, hdr); nla_put_failure: @@ -875,12 +846,12 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback * int if_idx = 0; int wp_start = cb->args[0]; int if_start = cb->args[1]; - struct cfg80211_registered_device *dev; + struct cfg80211_registered_device *rdev; struct wireless_dev *wdev; mutex_lock(&cfg80211_mutex); - list_for_each_entry(dev, &cfg80211_rdev_list, list) { - if (!net_eq(wiphy_net(&dev->wiphy), sock_net(skb->sk))) + list_for_each_entry(rdev, &cfg80211_rdev_list, list) { + if (!net_eq(wiphy_net(&rdev->wiphy), sock_net(skb->sk))) continue; if (wp_idx < wp_start) { wp_idx++; @@ -888,21 +859,21 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback * } if_idx = 0; - mutex_lock(&dev->devlist_mtx); - list_for_each_entry(wdev, &dev->netdev_list, list) { + mutex_lock(&rdev->devlist_mtx); + list_for_each_entry(wdev, &rdev->netdev_list, list) { if (if_idx < if_start) { if_idx++; continue; } if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, NLM_F_MULTI, - dev, wdev->netdev) < 0) { - mutex_unlock(&dev->devlist_mtx); + rdev, wdev->netdev) < 0) { + mutex_unlock(&rdev->devlist_mtx); goto out; } if_idx++; } - mutex_unlock(&dev->devlist_mtx); + mutex_unlock(&rdev->devlist_mtx); wp_idx++; } @@ -1006,12 +977,6 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) } } - if (!rdev->ops->change_virtual_intf || - !(rdev->wiphy.interface_modes & (1 << ntype))) { - err = -EOPNOTSUPP; - goto unlock; - } - if (info->attrs[NL80211_ATTR_MESH_ID]) { if (ntype != NL80211_IFTYPE_MESH_POINT) { err = -EINVAL; @@ -1037,18 +1002,10 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) } if (change) - err = rdev->ops->change_virtual_intf(&rdev->wiphy, dev, - ntype, flags, ¶ms); + err = cfg80211_change_iface(rdev, dev, ntype, flags, ¶ms); else err = 0; - WARN_ON(!err && dev->ieee80211_ptr->iftype != ntype); - - if (!err && (ntype != otype)) { - if (otype == NL80211_IFTYPE_ADHOC) - cfg80211_clear_ibss(dev, false); - } - unlock: dev_put(dev); cfg80211_unlock_rdev(rdev); @@ -1653,6 +1610,8 @@ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); + NLA_PUT_U32(msg, NL80211_ATTR_GENERATION, sinfo->generation); + sinfoattr = nla_nest_start(msg, NL80211_ATTR_STA_INFO); if (!sinfoattr) goto nla_put_failure; @@ -2138,6 +2097,8 @@ static int nl80211_send_mpath(struct sk_buff *msg, u32 pid, u32 seq, NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, dst); NLA_PUT(msg, NL80211_ATTR_MPATH_NEXT_HOP, ETH_ALEN, next_hop); + NLA_PUT_U32(msg, NL80211_ATTR_GENERATION, pinfo->generation); + pinfoattr = nla_nest_start(msg, NL80211_ATTR_MPATH_INFO); if (!pinfoattr) goto nla_put_failure; @@ -2220,7 +2181,7 @@ static int nl80211_dump_mpath(struct sk_buff *skb, if (netdev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) { err = -EOPNOTSUPP; - goto out; + goto out_err; } while (1) { @@ -3027,10 +2988,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) @@ -3127,8 +3087,7 @@ static int nl80211_send_bss(struct sk_buff *msg, u32 pid, u32 seq, int flags, if (!hdr) return -1; - NLA_PUT_U32(msg, NL80211_ATTR_SCAN_GENERATION, - rdev->bss_generation); + NLA_PUT_U32(msg, NL80211_ATTR_GENERATION, rdev->bss_generation); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, wdev->netdev->ifindex); bss = nla_nest_start(msg, NL80211_ATTR_BSS); @@ -3453,7 +3412,7 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) struct cfg80211_registered_device *rdev; struct net_device *dev; struct cfg80211_crypto_settings crypto; - struct ieee80211_channel *chan; + struct ieee80211_channel *chan, *fixedchan; const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL; int err, ssid_len, ie_len = 0; bool use_mfp = false; @@ -3496,6 +3455,15 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) goto out; } + mutex_lock(&rdev->devlist_mtx); + fixedchan = rdev_fixed_channel(rdev, NULL); + if (fixedchan && chan != fixedchan) { + err = -EBUSY; + mutex_unlock(&rdev->devlist_mtx); + goto out; + } + mutex_unlock(&rdev->devlist_mtx); + ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); |