wireless regulatory updates
Subsystems (4)
Johannes Berg
maintainercover wireless regulatory updates
Here's my set of updates, it removes the struct hint entirely as we've come up with a new and better way.
johannes
Johannes Berg
maintainerPATCH 1/4 wireless: make regdom passing semantics simpler
The regdom struct is given to the core, so it might as well free it in error conditions.
--- Documentation/networking/regulatory.txt | 13 +++---------- include/net/wireless.h | 3 +-- net/wireless/nl80211.c | 5 +---- net/wireless/reg.c | 9 +++++---- 4 files changed, 10 insertions(+), 20 deletions(-)
net/wireless/nl80211.c +1 -4
@@ -1935,12 +1935,9 @@ static int nl80211_set_reg(struct sk_bufmutex_lock (&cfg80211_drv_mutex); r =set_regdom (rd);mutex_unlock (&cfg80211_drv_mutex); -if (r) - goto bad_reg; -return r; -bad_reg: + bad_reg:kfree (rd);return -EINVAL ; }
net/wireless/reg.c +5 -4
@@ -605,7 +605,6 @@ int __regulatory_hint(struct wiphy *wiphreturn r; } -/* If rd is not NULL and if this call fails the caller must free it */ int regulatory_hint (struct wiphy *wiphy,const char *alpha2,struct ieee80211_regdomain *rd) {
@@ -690,6 +689,7 @@ void print_regdomain_info(const struct iprint_rd_rules (rd); } +/* Takes ownership of rd only if it doesn't fail */ static int __set_regdom (const struct ieee80211_regdomain *rd) {/* Some basic sanity checks first */
@@ -750,16 +750,17 @@ static int __set_regdom(const struct iee/* Use this call to set the current regulatory domain. Conflicts with * multiple drivers can be ironed out later. Caller must've already -* kmalloc'd the rd structure. If this calls fails you should kfree() -* the passed rd. Caller must hold cfg80211_drv_mutex */ +* kmalloc'd the rd structure. Caller must hold cfg80211_drv_mutex */ int set_regdom (const struct ieee80211_regdomain *rd) {int r;/* Note that this doesn't update the wiphys, this is done below */ r =__set_regdom (rd); -if (r) +if (r) { +kfree (rd);return r; + }/* This would make this whole thing pointless */ BUG_ON (rd != cfg80211_regdomain);
include/net/wireless.h +1 -2
@@ -358,8 +358,7 @@ ieee80211_get_channel(struct wiphy *wiph* for a regulatory domain structure for the respective country. If * a regulatory domain is build and passed you should set the alpha2 * if possible, otherwise set it to the special value of "99" which tells -* the wireless core it is unknown. If you pass a built regulatory domain -* and we return non zero you are in charge of kfree()'ing the structure. +* the wireless core it is unknown. * * Returns -EALREADY if *a regulatory domain* has already been set. Note that * this could be by another driver. It is safe for drivers to continue if
Documentation/networking/regulatory.txt +3 -10
@@ -167,7 +167,6 @@ struct ieee80211_regdomain mydriver_jp_r Then in some part of your code after your wiphy has been registered: - int r; struct ieee80211_regdomain *rd; int size_of_regd; int num_rules = mydriver_jp_regdom.n_reg_rules;
@@ -178,17 +177,11 @@ Then in some part of your code after you rd = kzalloc(size_of_regd, GFP_KERNEL); if (!rd) - return -ENOMEM; + return -ENOMEM; memcpy(rd, &mydriver_jp_regdom, sizeof(struct ieee80211_regdomain)); - for (i=0; i < num_rules; i++) { + for (i=0; i < num_rules; i++) memcpy(&rd->reg_rules[i], &mydriver_jp_regdom.reg_rules[i], sizeof(struct ieee80211_reg_rule)); - } - r = regulatory_hint(hw->wiphy, NULL, rd); - if (r) { - kfree(rd); - return r; - } - + return regulatory_hint(hw->wiphy, NULL, rd);
Johannes Berg
maintainerPATCH 2/4 wireless: remove struct regdom hinting
In reply to Johannes BergThe code needs to be split out and cleaned up, so as a first step remove the capability, to add it back in a subsequent patch as a separate function. Also remove the publically facing return value of the function and the wiphy argument. A number of internal functions go from being generic helpers to just being used for alpha2 setting.
--- Documentation/networking/regulatory.txt | 11 +++-- drivers/net/wireless/zd1211rw/zd_mac.c | 2 - include/net/wireless.h | 23 ++--------- net/wireless/nl80211.c | 2 - net/wireless/reg.c | 63 ++++++++------------------------ net/wireless/reg.h | 23 +++-------- 6 files changed, 36 insertions(+), 88 deletions(-)
include/net/wireless.h +4 -19
@@ -342,34 +342,19 @@ ieee80211_get_channel(struct wiphy *wiph/** * regulatory_hint - driver hint to the wireless core a regulatory domain -* @wiphy: the driver's very own &struct wiphy +* @wiphy: the wireless device giving the hint (used only for reporting +* conflicts) * @alpha2: the ISO/IEC 3166 alpha2 the driver claims its regulatory domain * should be in. If @rd is set this should be NULL. Note that if you * set this to NULL you should still set rd->alpha2 to some accepted * alpha2. -* @rd: a complete regulatory domain provided by the driver. If passed -* the driver does not need to worry about freeing it. * * Wireless drivers can use this function to hint to the wireless core * what it believes should be the current regulatory domain by * giving it an ISO/IEC 3166 alpha2 country code it knows its regulatory * domain should be in or by providing a completely build regulatory domain. * If the driver provides an ISO/IEC 3166 alpha2 userspace will be queried -* for a regulatory domain structure for the respective country. If -* a regulatory domain is build and passed you should set the alpha2 -* if possible, otherwise set it to the special value of "99" which tells -* the wireless core it is unknown. -* -* Returns -EALREADY if *a regulatory domain* has already been set. Note that -* this could be by another driver. It is safe for drivers to continue if -* -EALREADY is returned, if drivers are not capable of world roaming they -* should not register more channels than they support. Right now we only -* support listening to the first driver hint. If the driver is capable -* of world roaming but wants to respect its own EEPROM mappings for -* specific regulatory domains it should register the @reg_notifier callback -* on the &struct wiphy. Returns 0 if the hint went through fine or through an -* intersection operation. Otherwise a standard error code is returned. +* for a regulatory domain structure for the respective country. */ -extern int regulatory_hint (struct wiphy *wiphy, -const char *alpha2,struct ieee80211_regdomain *rd); +extern void regulatory_hint (struct wiphy *wiphy,const char *alpha2);#endif /* __NET_WIRELESS_H */
drivers/net/wireless/zd1211rw/zd_mac.c +1 -1
@@ -171,7 +171,7 @@ int zd_mac_init_hw(struct ieee80211_hw * r =zd_reg2alpha2 (mac->regdomain, alpha2);if (!r) -regulatory_hint (hw->wiphy, alpha2,NULL ); +regulatory_hint (hw->wiphy, alpha2); r =0 ; disable_int:
net/wireless/nl80211.c +1 -1
@@ -1695,7 +1695,7 @@ static int nl80211_req_set_reg(struct skreturn -EINVAL ;#endif mutex_lock (&cfg80211_drv_mutex); - r =__regulatory_hint (NULL ,REGDOM_SET_BY_USER , data,NULL ); + r =__regulatory_hint (NULL ,REGDOM_SET_BY_USER , data);mutex_unlock (&cfg80211_drv_mutex);return r; }
net/wireless/reg.c +16 -47
128 lines not on this page · raw message
net/wireless/reg.h +7 -16
@@ -11,30 +11,21 @@ int set_regdom(const struct ieee80211_re/** * __regulatory_hint - hint to the wireless core a regulatory domain -* @wiphy: if a driver is providing the hint this is the driver's very -* own &struct wiphy +* @wiphy: if the hint comes from country information from an AP, this +* is required to be set to the wiphy that received the information * @alpha2: the ISO/IEC 3166 alpha2 being claimed the regulatory domain -* should be in. If @rd is set this should be NULL -* @rd: a complete regulatory domain, if passed the caller need not worry -* about freeing it +* should be in. * * The Wireless subsystem can use this function to hint to the wireless core * what it believes should be the current regulatory domain by * giving it an ISO/IEC 3166 alpha2 country code it knows its regulatory -* domain should be in or by providing a completely build regulatory domain. +* domain should be in. * -* Returns -EALREADY if *a regulatory domain* has already been set. Note that -* this could be by another driver. It is safe for drivers to continue if -* -EALREADY is returned, if drivers are not capable of world roaming they -* should not register more channels than they support. Right now we only -* support listening to the first driver hint. If the driver is capable -* of world roaming but wants to respect its own EEPROM mappings for -* specific regulatory domains it should register the @reg_notifier callback -* on the &struct wiphy. Returns 0 if the hint went through fine or through an -* intersection operation. Otherwise a standard error code is returned. +* Returns zero if all went fine, %-EALREADY if a regulatory domain had +* already been set or other standard error codes. * */ extern int __regulatory_hint (struct wiphy *wiphy,enum reg_set_by set_by, -const char *alpha2,struct ieee80211_regdomain *rd); +const char *alpha2);#endif /* __NET_WIRELESS_REG_H */
Documentation/networking/regulatory.txt +7 -4
@@ -131,11 +131,13 @@ are expected to do this during initializ r = zd_reg2alpha2(mac->regdomain, alpha2); if (!r) - regulatory_hint(hw->wiphy, alpha2, NULL); + regulatory_hint(hw->wiphy, alpha2); Example code - drivers providing a built in regulatory domain: -------------------------------------------------------------- +[NOTE: This API is not currently available, it can be added when required] + If you have regulatory information you can obtain from your driver and you *need* to use this we let you build a regulatory domain structure and pass it to the wireless core. To do this you should
@@ -182,6 +184,7 @@ Then in some part of your code after you memcpy(rd, &mydriver_jp_regdom, sizeof(struct ieee80211_regdomain)); for (i=0; i < num_rules; i++) - memcpy(&rd->reg_rules[i], &mydriver_jp_regdom.reg_rules[i], - sizeof(struct ieee80211_reg_rule)); - return regulatory_hint(hw->wiphy, NULL, rd); + memcpy(&rd->reg_rules[i], + &mydriver_jp_regdom.reg_rules[i], + sizeof(struct ieee80211_reg_rule)); + regulatory_struct_hint(rd);
Johannes Berg
maintainerPATCH 3/4 wireless: clean up regulatory ignore_request function
In reply to Johannes BergThis function has a few WARNs that may eventually trigger when an AP sends rogue beacons, those must be removed. Some of the comments in the function are also inappropriate as this function is concerned with the global hint, not a per- wiphy thing (which a multidomain flag on a wiphy would imply).
I'm convinced that we don't need to do anything to implement multi-domain capability as 802.11-2007 specifies it because it makes only two things mandatory:
* starting of BSS/IBSS must have country information (this can easily be done with a mac80211 patch)
* a STA must adopt the country information (we already have the framework for this)
But we don't have anything implemented anyway for now.
--- net/wireless/reg.c | 67 +++++++++++++++++++++-------------------------------- 1 file changed, 27 insertions(+), 40 deletions(-)
net/wireless/reg.c +27 -40
@@ -311,24 +311,25 @@ static int ignore_request(struct wiphy *case REGDOM_SET_BY_INIT :return -EINVAL ;case REGDOM_SET_BY_CORE : -/* Always respect new wireless core hints, should only -* come in for updating the world regulatory domain at init -* anyway */ +/* +* Always respect new wireless core hints, should only happen +* when updating the world regulatory domain at init. +*/ return 0 ;case REGDOM_SET_BY_COUNTRY_IE : +if (unlikely (!is_an_alpha2 (alpha2))) +return -EINVAL ;if (last_request->initiator ==REGDOM_SET_BY_COUNTRY_IE ) {if (last_request->wiphy != wiphy) { -/* Two cards with two APs claiming different -* different Country IE alpha2s! -* You're special!! */ -if (!alpha2_equal (last_request->alpha2, - cfg80211_regdomain->alpha2)) { -/* XXX: Deal with conflict, consider -* building a new one out of the -* intersection */ -WARN_ON (1 ); +/* +* Two cards with two APs claiming different +* different Country IE alpha2s. We could +* intersect them, but that seems unlikely +* to be correct. Reject second one for now. +*/ +if (!alpha2_equal (alpha2, + cfg80211_regdomain->alpha2))return -EOPNOTSUPP ; - }return -EALREADY ; }/* Two consecutive Country IE hints on the same wiphy */
@@ -336,42 +337,28 @@ static int ignore_request(struct wiphy *return 0 ;return -EALREADY ; } -if (WARN_ON (!is_alpha2_set (alpha2) || !is_an_alpha2 (alpha2)), -"Invalid Country IE regulatory hint passed " -"to the wireless core\n" ) -return -EINVAL ; -/* We ignore Country IE hints for now, as we haven't yet -* added the dot11MultiDomainCapabilityEnabled flag -* for wiphys */ -return 1 ; +/* +* Ignore Country IE hints for now, need to think about +* what we need to do to support multi-domain operation. +*/ +return -EOPNOTSUPP ;case REGDOM_SET_BY_DRIVER : -BUG_ON (!wiphy);if (last_request->initiator ==REGDOM_SET_BY_DRIVER )return -EALREADY ; -if (last_request->initiator ==REGDOM_SET_BY_CORE ) -return 0 ; -/* XXX: Handle intersection, and add the -* dot11MultiDomainCapabilityEnabled flag to wiphy. For now -* we assume the driver has this set to false, following the -* 802.11d dot11MultiDomainCapabilityEnabled documentation */ -if (last_request->initiator ==REGDOM_SET_BY_COUNTRY_IE ) -return 0 ;return 0 ;case REGDOM_SET_BY_USER : -if (last_request->initiator ==REGDOM_SET_BY_USER || - last_request->initiator ==REGDOM_SET_BY_CORE ) -return 0 ; -/* Drivers can use their wiphy's reg_notifier() -* to override any information */ -if (last_request->initiator ==REGDOM_SET_BY_DRIVER ) -return 0 ; -/* XXX: Handle intersection */ +/* +* If the user wants to override the AP's hint, we may +* need to follow both and use the intersection. For now, +* reject any such attempt (but we don't support country +* IEs right now anyway.) +*/ if (last_request->initiator ==REGDOM_SET_BY_COUNTRY_IE )return -EOPNOTSUPP ;return 0 ; -default : -return -EINVAL ; } + +return -EINVAL ; }/* Used by nl80211 before kmalloc'ing our regulatory domain */
Johannes Berg
maintainerPATCH 4/4 wireless regulatory: move ignore_request
In reply to Johannes BergThis function is only used once, move it closer to its caller.
--- net/wireless/reg.c | 126 ++++++++++++++++++++++++++--------------------------- 1 file changed, 63 insertions(+), 63 deletions(-)
net/wireless/reg.c +63 -63
@@ -298,69 +298,6 @@ static int call_crda(const char *alpha2)return kobject_uevent_env (®_pdev->dev.kobj,KOBJ_CHANGE , envp); } -/* This has the logic which determines when a new request -* should be ignored. */ -static int ignore_request (struct wiphy *wiphy,enum reg_set_by set_by, -const char *alpha2) -{ -/* All initial requests are respected */ -if (!last_request) -return 0 ; - -switch (set_by) { -case REGDOM_SET_BY_INIT : -return -EINVAL ; -case REGDOM_SET_BY_CORE : -/* -* Always respect new wireless core hints, should only happen -* when updating the world regulatory domain at init. -*/ -return 0 ; -case REGDOM_SET_BY_COUNTRY_IE : -if (unlikely (!is_an_alpha2 (alpha2))) -return -EINVAL ; -if (last_request->initiator ==REGDOM_SET_BY_COUNTRY_IE ) { -if (last_request->wiphy != wiphy) { -/* -* Two cards with two APs claiming different -* different Country IE alpha2s. We could -* intersect them, but that seems unlikely -* to be correct. Reject second one for now. -*/ -if (!alpha2_equal (alpha2, - cfg80211_regdomain->alpha2)) -return -EOPNOTSUPP ; -return -EALREADY ; - } -/* Two consecutive Country IE hints on the same wiphy */ -if (!alpha2_equal (cfg80211_regdomain->alpha2, alpha2)) -return 0 ; -return -EALREADY ; - } -/* -* Ignore Country IE hints for now, need to think about -* what we need to do to support multi-domain operation. -*/ -return -EOPNOTSUPP ; -case REGDOM_SET_BY_DRIVER : -if (last_request->initiator ==REGDOM_SET_BY_DRIVER ) -return -EALREADY ; -return 0 ; -case REGDOM_SET_BY_USER : -/* -* If the user wants to override the AP's hint, we may -* need to follow both and use the intersection. For now, -* reject any such attempt (but we don't support country -* IEs right now anyway.) -*/ -if (last_request->initiator ==REGDOM_SET_BY_COUNTRY_IE ) -return -EOPNOTSUPP ; -return 0 ; - } - -return -EINVAL ; -} -/* Used by nl80211 before kmalloc'ing our regulatory domain */ bool reg_is_valid_request (const char *alpha2) {
@@ -531,6 +468,69 @@ void wiphy_update_regulatory(struct wiph } } +/* This has the logic which determines when a new request +* should be ignored. */ +static int ignore_request (struct wiphy *wiphy,enum reg_set_by set_by, +const char *alpha2) +{ +/* All initial requests are respected */ +if (!last_request) +return 0 ; + +switch (set_by) { +case REGDOM_SET_BY_INIT : +return -EINVAL ; +case REGDOM_SET_BY_CORE : +/* +* Always respect new wireless core hints, should only happen +* when updating the world regulatory domain at init. +*/ +return 0 ; +case REGDOM_SET_BY_COUNTRY_IE : +if (unlikely (!is_an_alpha2 (alpha2))) +return -EINVAL ; +if (last_request->initiator ==REGDOM_SET_BY_COUNTRY_IE ) { +if (last_request->wiphy != wiphy) { +/* +* Two cards with two APs claiming different +* different Country IE alpha2s. We could +* intersect them, but that seems unlikely +* to be correct. Reject second one for now. +*/ +if (!alpha2_equal (alpha2, + cfg80211_regdomain->alpha2)) +return -EOPNOTSUPP ; +return -EALREADY ; + } +/* Two consecutive Country IE hints on the same wiphy */ +if (!alpha2_equal (cfg80211_regdomain->alpha2, alpha2)) +return 0 ; +return -EALREADY ; + } +/* +* Ignore Country IE hints for now, need to think about +* what we need to do to support multi-domain operation. +*/ +return -EOPNOTSUPP ; +case REGDOM_SET_BY_DRIVER : +if (last_request->initiator ==REGDOM_SET_BY_DRIVER ) +return -EALREADY ; +return 0 ; +case REGDOM_SET_BY_USER : +/* +* If the user wants to override the AP's hint, we may +* need to follow both and use the intersection. For now, +* reject any such attempt (but we don't support country +* IEs right now anyway.) +*/ +if (last_request->initiator ==REGDOM_SET_BY_COUNTRY_IE ) +return -EOPNOTSUPP ; +return 0 ; + } + +return -EINVAL ; +} +/* Caller must hold &cfg80211_drv_mutex */ int __regulatory_hint (struct wiphy *wiphy,enum reg_set_by set_by,const char *alpha2)
Quoted 2 lines · Johannes Berg
Here's my set of updates, it removes the struct hint entirely as we've come up with a new and better way.
These all look very sexy now, thanks.
Luis