From 2afe38d15cee01b2bb8f22383571f7f4a95f2d99 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 6 Jan 2015 14:00:53 +0100 Subject: cfg80211-wext: export symbols only when needed When a fully converted cfg80211 driver needs cfg80211-wext for userspace API purposes, the symbols need not be exported. When other drivers (orinoco/hermes or ipw2200) are enabled, they do need the symbols exported as they use them directly. Make those drivers select a new CFG80211_WEXT_EXPORT Kconfig symbol (instead of just CFG80211_WEXT) and export the functions only if requested - this saves about 1/2k due to the size of EXPORT_SYMBOL() itself. Signed-off-by: Johannes Berg --- net/wireless/Kconfig | 8 ++++++++ net/wireless/scan.c | 4 ++-- net/wireless/wext-compat.c | 18 +++++++++--------- net/wireless/wext-compat.h | 6 ++++++ 4 files changed, 25 insertions(+), 11 deletions(-) (limited to 'net/wireless') diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig index 29c8675f9a11..b13dfb4ff001 100644 --- a/net/wireless/Kconfig +++ b/net/wireless/Kconfig @@ -178,10 +178,18 @@ config CFG80211_WEXT bool "cfg80211 wireless extensions compatibility" depends on CFG80211 select WEXT_CORE + default y if CFG80211_WEXT_EXPORT help Enable this option if you need old userspace for wireless extensions with cfg80211-based drivers. +config CFG80211_WEXT_EXPORT + bool + depends on CFG80211 + help + Drivers should select this option if they require cfg80211's + wext compatibility symbols to be exported. + config LIB80211 tristate default n diff --git a/net/wireless/scan.c b/net/wireless/scan.c index c705c3e2b751..25e1e1fad905 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -1237,7 +1237,7 @@ int cfg80211_wext_siwscan(struct net_device *dev, kfree(creq); return err; } -EXPORT_SYMBOL_GPL(cfg80211_wext_siwscan); +EXPORT_WEXT_HANDLER(cfg80211_wext_siwscan); static void ieee80211_scan_add_ies(struct iw_request_info *info, const struct cfg80211_bss_ies *ies, @@ -1545,5 +1545,5 @@ int cfg80211_wext_giwscan(struct net_device *dev, return res; } -EXPORT_SYMBOL_GPL(cfg80211_wext_giwscan); +EXPORT_WEXT_HANDLER(cfg80211_wext_giwscan); #endif diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 5b24d39d7903..fff1bef6ed6d 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -63,7 +63,7 @@ int cfg80211_wext_giwname(struct net_device *dev, return 0; } -EXPORT_SYMBOL_GPL(cfg80211_wext_giwname); +EXPORT_WEXT_HANDLER(cfg80211_wext_giwname); int cfg80211_wext_siwmode(struct net_device *dev, struct iw_request_info *info, u32 *mode, char *extra) @@ -99,7 +99,7 @@ int cfg80211_wext_siwmode(struct net_device *dev, struct iw_request_info *info, return cfg80211_change_iface(rdev, dev, type, NULL, &vifparams); } -EXPORT_SYMBOL_GPL(cfg80211_wext_siwmode); +EXPORT_WEXT_HANDLER(cfg80211_wext_siwmode); int cfg80211_wext_giwmode(struct net_device *dev, struct iw_request_info *info, u32 *mode, char *extra) @@ -134,7 +134,7 @@ int cfg80211_wext_giwmode(struct net_device *dev, struct iw_request_info *info, } return 0; } -EXPORT_SYMBOL_GPL(cfg80211_wext_giwmode); +EXPORT_WEXT_HANDLER(cfg80211_wext_giwmode); int cfg80211_wext_giwrange(struct net_device *dev, @@ -248,7 +248,7 @@ int cfg80211_wext_giwrange(struct net_device *dev, return 0; } -EXPORT_SYMBOL_GPL(cfg80211_wext_giwrange); +EXPORT_WEXT_HANDLER(cfg80211_wext_giwrange); /** @@ -303,7 +303,7 @@ int cfg80211_wext_siwrts(struct net_device *dev, return err; } -EXPORT_SYMBOL_GPL(cfg80211_wext_siwrts); +EXPORT_WEXT_HANDLER(cfg80211_wext_siwrts); int cfg80211_wext_giwrts(struct net_device *dev, struct iw_request_info *info, @@ -317,7 +317,7 @@ int cfg80211_wext_giwrts(struct net_device *dev, return 0; } -EXPORT_SYMBOL_GPL(cfg80211_wext_giwrts); +EXPORT_WEXT_HANDLER(cfg80211_wext_giwrts); int cfg80211_wext_siwfrag(struct net_device *dev, struct iw_request_info *info, @@ -343,7 +343,7 @@ int cfg80211_wext_siwfrag(struct net_device *dev, return err; } -EXPORT_SYMBOL_GPL(cfg80211_wext_siwfrag); +EXPORT_WEXT_HANDLER(cfg80211_wext_siwfrag); int cfg80211_wext_giwfrag(struct net_device *dev, struct iw_request_info *info, @@ -357,7 +357,7 @@ int cfg80211_wext_giwfrag(struct net_device *dev, return 0; } -EXPORT_SYMBOL_GPL(cfg80211_wext_giwfrag); +EXPORT_WEXT_HANDLER(cfg80211_wext_giwfrag); static int cfg80211_wext_siwretry(struct net_device *dev, struct iw_request_info *info, @@ -427,7 +427,7 @@ int cfg80211_wext_giwretry(struct net_device *dev, return 0; } -EXPORT_SYMBOL_GPL(cfg80211_wext_giwretry); +EXPORT_WEXT_HANDLER(cfg80211_wext_giwretry); static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, struct net_device *dev, bool pairwise, diff --git a/net/wireless/wext-compat.h b/net/wireless/wext-compat.h index ebcacca2f731..94c7405a5413 100644 --- a/net/wireless/wext-compat.h +++ b/net/wireless/wext-compat.h @@ -4,6 +4,12 @@ #include #include +#ifdef CONFIG_CFG80211_WEXT_EXPORT +#define EXPORT_WEXT_HANDLER(h) EXPORT_SYMBOL_GPL(h) +#else +#define EXPORT_WEXT_HANDLER(h) +#endif /* CONFIG_CFG80211_WEXT_EXPORT */ + int cfg80211_ibss_wext_siwfreq(struct net_device *dev, struct iw_request_info *info, struct iw_freq *freq, char *extra); -- cgit v1.2.3 From 31f909a2c0abfc1a1a76b2981d28ac85d33210e7 Mon Sep 17 00:00:00 2001 From: Masashi Honma Date: Tue, 24 Feb 2015 22:42:16 +0900 Subject: nl/mac80211: allow zero plink timeout to disable STA expiration Both wpa_supplicant and mac80211 have and inactivity timer. By default wpa_supplicant will be timed out in 5 minutes and mac80211's it is 30 minutes. If wpa_supplicant uses a longer timer than mac80211, it will get unexpected disconnection by mac80211. Using 0xffffffff instead as the configured value could solve this w/o changing the code, but due to integer overflow in the expression used this doesn't work. The expression is: (current jiffies) > (frame Rx jiffies + NL80211_MESHCONF_PLINK_TIMEOUT * 250) On 32bit system, the right side would overflow and be a very small value if NL80211_MESHCONF_PLINK_TIMEOUT is sufficiently large, causing unexpectedly early disconnections. Instead allow disabling the inactivity timer to avoid this situation, by passing the (previously invalid and useless) value 0. Signed-off-by: Masashi Honma [reword/rewrap commit log] Signed-off-by: Johannes Berg --- include/uapi/linux/nl80211.h | 3 ++- net/mac80211/mesh.c | 3 ++- net/wireless/nl80211.c | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) (limited to 'net/wireless') diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 68b294e83944..2dcf9bba317c 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -3092,7 +3092,8 @@ enum nl80211_mesh_power_mode { * * @NL80211_MESHCONF_PLINK_TIMEOUT: If no tx activity is seen from a STA we've * established peering with for longer than this time (in seconds), then - * remove it from the STA's list of peers. Default is 30 minutes. + * remove it from the STA's list of peers. You may set this to 0 to disable + * the removal of the STA. Default is 30 minutes. * * @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use */ diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 0c8b2a77d312..acf441ff9f4a 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -574,7 +574,8 @@ static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata) struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; u32 changed; - ieee80211_sta_expire(sdata, ifmsh->mshcfg.plink_timeout * HZ); + if (ifmsh->mshcfg.plink_timeout > 0) + ieee80211_sta_expire(sdata, ifmsh->mshcfg.plink_timeout * HZ); mesh_path_expire(sdata); changed = mesh_accept_plinks_update(sdata); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index d78fd8b54515..9c6e23ede5b2 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -5265,7 +5265,7 @@ do { \ FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshAwakeWindowDuration, 0, 65535, mask, NL80211_MESHCONF_AWAKE_WINDOW, nla_get_u16); - FILL_IN_MESH_PARAM_IF_SET(tb, cfg, plink_timeout, 1, 0xffffffff, + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, plink_timeout, 0, 0xffffffff, mask, NL80211_MESHCONF_PLINK_TIMEOUT, nla_get_u32); if (mask_out) -- cgit v1.2.3 From 76a70e9c4b45fc1dbcbff6f7ae88ac7e1ddfb677 Mon Sep 17 00:00:00 2001 From: James Minor Date: Tue, 24 Feb 2015 12:58:20 -0600 Subject: cfg80211-wext: return -E2BIG when buffer can't hold full BSS entry When using the wext compatibility code in cfg80211, part of the IEs can be truncated if the passed user buffer is large enough for part of the BSS but not large enough for all of the IEs. This can cause an EAP network to show up as a PSK network. Always return -E2BIG in this case to avoid truncating data. Since this changes the control flow, use an on-stack variable for a small buffer instead of allocating it. Signed-off-by: James Minor [rework patch to error out immediately, use _check wrappers] Signed-off-by: Johannes Berg --- net/wireless/scan.c | 212 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 136 insertions(+), 76 deletions(-) (limited to 'net/wireless') diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 25e1e1fad905..ceb8f0040dae 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -1239,15 +1239,15 @@ int cfg80211_wext_siwscan(struct net_device *dev, } EXPORT_WEXT_HANDLER(cfg80211_wext_siwscan); -static void ieee80211_scan_add_ies(struct iw_request_info *info, - const struct cfg80211_bss_ies *ies, - char **current_ev, char *end_buf) +static char *ieee80211_scan_add_ies(struct iw_request_info *info, + const struct cfg80211_bss_ies *ies, + char *current_ev, char *end_buf) { const u8 *pos, *end, *next; struct iw_event iwe; if (!ies) - return; + return current_ev; /* * If needed, fragment the IEs buffer (at IE boundaries) into short @@ -1264,10 +1264,11 @@ static void ieee80211_scan_add_ies(struct iw_request_info *info, memset(&iwe, 0, sizeof(iwe)); iwe.cmd = IWEVGENIE; iwe.u.data.length = next - pos; - *current_ev = iwe_stream_add_point(info, *current_ev, - end_buf, &iwe, - (void *)pos); - + current_ev = iwe_stream_add_point_check(info, current_ev, + end_buf, &iwe, + (void *)pos); + if (IS_ERR(current_ev)) + return current_ev; pos = next; } @@ -1275,10 +1276,14 @@ static void ieee80211_scan_add_ies(struct iw_request_info *info, memset(&iwe, 0, sizeof(iwe)); iwe.cmd = IWEVGENIE; iwe.u.data.length = end - pos; - *current_ev = iwe_stream_add_point(info, *current_ev, - end_buf, &iwe, - (void *)pos); + current_ev = iwe_stream_add_point_check(info, current_ev, + end_buf, &iwe, + (void *)pos); + if (IS_ERR(current_ev)) + return current_ev; } + + return current_ev; } static char * @@ -1289,7 +1294,8 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info, const struct cfg80211_bss_ies *ies; struct iw_event iwe; const u8 *ie; - u8 *buf, *cfg, *p; + u8 buf[50]; + u8 *cfg, *p, *tmp; int rem, i, sig; bool ismesh = false; @@ -1297,22 +1303,28 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info, iwe.cmd = SIOCGIWAP; iwe.u.ap_addr.sa_family = ARPHRD_ETHER; memcpy(iwe.u.ap_addr.sa_data, bss->pub.bssid, ETH_ALEN); - current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, - IW_EV_ADDR_LEN); + current_ev = iwe_stream_add_event_check(info, current_ev, end_buf, &iwe, + IW_EV_ADDR_LEN); + if (IS_ERR(current_ev)) + return current_ev; memset(&iwe, 0, sizeof(iwe)); iwe.cmd = SIOCGIWFREQ; iwe.u.freq.m = ieee80211_frequency_to_channel(bss->pub.channel->center_freq); iwe.u.freq.e = 0; - current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, - IW_EV_FREQ_LEN); + current_ev = iwe_stream_add_event_check(info, current_ev, end_buf, &iwe, + IW_EV_FREQ_LEN); + if (IS_ERR(current_ev)) + return current_ev; memset(&iwe, 0, sizeof(iwe)); iwe.cmd = SIOCGIWFREQ; iwe.u.freq.m = bss->pub.channel->center_freq; iwe.u.freq.e = 6; - current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, - IW_EV_FREQ_LEN); + current_ev = iwe_stream_add_event_check(info, current_ev, end_buf, &iwe, + IW_EV_FREQ_LEN); + if (IS_ERR(current_ev)) + return current_ev; if (wiphy->signal_type != CFG80211_SIGNAL_TYPE_NONE) { memset(&iwe, 0, sizeof(iwe)); @@ -1341,8 +1353,11 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info, /* not reached */ break; } - current_ev = iwe_stream_add_event(info, current_ev, end_buf, - &iwe, IW_EV_QUAL_LEN); + current_ev = iwe_stream_add_event_check(info, current_ev, + end_buf, &iwe, + IW_EV_QUAL_LEN); + if (IS_ERR(current_ev)) + return current_ev; } memset(&iwe, 0, sizeof(iwe)); @@ -1352,8 +1367,10 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info, else iwe.u.data.flags = IW_ENCODE_DISABLED; iwe.u.data.length = 0; - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, ""); + current_ev = iwe_stream_add_point_check(info, current_ev, end_buf, + &iwe, ""); + if (IS_ERR(current_ev)) + return current_ev; rcu_read_lock(); ies = rcu_dereference(bss->pub.ies); @@ -1371,66 +1388,91 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info, iwe.cmd = SIOCGIWESSID; iwe.u.data.length = ie[1]; iwe.u.data.flags = 1; - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, (u8 *)ie + 2); + current_ev = iwe_stream_add_point_check(info, + current_ev, + end_buf, &iwe, + (u8 *)ie + 2); + if (IS_ERR(current_ev)) + goto unlock; break; case WLAN_EID_MESH_ID: memset(&iwe, 0, sizeof(iwe)); iwe.cmd = SIOCGIWESSID; iwe.u.data.length = ie[1]; iwe.u.data.flags = 1; - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, (u8 *)ie + 2); + current_ev = iwe_stream_add_point_check(info, + current_ev, + end_buf, &iwe, + (u8 *)ie + 2); + if (IS_ERR(current_ev)) + goto unlock; break; case WLAN_EID_MESH_CONFIG: ismesh = true; if (ie[1] != sizeof(struct ieee80211_meshconf_ie)) break; - buf = kmalloc(50, GFP_ATOMIC); - if (!buf) - break; cfg = (u8 *)ie + 2; memset(&iwe, 0, sizeof(iwe)); iwe.cmd = IWEVCUSTOM; sprintf(buf, "Mesh Network Path Selection Protocol ID: " "0x%02X", cfg[0]); iwe.u.data.length = strlen(buf); - current_ev = iwe_stream_add_point(info, current_ev, - end_buf, - &iwe, buf); + current_ev = iwe_stream_add_point_check(info, + current_ev, + end_buf, + &iwe, buf); + if (IS_ERR(current_ev)) + goto unlock; sprintf(buf, "Path Selection Metric ID: 0x%02X", cfg[1]); iwe.u.data.length = strlen(buf); - current_ev = iwe_stream_add_point(info, current_ev, - end_buf, - &iwe, buf); + current_ev = iwe_stream_add_point_check(info, + current_ev, + end_buf, + &iwe, buf); + if (IS_ERR(current_ev)) + goto unlock; sprintf(buf, "Congestion Control Mode ID: 0x%02X", cfg[2]); iwe.u.data.length = strlen(buf); - current_ev = iwe_stream_add_point(info, current_ev, - end_buf, - &iwe, buf); + current_ev = iwe_stream_add_point_check(info, + current_ev, + end_buf, + &iwe, buf); + if (IS_ERR(current_ev)) + goto unlock; sprintf(buf, "Synchronization ID: 0x%02X", cfg[3]); iwe.u.data.length = strlen(buf); - current_ev = iwe_stream_add_point(info, current_ev, - end_buf, - &iwe, buf); + current_ev = iwe_stream_add_point_check(info, + current_ev, + end_buf, + &iwe, buf); + if (IS_ERR(current_ev)) + goto unlock; sprintf(buf, "Authentication ID: 0x%02X", cfg[4]); iwe.u.data.length = strlen(buf); - current_ev = iwe_stream_add_point(info, current_ev, - end_buf, - &iwe, buf); + current_ev = iwe_stream_add_point_check(info, + current_ev, + end_buf, + &iwe, buf); + if (IS_ERR(current_ev)) + goto unlock; sprintf(buf, "Formation Info: 0x%02X", cfg[5]); iwe.u.data.length = strlen(buf); - current_ev = iwe_stream_add_point(info, current_ev, - end_buf, - &iwe, buf); + current_ev = iwe_stream_add_point_check(info, + current_ev, + end_buf, + &iwe, buf); + if (IS_ERR(current_ev)) + goto unlock; sprintf(buf, "Capabilities: 0x%02X", cfg[6]); iwe.u.data.length = strlen(buf); - current_ev = iwe_stream_add_point(info, current_ev, - end_buf, - &iwe, buf); - kfree(buf); + current_ev = iwe_stream_add_point_check(info, + current_ev, + end_buf, + &iwe, buf); + if (IS_ERR(current_ev)) + goto unlock; break; case WLAN_EID_SUPP_RATES: case WLAN_EID_EXT_SUPP_RATES: @@ -1445,8 +1487,14 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info, for (i = 0; i < ie[1]; i++) { iwe.u.bitrate.value = ((ie[i + 2] & 0x7f) * 500000); + tmp = p; p = iwe_stream_add_value(info, current_ev, p, - end_buf, &iwe, IW_EV_PARAM_LEN); + end_buf, &iwe, + IW_EV_PARAM_LEN); + if (p == tmp) { + current_ev = ERR_PTR(-E2BIG); + goto unlock; + } } current_ev = p; break; @@ -1465,31 +1513,35 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info, iwe.u.mode = IW_MODE_MASTER; else iwe.u.mode = IW_MODE_ADHOC; - current_ev = iwe_stream_add_event(info, current_ev, end_buf, - &iwe, IW_EV_UINT_LEN); - } - - buf = kmalloc(31, GFP_ATOMIC); - if (buf) { - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = IWEVCUSTOM; - sprintf(buf, "tsf=%016llx", (unsigned long long)(ies->tsf)); - iwe.u.data.length = strlen(buf); - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, buf); - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = IWEVCUSTOM; - sprintf(buf, " Last beacon: %ums ago", - elapsed_jiffies_msecs(bss->ts)); - iwe.u.data.length = strlen(buf); - current_ev = iwe_stream_add_point(info, current_ev, - end_buf, &iwe, buf); - kfree(buf); + current_ev = iwe_stream_add_event_check(info, current_ev, + end_buf, &iwe, + IW_EV_UINT_LEN); + if (IS_ERR(current_ev)) + goto unlock; } - ieee80211_scan_add_ies(info, ies, ¤t_ev, end_buf); + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = IWEVCUSTOM; + sprintf(buf, "tsf=%016llx", (unsigned long long)(ies->tsf)); + iwe.u.data.length = strlen(buf); + current_ev = iwe_stream_add_point_check(info, current_ev, end_buf, + &iwe, buf); + if (IS_ERR(current_ev)) + goto unlock; + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = IWEVCUSTOM; + sprintf(buf, " Last beacon: %ums ago", + elapsed_jiffies_msecs(bss->ts)); + iwe.u.data.length = strlen(buf); + current_ev = iwe_stream_add_point_check(info, current_ev, + end_buf, &iwe, buf); + if (IS_ERR(current_ev)) + goto unlock; + + current_ev = ieee80211_scan_add_ies(info, ies, current_ev, end_buf); + + unlock: rcu_read_unlock(); - return current_ev; } @@ -1501,19 +1553,27 @@ static int ieee80211_scan_results(struct cfg80211_registered_device *rdev, char *current_ev = buf; char *end_buf = buf + len; struct cfg80211_internal_bss *bss; + int err = 0; spin_lock_bh(&rdev->bss_lock); cfg80211_bss_expire(rdev); list_for_each_entry(bss, &rdev->bss_list, list) { if (buf + len - current_ev <= IW_EV_ADDR_LEN) { - spin_unlock_bh(&rdev->bss_lock); - return -E2BIG; + err = -E2BIG; + break; } current_ev = ieee80211_bss(&rdev->wiphy, info, bss, current_ev, end_buf); + if (IS_ERR(current_ev)) { + err = PTR_ERR(current_ev); + break; + } } spin_unlock_bh(&rdev->bss_lock); + + if (err) + return err; return current_ev - buf; } -- cgit v1.2.3 From 6eb18137643fee5f182d85c818062b4feddfb76b Mon Sep 17 00:00:00 2001 From: Dedy Lansky Date: Sun, 8 Feb 2015 15:52:03 +0200 Subject: cfg80211: add bss_type and privacy arguments in cfg80211_get_bss() 802.11ad adds new a network type (PBSS) and changes the capability field interpretation for the DMG (60G) band. The same 2 bits that were interpreted as "ESS" and "IBSS" before are re-used as a 2-bit field with 3 valid values (and 1 reserved). Valid values are: "IBSS", "PBSS" (new) and "AP". In order to get the BSS struct for the new PBSS networks, change the cfg80211_get_bss() function to take a new enum ieee80211_bss_type argument with the valid network types, as "capa_mask" and "capa_val" no longer work correctly (the search must be band-aware now.) The remaining bits in "capa_mask" and "capa_val" are used only for privacy matching so replace those two with a privacy enum as well. Signed-off-by: Dedy Lansky [rewrite commit log, tiny fixes] Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath10k/mac.c | 3 +- drivers/net/wireless/ath/ath6kl/cfg80211.c | 9 +-- drivers/net/wireless/ath/wil6210/cfg80211.c | 2 +- drivers/net/wireless/cw1200/sta.c | 4 +- drivers/net/wireless/libertas/cfg.c | 6 +- drivers/net/wireless/mwifiex/cfg80211.c | 8 +-- include/net/cfg80211.h | 39 ++++++++++++- net/mac80211/ibss.c | 43 ++++----------- net/wireless/ibss.c | 2 +- net/wireless/mlme.c | 6 +- net/wireless/scan.c | 86 ++++++++++++++++++++++++++--- net/wireless/sme.c | 16 ++---- net/wireless/trace.h | 24 ++++---- 13 files changed, 168 insertions(+), 80 deletions(-) (limited to 'net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index d6d2f0f00caa..d372ebfd933d 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -1386,7 +1386,8 @@ static void ath10k_peer_assoc_h_crypto(struct ath10k *ar, lockdep_assert_held(&ar->conf_mutex); bss = cfg80211_get_bss(ar->hw->wiphy, ar->hw->conf.chandef.chan, - info->bssid, NULL, 0, 0, 0); + info->bssid, NULL, 0, IEEE80211_BSS_TYPE_ANY, + IEEE80211_PRIVACY_ANY); if (bss) { const struct cfg80211_bss_ies *ies; diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 85da63a67faf..ff7ba5c195c6 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -686,20 +686,21 @@ ath6kl_add_bss_if_needed(struct ath6kl_vif *vif, { struct ath6kl *ar = vif->ar; struct cfg80211_bss *bss; - u16 cap_mask, cap_val; + u16 cap_val; + enum ieee80211_bss_type bss_type; u8 *ie; if (nw_type & ADHOC_NETWORK) { - cap_mask = WLAN_CAPABILITY_IBSS; cap_val = WLAN_CAPABILITY_IBSS; + bss_type = IEEE80211_BSS_TYPE_IBSS; } else { - cap_mask = WLAN_CAPABILITY_ESS; cap_val = WLAN_CAPABILITY_ESS; + bss_type = IEEE80211_BSS_TYPE_ESS; } bss = cfg80211_get_bss(ar->wiphy, chan, bssid, vif->ssid, vif->ssid_len, - cap_mask, cap_val); + bss_type, IEEE80211_PRIVACY_ANY); if (bss == NULL) { /* * Since cfg80211 may not yet know about the BSS, diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 2d5ea21be47e..adfd815e3f7d 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -395,7 +395,7 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, bss = cfg80211_get_bss(wiphy, sme->channel, sme->bssid, sme->ssid, sme->ssid_len, - WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); + IEEE80211_BSS_TYPE_ESS, IEEE80211_PRIVACY_ANY); if (!bss) { wil_err(wil, "Unable to find BSS\n"); return -ENOENT; diff --git a/drivers/net/wireless/cw1200/sta.c b/drivers/net/wireless/cw1200/sta.c index 4a47c7f8a246..1b58b2e2a538 100644 --- a/drivers/net/wireless/cw1200/sta.c +++ b/drivers/net/wireless/cw1200/sta.c @@ -1240,8 +1240,8 @@ static void cw1200_do_join(struct cw1200_common *priv) bssid = priv->vif->bss_conf.bssid; - bss = cfg80211_get_bss(priv->hw->wiphy, priv->channel, - bssid, NULL, 0, 0, 0); + bss = cfg80211_get_bss(priv->hw->wiphy, priv->channel, bssid, NULL, 0, + IEEE80211_BSS_TYPE_ANY, IEEE80211_PRIVACY_ANY); if (!bss && !conf->ibss_joined) { wsm_unlock_tx(priv); diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c index a92985a6ea21..1a4d558022d8 100644 --- a/drivers/net/wireless/libertas/cfg.c +++ b/drivers/net/wireless/libertas/cfg.c @@ -1356,8 +1356,8 @@ static int lbs_cfg_connect(struct wiphy *wiphy, struct net_device *dev, /* Find the BSS we want using available scan results */ bss = cfg80211_get_bss(wiphy, sme->channel, sme->bssid, - sme->ssid, sme->ssid_len, - WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); + sme->ssid, sme->ssid_len, IEEE80211_BSS_TYPE_ESS, + IEEE80211_PRIVACY_ANY); if (!bss) { wiphy_err(wiphy, "assoc: bss %pM not in scan results\n", sme->bssid); @@ -2000,7 +2000,7 @@ static int lbs_join_ibss(struct wiphy *wiphy, struct net_device *dev, * bss list is populated already */ bss = cfg80211_get_bss(wiphy, params->chandef.chan, params->bssid, params->ssid, params->ssid_len, - WLAN_CAPABILITY_IBSS, WLAN_CAPABILITY_IBSS); + IEEE80211_BSS_TYPE_IBSS, IEEE80211_PRIVACY_ANY); if (bss) { ret = lbs_ibss_join_existing(priv, params, bss); diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 41c8e25df954..a47eb55bb6da 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -1954,13 +1954,13 @@ done: if (mode == NL80211_IFTYPE_ADHOC) bss = cfg80211_get_bss(priv->wdev.wiphy, channel, bssid, ssid, ssid_len, - WLAN_CAPABILITY_IBSS, - WLAN_CAPABILITY_IBSS); + IEEE80211_BSS_TYPE_IBSS, + IEEE80211_PRIVACY_ANY); else bss = cfg80211_get_bss(priv->wdev.wiphy, channel, bssid, ssid, ssid_len, - WLAN_CAPABILITY_ESS, - WLAN_CAPABILITY_ESS); + IEEE80211_BSS_TYPE_ESS, + IEEE80211_PRIVACY_ANY); if (!bss) { if (is_scanning_required) { diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 64e09e1e8099..28fff56f5606 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -214,6 +214,39 @@ enum ieee80211_rate_flags { IEEE80211_RATE_SUPPORTS_10MHZ = 1<<6, }; +/** + * enum ieee80211_bss_type - BSS type filter + * + * @IEEE80211_BSS_TYPE_ESS: Infrastructure BSS + * @IEEE80211_BSS_TYPE_PBSS: Personal BSS + * @IEEE80211_BSS_TYPE_IBSS: Independent BSS + * @IEEE80211_BSS_TYPE_MBSS: Mesh BSS + * @IEEE80211_BSS_TYPE_ANY: Wildcard value for matching any BSS type + */ +enum ieee80211_bss_type { + IEEE80211_BSS_TYPE_ESS, + IEEE80211_BSS_TYPE_PBSS, + IEEE80211_BSS_TYPE_IBSS, + IEEE80211_BSS_TYPE_MBSS, + IEEE80211_BSS_TYPE_ANY +}; + +/** + * enum ieee80211_privacy - BSS privacy filter + * + * @IEEE80211_PRIVACY_ON: privacy bit set + * @IEEE80211_PRIVACY_OFF: privacy bit clear + * @IEEE80211_PRIVACY_ANY: Wildcard value for matching any privacy setting + */ +enum ieee80211_privacy { + IEEE80211_PRIVACY_ON, + IEEE80211_PRIVACY_OFF, + IEEE80211_PRIVACY_ANY +}; + +#define IEEE80211_PRIVACY(x) \ + ((x) ? IEEE80211_PRIVACY_ON : IEEE80211_PRIVACY_OFF) + /** * struct ieee80211_rate - bitrate definition * @@ -4012,14 +4045,16 @@ struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy, struct ieee80211_channel *channel, const u8 *bssid, const u8 *ssid, size_t ssid_len, - u16 capa_mask, u16 capa_val); + enum ieee80211_bss_type bss_type, + enum ieee80211_privacy); static inline struct cfg80211_bss * cfg80211_get_ibss(struct wiphy *wiphy, struct ieee80211_channel *channel, const u8 *ssid, size_t ssid_len) { return cfg80211_get_bss(wiphy, channel, NULL, ssid, ssid_len, - WLAN_CAPABILITY_IBSS, WLAN_CAPABILITY_IBSS); + IEEE80211_BSS_TYPE_IBSS, + IEEE80211_PRIVACY_ANY); } /** diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index b606b53a49a7..ee93d7d9aa4b 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -470,22 +470,19 @@ int ieee80211_ibss_csa_beacon(struct ieee80211_sub_if_data *sdata, struct beacon_data *presp, *old_presp; struct cfg80211_bss *cbss; const struct cfg80211_bss_ies *ies; - u16 capability; + u16 capability = 0; u64 tsf; int ret = 0; sdata_assert_lock(sdata); - capability = WLAN_CAPABILITY_IBSS; - if (ifibss->privacy) - capability |= WLAN_CAPABILITY_PRIVACY; + capability = WLAN_CAPABILITY_PRIVACY; cbss = cfg80211_get_bss(sdata->local->hw.wiphy, ifibss->chandef.chan, ifibss->bssid, ifibss->ssid, - ifibss->ssid_len, WLAN_CAPABILITY_IBSS | - WLAN_CAPABILITY_PRIVACY, - capability); + ifibss->ssid_len, IEEE80211_BSS_TYPE_IBSS, + IEEE80211_PRIVACY(ifibss->privacy)); if (WARN_ON(!cbss)) { ret = -EINVAL; @@ -525,23 +522,17 @@ int ieee80211_ibss_finish_csa(struct ieee80211_sub_if_data *sdata) struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; struct cfg80211_bss *cbss; int err, changed = 0; - u16 capability; sdata_assert_lock(sdata); /* update cfg80211 bss information with the new channel */ if (!is_zero_ether_addr(ifibss->bssid)) { - capability = WLAN_CAPABILITY_IBSS; - - if (ifibss->privacy) - capability |= WLAN_CAPABILITY_PRIVACY; - cbss = cfg80211_get_bss(sdata->local->hw.wiphy, ifibss->chandef.chan, ifibss->bssid, ifibss->ssid, - ifibss->ssid_len, WLAN_CAPABILITY_IBSS | - WLAN_CAPABILITY_PRIVACY, - capability); + ifibss->ssid_len, + IEEE80211_BSS_TYPE_IBSS, + IEEE80211_PRIVACY(ifibss->privacy)); /* XXX: should not really modify cfg80211 data */ if (cbss) { cbss->channel = sdata->csa_chandef.chan; @@ -682,19 +673,13 @@ static void ieee80211_ibss_disconnect(struct ieee80211_sub_if_data *sdata) struct cfg80211_bss *cbss; struct beacon_data *presp; struct sta_info *sta; - u16 capability; if (!is_zero_ether_addr(ifibss->bssid)) { - capability = WLAN_CAPABILITY_IBSS; - - if (ifibss->privacy) - capability |= WLAN_CAPABILITY_PRIVACY; - cbss = cfg80211_get_bss(local->hw.wiphy, ifibss->chandef.chan, ifibss->bssid, ifibss->ssid, - ifibss->ssid_len, WLAN_CAPABILITY_IBSS | - WLAN_CAPABILITY_PRIVACY, - capability); + ifibss->ssid_len, + IEEE80211_BSS_TYPE_IBSS, + IEEE80211_PRIVACY(ifibss->privacy)); if (cbss) { cfg80211_unlink_bss(local->hw.wiphy, cbss); @@ -1325,7 +1310,6 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) const u8 *bssid = NULL; enum nl80211_bss_scan_width scan_width; int active_ibss; - u16 capability; sdata_assert_lock(sdata); @@ -1335,9 +1319,6 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) if (active_ibss) return; - capability = WLAN_CAPABILITY_IBSS; - if (ifibss->privacy) - capability |= WLAN_CAPABILITY_PRIVACY; if (ifibss->fixed_bssid) bssid = ifibss->bssid; if (ifibss->fixed_channel) @@ -1346,8 +1327,8 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) bssid = ifibss->bssid; cbss = cfg80211_get_bss(local->hw.wiphy, chan, bssid, ifibss->ssid, ifibss->ssid_len, - WLAN_CAPABILITY_IBSS | WLAN_CAPABILITY_PRIVACY, - capability); + IEEE80211_BSS_TYPE_IBSS, + IEEE80211_PRIVACY(ifibss->privacy)); if (cbss) { struct ieee80211_bss *bss; diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index e24fc585c883..1a65662a5d73 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c @@ -30,7 +30,7 @@ void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, return; bss = cfg80211_get_bss(wdev->wiphy, channel, bssid, NULL, 0, - WLAN_CAPABILITY_IBSS, WLAN_CAPABILITY_IBSS); + IEEE80211_BSS_TYPE_IBSS, IEEE80211_PRIVACY_ANY); if (WARN_ON(!bss)) return; diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 2c52b59e43f3..7aae329e2b4e 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -229,7 +229,8 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, return -EALREADY; req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len, - WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); + IEEE80211_BSS_TYPE_ESS, + IEEE80211_PRIVACY_ANY); if (!req.bss) return -ENOENT; @@ -296,7 +297,8 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, rdev->wiphy.vht_capa_mod_mask); req->bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len, - WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); + IEEE80211_BSS_TYPE_ESS, + IEEE80211_PRIVACY_ANY); if (!req->bss) return -ENOENT; diff --git a/net/wireless/scan.c b/net/wireless/scan.c index ceb8f0040dae..3a50aa2553bf 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -531,24 +531,78 @@ static int cmp_bss(struct cfg80211_bss *a, } } +static bool cfg80211_bss_type_match(u16 capability, + enum ieee80211_band band, + enum ieee80211_bss_type bss_type) +{ + bool ret = true; + u16 mask, val; + + if (bss_type == IEEE80211_BSS_TYPE_ANY) + return ret; + + if (band == IEEE80211_BAND_60GHZ) { + mask = WLAN_CAPABILITY_DMG_TYPE_MASK; + switch (bss_type) { + case IEEE80211_BSS_TYPE_ESS: + val = WLAN_CAPABILITY_DMG_TYPE_AP; + break; + case IEEE80211_BSS_TYPE_PBSS: + val = WLAN_CAPABILITY_DMG_TYPE_PBSS; + break; + case IEEE80211_BSS_TYPE_IBSS: + val = WLAN_CAPABILITY_DMG_TYPE_IBSS; + break; + default: + return false; + } + } else { + mask = WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS; + switch (bss_type) { + case IEEE80211_BSS_TYPE_ESS: + val = WLAN_CAPABILITY_ESS; + break; + case IEEE80211_BSS_TYPE_IBSS: + val = WLAN_CAPABILITY_IBSS; + break; + case IEEE80211_BSS_TYPE_MBSS: + val = 0; + break; + default: + return false; + } + } + + ret = ((capability & mask) == val); + return ret; +} + /* Returned bss is reference counted and must be cleaned up appropriately. */ struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy, struct ieee80211_channel *channel, const u8 *bssid, const u8 *ssid, size_t ssid_len, - u16 capa_mask, u16 capa_val) + enum ieee80211_bss_type bss_type, + enum ieee80211_privacy privacy) { struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); struct cfg80211_internal_bss *bss, *res = NULL; unsigned long now = jiffies; + int bss_privacy; - trace_cfg80211_get_bss(wiphy, channel, bssid, ssid, ssid_len, capa_mask, - capa_val); + trace_cfg80211_get_bss(wiphy, channel, bssid, ssid, ssid_len, bss_type, + privacy); spin_lock_bh(&rdev->bss_lock); list_for_each_entry(bss, &rdev->bss_list, list) { - if ((bss->pub.capability & capa_mask) != capa_val) + if (!cfg80211_bss_type_match(bss->pub.capability, + bss->pub.channel->band, bss_type)) + continue; + + bss_privacy = (bss->pub.capability & WLAN_CAPABILITY_PRIVACY); + if ((privacy == IEEE80211_PRIVACY_ON && !bss_privacy) || + (privacy == IEEE80211_PRIVACY_OFF && bss_privacy)) continue; if (channel && bss->pub.channel != channel) continue; @@ -896,6 +950,7 @@ cfg80211_inform_bss_width(struct wiphy *wiphy, struct cfg80211_bss_ies *ies; struct ieee80211_channel *channel; struct cfg80211_internal_bss tmp = {}, *res; + int bss_type; bool signal_valid; if (WARN_ON(!wiphy)) @@ -950,8 +1005,15 @@ cfg80211_inform_bss_width(struct wiphy *wiphy, if (!res) return NULL; - if (res->pub.capability & WLAN_CAPABILITY_ESS) - regulatory_hint_found_beacon(wiphy, channel, gfp); + if (channel->band == IEEE80211_BAND_60GHZ) { + bss_type = res->pub.capability & WLAN_CAPABILITY_DMG_TYPE_MASK; + if (bss_type == WLAN_CAPABILITY_DMG_TYPE_AP || + bss_type == WLAN_CAPABILITY_DMG_TYPE_PBSS) + regulatory_hint_found_beacon(wiphy, channel, gfp); + } else { + if (res->pub.capability & WLAN_CAPABILITY_ESS) + regulatory_hint_found_beacon(wiphy, channel, gfp); + } trace_cfg80211_return_bss(&res->pub); /* cfg80211_bss_update gives us a referenced result */ @@ -973,6 +1035,7 @@ cfg80211_inform_bss_width_frame(struct wiphy *wiphy, bool signal_valid; size_t ielen = len - offsetof(struct ieee80211_mgmt, u.probe_resp.variable); + int bss_type; BUILD_BUG_ON(offsetof(struct ieee80211_mgmt, u.probe_resp.variable) != offsetof(struct ieee80211_mgmt, u.beacon.variable)); @@ -1025,8 +1088,15 @@ cfg80211_inform_bss_width_frame(struct wiphy *wiphy, if (!res) return NULL; - if (res->pub.capability & WLAN_CAPABILITY_ESS) - regulatory_hint_found_beacon(wiphy, channel, gfp); + if (channel->band == IEEE80211_BAND_60GHZ) { + bss_type = res->pub.capability & WLAN_CAPABILITY_DMG_TYPE_MASK; + if (bss_type == WLAN_CAPABILITY_DMG_TYPE_AP || + bss_type == WLAN_CAPABILITY_DMG_TYPE_PBSS) + regulatory_hint_found_beacon(wiphy, channel, gfp); + } else { + if (res->pub.capability & WLAN_CAPABILITY_ESS) + regulatory_hint_found_beacon(wiphy, channel, gfp); + } trace_cfg80211_return_bss(&res->pub); /* cfg80211_bss_update gives us a referenced result */ diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 0ab3711c79a0..ea1da6621ff0 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -257,19 +257,15 @@ static struct cfg80211_bss *cfg80211_get_conn_bss(struct wireless_dev *wdev) { struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); struct cfg80211_bss *bss; - u16 capa = WLAN_CAPABILITY_ESS; ASSERT_WDEV_LOCK(wdev); - if (wdev->conn->params.privacy) - capa |= WLAN_CAPABILITY_PRIVACY; - bss = cfg80211_get_bss(wdev->wiphy, wdev->conn->params.channel, wdev->conn->params.bssid, wdev->conn->params.ssid, wdev->conn->params.ssid_len, - WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_PRIVACY, - capa); + IEEE80211_BSS_TYPE_ESS, + IEEE80211_PRIVACY(wdev->conn->params.privacy)); if (!bss) return NULL; @@ -637,8 +633,8 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, WARN_ON_ONCE(!wiphy_to_rdev(wdev->wiphy)->ops->connect); bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid, wdev->ssid, wdev->ssid_len, - WLAN_CAPABILITY_ESS, - WLAN_CAPABILITY_ESS); + IEEE80211_BSS_TYPE_ESS, + IEEE80211_PRIVACY_ANY); if (bss) cfg80211_hold_bss(bss_from_pub(bss)); } @@ -795,8 +791,8 @@ void cfg80211_roamed(struct net_device *dev, struct cfg80211_bss *bss; bss = cfg80211_get_bss(wdev->wiphy, channel, bssid, wdev->ssid, - wdev->ssid_len, WLAN_CAPABILITY_ESS, - WLAN_CAPABILITY_ESS); + wdev->ssid_len, + IEEE80211_BSS_TYPE_ESS, IEEE80211_PRIVACY_ANY); if (WARN_ON(!bss)) return; diff --git a/net/wireless/trace.h b/net/wireless/trace.h index b17b3692f8c2..b19773c9c81b 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h @@ -2636,28 +2636,30 @@ DEFINE_EVENT(wiphy_only_evt, cfg80211_sched_scan_stopped, TRACE_EVENT(cfg80211_get_bss, TP_PROTO(struct wiphy *wiphy, struct ieee80211_channel *channel, const u8 *bssid, const u8 *ssid, size_t ssid_len, - u16 capa_mask, u16 capa_val), - TP_ARGS(wiphy, channel, bssid, ssid, ssid_len, capa_mask, capa_val), + enum ieee80211_bss_type bss_type, + enum ieee80211_privacy privacy), + TP_ARGS(wiphy, channel, bssid, ssid, ssid_len, bss_type, privacy), TP_STRUCT__entry( WIPHY_ENTRY CHAN_ENTRY MAC_ENTRY(bssid) __dynamic_array(u8, ssid, ssid_len) - __field(u16, capa_mask) - __field(u16, capa_val) + __field(enum ieee80211_bss_type, bss_type) + __field(enum ieee80211_privacy, privacy) ), TP_fast_assign( WIPHY_ASSIGN; CHAN_ASSIGN(channel); MAC_ASSIGN(bssid, bssid); memcpy(__get_dynamic_array(ssid), ssid, ssid_len); - __entry->capa_mask = capa_mask; - __entry->capa_val = capa_val; - ), - TP_printk(WIPHY_PR_FMT ", " CHAN_PR_FMT ", " MAC_PR_FMT ", buf: %#.2x, " - "capa_mask: %d, capa_val: %u", WIPHY_PR_ARG, CHAN_PR_ARG, - MAC_PR_ARG(bssid), ((u8 *)__get_dynamic_array(ssid))[0], - __entry->capa_mask, __entry->capa_val) + __entry->bss_type = bss_type; + __entry->privacy = privacy; + ), + TP_printk(WIPHY_PR_FMT ", " CHAN_PR_FMT ", " MAC_PR_FMT + ", buf: %#.2x, bss_type: %d, privacy: %d", + WIPHY_PR_ARG, CHAN_PR_ARG, MAC_PR_ARG(bssid), + ((u8 *)__get_dynamic_array(ssid))[0], __entry->bss_type, + __entry->privacy) ); TRACE_EVENT(cfg80211_inform_bss_width_frame, -- cgit v1.2.3 From ffc1199122d83d60ad99f9c55df32feb650b7bff Mon Sep 17 00:00:00 2001 From: "Janusz.Dziedzic@tieto.com" Date: Sat, 21 Feb 2015 16:52:39 +0100 Subject: cfg80211: add VHT support for IBSS Add NL80211_EXT_FEATURE_VHT_IBSS flag and VHT support for IBSS. Signed-off-by: Janusz Dziedzic Signed-off-by: Johannes Berg --- include/uapi/linux/nl80211.h | 2 ++ net/wireless/nl80211.c | 14 ++++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) (limited to 'net/wireless') diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 2dcf9bba317c..8ee31f108407 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -4328,11 +4328,13 @@ enum nl80211_feature_flags { /** * enum nl80211_ext_feature_index - bit index of extended features. + * @NL80211_EXT_FEATURE_VHT_IBSS: This driver supports IBSS with VHT datarates. * * @NUM_NL80211_EXT_FEATURES: number of extended features. * @MAX_NL80211_EXT_FEATURES: highest extended feature index. */ enum nl80211_ext_feature_index { + NL80211_EXT_FEATURE_VHT_IBSS, /* add new features before the definition below */ NUM_NL80211_EXT_FEATURES, diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 9c6e23ede5b2..66666fdf1c8d 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -7265,8 +7265,18 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) break; case NL80211_CHAN_WIDTH_20: case NL80211_CHAN_WIDTH_40: - if (rdev->wiphy.features & NL80211_FEATURE_HT_IBSS) - break; + if (!(rdev->wiphy.features & NL80211_FEATURE_HT_IBSS)) + return -EINVAL; + break; + case NL80211_CHAN_WIDTH_80: + case NL80211_CHAN_WIDTH_80P80: + case NL80211_CHAN_WIDTH_160: + if (!(rdev->wiphy.features & NL80211_FEATURE_HT_IBSS)) + return -EINVAL; + if (!wiphy_ext_feature_isset(&rdev->wiphy, + NL80211_EXT_FEATURE_VHT_IBSS)) + return -EINVAL; + break; default: return -EINVAL; } -- cgit v1.2.3 From 6c09e791b21309a1ad71f9702b766dae12a3cb0a Mon Sep 17 00:00:00 2001 From: Ahmad Kholaif Date: Thu, 26 Feb 2015 15:26:53 +0200 Subject: cfg80211: Allow NL80211_ATTR_IFINDEX to be added to vendor events This modifies cfg80211_vendor_event_alloc() with an additional argument struct wireless_dev *wdev. __cfg80211_alloc_event_skb() is modified to take in *wdev argument, if wdev != NULL, both the NL80211_ATTR_IFINDEX and wdev identifier are added to the vendor event. These changes make it easier for drivers to add ifindex indication in vendor events cleanly. This also updates all existing users of cfg80211_vendor_event_alloc() and __cfg80211_alloc_event_skb() in the kernel tree. Signed-off-by: Ahmad Kholaif Signed-off-by: Jouni Malinen Signed-off-by: Johannes Berg --- drivers/net/wireless/ti/wl18xx/event.c | 4 ++-- include/net/cfg80211.h | 14 ++++++++++---- net/wireless/nl80211.c | 19 +++++++++++++++---- 3 files changed, 27 insertions(+), 10 deletions(-) (limited to 'net/wireless') diff --git a/drivers/net/wireless/ti/wl18xx/event.c b/drivers/net/wireless/ti/wl18xx/event.c index c28f06854195..548bb9e7e91e 100644 --- a/drivers/net/wireless/ti/wl18xx/event.c +++ b/drivers/net/wireless/ti/wl18xx/event.c @@ -77,7 +77,7 @@ static int wlcore_smart_config_sync_event(struct wl1271 *wl, u8 sync_channel, wl1271_debug(DEBUG_EVENT, "SMART_CONFIG_SYNC_EVENT_ID, freq: %d (chan: %d band %d)", freq, sync_channel, sync_band); - skb = cfg80211_vendor_event_alloc(wl->hw->wiphy, 20, + skb = cfg80211_vendor_event_alloc(wl->hw->wiphy, NULL, 20, WLCORE_VENDOR_EVENT_SC_SYNC, GFP_KERNEL); @@ -98,7 +98,7 @@ static int wlcore_smart_config_decode_event(struct wl1271 *wl, wl1271_debug(DEBUG_EVENT, "SMART_CONFIG_DECODE_EVENT_ID"); wl1271_dump_ascii(DEBUG_EVENT, "SSID:", ssid, ssid_len); - skb = cfg80211_vendor_event_alloc(wl->hw->wiphy, + skb = cfg80211_vendor_event_alloc(wl->hw->wiphy, NULL, ssid_len + pwd_len + 20, WLCORE_VENDOR_EVENT_SC_DECODE, GFP_KERNEL); diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 28fff56f5606..12a6121ea76e 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -4295,6 +4295,7 @@ struct sk_buff *__cfg80211_alloc_reply_skb(struct wiphy *wiphy, int approxlen); struct sk_buff *__cfg80211_alloc_event_skb(struct wiphy *wiphy, + struct wireless_dev *wdev, enum nl80211_commands cmd, enum nl80211_attrs attr, int vendor_event_idx, @@ -4349,6 +4350,7 @@ int cfg80211_vendor_cmd_reply(struct sk_buff *skb); /** * cfg80211_vendor_event_alloc - allocate vendor-specific event skb * @wiphy: the wiphy + * @wdev: the wireless device * @event_idx: index of the vendor event in the wiphy's vendor_events * @approxlen: an upper bound of the length of the data that will * be put into the skb @@ -4357,16 +4359,20 @@ int cfg80211_vendor_cmd_reply(struct sk_buff *skb); * This function allocates and pre-fills an skb for an event on the * vendor-specific multicast group. * + * If wdev != NULL, both the ifindex and identifier of the specified + * wireless device are added to the event message before the vendor data + * attribute. + * * When done filling the skb, call cfg80211_vendor_event() with the * skb to send the event. * * Return: An allocated and pre-filled skb. %NULL if any errors happen. */ static inline struct sk_buff * -cfg80211_vendor_event_alloc(struct wiphy *wiphy, int approxlen, - int event_idx, gfp_t gfp) +cfg80211_vendor_event_alloc(struct wiphy *wiphy, struct wireless_dev *wdev, + int approxlen, int event_idx, gfp_t gfp) { - return __cfg80211_alloc_event_skb(wiphy, NL80211_CMD_VENDOR, + return __cfg80211_alloc_event_skb(wiphy, wdev, NL80211_CMD_VENDOR, NL80211_ATTR_VENDOR_DATA, event_idx, approxlen, gfp); } @@ -4467,7 +4473,7 @@ static inline int cfg80211_testmode_reply(struct sk_buff *skb) static inline struct sk_buff * cfg80211_testmode_alloc_event_skb(struct wiphy *wiphy, int approxlen, gfp_t gfp) { - return __cfg80211_alloc_event_skb(wiphy, NL80211_CMD_TESTMODE, + return __cfg80211_alloc_event_skb(wiphy, NULL, NL80211_CMD_TESTMODE, NL80211_ATTR_TESTDATA, -1, approxlen, gfp); } diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 66666fdf1c8d..01874628ae00 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -7389,8 +7389,8 @@ static int nl80211_set_mcast_rate(struct sk_buff *skb, struct genl_info *info) static struct sk_buff * __cfg80211_alloc_vendor_skb(struct cfg80211_registered_device *rdev, - int approxlen, u32 portid, u32 seq, - enum nl80211_commands cmd, + struct wireless_dev *wdev, int approxlen, + u32 portid, u32 seq, enum nl80211_commands cmd, enum nl80211_attrs attr, const struct nl80211_vendor_cmd_info *info, gfp_t gfp) @@ -7421,6 +7421,16 @@ __cfg80211_alloc_vendor_skb(struct cfg80211_registered_device *rdev, goto nla_put_failure; } + if (wdev) { + if (nla_put_u64(skb, NL80211_ATTR_WDEV, + wdev_id(wdev))) + goto nla_put_failure; + if (wdev->netdev && + nla_put_u32(skb, NL80211_ATTR_IFINDEX, + wdev->netdev->ifindex)) + goto nla_put_failure; + } + data = nla_nest_start(skb, attr); ((void **)skb->cb)[0] = rdev; @@ -7435,6 +7445,7 @@ __cfg80211_alloc_vendor_skb(struct cfg80211_registered_device *rdev, } struct sk_buff *__cfg80211_alloc_event_skb(struct wiphy *wiphy, + struct wireless_dev *wdev, enum nl80211_commands cmd, enum nl80211_attrs attr, int vendor_event_idx, @@ -7460,7 +7471,7 @@ struct sk_buff *__cfg80211_alloc_event_skb(struct wiphy *wiphy, return NULL; } - return __cfg80211_alloc_vendor_skb(rdev, approxlen, 0, 0, + return __cfg80211_alloc_vendor_skb(rdev, wdev, approxlen, 0, 0, cmd, attr, info, gfp); } EXPORT_SYMBOL(__cfg80211_alloc_event_skb); @@ -9906,7 +9917,7 @@ struct sk_buff *__cfg80211_alloc_reply_skb(struct wiphy *wiphy, if (WARN_ON(!rdev->cur_cmd_info)) return NULL; - return __cfg80211_alloc_vendor_skb(rdev, approxlen, + return __cfg80211_alloc_vendor_skb(rdev, NULL, approxlen, rdev->cur_cmd_info->snd_portid, rdev->cur_cmd_info->snd_seq, cmd, attr, NULL, GFP_KERNEL); -- cgit v1.2.3 From 954a86ef45ffa2db4e361d5344ed61464fb2a204 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Sun, 1 Mar 2015 09:10:01 +0200 Subject: cfg80211: add operating classes 128-130 Operating classes 128-130 are defined in the 11ac spec for the 5GHz band. Update ieee80211_operating_class_to_band() to support them. Signed-off-by: Eliad Peller Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- net/wireless/util.c | 1 + 1 file changed, 1 insertion(+) (limited to 'net/wireless') diff --git a/net/wireless/util.c b/net/wireless/util.c index 6903dbdcb8c1..f7b35980af69 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -1296,6 +1296,7 @@ bool ieee80211_operating_class_to_band(u8 operating_class, switch (operating_class) { case 112: case 115 ... 127: + case 128 ... 130: *band = IEEE80211_BAND_5GHZ; return true; case 81: -- cgit v1.2.3 From 98fc43864af9e74116eec81c290db048cded15d8 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 1 Mar 2015 09:10:13 +0200 Subject: nl80211: prohibit mixing 'any' and regular wowlan triggers If the device supports waking up on 'any' signal - i.e. it continues operating as usual and wakes up the host on pretty much anything that happens, then it makes no sense to also configure the more restricted WoWLAN mode where the device operates more autonomously but also in a more restricted fashion. Currently only cw2100 supports both 'any' and other triggers, but it seems to be broken as it doesn't configure anything to the device, so we can't currently get into a situation where both even can correctly be configured. This is about to change (Intel devices are going to support both and have different behaviour depending on configuration) so make sure the conflicting modes cannot be configured. (It seems that cw2100 advertises 'any' and 'disconnect' as a means of saying that's what it will always do, but that isn't really the way this API was meant to be used nor does it actually mean anything as 'any' always implies 'disconnect' already, and the driver doesn't change device configuration in any way depending on the settings.) Signed-off-by: Johannes Berg --- include/uapi/linux/nl80211.h | 2 ++ net/wireless/nl80211.c | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+) (limited to 'net/wireless') diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 90c5aeb3cca7..37e7f39441e5 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -3708,6 +3708,8 @@ struct nl80211_pattern_support { * @NL80211_WOWLAN_TRIG_ANY: wake up on any activity, do not really put * the chip into a special state -- works best with chips that have * support for low-power operation already (flag) + * Note that this mode is incompatible with all of the others, if + * any others are even supported by the device. * @NL80211_WOWLAN_TRIG_DISCONNECT: wake up on disconnect, the way disconnect * is detected is implementation-specific (flag) * @NL80211_WOWLAN_TRIG_MAGIC_PKT: wake up on magic packet (6x 0xff, followed diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 01874628ae00..07cef3d7653e 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -9105,6 +9105,7 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) const struct wiphy_wowlan_support *wowlan = rdev->wiphy.wowlan; int err, i; bool prev_enabled = rdev->wiphy.wowlan_config; + bool regular = false; if (!wowlan) return -EOPNOTSUPP; @@ -9132,12 +9133,14 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) if (!(wowlan->flags & WIPHY_WOWLAN_DISCONNECT)) return -EINVAL; new_triggers.disconnect = true; + regular = true; } if (tb[NL80211_WOWLAN_TRIG_MAGIC_PKT]) { if (!(wowlan->flags & WIPHY_WOWLAN_MAGIC_PKT)) return -EINVAL; new_triggers.magic_pkt = true; + regular = true; } if (tb[NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED]) @@ -9147,24 +9150,28 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) if (!(wowlan->flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE)) return -EINVAL; new_triggers.gtk_rekey_failure = true; + regular = true; } if (tb[NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST]) { if (!(wowlan->flags & WIPHY_WOWLAN_EAP_IDENTITY_REQ)) return -EINVAL; new_triggers.eap_identity_req = true; + regular = true; } if (tb[NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE]) { if (!(wowlan->flags & WIPHY_WOWLAN_4WAY_HANDSHAKE)) return -EINVAL; new_triggers.four_way_handshake = true; + regular = true; } if (tb[NL80211_WOWLAN_TRIG_RFKILL_RELEASE]) { if (!(wowlan->flags & WIPHY_WOWLAN_RFKILL_RELEASE)) return -EINVAL; new_triggers.rfkill_release = true; + regular = true; } if (tb[NL80211_WOWLAN_TRIG_PKT_PATTERN]) { @@ -9173,6 +9180,8 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) int rem, pat_len, mask_len, pkt_offset; struct nlattr *pat_tb[NUM_NL80211_PKTPAT]; + regular = true; + nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN], rem) n_patterns++; @@ -9234,6 +9243,7 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) } if (tb[NL80211_WOWLAN_TRIG_TCP_CONNECTION]) { + regular = true; err = nl80211_parse_wowlan_tcp( rdev, tb[NL80211_WOWLAN_TRIG_TCP_CONNECTION], &new_triggers); @@ -9242,6 +9252,7 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) } if (tb[NL80211_WOWLAN_TRIG_NET_DETECT]) { + regular = true; err = nl80211_parse_wowlan_nd( rdev, wowlan, tb[NL80211_WOWLAN_TRIG_NET_DETECT], &new_triggers); @@ -9249,6 +9260,17 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) goto error; } + /* The 'any' trigger means the device continues operating more or less + * as in its normal operation mode and wakes up the host on most of the + * normal interrupts (like packet RX, ...) + * It therefore makes little sense to combine with the more constrained + * wakeup trigger modes. + */ + if (new_triggers.any && regular) { + err = -EINVAL; + goto error; + } + ntrig = kmemdup(&new_triggers, sizeof(new_triggers), GFP_KERNEL); if (!ntrig) { err = -ENOMEM; -- cgit v1.2.3 From 0c4ddcd214f5bc72713473e8383041ab7a2c6bb7 Mon Sep 17 00:00:00 2001 From: Ilan peer Date: Wed, 4 Mar 2015 00:32:05 -0500 Subject: cfg80211: Simplify the handling of regulatory indoor setting Directly update the indoor setting without wrapping it as a regulatory request, to simplify the processing. Acked-by: Luis R. Rodriguez Signed-off-by: Ilan Peer Signed-off-by: Johannes Berg --- net/wireless/reg.c | 34 +++------------------------------- 1 file changed, 3 insertions(+), 31 deletions(-) (limited to 'net/wireless') diff --git a/net/wireless/reg.c b/net/wireless/reg.c index b586d0dcb09e..c24c8bf3c988 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -82,17 +82,12 @@ * be intersected with the current one. * @REG_REQ_ALREADY_SET: the regulatory request will not change the current * regulatory settings, and no further processing is required. - * @REG_REQ_USER_HINT_HANDLED: a non alpha2 user hint was handled and no - * further processing is required, i.e., not need to update last_request - * etc. This should be used for user hints that do not provide an alpha2 - * but some other type of regulatory hint, i.e., indoor operation. */ enum reg_request_treatment { REG_REQ_OK, REG_REQ_IGNORE, REG_REQ_INTERSECT, REG_REQ_ALREADY_SET, - REG_REQ_USER_HINT_HANDLED, }; static struct regulatory_request core_request_world = { @@ -1248,13 +1243,6 @@ static bool reg_request_cell_base(struct regulatory_request *request) return request->user_reg_hint_type == NL80211_USER_REG_HINT_CELL_BASE; } -static bool reg_request_indoor(struct regulatory_request *request) -{ - if (request->initiator != NL80211_REGDOM_SET_BY_USER) - return false; - return request->user_reg_hint_type == NL80211_USER_REG_HINT_INDOOR; -} - bool reg_last_request_cell_base(void) { return reg_request_cell_base(get_last_request()); @@ -1833,11 +1821,6 @@ __reg_process_hint_user(struct regulatory_request *user_request) { struct regulatory_request *lr = get_last_request(); - if (reg_request_indoor(user_request)) { - reg_is_indoor = true; - return REG_REQ_USER_HINT_HANDLED; - } - if (reg_request_cell_base(user_request)) return reg_ignore_cell_hint(user_request); @@ -1885,8 +1868,7 @@ reg_process_hint_user(struct regulatory_request *user_request) treatment = __reg_process_hint_user(user_request); if (treatment == REG_REQ_IGNORE || - treatment == REG_REQ_ALREADY_SET || - treatment == REG_REQ_USER_HINT_HANDLED) { + treatment == REG_REQ_ALREADY_SET) { reg_free_request(user_request); return treatment; } @@ -1947,7 +1929,6 @@ reg_process_hint_driver(struct wiphy *wiphy, case REG_REQ_OK: break; case REG_REQ_IGNORE: - case REG_REQ_USER_HINT_HANDLED: reg_free_request(driver_request); return treatment; case REG_REQ_INTERSECT: @@ -2047,7 +2028,6 @@ reg_process_hint_country_ie(struct wiphy *wiphy, case REG_REQ_OK: break; case REG_REQ_IGNORE: - case REG_REQ_USER_HINT_HANDLED: /* fall through */ case REG_REQ_ALREADY_SET: reg_free_request(country_ie_request); @@ -2086,8 +2066,7 @@ static void reg_process_hint(struct regulatory_request *reg_request) case NL80211_REGDOM_SET_BY_USER: treatment = reg_process_hint_user(reg_request); if (treatment == REG_REQ_IGNORE || - treatment == REG_REQ_ALREADY_SET || - treatment == REG_REQ_USER_HINT_HANDLED) + treatment == REG_REQ_ALREADY_SET) return; queue_delayed_work(system_power_efficient_wq, ®_timeout, msecs_to_jiffies(3142)); @@ -2311,16 +2290,9 @@ int regulatory_hint_user(const char *alpha2, int regulatory_hint_indoor_user(void) { - struct regulatory_request *request; - request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL); - if (!request) - return -ENOMEM; - request->wiphy_idx = WIPHY_IDX_INVALID; - request->initiator = NL80211_REGDOM_SET_BY_USER; - request->user_reg_hint_type = NL80211_USER_REG_HINT_INDOOR; - queue_regulatory_request(request); + reg_is_indoor = true; return 0; } -- cgit v1.2.3 From 05050753602626ed4c46271c689929b625f409e7 Mon Sep 17 00:00:00 2001 From: Ilan peer Date: Wed, 4 Mar 2015 00:32:06 -0500 Subject: cfg80211: Add API to change the indoor regulatory setting Previously, the indoor setting configuration assumed that as long as a station interface is connected, the indoor environment setting does not change. However, this assumption is problematic as: - It is possible that a station interface is connected to a mobile AP, e.g., softAP or a P2P GO, where it is possible that both the station and the mobile AP move out of the indoor environment making the indoor setting invalid. In such a case, user space has no way to invalidate the setting. - A station interface disconnection does not necessarily imply that the device is no longer operating in an indoor environment, e.g., it is possible that the station interface is roaming but is still stays indoor. To handle the above, extend the indoor configuration API to allow user space to indicate a change of indoor settings, and allow it to indicate weather it controls the indoor setting, such that: 1. If the user space process explicitly indicates that it is going to control the indoor setting, do not clear the indoor setting internally, unless the socket is released. The user space process should use the NL80211_ATTR_SOCKET_OWNER attribute in the command to state that it is going to control the indoor setting. 2. Reset the indoor setting when restoring the regulatory settings in case it is not owned by a user space process. Based on the above, a user space tool that continuously monitors the indoor settings, i.e., tracking power setting, location etc., can indicate environment changes to the regulatory core. It should be noted that currently user space is the only provided mechanism used to hint to the regulatory core over the indoor/outdoor environment -- while the country IEs do have an environment setting this has been completely ignored by the regulatory core by design for a while now since country IEs typically can contain bogus data. Acked-by: Luis R. Rodriguez Signed-off-by: ArikX Nemtsov Signed-off-by: Ilan Peer Signed-off-by: Johannes Berg --- include/uapi/linux/nl80211.h | 9 +++++++ net/wireless/nl80211.c | 19 ++++++++++++++- net/wireless/reg.c | 57 ++++++++++++++++++++++++++++++++++++++++---- net/wireless/reg.h | 15 +++++++++++- 4 files changed, 94 insertions(+), 6 deletions(-) (limited to 'net/wireless') diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 37e7f39441e5..ae16ba9cb1e3 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -1697,6 +1697,10 @@ enum nl80211_commands { * If set during scheduled scan start then the new scan req will be * owned by the netlink socket that created it and the scheduled scan will * be stopped when the socket is closed. + * If set during configuration of regulatory indoor operation then the + * regulatory indoor configuration would be owned by the netlink socket + * that configured the indoor setting, and the indoor operation would be + * cleared when the socket is closed. * * @NL80211_ATTR_TDLS_INITIATOR: flag attribute indicating the current end is * the TDLS link initiator. @@ -1752,6 +1756,9 @@ enum nl80211_commands { * * @NL80211_ATTR_SCHED_SCAN_DELAY: delay before a scheduled scan (or a * WoWLAN net-detect scan) is started, u32 in seconds. + + * @NL80211_ATTR_REG_INDOOR: flag attribute, if set indicates that the device + * is operating in an indoor environment. * * @NUM_NL80211_ATTR: total number of nl80211_attrs available * @NL80211_ATTR_MAX: highest attribute number currently defined @@ -2120,6 +2127,8 @@ enum nl80211_attrs { NL80211_ATTR_SCHED_SCAN_DELAY, + NL80211_ATTR_REG_INDOOR, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 07cef3d7653e..b02085301785 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -399,6 +399,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { [NL80211_ATTR_WIPHY_SELF_MANAGED_REG] = { .type = NLA_FLAG }, [NL80211_ATTR_NETNS_FD] = { .type = NLA_U32 }, [NL80211_ATTR_SCHED_SCAN_DELAY] = { .type = NLA_U32 }, + [NL80211_ATTR_REG_INDOOR] = { .type = NLA_FLAG }, }; /* policy for the key attributes */ @@ -4958,7 +4959,10 @@ static int parse_reg_rule(struct nlattr *tb[], static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info) { char *data = NULL; + bool is_indoor; enum nl80211_user_reg_hint_type user_reg_hint_type; + u32 owner_nlportid; + /* * You should only get this when cfg80211 hasn't yet initialized @@ -4984,7 +4988,15 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info) data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]); return regulatory_hint_user(data, user_reg_hint_type); case NL80211_USER_REG_HINT_INDOOR: - return regulatory_hint_indoor_user(); + if (info->attrs[NL80211_ATTR_SOCKET_OWNER]) { + owner_nlportid = info->snd_portid; + is_indoor = !!info->attrs[NL80211_ATTR_REG_INDOOR]; + } else { + owner_nlportid = 0; + is_indoor = true; + } + + return regulatory_hint_indoor(is_indoor, owner_nlportid); default: return -EINVAL; } @@ -12810,6 +12822,11 @@ static int nl80211_netlink_notify(struct notifier_block * nb, rcu_read_unlock(); + /* + * It is possible that the user space process that is controlling the + * indoor setting disappeared, so notify the regulatory core. + */ + regulatory_netlink_notify(notify->portid); return NOTIFY_OK; } diff --git a/net/wireless/reg.c b/net/wireless/reg.c index c24c8bf3c988..4239dd408137 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -128,9 +128,12 @@ static int reg_num_devs_support_basehint; * State variable indicating if the platform on which the devices * are attached is operating in an indoor environment. The state variable * is relevant for all registered devices. - * (protected by RTNL) */ static bool reg_is_indoor; +static spinlock_t reg_indoor_lock; + +/* Used to track the userspace process controlling the indoor setting */ +static u32 reg_is_indoor_portid; static const struct ieee80211_regdomain *get_cfg80211_regdom(void) { @@ -2288,15 +2291,50 @@ int regulatory_hint_user(const char *alpha2, return 0; } -int regulatory_hint_indoor_user(void) +int regulatory_hint_indoor(bool is_indoor, u32 portid) { + spin_lock(®_indoor_lock); + + /* It is possible that more than one user space process is trying to + * configure the indoor setting. To handle such cases, clear the indoor + * setting in case that some process does not think that the device + * is operating in an indoor environment. In addition, if a user space + * process indicates that it is controlling the indoor setting, save its + * portid, i.e., make it the owner. + */ + reg_is_indoor = is_indoor; + if (reg_is_indoor) { + if (!reg_is_indoor_portid) + reg_is_indoor_portid = portid; + } else { + reg_is_indoor_portid = 0; + } + spin_unlock(®_indoor_lock); - reg_is_indoor = true; + if (!is_indoor) + reg_check_channels(); return 0; } +void regulatory_netlink_notify(u32 portid) +{ + spin_lock(®_indoor_lock); + + if (reg_is_indoor_portid != portid) { + spin_unlock(®_indoor_lock); + return; + } + + reg_is_indoor = false; + reg_is_indoor_portid = 0; + + spin_unlock(®_indoor_lock); + + reg_check_channels(); +} + /* Driver hints */ int regulatory_hint(struct wiphy *wiphy, const char *alpha2) { @@ -2464,7 +2502,17 @@ static void restore_regulatory_settings(bool reset_user) ASSERT_RTNL(); - reg_is_indoor = false; + /* + * Clear the indoor setting in case that it is not controlled by user + * space, as otherwise there is no guarantee that the device is still + * operating in an indoor environment. + */ + spin_lock(®_indoor_lock); + if (reg_is_indoor && !reg_is_indoor_portid) { + reg_is_indoor = false; + reg_check_channels(); + } + spin_unlock(®_indoor_lock); reset_regdomains(true, &world_regdom); restore_alpha2(alpha2, reset_user); @@ -3061,6 +3109,7 @@ int __init regulatory_init(void) spin_lock_init(®_requests_lock); spin_lock_init(®_pending_beacons_lock); + spin_lock_init(®_indoor_lock); reg_regdb_size_check(); diff --git a/net/wireless/reg.h b/net/wireless/reg.h index 4b45d6e61d24..a2c4e16459da 100644 --- a/net/wireless/reg.h +++ b/net/wireless/reg.h @@ -25,7 +25,20 @@ enum nl80211_dfs_regions reg_get_dfs_region(struct wiphy *wiphy); int regulatory_hint_user(const char *alpha2, enum nl80211_user_reg_hint_type user_reg_hint_type); -int regulatory_hint_indoor_user(void); + +/** + * regulatory_hint_indoor - hint operation in indoor env. or not + * @is_indoor: if true indicates that user space thinks that the + * device is operating in an indoor environment. + * @portid: the netlink port ID on which the hint was given. + */ +int regulatory_hint_indoor(bool is_indoor, u32 portid); + +/** + * regulatory_netlink_notify - notify on released netlink socket + * @portid: the netlink socket port ID + */ +void regulatory_netlink_notify(u32 portid); void wiphy_regulatory_register(struct wiphy *wiphy); void wiphy_regulatory_deregister(struct wiphy *wiphy); -- cgit v1.2.3 From eeca9fce1d71a4955855ceb0c3b13c1eb9db27c1 Mon Sep 17 00:00:00 2001 From: Ilan peer Date: Wed, 4 Mar 2015 00:32:07 -0500 Subject: cfg80211: Schedule timeout for all CRDA calls Timeout was scheduled only in case CRDA was called due to user hints, but was not scheduled for other cases. This can result in regulatory hint processing getting stuck in case that there is no CRDA configured. Change this by scheduling a timeout every time CRDA is called. In addition, in restore_regulatory_settings() all pending requests are restored (and not only the user ones). Signed-off-by: Ilan Peer Acked-by: Luis R. Rodriguez Signed-off-by: Johannes Berg --- net/wireless/reg.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) (limited to 'net/wireless') diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 4239dd408137..d8671036c264 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -552,6 +552,9 @@ reg_call_crda(struct regulatory_request *request) { if (call_crda(request->alpha2)) return REG_REQ_IGNORE; + + queue_delayed_work(system_power_efficient_wq, + ®_timeout, msecs_to_jiffies(3142)); return REG_REQ_OK; } @@ -1791,8 +1794,7 @@ static void reg_set_request_processed(void) need_more_processing = true; spin_unlock(®_requests_lock); - if (lr->initiator == NL80211_REGDOM_SET_BY_USER) - cancel_delayed_work(®_timeout); + cancel_delayed_work(®_timeout); if (need_more_processing) schedule_work(®_work); @@ -2071,8 +2073,6 @@ static void reg_process_hint(struct regulatory_request *reg_request) if (treatment == REG_REQ_IGNORE || treatment == REG_REQ_ALREADY_SET) return; - queue_delayed_work(system_power_efficient_wq, - ®_timeout, msecs_to_jiffies(3142)); return; case NL80211_REGDOM_SET_BY_DRIVER: if (!wiphy) @@ -2496,7 +2496,6 @@ static void restore_regulatory_settings(bool reset_user) char alpha2[2]; char world_alpha2[2]; struct reg_beacon *reg_beacon, *btmp; - struct regulatory_request *reg_request, *tmp; LIST_HEAD(tmp_reg_req_list); struct cfg80211_registered_device *rdev; @@ -2524,11 +2523,7 @@ static void restore_regulatory_settings(bool reset_user) * settings. */ spin_lock(®_requests_lock); - list_for_each_entry_safe(reg_request, tmp, ®_requests_list, list) { - if (reg_request->initiator != NL80211_REGDOM_SET_BY_USER) - continue; - list_move_tail(®_request->list, &tmp_reg_req_list); - } + list_splice_tail_init(®_requests_list, &tmp_reg_req_list); spin_unlock(®_requests_lock); /* Clear beacon hints */ -- cgit v1.2.3 From 2e54a6895e3e0cada8d194ace4f5baae643a073f Mon Sep 17 00:00:00 2001 From: Ben Date: Thu, 12 Mar 2015 09:37:34 -0400 Subject: cfg80211: Process all pending regulatory requests/hints It is possible that there are several regulatory requests pending, but the processing of the last one does not call CRDA, and thus the other requests are not handled. Fix this by rescheduling the work until all requests have been processed. Signed-off-by: Ben Rosenfeld Signed-off-by: Ilan Peer Signed-off-by: Johannes Berg --- net/wireless/reg.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'net/wireless') diff --git a/net/wireless/reg.c b/net/wireless/reg.c index d8671036c264..8c6cf52b9f1d 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -2159,6 +2159,13 @@ static void reg_process_pending_hints(void) } reg_process_hint(reg_request); + + lr = get_last_request(); + + spin_lock(®_requests_lock); + if (!list_empty(®_requests_list) && lr && lr->processed) + schedule_work(®_work); + spin_unlock(®_requests_lock); } /* Processes beacon hints -- this has nothing to do with country IEs */ -- cgit v1.2.3 From 5d8325ecb9c21015f330eb0dcffcc5fc1b1fe5b8 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 20 Mar 2015 19:56:41 +0100 Subject: cfg80211: add vlan to station add/change tracing This helps debug issues with VLAN modifications that are otherwise not really visible in any tracing/debugging. Signed-off-by: Johannes Berg --- net/wireless/trace.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'net/wireless') diff --git a/net/wireless/trace.h b/net/wireless/trace.h index b19773c9c81b..e4e39143728c 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h @@ -627,6 +627,7 @@ DECLARE_EVENT_CLASS(station_add_change, __field(u8, plink_state) __field(u8, uapsd_queues) __array(u8, ht_capa, (int)sizeof(struct ieee80211_ht_cap)) + __array(char, vlan, IFNAMSIZ) ), TP_fast_assign( WIPHY_ASSIGN; @@ -644,16 +645,19 @@ DECLARE_EVENT_CLASS(station_add_change, if (params->ht_capa) memcpy(__entry->ht_capa, params->ht_capa, sizeof(struct ieee80211_ht_cap)); + memset(__entry->vlan, 0, sizeof(__entry->vlan)); + if (params->vlan) + memcpy(__entry->vlan, params->vlan->name, IFNAMSIZ); ), TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", station mac: " MAC_PR_FMT ", station flags mask: %u, station flags set: %u, " "station modify mask: %u, listen interval: %d, aid: %u, " - "plink action: %u, plink state: %u, uapsd queues: %u", + "plink action: %u, plink state: %u, uapsd queues: %u, vlan:%s", WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(sta_mac), __entry->sta_flags_mask, __entry->sta_flags_set, __entry->sta_modify_mask, __entry->listen_interval, __entry->aid, __entry->plink_action, __entry->plink_state, - __entry->uapsd_queues) + __entry->uapsd_queues, __entry->vlan) ); DEFINE_EVENT(station_add_change, rdev_add_station, -- cgit v1.2.3 From 21fea567313641b6be69e0c684dc36c871ac848c Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Tue, 17 Mar 2015 16:36:01 +0200 Subject: nl80211: add net-detect delay to wowlan info Pass the initial net-detect delay (NL80211_ATTR_SCHED_SCAN_DELAY) attribute in the WoWLAN info response. Additionally, remove a bogus TODO comment. Signed-off-by: Luciano Coelho Reviewed-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- net/wireless/nl80211.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'net/wireless') diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index b02085301785..543dd51342f0 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -1099,8 +1099,6 @@ static int nl80211_send_wowlan(struct sk_buff *msg, if (large && nl80211_send_wowlan_tcp_caps(rdev, msg)) return -ENOBUFS; - /* TODO: send wowlan net detect */ - nla_nest_end(msg, nl_wowlan); return 0; @@ -8831,6 +8829,9 @@ static int nl80211_send_wowlan_nd(struct sk_buff *msg, if (nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_INTERVAL, req->interval)) return -ENOBUFS; + if (nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_DELAY, req->delay)) + return -ENOBUFS; + freqs = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQUENCIES); if (!freqs) return -ENOBUFS; -- cgit v1.2.3 From a38700dd486f3def34cef47d00e2d360a04a7bc8 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Wed, 18 Mar 2015 08:46:08 +0200 Subject: cfg/mac80211: add regulatory classes IE during TDLS setup Seems Broadcom TDLS peers (Nexus 5, Xperia Z3) refuse to allow TDLS connection when channel-switching is supported but the regulatory classes IE is missing from the setup request. Add a chandef to reg-class translation function to cfg80211 and use it to add the required IE during setup. For now add only the current regulatory class as supported - it is enough to resolve the compatibility issue. Signed-off-by: Arik Nemtsov Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 11 +++++ net/mac80211/tdls.c | 21 ++++++++ net/wireless/util.c | 129 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 161 insertions(+) (limited to 'net/wireless') diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 12a6121ea76e..c4d873b8f32d 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -4903,6 +4903,17 @@ void cfg80211_ch_switch_started_notify(struct net_device *dev, bool ieee80211_operating_class_to_band(u8 operating_class, enum ieee80211_band *band); +/** + * ieee80211_chandef_to_operating_class - convert chandef to operation class + * + * @chandef: the chandef to convert + * @op_class: a pointer to the resulting operating class + * + * Returns %true if the conversion was successful, %false otherwise. + */ +bool ieee80211_chandef_to_operating_class(struct cfg80211_chan_def *chandef, + u8 *op_class); + /* * cfg80211_tdls_oper_request - request userspace to perform TDLS operation * @dev: the device on which the operation is requested diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index bc7e4049896f..79ed59acf0d4 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c @@ -136,6 +136,24 @@ ieee80211_tdls_add_supp_channels(struct ieee80211_sub_if_data *sdata, *pos = 2 * subband_cnt; } +static void ieee80211_tdls_add_oper_classes(struct ieee80211_sub_if_data *sdata, + struct sk_buff *skb) +{ + u8 *pos; + u8 op_class; + + if (!ieee80211_chandef_to_operating_class(&sdata->vif.bss_conf.chandef, + &op_class)) + return; + + pos = skb_put(skb, 4); + *pos++ = WLAN_EID_SUPPORTED_REGULATORY_CLASSES; + *pos++ = 2; /* len */ + + *pos++ = op_class; + *pos++ = op_class; /* give current operating class as alternate too */ +} + static void ieee80211_tdls_add_bss_coex_ie(struct sk_buff *skb) { u8 *pos = (void *)skb_put(skb, 3); @@ -350,6 +368,8 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata, } } + ieee80211_tdls_add_oper_classes(sdata, skb); + /* * with TDLS we can switch channels, and HT-caps are not necessarily * the same on all bands. The specification limits the setup to a @@ -786,6 +806,7 @@ ieee80211_tdls_build_mgmt_packet_data(struct ieee80211_sub_if_data *sdata, 50 + /* supported channels */ 3 + /* 40/20 BSS coex */ 4 + /* AID */ + 4 + /* oper classes */ extra_ies_len + sizeof(struct ieee80211_tdls_lnkie)); if (!skb) diff --git a/net/wireless/util.c b/net/wireless/util.c index f7b35980af69..f218b151530a 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -1314,6 +1314,135 @@ bool ieee80211_operating_class_to_band(u8 operating_class, } EXPORT_SYMBOL(ieee80211_operating_class_to_band); +bool ieee80211_chandef_to_operating_class(struct cfg80211_chan_def *chandef, + u8 *op_class) +{ + u8 vht_opclass; + u16 freq = chandef->center_freq1; + + if (freq >= 2412 && freq <= 2472) { + if (chandef->width > NL80211_CHAN_WIDTH_40) + return false; + + /* 2.407 GHz, channels 1..13 */ + if (chandef->width == NL80211_CHAN_WIDTH_40) { + if (freq > chandef->chan->center_freq) + *op_class = 83; /* HT40+ */ + else + *op_class = 84; /* HT40- */ + } else { + *op_class = 81; + } + + return true; + } + + if (freq == 2484) { + if (chandef->width > NL80211_CHAN_WIDTH_40) + return false; + + *op_class = 82; /* channel 14 */ + return true; + } + + switch (chandef->width) { + case NL80211_CHAN_WIDTH_80: + vht_opclass = 128; + break; + case NL80211_CHAN_WIDTH_160: + vht_opclass = 129; + break; + case NL80211_CHAN_WIDTH_80P80: + vht_opclass = 130; + break; + case NL80211_CHAN_WIDTH_10: + case NL80211_CHAN_WIDTH_5: + return false; /* unsupported for now */ + default: + vht_opclass = 0; + break; + } + + /* 5 GHz, channels 36..48 */ + if (freq >= 5180 && freq <= 5240) { + if (vht_opclass) { + *op_class = vht_opclass; + } else if (chandef->width == NL80211_CHAN_WIDTH_40) { + if (freq > chandef->chan->center_freq) + *op_class = 116; + else + *op_class = 117; + } else { + *op_class = 115; + } + + return true; + } + + /* 5 GHz, channels 52..64 */ + if (freq >= 5260 && freq <= 5320) { + if (vht_opclass) { + *op_class = vht_opclass; + } else if (chandef->width == NL80211_CHAN_WIDTH_40) { + if (freq > chandef->chan->center_freq) + *op_class = 119; + else + *op_class = 120; + } else { + *op_class = 118; + } + + return true; + } + + /* 5 GHz, channels 100..144 */ + if (freq >= 5500 && freq <= 5720) { + if (vht_opclass) { + *op_class = vht_opclass; + } else if (chandef->width == NL80211_CHAN_WIDTH_40) { + if (freq > chandef->chan->center_freq) + *op_class = 122; + else + *op_class = 123; + } else { + *op_class = 121; + } + + return true; + } + + /* 5 GHz, channels 149..169 */ + if (freq >= 5745 && freq <= 5845) { + if (vht_opclass) { + *op_class = vht_opclass; + } else if (chandef->width == NL80211_CHAN_WIDTH_40) { + if (freq > chandef->chan->center_freq) + *op_class = 126; + else + *op_class = 127; + } else if (freq <= 5805) { + *op_class = 124; + } else { + *op_class = 125; + } + + return true; + } + + /* 56.16 GHz, channel 1..4 */ + if (freq >= 56160 + 2160 * 1 && freq <= 56160 + 2160 * 4) { + if (chandef->width >= NL80211_CHAN_WIDTH_40) + return false; + + *op_class = 180; + return true; + } + + /* not supported yet */ + return false; +} +EXPORT_SYMBOL(ieee80211_chandef_to_operating_class); + int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, u32 beacon_int) { -- cgit v1.2.3 From 6bab2e19c5ffd1f21b28c2cabb3801a37b77ae69 Mon Sep 17 00:00:00 2001 From: Tom Gundersen Date: Wed, 18 Mar 2015 11:13:39 +0100 Subject: cfg80211: pass name_assign_type to rdev_add_virtual_intf() This will expose in /sys whether the ifname of a device is set by userspace or generated by the kernel. The latter kind (wlanX, etc) is not deterministic, so userspace needs to rename these devices to names that are guaranteed to stay the same between reboots. The former, however should never be renamed, so userspace needs to be able to reliably tell the difference. Similar functionality was introduced for the rtnetlink core in commit 5517750f058e ("net: rtnetlink - make create_link take name_assign_type") Signed-off-by: Tom Gundersen Cc: Kalle Valo Cc: Brett Rudley Cc: Arend van Spriel Cc: Franky (Zhenhui) Lin Cc: Hante Meuleman Cc: Johannes Berg [reformat changelog to fit 72 cols] Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 6 ++++-- drivers/net/wireless/ath/ath6kl/cfg80211.h | 1 + drivers/net/wireless/ath/ath6kl/core.c | 4 ++-- drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c | 3 ++- drivers/net/wireless/brcm80211/brcmfmac/p2p.c | 3 +++ drivers/net/wireless/brcm80211/brcmfmac/p2p.h | 1 + drivers/net/wireless/mwifiex/cfg80211.c | 5 +++-- drivers/net/wireless/mwifiex/main.c | 6 +++--- drivers/net/wireless/mwifiex/main.h | 1 + drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c | 6 +++++- include/net/cfg80211.h | 1 + net/mac80211/cfg.c | 3 ++- net/mac80211/ieee80211_i.h | 1 + net/mac80211/iface.c | 3 ++- net/mac80211/main.c | 2 +- net/wireless/nl80211.c | 3 ++- net/wireless/rdev-ops.h | 5 +++-- 17 files changed, 37 insertions(+), 17 deletions(-) (limited to 'net/wireless') diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index ff7ba5c195c6..d740f14f3539 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -1496,6 +1496,7 @@ static int ath6kl_cfg80211_set_power_mgmt(struct wiphy *wiphy, static struct wireless_dev *ath6kl_cfg80211_add_iface(struct wiphy *wiphy, const char *name, + unsigned char name_assign_type, enum nl80211_iftype type, u32 *flags, struct vif_params *params) @@ -1514,7 +1515,7 @@ static struct wireless_dev *ath6kl_cfg80211_add_iface(struct wiphy *wiphy, return ERR_PTR(-EINVAL); } - wdev = ath6kl_interface_add(ar, name, type, if_idx, nw_type); + wdev = ath6kl_interface_add(ar, name, name_assign_type, type, if_idx, nw_type); if (!wdev) return ERR_PTR(-ENOMEM); @@ -3634,13 +3635,14 @@ void ath6kl_cfg80211_vif_cleanup(struct ath6kl_vif *vif) } struct wireless_dev *ath6kl_interface_add(struct ath6kl *ar, const char *name, + unsigned char name_assign_type, enum nl80211_iftype type, u8 fw_vif_idx, u8 nw_type) { struct net_device *ndev; struct ath6kl_vif *vif; - ndev = alloc_netdev(sizeof(*vif), name, NET_NAME_UNKNOWN, ether_setup); + ndev = alloc_netdev(sizeof(*vif), name, name_assign_type, ether_setup); if (!ndev) return NULL; diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.h b/drivers/net/wireless/ath/ath6kl/cfg80211.h index b59becd91aea..5aa57a7639bf 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.h +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.h @@ -25,6 +25,7 @@ enum ath6kl_cfg_suspend_mode { }; struct wireless_dev *ath6kl_interface_add(struct ath6kl *ar, const char *name, + unsigned char name_assign_type, enum nl80211_iftype type, u8 fw_vif_idx, u8 nw_type); void ath6kl_cfg80211_ch_switch_notify(struct ath6kl_vif *vif, int freq, diff --git a/drivers/net/wireless/ath/ath6kl/core.c b/drivers/net/wireless/ath/ath6kl/core.c index 0df74b245af4..4ec02cea0f43 100644 --- a/drivers/net/wireless/ath/ath6kl/core.c +++ b/drivers/net/wireless/ath/ath6kl/core.c @@ -211,8 +211,8 @@ int ath6kl_core_init(struct ath6kl *ar, enum ath6kl_htc_type htc_type) rtnl_lock(); /* Add an initial station interface */ - wdev = ath6kl_interface_add(ar, "wlan%d", NL80211_IFTYPE_STATION, 0, - INFRA_NETWORK); + wdev = ath6kl_interface_add(ar, "wlan%d", NET_NAME_ENUM, + NL80211_IFTYPE_STATION, 0, INFRA_NETWORK); rtnl_unlock(); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c index b59b8c6c42ab..bcbccba4cdbf 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c @@ -625,6 +625,7 @@ static bool brcmf_is_ibssmode(struct brcmf_cfg80211_vif *vif) static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy, const char *name, + unsigned char name_assign_type, enum nl80211_iftype type, u32 *flags, struct vif_params *params) @@ -648,7 +649,7 @@ static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy, case NL80211_IFTYPE_P2P_CLIENT: case NL80211_IFTYPE_P2P_GO: case NL80211_IFTYPE_P2P_DEVICE: - wdev = brcmf_p2p_add_vif(wiphy, name, type, flags, params); + wdev = brcmf_p2p_add_vif(wiphy, name, name_assign_type, type, flags, params); if (!IS_ERR(wdev)) brcmf_cfg80211_update_proto_addr_mode(wdev); return wdev; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c index effb48ebd864..b44ea85dd9db 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c @@ -2246,11 +2246,13 @@ static void brcmf_p2p_delete_p2pdev(struct brcmf_p2p_info *p2p, * * @wiphy: wiphy device of new interface. * @name: name of the new interface. + * @name_assign_type: origin of the interface name * @type: nl80211 interface type. * @flags: not used. * @params: contains mac address for P2P device. */ struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name, + unsigned char name_assign_type, enum nl80211_iftype type, u32 *flags, struct vif_params *params) { @@ -2310,6 +2312,7 @@ struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name, } strncpy(ifp->ndev->name, name, sizeof(ifp->ndev->name) - 1); + ifp->ndev->name_assign_type = name_assign_type; err = brcmf_net_attach(ifp, true); if (err) { brcmf_err("Registering netdevice failed\n"); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/p2p.h b/drivers/net/wireless/brcm80211/brcmfmac/p2p.h index 6821b26224be..872f382d9e49 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/p2p.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.h @@ -149,6 +149,7 @@ struct brcmf_p2p_info { s32 brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg); void brcmf_p2p_detach(struct brcmf_p2p_info *p2p); struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name, + unsigned char name_assign_type, enum nl80211_iftype type, u32 *flags, struct vif_params *params); int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev); diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index a47eb55bb6da..2d489bfaea08 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -2399,10 +2399,11 @@ mwifiex_setup_ht_caps(struct ieee80211_sta_ht_cap *ht_info, #define MWIFIEX_MAX_WQ_LEN 30 /* - * create a new virtual interface with the given name + * create a new virtual interface with the given name and name assign type */ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, const char *name, + unsigned char name_assign_type, enum nl80211_iftype type, u32 *flags, struct vif_params *params) @@ -2523,7 +2524,7 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, } dev = alloc_netdev_mqs(sizeof(struct mwifiex_private *), name, - NET_NAME_UNKNOWN, ether_setup, + name_assign_type, ether_setup, IEEE80211_NUM_ACS, 1); if (!dev) { wiphy_err(wiphy, "no memory available for netdevice\n"); diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index 7e74b4fccddd..6f55e84fcab1 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -466,7 +466,7 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context) rtnl_lock(); /* Create station interface by default */ - wdev = mwifiex_add_virtual_intf(adapter->wiphy, "mlan%d", + wdev = mwifiex_add_virtual_intf(adapter->wiphy, "mlan%d", NET_NAME_ENUM, NL80211_IFTYPE_STATION, NULL, NULL); if (IS_ERR(wdev)) { dev_err(adapter->dev, "cannot create default STA interface\n"); @@ -475,7 +475,7 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context) } if (driver_mode & MWIFIEX_DRIVER_MODE_UAP) { - wdev = mwifiex_add_virtual_intf(adapter->wiphy, "uap%d", + wdev = mwifiex_add_virtual_intf(adapter->wiphy, "uap%d", NET_NAME_ENUM, NL80211_IFTYPE_AP, NULL, NULL); if (IS_ERR(wdev)) { dev_err(adapter->dev, "cannot create AP interface\n"); @@ -485,7 +485,7 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context) } if (driver_mode & MWIFIEX_DRIVER_MODE_P2P) { - wdev = mwifiex_add_virtual_intf(adapter->wiphy, "p2p%d", + wdev = mwifiex_add_virtual_intf(adapter->wiphy, "p2p%d", NET_NAME_ENUM, NL80211_IFTYPE_P2P_CLIENT, NULL, NULL); if (IS_ERR(wdev)) { diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index f0a6af179af0..3f0625f22265 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -1318,6 +1318,7 @@ u8 mwifiex_chan_type_to_sec_chan_offset(enum nl80211_channel_type chan_type); struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, const char *name, + unsigned char name_assign_type, enum nl80211_iftype type, u32 *flags, struct vif_params *params); diff --git a/drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c b/drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c index 537bd8214efe..a6116fdc8678 100644 --- a/drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c +++ b/drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c @@ -2580,6 +2580,7 @@ static const struct net_device_ops rtw_cfg80211_monitor_if_ops = { }; static int rtw_cfg80211_add_monitor_if(struct rtw_adapter *padapter, char *name, + unsigned char name_assign_type, struct net_device **ndev) { int ret = 0; @@ -2612,6 +2613,7 @@ static int rtw_cfg80211_add_monitor_if(struct rtw_adapter *padapter, char *name, mon_ndev->type = ARPHRD_IEEE80211_RADIOTAP; strncpy(mon_ndev->name, name, IFNAMSIZ); mon_ndev->name[IFNAMSIZ - 1] = 0; + mon_ndev->name_assign_type = name_assign_type; mon_ndev->destructor = rtw_ndev_destructor; mon_ndev->netdev_ops = &rtw_cfg80211_monitor_if_ops; @@ -2654,6 +2656,7 @@ out: static struct wireless_dev * cfg80211_rtw_add_virtual_intf(struct wiphy *wiphy, const char *name, + unsigned char name_assign_type, enum nl80211_iftype type, u32 *flags, struct vif_params *params) { @@ -2673,7 +2676,8 @@ cfg80211_rtw_add_virtual_intf(struct wiphy *wiphy, const char *name, break; case NL80211_IFTYPE_MONITOR: ret = - rtw_cfg80211_add_monitor_if(padapter, (char *)name, &ndev); + rtw_cfg80211_add_monitor_if(padapter, (char *)name, + name_assign_type, &ndev); break; case NL80211_IFTYPE_P2P_CLIENT: diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index c4d873b8f32d..ab667fbc743d 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -2456,6 +2456,7 @@ struct cfg80211_ops { struct wireless_dev * (*add_virtual_intf)(struct wiphy *wiphy, const char *name, + unsigned char name_assign_type, enum nl80211_iftype type, u32 *flags, struct vif_params *params); diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index e01cea3b9043..49401238ac39 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -24,6 +24,7 @@ static struct wireless_dev *ieee80211_add_iface(struct wiphy *wiphy, const char *name, + unsigned char name_assign_type, enum nl80211_iftype type, u32 *flags, struct vif_params *params) @@ -33,7 +34,7 @@ static struct wireless_dev *ieee80211_add_iface(struct wiphy *wiphy, struct ieee80211_sub_if_data *sdata; int err; - err = ieee80211_if_add(local, name, &wdev, type, params); + err = ieee80211_if_add(local, name, name_assign_type, &wdev, type, params); if (err) return ERR_PTR(err); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index ebc8135e0aaa..3e3cfe8da4ef 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1578,6 +1578,7 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, int ieee80211_iface_init(void); void ieee80211_iface_exit(void); int ieee80211_if_add(struct ieee80211_local *local, const char *name, + unsigned char name_assign_type, struct wireless_dev **new_wdev, enum nl80211_iftype type, struct vif_params *params); int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata, diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 9689d3b1133b..a0cd97fd0c49 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -1648,6 +1648,7 @@ static void ieee80211_assign_perm_addr(struct ieee80211_local *local, } int ieee80211_if_add(struct ieee80211_local *local, const char *name, + unsigned char name_assign_type, struct wireless_dev **new_wdev, enum nl80211_iftype type, struct vif_params *params) { @@ -1676,7 +1677,7 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, txqs = IEEE80211_NUM_ACS; ndev = alloc_netdev_mqs(sizeof(*sdata) + local->hw.vif_data_size, - name, NET_NAME_UNKNOWN, + name, name_assign_type, ieee80211_if_setup, txqs, 1); if (!ndev) return -ENOMEM; diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 2f51e6d1f2b3..4977967c8b00 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -1057,7 +1057,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) /* add one default STA interface if supported */ if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_STATION) && !(hw->flags & IEEE80211_HW_NO_AUTO_VIF)) { - result = ieee80211_if_add(local, "wlan%d", NULL, + result = ieee80211_if_add(local, "wlan%d", NET_NAME_ENUM, NULL, NL80211_IFTYPE_STATION, NULL); if (result) wiphy_warn(local->hw.wiphy, diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 543dd51342f0..f60ee5b45c0c 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -2667,7 +2667,8 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) wdev = rdev_add_virtual_intf(rdev, nla_data(info->attrs[NL80211_ATTR_IFNAME]), - type, err ? NULL : &flags, ¶ms); + NET_NAME_USER, type, err ? NULL : &flags, + ¶ms); if (WARN_ON(!wdev)) { nlmsg_free(msg); return -EPROTO; diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h index 35cfb7134bdb..c6e83a7468c0 100644 --- a/net/wireless/rdev-ops.h +++ b/net/wireless/rdev-ops.h @@ -35,13 +35,14 @@ static inline void rdev_set_wakeup(struct cfg80211_registered_device *rdev, static inline struct wireless_dev *rdev_add_virtual_intf(struct cfg80211_registered_device *rdev, char *name, + unsigned char name_assign_type, enum nl80211_iftype type, u32 *flags, struct vif_params *params) { struct wireless_dev *ret; trace_rdev_add_virtual_intf(&rdev->wiphy, name, type); - ret = rdev->ops->add_virtual_intf(&rdev->wiphy, name, type, flags, - params); + ret = rdev->ops->add_virtual_intf(&rdev->wiphy, name, name_assign_type, + type, flags, params); trace_rdev_return_wdev(&rdev->wiphy, ret); return ret; } -- cgit v1.2.3