Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 278976
b: refs/heads/master
c: bdd90d5
h: refs/heads/master
v: v3
  • Loading branch information
Johannes Berg authored and John W. Linville committed Dec 15, 2011
1 parent 7018796 commit 02c0184
Show file tree
Hide file tree
Showing 5 changed files with 132 additions and 90 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: d83023daa219486e9aa139d423308a045bf0438b
refs/heads/master: bdd90d5e36a55271beb957b3d7ca3e29b2a90207
6 changes: 5 additions & 1 deletion trunk/include/linux/nl80211.h
Original file line number Diff line number Diff line change
Expand Up @@ -1536,7 +1536,11 @@ enum nl80211_iftype {
* @NL80211_STA_FLAG_WME: station is WME/QoS capable
* @NL80211_STA_FLAG_MFP: station uses management frame protection
* @NL80211_STA_FLAG_AUTHENTICATED: station is authenticated
* @NL80211_STA_FLAG_TDLS_PEER: station is a TDLS peer
* @NL80211_STA_FLAG_TDLS_PEER: station is a TDLS peer -- this flag should
* only be used in managed mode (even in the flags mask). Note that the
* flag can't be changed, it is only valid while adding a station, and
* attempts to change it will silently be ignored (rather than rejected
* as errors.)
* @NL80211_STA_FLAG_MAX: highest station flag number currently defined
* @__NL80211_STA_FLAG_AFTER_LAST: internal use
*/
Expand Down
7 changes: 6 additions & 1 deletion trunk/include/net/cfg80211.h
Original file line number Diff line number Diff line change
Expand Up @@ -1346,7 +1346,12 @@ struct cfg80211_gtk_rekey_data {
*
* @add_station: Add a new station.
* @del_station: Remove a station; @mac may be NULL to remove all stations.
* @change_station: Modify a given station.
* @change_station: Modify a given station. Note that flags changes are not much
* validated in cfg80211, in particular the auth/assoc/authorized flags
* might come to the driver in invalid combinations -- make sure to check
* them, also against the existing state! Also, supported_rates changes are
* not checked in station mode -- drivers need to reject (or ignore) them
* for anything but TDLS peers.
* @get_station: get station information for the station identified by @mac
* @dump_station: dump station callback -- resume dump at index @idx
*
Expand Down
8 changes: 8 additions & 0 deletions trunk/net/mac80211/cfg.c
Original file line number Diff line number Diff line change
Expand Up @@ -976,6 +976,14 @@ static int ieee80211_change_station(struct wiphy *wiphy,
return -EINVAL;
}

/* in station mode, supported rates are only valid with TDLS */
if (sdata->vif.type == NL80211_IFTYPE_STATION &&
params->supported_rates &&
!test_sta_flag(sta, WLAN_STA_TDLS_PEER)) {
rcu_read_unlock();
return -EINVAL;
}

if (params->vlan && params->vlan != sta->sdata->dev) {
vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);

Expand Down
199 changes: 112 additions & 87 deletions trunk/net/wireless/nl80211.c
Original file line number Diff line number Diff line change
Expand Up @@ -2579,6 +2579,9 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
params.ht_capa =
nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]);

if (!rdev->ops->change_station)
return -EOPNOTSUPP;

if (parse_station_flags(info, &params))
return -EINVAL;

Expand All @@ -2590,73 +2593,84 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
params.plink_state =
nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_STATE]);

params.vlan = get_vlan(info, rdev);
if (IS_ERR(params.vlan))
return PTR_ERR(params.vlan);

/* validate settings */
err = 0;

switch (dev->ieee80211_ptr->iftype) {
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_AP_VLAN:
case NL80211_IFTYPE_P2P_GO:
/* disallow mesh-specific things */
if (params.plink_action)
err = -EINVAL;
return -EINVAL;

/* TDLS can't be set, ... */
if (params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))
return -EINVAL;
/*
* ... but don't bother the driver with it. This works around
* a hostapd/wpa_supplicant issue -- it always includes the
* TLDS_PEER flag in the mask even for AP mode.
*/
params.sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);

/* accept only the listed bits */
if (params.sta_flags_mask &
~(BIT(NL80211_STA_FLAG_AUTHORIZED) |
BIT(NL80211_STA_FLAG_SHORT_PREAMBLE) |
BIT(NL80211_STA_FLAG_WME) |
BIT(NL80211_STA_FLAG_MFP)))
return -EINVAL;

/* must be last in here for error handling */
params.vlan = get_vlan(info, rdev);
if (IS_ERR(params.vlan))
return PTR_ERR(params.vlan);
break;
case NL80211_IFTYPE_P2P_CLIENT:
case NL80211_IFTYPE_STATION:
/* disallow things sta doesn't support */
if (params.plink_action)
err = -EINVAL;
if (params.vlan)
err = -EINVAL;
if (params.supported_rates &&
!(params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)))
err = -EINVAL;
return -EINVAL;
if (params.ht_capa)
err = -EINVAL;
return -EINVAL;
if (params.listen_interval >= 0)
err = -EINVAL;
if (params.sta_flags_mask &
~(BIT(NL80211_STA_FLAG_AUTHORIZED) |
BIT(NL80211_STA_FLAG_TDLS_PEER)))
err = -EINVAL;
/* can't change the TDLS bit */
if (!(params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) &&
(params.sta_flags_mask & BIT(NL80211_STA_FLAG_TDLS_PEER)))
err = -EINVAL;
return -EINVAL;
/*
* Don't allow userspace to change the TDLS_PEER flag,
* but silently ignore attempts to change it since we
* don't have state here to verify that it doesn't try
* to change the flag.
*/
params.sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);

/* reject any changes other than AUTHORIZED */
if (params.sta_flags_mask & ~BIT(NL80211_STA_FLAG_AUTHORIZED))
return -EINVAL;
break;
case NL80211_IFTYPE_MESH_POINT:
/* disallow things mesh doesn't support */
if (params.vlan)
err = -EINVAL;
return -EINVAL;
if (params.ht_capa)
err = -EINVAL;
return -EINVAL;
if (params.listen_interval >= 0)
err = -EINVAL;
return -EINVAL;
/*
* No special handling for TDLS here -- the userspace
* mesh code doesn't have this bug.
*/
if (params.sta_flags_mask &
~(BIT(NL80211_STA_FLAG_AUTHENTICATED) |
BIT(NL80211_STA_FLAG_MFP) |
BIT(NL80211_STA_FLAG_AUTHORIZED)))
err = -EINVAL;
return -EINVAL;
break;
default:
err = -EINVAL;
return -EOPNOTSUPP;
}

if (err)
goto out;

if (!rdev->ops->change_station) {
err = -EOPNOTSUPP;
goto out;
}
/* be aware of params.vlan when changing code here */

err = rdev->ops->change_station(&rdev->wiphy, dev, mac_addr, &params);

out:
if (params.vlan)
dev_put(params.vlan);

Expand Down Expand Up @@ -2711,70 +2725,81 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
params.plink_action =
nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]);

if (!rdev->ops->add_station)
return -EOPNOTSUPP;

if (parse_station_flags(info, &params))
return -EINVAL;

/* parse WME attributes if sta is WME capable */
if ((rdev->wiphy.flags & WIPHY_FLAG_AP_UAPSD) &&
(params.sta_flags_set & BIT(NL80211_STA_FLAG_WME)) &&
info->attrs[NL80211_ATTR_STA_WME]) {
struct nlattr *tb[NL80211_STA_WME_MAX + 1];
struct nlattr *nla;
switch (dev->ieee80211_ptr->iftype) {
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_AP_VLAN:
case NL80211_IFTYPE_P2P_GO:
/* parse WME attributes if sta is WME capable */
if ((rdev->wiphy.flags & WIPHY_FLAG_AP_UAPSD) &&
(params.sta_flags_set & BIT(NL80211_STA_FLAG_WME)) &&
info->attrs[NL80211_ATTR_STA_WME]) {
struct nlattr *tb[NL80211_STA_WME_MAX + 1];
struct nlattr *nla;

nla = info->attrs[NL80211_ATTR_STA_WME];
err = nla_parse_nested(tb, NL80211_STA_WME_MAX, nla,
nl80211_sta_wme_policy);
if (err)
return err;

nla = info->attrs[NL80211_ATTR_STA_WME];
err = nla_parse_nested(tb, NL80211_STA_WME_MAX, nla,
nl80211_sta_wme_policy);
if (err)
return err;
if (tb[NL80211_STA_WME_UAPSD_QUEUES])
params.uapsd_queues =
nla_get_u8(tb[NL80211_STA_WME_UAPSD_QUEUES]);
if (params.uapsd_queues &
~IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK)
return -EINVAL;

if (tb[NL80211_STA_WME_UAPSD_QUEUES])
params.uapsd_queues =
nla_get_u8(tb[NL80211_STA_WME_UAPSD_QUEUES]);
if (params.uapsd_queues & ~IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK)
return -EINVAL;
if (tb[NL80211_STA_WME_MAX_SP])
params.max_sp =
nla_get_u8(tb[NL80211_STA_WME_MAX_SP]);

if (tb[NL80211_STA_WME_MAX_SP])
params.max_sp =
nla_get_u8(tb[NL80211_STA_WME_MAX_SP]);
if (params.max_sp &
~IEEE80211_WMM_IE_STA_QOSINFO_SP_MASK)
return -EINVAL;

if (params.max_sp & ~IEEE80211_WMM_IE_STA_QOSINFO_SP_MASK)
params.sta_modify_mask |= STATION_PARAM_APPLY_UAPSD;
}
/* TDLS peers cannot be added */
if (params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))
return -EINVAL;
/* but don't bother the driver with it */
params.sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);

params.sta_modify_mask |= STATION_PARAM_APPLY_UAPSD;
/* must be last in here for error handling */
params.vlan = get_vlan(info, rdev);
if (IS_ERR(params.vlan))
return PTR_ERR(params.vlan);
break;
case NL80211_IFTYPE_MESH_POINT:
/* TDLS peers cannot be added */
if (params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))
return -EINVAL;
break;
case NL80211_IFTYPE_STATION:
/* Only TDLS peers can be added */
if (!(params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)))
return -EINVAL;
/* Can only add if TDLS ... */
if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS))
return -EOPNOTSUPP;
/* ... with external setup is supported */
if (!(rdev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP))
return -EOPNOTSUPP;
break;
default:
return -EOPNOTSUPP;
}

if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION)
return -EINVAL;

/*
* Only managed stations can add TDLS peers, and only when the
* wiphy supports external TDLS setup.
*/
if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION &&
!((params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) &&
(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) &&
(rdev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP)))
return -EINVAL;

params.vlan = get_vlan(info, rdev);
if (IS_ERR(params.vlan))
return PTR_ERR(params.vlan);

/* validate settings */
err = 0;

if (!rdev->ops->add_station) {
err = -EOPNOTSUPP;
goto out;
}
/* be aware of params.vlan when changing code here */

err = rdev->ops->add_station(&rdev->wiphy, dev, mac_addr, &params);

out:
if (params.vlan)
dev_put(params.vlan);
return err;
Expand Down

0 comments on commit 02c0184

Please sign in to comment.