brcmfmac: follow user-space regulatory domain selection
authorArend van Spriel <arend@broadcom.com>
Sun, 21 Dec 2014 11:43:51 +0000 (12:43 +0100)
committerKalle Valo <kvalo@codeaurora.org>
Tue, 6 Jan 2015 18:29:42 +0000 (20:29 +0200)
When user-space uses a valid ISO-3166-1 country code for its
regulatory domain selection, the driver will try to configure
the firmware to use the same.

Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
Signed-off-by: Arend van Spriel <arend@broadcom.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h

index 11725518d19ac7d89e20eefe07da03f6fbf9ecfa..2471dd58f17f757833c52d6d0195f50f2100df89 100644 (file)
@@ -3982,7 +3982,6 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
        brcmf_dbg(TRACE, "ssid=%s(%zu), auth_type=%d, inactivity_timeout=%d\n",
                  settings->ssid, settings->ssid_len, settings->auth_type,
                  settings->inactivity_timeout);
-
        dev_role = ifp->vif->wdev.iftype;
        mbss = ifp->vif->mbss;
 
@@ -5921,6 +5920,29 @@ int brcmf_cfg80211_wait_vif_event_timeout(struct brcmf_cfg80211_info *cfg,
                                  vif_event_equals(event, action), timeout);
 }
 
+static void brcmf_cfg80211_reg_notifier(struct wiphy *wiphy,
+                                       struct regulatory_request *req)
+{
+       struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
+       struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
+       struct brcmf_fil_country_le ccreq;
+       int i;
+
+       brcmf_dbg(TRACE, "enter: initiator=%d, alpha=%c%c\n", req->initiator,
+                 req->alpha2[0], req->alpha2[1]);
+
+       /* ignore non-ISO3166 country codes */
+       for (i = 0; i < sizeof(req->alpha2); i++)
+               if (req->alpha2[i] < 'A' || req->alpha2[i] > 'Z') {
+                       brcmf_err("not a ISO3166 code\n");
+                       return;
+               }
+       memset(&ccreq, 0, sizeof(ccreq));
+       ccreq.rev = cpu_to_le32(-1);
+       memcpy(ccreq.ccode, req->alpha2, sizeof(req->alpha2));
+       brcmf_fil_iovar_data_set(ifp, "country", &ccreq, sizeof(ccreq));
+}
+
 static void brcmf_free_wiphy(struct wiphy *wiphy)
 {
        kfree(wiphy->iface_combinations);
@@ -5997,6 +6019,7 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
                goto priv_out;
 
        brcmf_dbg(INFO, "Registering custom regulatory\n");
+       wiphy->reg_notifier = brcmf_cfg80211_reg_notifier;
        wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
        wiphy_apply_custom_regulatory(wiphy, &brcmf_regdom);
 
index 50891c02c4c162640acca7dc44ed56aec27b7385..619669bbdb83b602532b4c0bc8abf73c0588fd0f 100644 (file)
 #define BRCMF_WOWL_MAXPATTERNS         8
 #define BRCMF_WOWL_MAXPATTERNSIZE      128
 
+#define BRCMF_COUNTRY_BUF_SZ           4
 
 /* join preference types for join_pref iovar */
 enum brcmf_join_pref_types {
@@ -525,4 +526,17 @@ struct brcmf_mbss_ssid_le {
        unsigned char SSID[32];
 };
 
+/**
+ * struct brcmf_fil_country_le - country configuration structure.
+ *
+ * @country_abbrev: null-terminated country code used in the country IE.
+ * @rev: revision specifier for ccode. on set, -1 indicates unspecified.
+ * @ccode: null-terminated built-in country code.
+ */
+struct brcmf_fil_country_le {
+       char country_abbrev[BRCMF_COUNTRY_BUF_SZ];
+       __le32 rev;
+       char ccode[BRCMF_COUNTRY_BUF_SZ];
+};
+
 #endif /* FWIL_TYPES_H_ */