brcmfmac: Correct mcs index report
[deliverable/linux.git] / drivers / net / wireless / brcm80211 / brcmfmac / wl_cfg80211.c
index d7718a5fa2f0323c46458300f417b7dbd6e46b8e..00bd1e16c3ce7155e0f575e2682a29714b8df50b 100644 (file)
@@ -18,6 +18,7 @@
 
 #include <linux/kernel.h>
 #include <linux/etherdevice.h>
+#include <linux/module.h>
 #include <net/cfg80211.h>
 #include <net/netlink.h>
 
@@ -251,6 +252,10 @@ struct parsed_vndr_ies {
        struct parsed_vndr_ie_info ie_info[VNDR_IE_PARSE_LIMIT];
 };
 
+static int brcmf_roamoff;
+module_param_named(roamoff, brcmf_roamoff, int, S_IRUSR);
+MODULE_PARM_DESC(roamoff, "do not use internal roaming engine");
+
 /* Quarter dBm units to mW
  * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
  * Table is offset so the last entry is largest mW value that fits in
@@ -351,13 +356,11 @@ u16 channel_to_chanspec(struct brcmu_d11inf *d11inf,
  * triples, returning a pointer to the substring whose first element
  * matches tag
  */
-struct brcmf_tlv *brcmf_parse_tlvs(void *buf, int buflen, uint key)
+const struct brcmf_tlv *
+brcmf_parse_tlvs(const void *buf, int buflen, uint key)
 {
-       struct brcmf_tlv *elt;
-       int totlen;
-
-       elt = (struct brcmf_tlv *)buf;
-       totlen = buflen;
+       const struct brcmf_tlv *elt = buf;
+       int totlen = buflen;
 
        /* find tagged parameter */
        while (totlen >= TLV_HDR_LEN) {
@@ -378,8 +381,8 @@ struct brcmf_tlv *brcmf_parse_tlvs(void *buf, int buflen, uint key)
  * not update the tlvs buffer pointer/length.
  */
 static bool
-brcmf_tlv_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len,
-                u8 *oui, u32 oui_len, u8 type)
+brcmf_tlv_has_ie(const u8 *ie, const u8 **tlvs, u32 *tlvs_len,
+                const u8 *oui, u32 oui_len, u8 type)
 {
        /* If the contents match the OUI and the type */
        if (ie[TLV_LEN_OFF] >= oui_len + 1 &&
@@ -401,12 +404,12 @@ brcmf_tlv_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len,
 }
 
 static struct brcmf_vs_tlv *
-brcmf_find_wpaie(u8 *parse, u32 len)
+brcmf_find_wpaie(const u8 *parse, u32 len)
 {
-       struct brcmf_tlv *ie;
+       const struct brcmf_tlv *ie;
 
        while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) {
-               if (brcmf_tlv_has_ie((u8 *)ie, &parse, &len,
+               if (brcmf_tlv_has_ie((const u8 *)ie, &parse, &len,
                                     WPA_OUI, TLV_OUI_LEN, WPA_OUI_TYPE))
                        return (struct brcmf_vs_tlv *)ie;
        }
@@ -414,9 +417,9 @@ brcmf_find_wpaie(u8 *parse, u32 len)
 }
 
 static struct brcmf_vs_tlv *
-brcmf_find_wpsie(u8 *parse, u32 len)
+brcmf_find_wpsie(const u8 *parse, u32 len)
 {
-       struct brcmf_tlv *ie;
+       const struct brcmf_tlv *ie;
 
        while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) {
                if (brcmf_tlv_has_ie((u8 *)ie, &parse, &len,
@@ -1562,9 +1565,9 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
        struct ieee80211_channel *chan = sme->channel;
        struct brcmf_join_params join_params;
        size_t join_params_size;
-       struct brcmf_tlv *rsn_ie;
-       struct brcmf_vs_tlv *wpa_ie;
-       void *ie;
+       const struct brcmf_tlv *rsn_ie;
+       const struct brcmf_vs_tlv *wpa_ie;
+       const void *ie;
        u32 ie_len;
        struct brcmf_ext_join_params_le *ext_join_params;
        u16 chanspec;
@@ -1591,7 +1594,8 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
                        ie_len = wpa_ie->len + TLV_HDR_LEN;
                } else {
                        /* find the RSN_IE */
-                       rsn_ie = brcmf_parse_tlvs((u8 *)sme->ie, sme->ie_len,
+                       rsn_ie = brcmf_parse_tlvs((const u8 *)sme->ie,
+                                                 sme->ie_len,
                                                  WLAN_EID_RSN);
                        if (rsn_ie) {
                                ie = rsn_ie;
@@ -1981,7 +1985,9 @@ brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
        if (!check_vif_up(ifp->vif))
                return -EIO;
 
-       if (mac_addr) {
+       if (mac_addr &&
+               (params->cipher != WLAN_CIPHER_SUITE_WEP40) &&
+               (params->cipher != WLAN_CIPHER_SUITE_WEP104)) {
                brcmf_dbg(TRACE, "Exit");
                return brcmf_add_keyext(wiphy, ndev, key_idx, mac_addr, params);
        }
@@ -2164,6 +2170,8 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
        s32 err = 0;
        u8 *bssid = profile->bssid;
        struct brcmf_sta_info_le sta_info_le;
+       u32 beacon_period;
+       u32 dtim_period;
 
        brcmf_dbg(TRACE, "Enter, MAC %pM\n", mac);
        if (!check_vif_up(ifp->vif))
@@ -2218,6 +2226,30 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
                                sinfo->signal = rssi;
                                brcmf_dbg(CONN, "RSSI %d dBm\n", rssi);
                        }
+                       err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_BCNPRD,
+                                                   &beacon_period);
+                       if (err) {
+                               brcmf_err("Could not get beacon period (%d)\n",
+                                         err);
+                               goto done;
+                       } else {
+                               sinfo->bss_param.beacon_interval =
+                                       beacon_period;
+                               brcmf_dbg(CONN, "Beacon peroid %d\n",
+                                         beacon_period);
+                       }
+                       err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_DTIMPRD,
+                                                   &dtim_period);
+                       if (err) {
+                               brcmf_err("Could not get DTIM period (%d)\n",
+                                         err);
+                               goto done;
+                       } else {
+                               sinfo->bss_param.dtim_period = dtim_period;
+                               brcmf_dbg(CONN, "DTIM peroid %d\n",
+                                         dtim_period);
+                       }
+                       sinfo->filled |= STATION_INFO_BSS_PARAM;
                }
        } else
                err = -EPERM;
@@ -2455,7 +2487,7 @@ static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg,
        struct brcmf_cfg80211_profile *profile = ndev_to_prof(ifp->ndev);
        struct brcmf_bss_info_le *bi;
        struct brcmf_ssid *ssid;
-       struct brcmf_tlv *tim;
+       const struct brcmf_tlv *tim;
        u16 beacon_interval;
        u8 dtim_period;
        size_t ie_len;
@@ -3220,8 +3252,9 @@ static bool brcmf_valid_wpa_oui(u8 *oui, bool is_rsn_ie)
 }
 
 static s32
-brcmf_configure_wpaie(struct net_device *ndev, struct brcmf_vs_tlv *wpa_ie,
-                    bool is_rsn_ie)
+brcmf_configure_wpaie(struct net_device *ndev,
+                     const struct brcmf_vs_tlv *wpa_ie,
+                     bool is_rsn_ie)
 {
        struct brcmf_if *ifp = netdev_priv(ndev);
        u32 auth = 0; /* d11 open authentication */
@@ -3707,11 +3740,11 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
        s32 ie_offset;
        struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
        struct brcmf_if *ifp = netdev_priv(ndev);
-       struct brcmf_tlv *ssid_ie;
+       const struct brcmf_tlv *ssid_ie;
        struct brcmf_ssid_le ssid_le;
        s32 err = -EPERM;
-       struct brcmf_tlv *rsn_ie;
-       struct brcmf_vs_tlv *wpa_ie;
+       const struct brcmf_tlv *rsn_ie;
+       const struct brcmf_vs_tlv *wpa_ie;
        struct brcmf_join_params join_params;
        enum nl80211_iftype dev_role;
        struct brcmf_fil_bss_enable_le bss_enable;
@@ -4416,7 +4449,9 @@ static bool brcmf_is_linkdown(const struct brcmf_event_msg *e)
        u32 event = e->event_code;
        u16 flags = e->flags;
 
-       if (event == BRCMF_E_LINK && (!(flags & BRCMF_EVENT_MSG_LINK))) {
+       if ((event == BRCMF_E_DEAUTH) || (event == BRCMF_E_DEAUTH_IND) ||
+           (event == BRCMF_E_DISASSOC_IND) ||
+           ((event == BRCMF_E_LINK) && (!(flags & BRCMF_EVENT_MSG_LINK)))) {
                brcmf_dbg(CONN, "Processing link down\n");
                return true;
        }
@@ -4658,16 +4693,19 @@ brcmf_notify_connect_status(struct brcmf_if *ifp,
        struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
        struct net_device *ndev = ifp->ndev;
        struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
+       struct ieee80211_channel *chan;
        s32 err = 0;
+       u16 reason;
 
        if (ifp->vif->mode == WL_MODE_AP) {
                err = brcmf_notify_connect_status_ap(cfg, ndev, e, data);
        } else if (brcmf_is_linkup(e)) {
                brcmf_dbg(CONN, "Linkup\n");
                if (brcmf_is_ibssmode(ifp->vif)) {
+                       chan = ieee80211_get_channel(cfg->wiphy, cfg->channel);
                        memcpy(profile->bssid, e->addr, ETH_ALEN);
                        wl_inform_ibss(cfg, ndev, e->addr);
-                       cfg80211_ibss_joined(ndev, e->addr, GFP_KERNEL);
+                       cfg80211_ibss_joined(ndev, e->addr, chan, GFP_KERNEL);
                        clear_bit(BRCMF_VIF_STATUS_CONNECTING,
                                  &ifp->vif->sme_state);
                        set_bit(BRCMF_VIF_STATUS_CONNECTED,
@@ -4679,9 +4717,15 @@ brcmf_notify_connect_status(struct brcmf_if *ifp,
                if (!brcmf_is_ibssmode(ifp->vif)) {
                        brcmf_bss_connect_done(cfg, ndev, e, false);
                        if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTED,
-                                              &ifp->vif->sme_state))
-                               cfg80211_disconnected(ndev, 0, NULL, 0,
+                                              &ifp->vif->sme_state)) {
+                               reason = 0;
+                               if (((e->event_code == BRCMF_E_DEAUTH_IND) ||
+                                    (e->event_code == BRCMF_E_DISASSOC_IND)) &&
+                                   (e->reason != WLAN_REASON_UNSPECIFIED))
+                                       reason = e->reason;
+                               cfg80211_disconnected(ndev, reason, NULL, 0,
                                                      GFP_KERNEL);
+                       }
                }
                brcmf_link_down(ifp->vif);
                brcmf_init_prof(ndev_to_prof(ndev));
@@ -4875,11 +4919,8 @@ static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg)
 
        cfg->scan_request = NULL;
        cfg->pwr_save = true;
-       cfg->roam_on = true;    /* roam on & off switch.
-                                we enable roam per default */
-       cfg->active_scan = true;        /* we do active scan for
-                                specific scan per default */
-       cfg->dongle_up = false; /* dongle is not up yet */
+       cfg->active_scan = true;        /* we do active scan per default */
+       cfg->dongle_up = false;         /* dongle is not up yet */
        err = brcmf_init_priv_mem(cfg);
        if (err)
                return err;
@@ -4999,7 +5040,7 @@ void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
 }
 
 static s32
-brcmf_dongle_roam(struct brcmf_if *ifp, u32 roamvar, u32 bcn_timeout)
+brcmf_dongle_roam(struct brcmf_if *ifp, u32 bcn_timeout)
 {
        s32 err = 0;
        __le32 roamtrigger[2];
@@ -5009,7 +5050,7 @@ brcmf_dongle_roam(struct brcmf_if *ifp, u32 roamvar, u32 bcn_timeout)
         * Setup timeout if Beacons are lost and roam is
         * off to report link down
         */
-       if (roamvar) {
+       if (brcmf_roamoff) {
                err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout", bcn_timeout);
                if (err) {
                        brcmf_err("bcn_timeout error (%d)\n", err);
@@ -5021,8 +5062,9 @@ brcmf_dongle_roam(struct brcmf_if *ifp, u32 roamvar, u32 bcn_timeout)
         * Enable/Disable built-in roaming to allow supplicant
         * to take care of roaming
         */
-       brcmf_dbg(INFO, "Internal Roaming = %s\n", roamvar ? "Off" : "On");
-       err = brcmf_fil_iovar_int_set(ifp, "roam_off", roamvar);
+       brcmf_dbg(INFO, "Internal Roaming = %s\n",
+                 brcmf_roamoff ? "Off" : "On");
+       err = brcmf_fil_iovar_int_set(ifp, "roam_off", !!(brcmf_roamoff));
        if (err) {
                brcmf_err("roam_off error (%d)\n", err);
                goto dongle_rom_out;
@@ -5164,9 +5206,6 @@ static s32 brcmf_construct_reginfo(struct brcmf_cfg80211_info *cfg,
                                ieee80211_channel_to_frequency(ch.chnum, band);
                        band_chan_arr[index].hw_value = ch.chnum;
 
-                       brcmf_err("channel %d: f=%d bw=%d sb=%d\n",
-                                 ch.chnum, band_chan_arr[index].center_freq,
-                                 ch.bw, ch.sb);
                        if (ch.bw == BRCMU_CHAN_BW_40) {
                                /* assuming the order is HT20, HT40 Upper,
                                 * HT40 lower from chanspecs
@@ -5267,6 +5306,8 @@ static s32 brcmf_update_wiphybands(struct brcmf_cfg80211_info *cfg)
        u32 band_list[3];
        u32 nmode;
        u32 bw_cap[2] = { 0, 0 };
+       u32 rxchain;
+       u32 nchain;
        s8 phy;
        s32 err;
        u32 nband;
@@ -5303,6 +5344,16 @@ static s32 brcmf_update_wiphybands(struct brcmf_cfg80211_info *cfg)
        brcmf_dbg(INFO, "nmode=%d, bw_cap=(%d, %d)\n", nmode,
                  bw_cap[IEEE80211_BAND_2GHZ], bw_cap[IEEE80211_BAND_5GHZ]);
 
+       err = brcmf_fil_iovar_int_get(ifp, "rxchain", &rxchain);
+       if (err) {
+               brcmf_err("rxchain error (%d)\n", err);
+               nchain = 1;
+       } else {
+               for (nchain = 0; rxchain; nchain++)
+                       rxchain = rxchain & (rxchain - 1);
+       }
+       brcmf_dbg(INFO, "nchain=%d\n", nchain);
+
        err = brcmf_construct_reginfo(cfg, bw_cap);
        if (err) {
                brcmf_err("brcmf_construct_reginfo failed (%d)\n", err);
@@ -5331,10 +5382,7 @@ static s32 brcmf_update_wiphybands(struct brcmf_cfg80211_info *cfg)
                band->ht_cap.ht_supported = true;
                band->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
                band->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16;
-               /* An HT shall support all EQM rates for one spatial
-                * stream
-                */
-               band->ht_cap.mcs.rx_mask[0] = 0xff;
+               memset(band->ht_cap.mcs.rx_mask, 0xff, nchain);
                band->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
                bands[band->band] = band;
        }
@@ -5381,7 +5429,7 @@ static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
        brcmf_dbg(INFO, "power save set to %s\n",
                  (power_mode ? "enabled" : "disabled"));
 
-       err = brcmf_dongle_roam(ifp, (cfg->roam_on ? 0 : 1), WL_BEACON_TIMEOUT);
+       err = brcmf_dongle_roam(ifp, WL_BEACON_TIMEOUT);
        if (err)
                goto default_conf_out;
        err = brcmf_cfg80211_change_iface(wdev->wiphy, ndev, wdev->iftype,
This page took 0.043027 seconds and 5 git commands to generate.