Merge branch 'for-john' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next

Conflicts:
	net/wireless/reg.c
This commit is contained in:
John W. Linville 2013-11-05 15:49:02 -05:00
commit 353c78152c
38 changed files with 1302 additions and 453 deletions

View file

@ -504,7 +504,8 @@ cfg80211_get_chan_state(struct wireless_dev *wdev,
case NL80211_IFTYPE_ADHOC:
if (wdev->current_bss) {
*chan = wdev->current_bss->pub.channel;
*chanmode = wdev->ibss_fixed
*chanmode = (wdev->ibss_fixed &&
!wdev->ibss_dfs_possible)
? CHAN_MODE_SHARED
: CHAN_MODE_EXCLUSIVE;
return;

View file

@ -83,6 +83,8 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
struct cfg80211_cached_keys *connkeys)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct ieee80211_channel *check_chan;
u8 radar_detect_width = 0;
int err;
ASSERT_WDEV_LOCK(wdev);
@ -114,14 +116,28 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
wdev->connect_keys = connkeys;
wdev->ibss_fixed = params->channel_fixed;
wdev->ibss_dfs_possible = params->userspace_handles_dfs;
#ifdef CONFIG_CFG80211_WEXT
wdev->wext.ibss.chandef = params->chandef;
#endif
check_chan = params->chandef.chan;
if (params->userspace_handles_dfs) {
/* use channel NULL to check for radar even if the current
* channel is not a radar channel - it might decide to change
* to DFS channel later.
*/
radar_detect_width = BIT(params->chandef.width);
check_chan = NULL;
}
err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype,
check_chan,
(params->channel_fixed &&
!radar_detect_width)
? CHAN_MODE_SHARED
: CHAN_MODE_EXCLUSIVE,
radar_detect_width);
err = cfg80211_can_use_chan(rdev, wdev, params->chandef.chan,
params->channel_fixed
? CHAN_MODE_SHARED
: CHAN_MODE_EXCLUSIVE);
if (err) {
wdev->connect_keys = NULL;
return err;

View file

@ -354,6 +354,9 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
[NL80211_ATTR_CSA_IES] = { .type = NLA_NESTED },
[NL80211_ATTR_CSA_C_OFF_BEACON] = { .type = NLA_U16 },
[NL80211_ATTR_CSA_C_OFF_PRESP] = { .type = NLA_U16 },
[NL80211_ATTR_STA_SUPPORTED_CHANNELS] = { .type = NLA_BINARY },
[NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES] = { .type = NLA_BINARY },
[NL80211_ATTR_HANDLE_DFS] = { .type = NLA_FLAG },
};
/* policy for the key attributes */
@ -3896,9 +3899,45 @@ static int nl80211_parse_sta_wme(struct genl_info *info,
return 0;
}
static int nl80211_parse_sta_channel_info(struct genl_info *info,
struct station_parameters *params)
{
if (info->attrs[NL80211_ATTR_STA_SUPPORTED_CHANNELS]) {
params->supported_channels =
nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_CHANNELS]);
params->supported_channels_len =
nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_CHANNELS]);
/*
* Need to include at least one (first channel, number of
* channels) tuple for each subband, and must have proper
* tuples for the rest of the data as well.
*/
if (params->supported_channels_len < 2)
return -EINVAL;
if (params->supported_channels_len % 2)
return -EINVAL;
}
if (info->attrs[NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES]) {
params->supported_oper_classes =
nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES]);
params->supported_oper_classes_len =
nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES]);
/*
* The value of the Length field of the Supported Operating
* Classes element is between 2 and 253.
*/
if (params->supported_oper_classes_len < 2 ||
params->supported_oper_classes_len > 253)
return -EINVAL;
}
return 0;
}
static int nl80211_set_station_tdls(struct genl_info *info,
struct station_parameters *params)
{
int err;
/* Dummy STA entry gets updated once the peer capabilities are known */
if (info->attrs[NL80211_ATTR_PEER_AID])
params->aid = nla_get_u16(info->attrs[NL80211_ATTR_PEER_AID]);
@ -3909,6 +3948,10 @@ static int nl80211_set_station_tdls(struct genl_info *info,
params->vht_capa =
nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]);
err = nl80211_parse_sta_channel_info(info, params);
if (err)
return err;
return nl80211_parse_sta_wme(info, params);
}
@ -4089,6 +4132,10 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
return -EINVAL;
}
err = nl80211_parse_sta_channel_info(info, &params);
if (err)
return err;
err = nl80211_parse_sta_wme(info, &params);
if (err)
return err;
@ -5653,6 +5700,7 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
return -EINVAL;
break;
case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_MESH_POINT:
break;
default:
return -EOPNOTSUPP;
@ -5665,9 +5713,7 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
return -EINVAL;
/* only important for AP, IBSS and mesh create IEs internally */
if (need_new_beacon &&
(!info->attrs[NL80211_ATTR_CSA_IES] ||
!info->attrs[NL80211_ATTR_CSA_C_OFF_BEACON]))
if (need_new_beacon && !info->attrs[NL80211_ATTR_CSA_IES])
return -EINVAL;
params.count = nla_get_u32(info->attrs[NL80211_ATTR_CH_SWITCH_COUNT]);
@ -5722,9 +5768,9 @@ skip_beacons:
if (!cfg80211_reg_can_beacon(&rdev->wiphy, &params.chandef))
return -EINVAL;
/* DFS channels are only supported for AP/P2P GO ... for now. */
if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP ||
dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) {
dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO ||
dev->ieee80211_ptr->iftype == NL80211_IFTYPE_ADHOC) {
err = cfg80211_chandef_dfs_required(wdev->wiphy,
&params.chandef);
if (err < 0) {
@ -6556,6 +6602,9 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
ibss.control_port =
nla_get_flag(info->attrs[NL80211_ATTR_CONTROL_PORT]);
ibss.userspace_handles_dfs =
nla_get_flag(info->attrs[NL80211_ATTR_HANDLE_DFS]);
err = cfg80211_join_ibss(rdev, dev, &ibss, connkeys);
if (err)
kfree(connkeys);
@ -10762,7 +10811,8 @@ void cfg80211_ch_switch_notify(struct net_device *dev,
if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
wdev->iftype != NL80211_IFTYPE_P2P_GO &&
wdev->iftype != NL80211_IFTYPE_ADHOC))
wdev->iftype != NL80211_IFTYPE_ADHOC &&
wdev->iftype != NL80211_IFTYPE_MESH_POINT))
goto out;
wdev->channel = chandef->chan;

