Merge remote branch 'wireless-next/master' into ath6kl-next
authorKalle Valo <kvalo@qca.qualcomm.com>
Mon, 5 Mar 2012 17:32:58 +0000 (19:32 +0200)
committerKalle Valo <kvalo@qca.qualcomm.com>
Mon, 5 Mar 2012 17:32:58 +0000 (19:32 +0200)
Conflicts:
drivers/net/wireless/ath/ath6kl/cfg80211.c

1  2 
drivers/net/wireless/ath/ath6kl/cfg80211.c

@@@ -1,6 -1,5 +1,6 @@@
  /*
   * Copyright (c) 2004-2011 Atheros Communications Inc.
 + * Copyright (c) 2011-2012 Qualcomm Atheros, Inc.
   *
   * Permission to use, copy, modify, and/or distribute this software for any
   * purpose with or without fee is hereby granted, provided that the above
@@@ -69,10 -68,6 +69,10 @@@ static struct ieee80211_rate ath6kl_rat
  #define ath6kl_g_rates     (ath6kl_rates + 0)
  #define ath6kl_g_rates_size    12
  
 +#define ath6kl_g_htcap (IEEE80211_HT_CAP_SUP_WIDTH_20_40 | \
 +                      IEEE80211_HT_CAP_SGI_20          | \
 +                      IEEE80211_HT_CAP_SGI_40)
 +
  static struct ieee80211_channel ath6kl_2ghz_channels[] = {
        CHAN2G(1, 2412, 0),
        CHAN2G(2, 2417, 0),
@@@ -117,8 -112,6 +117,8 @@@ static struct ieee80211_supported_band 
        .channels = ath6kl_2ghz_channels,
        .n_bitrates = ath6kl_g_rates_size,
        .bitrates = ath6kl_g_rates,
 +      .ht_cap.cap = ath6kl_g_htcap,
 +      .ht_cap.ht_supported = true,
  };
  
  static struct ieee80211_supported_band ath6kl_band_5ghz = {
        .channels = ath6kl_5ghz_a_channels,
        .n_bitrates = ath6kl_a_rates_size,
        .bitrates = ath6kl_a_rates,
 +      .ht_cap.cap = ath6kl_g_htcap,
 +      .ht_cap.ht_supported = true,
  };
  
  #define CCKM_KRK_CIPHER_SUITE 0x004096ff /* use for KRK */
@@@ -885,14 -876,19 +885,14 @@@ static int ath6kl_cfg80211_scan(struct 
                                                  request->ssids[i].ssid);
        }
  
 -      /*
 -       * FIXME: we should clear the IE in fw if it's not set so just
 -       * remove the check altogether
 -       */
 -      if (request->ie) {
 -              ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
 -                                             WMI_FRAME_PROBE_REQ,
 -                                             request->ie, request->ie_len);
 -              if (ret) {
 -                      ath6kl_err("failed to set Probe Request appie for "
 -                                 "scan");
 -                      return ret;
 -              }
 +      /* this also clears IE in fw if it's not set */
 +      ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
 +                                     WMI_FRAME_PROBE_REQ,
 +                                     request->ie, request->ie_len);
 +      if (ret) {
 +              ath6kl_err("failed to set Probe Request appie for "
 +                         "scan");
 +              return ret;
        }
  
        /*
                 */
                ret = ath6kl_wmi_beginscan_cmd(ar->wmi, vif->fw_vif_idx,
                                                WMI_LONG_SCAN, force_fg_scan,
 -                                              false, 0, 0, n_channels,
 -                                              channels, request->no_cck,
 +                                              false, 0,
 +                                              ATH6KL_FG_SCAN_INTERVAL,
 +                                              n_channels, channels,
 +                                              request->no_cck,
                                                request->rates);
        } else {
                ret = ath6kl_wmi_startscan_cmd(ar->wmi, vif->fw_vif_idx,
                                                WMI_LONG_SCAN, force_fg_scan,
 -                                              false, 0, 0, n_channels,
 -                                              channels);
 +                                              false, 0,
 +                                              ATH6KL_FG_SCAN_INTERVAL,
 +                                              n_channels, channels);
        }
        if (ret)
                ath6kl_err("wmi_startscan_cmd failed\n");
@@@ -1065,7 -1058,7 +1065,7 @@@ static int ath6kl_cfg80211_add_key(stru
  
        if (vif->nw_type == AP_NETWORK && !pairwise &&
            (key_type == TKIP_CRYPT || key_type == AES_CRYPT ||
 -           key_type == WAPI_CRYPT) && params) {
 +           key_type == WAPI_CRYPT)) {
                ar->ap_mode_bkey.valid = true;
                ar->ap_mode_bkey.key_index = key_index;
                ar->ap_mode_bkey.key_type = key_type;
@@@ -2276,20 -2269,53 +2276,54 @@@ static int ath6kl_set_ap_probe_resp_ies
        return ret;
  }
  
- static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
-                           struct beacon_parameters *info, bool add)
+ static int ath6kl_set_ies(struct ath6kl_vif *vif,
+                         struct cfg80211_beacon_data *info)
+ {
+       struct ath6kl *ar = vif->ar;
+       int res;
+       if (info->beacon_ies) {
+               res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
+                                              WMI_FRAME_BEACON,
+                                              info->beacon_ies,
+                                              info->beacon_ies_len);
+               if (res)
+                       return res;
+       }
+       if (info->proberesp_ies) {
+               res = ath6kl_set_ap_probe_resp_ies(vif, info->proberesp_ies,
+                                                  info->proberesp_ies_len);
+               if (res)
+                       return res;
+       }
+       if (info->assocresp_ies) {
+               res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
+                                              WMI_FRAME_ASSOC_RESP,
+                                              info->assocresp_ies,
+                                              info->assocresp_ies_len);
+               if (res)
+                       return res;
+       }
+       return 0;
+ }
+ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,
+                          struct cfg80211_ap_settings *info)
  {
        struct ath6kl *ar = ath6kl_priv(dev);
        struct ath6kl_vif *vif = netdev_priv(dev);
        struct ieee80211_mgmt *mgmt;
 +      bool hidden = false;
        u8 *ies;
        int ies_len;
        struct wmi_connect_cmd p;
        int res;
        int i, ret;
  
-       ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: add=%d\n", __func__, add);
+       ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s:\n", __func__);
  
        if (!ath6kl_cfg80211_ready(vif))
                return -EIO;
        if (vif->next_mode != AP_NETWORK)
                return -EOPNOTSUPP;
  
-       /* this also clears IE in fw if it's not set */
-       res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
-                                      WMI_FRAME_BEACON,
-                                      info->beacon_ies,
-                                      info->beacon_ies_len);
-       if (res)
-               return res;
-       /* this also clears IE in fw if it's not set */
-       res = ath6kl_set_ap_probe_resp_ies(vif, info->proberesp_ies,
-                                          info->proberesp_ies_len);
-       if (res)
-               return res;
-       /* this also clears IE in fw if it's not set */
-       res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
-                                      WMI_FRAME_ASSOC_RESP,
-                                      info->assocresp_ies,
-                                      info->assocresp_ies_len);
-       if (res)
-               return res;
-       if (!add)
-               return 0;
+       res = ath6kl_set_ies(vif, &info->beacon);
  
        ar->ap_mode_bkey.valid = false;
  
         * info->dtim_period
         */
  
-       if (info->head == NULL)
+       if (info->beacon.head == NULL)
                return -EINVAL;
-       mgmt = (struct ieee80211_mgmt *) info->head;
+       mgmt = (struct ieee80211_mgmt *) info->beacon.head;
        ies = mgmt->u.beacon.variable;
-       if (ies > info->head + info->head_len)
+       if (ies > info->beacon.head + info->beacon.head_len)
                return -EINVAL;
-       ies_len = info->head + info->head_len - ies;
+       ies_len = info->beacon.head + info->beacon.head_len - ies;
  
        if (info->ssid == NULL)
                return -EINVAL;
        memcpy(vif->ssid, info->ssid, info->ssid_len);
        vif->ssid_len = info->ssid_len;
        if (info->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE)
 -              return -EOPNOTSUPP; /* TODO */
 +              hidden = true;
 +
 +      res = ath6kl_wmi_ap_hidden_ssid(ar->wmi, vif->fw_vif_idx, hidden);
 +      if (res)
 +              return res;
  
        ret = ath6kl_set_auth_type(vif, info->auth_type);
        if (ret)
        return 0;
  }
  
- static int ath6kl_add_beacon(struct wiphy *wiphy, struct net_device *dev,
-                            struct beacon_parameters *info)
+ static int ath6kl_change_beacon(struct wiphy *wiphy, struct net_device *dev,
+                               struct cfg80211_beacon_data *beacon)
  {
-       return ath6kl_ap_beacon(wiphy, dev, info, true);
- }
+       struct ath6kl_vif *vif = netdev_priv(dev);
  
- static int ath6kl_set_beacon(struct wiphy *wiphy, struct net_device *dev,
-                            struct beacon_parameters *info)
- {
-       return ath6kl_ap_beacon(wiphy, dev, info, false);
+       if (!ath6kl_cfg80211_ready(vif))
+               return -EIO;
+       if (vif->next_mode != AP_NETWORK)
+               return -EOPNOTSUPP;
+       return ath6kl_set_ies(vif, beacon);
  }
  
- static int ath6kl_del_beacon(struct wiphy *wiphy, struct net_device *dev)
+ static int ath6kl_stop_ap(struct wiphy *wiphy, struct net_device *dev)
  {
        struct ath6kl *ar = ath6kl_priv(dev);
        struct ath6kl_vif *vif = netdev_priv(dev);
@@@ -2583,76 -2584,6 +2596,76 @@@ static int ath6kl_send_go_probe_resp(st
        return ret;
  }
  
 +static bool ath6kl_mgmt_powersave_ap(struct ath6kl_vif *vif,
 +                                   u32 id,
 +                                   u32 freq,
 +                                   u32 wait,
 +                                   const u8 *buf,
 +                                   size_t len,
 +                                   bool *more_data,
 +                                   bool no_cck)
 +{
 +      struct ieee80211_mgmt *mgmt;
 +      struct ath6kl_sta *conn;
 +      bool is_psq_empty = false;
 +      struct ath6kl_mgmt_buff *mgmt_buf;
 +      size_t mgmt_buf_size;
 +      struct ath6kl *ar = vif->ar;
 +
 +      mgmt = (struct ieee80211_mgmt *) buf;
 +      if (is_multicast_ether_addr(mgmt->da))
 +              return false;
 +
 +      conn = ath6kl_find_sta(vif, mgmt->da);
 +      if (!conn)
 +              return false;
 +
 +      if (conn->sta_flags & STA_PS_SLEEP) {
 +              if (!(conn->sta_flags & STA_PS_POLLED)) {
 +                      /* Queue the frames if the STA is sleeping */
 +                      mgmt_buf_size = len + sizeof(struct ath6kl_mgmt_buff);
 +                      mgmt_buf = kmalloc(mgmt_buf_size, GFP_KERNEL);
 +                      if (!mgmt_buf)
 +                              return false;
 +
 +                      INIT_LIST_HEAD(&mgmt_buf->list);
 +                      mgmt_buf->id = id;
 +                      mgmt_buf->freq = freq;
 +                      mgmt_buf->wait = wait;
 +                      mgmt_buf->len = len;
 +                      mgmt_buf->no_cck = no_cck;
 +                      memcpy(mgmt_buf->buf, buf, len);
 +                      spin_lock_bh(&conn->psq_lock);
 +                      is_psq_empty = skb_queue_empty(&conn->psq) &&
 +                                      (conn->mgmt_psq_len == 0);
 +                      list_add_tail(&mgmt_buf->list, &conn->mgmt_psq);
 +                      conn->mgmt_psq_len++;
 +                      spin_unlock_bh(&conn->psq_lock);
 +
 +                      /*
 +                       * If this is the first pkt getting queued
 +                       * for this STA, update the PVB for this
 +                       * STA.
 +                       */
 +                      if (is_psq_empty)
 +                              ath6kl_wmi_set_pvb_cmd(ar->wmi, vif->fw_vif_idx,
 +                                                     conn->aid, 1);
 +                      return true;
 +              }
 +
 +              /*
 +               * This tx is because of a PsPoll.
 +               * Determine if MoreData bit has to be set.
 +               */
 +              spin_lock_bh(&conn->psq_lock);
 +              if (!skb_queue_empty(&conn->psq) || (conn->mgmt_psq_len != 0))
 +                      *more_data = true;
 +              spin_unlock_bh(&conn->psq_lock);
 +      }
 +
 +      return false;
 +}
 +
  static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
                          struct ieee80211_channel *chan, bool offchan,
                          enum nl80211_channel_type channel_type,
        struct ath6kl_vif *vif = netdev_priv(dev);
        u32 id;
        const struct ieee80211_mgmt *mgmt;
 +      bool more_data, queued;
  
        mgmt = (const struct ieee80211_mgmt *) buf;
        if (buf + len >= mgmt->u.probe_resp.variable &&
  
        *cookie = id;
  
 -      if (test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX,
 -                  ar->fw_capabilities)) {
 -              /*
 -               * If capable of doing P2P mgmt operations using
 -               * station interface, send additional information like
 -               * supported rates to advertise and xmit rates for
 -               * probe requests
 -               */
 -              return ath6kl_wmi_send_mgmt_cmd(ar->wmi, vif->fw_vif_idx, id,
 -                                              chan->center_freq, wait,
 -                                              buf, len, no_cck);
 -      } else {
 -              return ath6kl_wmi_send_action_cmd(ar->wmi, vif->fw_vif_idx, id,
 -                                                chan->center_freq, wait,
 -                                                buf, len);
 +      /* AP mode Power saving processing */
 +      if (vif->nw_type == AP_NETWORK) {
 +              queued = ath6kl_mgmt_powersave_ap(vif,
 +                                      id, chan->center_freq,
 +                                      wait, buf,
 +                                      len, &more_data, no_cck);
 +              if (queued)
 +                      return 0;
        }
 +
 +      return ath6kl_wmi_send_mgmt_cmd(ar->wmi, vif->fw_vif_idx, id,
 +                                      chan->center_freq, wait,
 +                                      buf, len, no_cck);
  }
  
  static void ath6kl_mgmt_frame_register(struct wiphy *wiphy,
@@@ -2862,9 -2795,9 +2875,9 @@@ static struct cfg80211_ops ath6kl_cfg80
        .resume = __ath6kl_cfg80211_resume,
  #endif
        .set_channel = ath6kl_set_channel,
-       .add_beacon = ath6kl_add_beacon,
-       .set_beacon = ath6kl_set_beacon,
-       .del_beacon = ath6kl_del_beacon,
+       .start_ap = ath6kl_start_ap,
+       .change_beacon = ath6kl_change_beacon,
+       .stop_ap = ath6kl_stop_ap,
        .del_station = ath6kl_del_station,
        .change_station = ath6kl_change_station,
        .remain_on_channel = ath6kl_remain_on_channel,
@@@ -3076,36 -3009,18 +3089,36 @@@ int ath6kl_cfg80211_init(struct ath6kl 
  
        wiphy->max_sched_scan_ssids = 10;
  
 +      ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM |
 +                          WIPHY_FLAG_HAVE_AP_SME |
 +                          WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
 +                          WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
 +
 +      if (test_bit(ATH6KL_FW_CAPABILITY_SCHED_SCAN, ar->fw_capabilities))
 +              ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
 +
 +      ar->wiphy->probe_resp_offload =
 +              NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
 +              NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
 +              NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P |
 +              NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U;
 +
        ret = wiphy_register(wiphy);
        if (ret < 0) {
                ath6kl_err("couldn't register wiphy device\n");
                return ret;
        }
  
 +      ar->wiphy_registered = true;
 +
        return 0;
  }
  
  void ath6kl_cfg80211_cleanup(struct ath6kl *ar)
  {
        wiphy_unregister(ar->wiphy);
 +
 +      ar->wiphy_registered = false;
  }
  
  struct ath6kl *ath6kl_cfg80211_create(void)