View file

@ -787,7 +787,6 @@ const char *reg_initiator_name(enum nl80211_reg_initiator initiator)
EXPORT_SYMBOL(reg_initiator_name);
#ifdef CONFIG_CFG80211_REG_DEBUG
static void chan_reg_rule_print_dbg(struct ieee80211_channel *chan,
const struct ieee80211_reg_rule *reg_rule)
{
@ -974,6 +973,13 @@ static bool reg_dev_ignore_cell_hint(struct wiphy *wiphy)
}
#endif
static bool wiphy_strict_alpha2_regd(struct wiphy *wiphy)
{
if (wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY &&
!(wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY))
return true;
return false;
}
static bool ignore_reg_update(struct wiphy *wiphy,
enum nl80211_reg_initiator initiator)
@ -1000,7 +1006,7 @@ static bool ignore_reg_update(struct wiphy *wiphy,
* wiphy->regd will be set once the device has its own
* desired regulatory domain set
*/
if (wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY && !wiphy->regd &&
if (wiphy_strict_alpha2_regd(wiphy) && !wiphy->regd &&
initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE &&
!is_world_regdom(lr->alpha2)) {
REG_DBG_PRINT("Ignoring regulatory request set by %s "
@ -1706,8 +1712,8 @@ int regulatory_hint(struct wiphy *wiphy, const char *alpha2)
}
EXPORT_SYMBOL(regulatory_hint);
void regulatory_hint_11d(struct wiphy *wiphy, enum ieee80211_band band,
const u8 *country_ie, u8 country_ie_len)
void regulatory_hint_country_ie(struct wiphy *wiphy, enum ieee80211_band band,
const u8 *country_ie, u8 country_ie_len)
{
char alpha2[2];
enum environment_cap env = ENVIRON_ANY;

View file

@ -58,7 +58,7 @@ int regulatory_hint_found_beacon(struct wiphy *wiphy,
gfp_t gfp);
/**
* regulatory_hint_11d - hints a country IE as a regulatory domain
* regulatory_hint_country_ie - hints a country IE as a regulatory domain
* @wiphy: the wireless device giving the hint (used only for reporting
* conflicts)
* @band: the band on which the country IE was received on. This determines
@ -78,7 +78,7 @@ int regulatory_hint_found_beacon(struct wiphy *wiphy,
* not observed. For this reason if a triplet is seen with channel
* information for a band the BSS is not present in it will be ignored.
*/
void regulatory_hint_11d(struct wiphy *wiphy,
void regulatory_hint_country_ie(struct wiphy *wiphy,
enum ieee80211_band band,
const u8 *country_ie,
u8 country_ie_len);

View file

@ -682,8 +682,8 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
* - country_ie + 2, the start of the country ie data, and
* - and country_ie[1] which is the IE length
*/
regulatory_hint_11d(wdev->wiphy, bss->channel->band,
country_ie + 2, country_ie[1]);
regulatory_hint_country_ie(wdev->wiphy, bss->channel->band,
country_ie + 2, country_ie[1]);
kfree(country_ie);
}

View file

@ -1249,7 +1249,7 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
enum cfg80211_chan_mode chmode;
int num_different_channels = 0;
int total = 1;
bool radar_required;
bool radar_required = false;
int i, j;
ASSERT_RTNL();
@ -1264,14 +1264,20 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_P2P_GO:
case NL80211_IFTYPE_WDS:
radar_required = !!(chan &&
(chan->flags & IEEE80211_CHAN_RADAR));
/* if the interface could potentially choose a DFS channel,
* then mark DFS as required.
*/
if (!chan) {
if (chanmode != CHAN_MODE_UNDEFINED && radar_detect)
radar_required = true;
break;
}
radar_required = !!(chan->flags & IEEE80211_CHAN_RADAR);
break;
case NL80211_IFTYPE_P2P_CLIENT:
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_P2P_DEVICE:
case NL80211_IFTYPE_MONITOR:
radar_required = false;
break;
case NUM_NL80211_IFTYPES:
case NL80211_IFTYPE_UNSPECIFIED: