ath6kl: Update license header
[deliverable/linux.git] / drivers / net / wireless / ath / ath6kl / cfg80211.c
index 14f180eac4855baaa0073850a99f6a831889f28f..a91f521c5227004ec1ed635716f87fb8026f0891 100644 (file)
@@ -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
@@ -16,6 +17,7 @@
 
 #include <linux/moduleparam.h>
 #include <linux/inetdevice.h>
+#include <linux/export.h>
 
 #include "core.h"
 #include "cfg80211.h"
 #include "hif-ops.h"
 #include "testmode.h"
 
-static unsigned int ath6kl_p2p;
-
-module_param(ath6kl_p2p, uint, 0644);
-
 #define RATETAB_ENT(_rate, _rateid, _flags) {   \
        .bitrate    = (_rate),                  \
        .flags      = (_flags),                 \
@@ -197,7 +195,7 @@ static int ath6kl_set_auth_type(struct ath6kl_vif *vif,
                break;
 
        default:
-               ath6kl_err("%s: 0x%x not spported\n", __func__, auth_type);
+               ath6kl_err("%s: 0x%x not supported\n", __func__, auth_type);
                return -ENOTSUPP;
        }
 
@@ -983,6 +981,7 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
        struct ath6kl *ar = ath6kl_priv(ndev);
        struct ath6kl_vif *vif = netdev_priv(ndev);
        struct ath6kl_key *key = NULL;
+       int seq_len;
        u8 key_usage;
        u8 key_type;
 
@@ -1011,23 +1010,21 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
        else
                key_usage = GROUP_USAGE;
 
-       if (params) {
-               int seq_len = params->seq_len;
-               if (params->cipher == WLAN_CIPHER_SUITE_SMS4 &&
-                   seq_len > ATH6KL_KEY_SEQ_LEN) {
-                       /* Only first half of the WPI PN is configured */
-                       seq_len = ATH6KL_KEY_SEQ_LEN;
-               }
-               if (params->key_len > WLAN_MAX_KEY_LEN ||
-                   seq_len > sizeof(key->seq))
-                       return -EINVAL;
-
-               key->key_len = params->key_len;
-               memcpy(key->key, params->key, key->key_len);
-               key->seq_len = seq_len;
-               memcpy(key->seq, params->seq, key->seq_len);
-               key->cipher = params->cipher;
+       seq_len = params->seq_len;
+       if (params->cipher == WLAN_CIPHER_SUITE_SMS4 &&
+           seq_len > ATH6KL_KEY_SEQ_LEN) {
+               /* Only first half of the WPI PN is configured */
+               seq_len = ATH6KL_KEY_SEQ_LEN;
        }
+       if (params->key_len > WLAN_MAX_KEY_LEN ||
+           seq_len > sizeof(key->seq))
+               return -EINVAL;
+
+       key->key_len = params->key_len;
+       memcpy(key->key, params->key, key->key_len);
+       key->seq_len = seq_len;
+       memcpy(key->seq, params->seq, key->seq_len);
+       key->cipher = params->cipher;
 
        switch (key->cipher) {
        case WLAN_CIPHER_SUITE_WEP40:
@@ -1402,7 +1399,7 @@ static int ath6kl_cfg80211_del_iface(struct wiphy *wiphy,
 
        ath6kl_cleanup_vif(vif, test_bit(WMI_READY, &ar->flag));
 
-       ath6kl_deinit_if_data(vif);
+       ath6kl_cfg80211_vif_cleanup(vif);
 
        return 0;
 }
@@ -1727,32 +1724,14 @@ static int ath6kl_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev)
        return 0;
 }
 
-static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
+static int ath6kl_wow_usr(struct ath6kl *ar, struct ath6kl_vif *vif,
+                         struct cfg80211_wowlan *wow, u32 *filter)
 {
-       struct in_device *in_dev;
-       struct in_ifaddr *ifa;
-       struct ath6kl_vif *vif;
-       int ret, pos, left;
-       u32 filter = 0;
+       int ret, pos;
+       u8 mask[WOW_MASK_SIZE];
        u16 i;
-       u8 mask[WOW_MASK_SIZE], index = 0;
-       __be32 ips[MAX_IP_ADDRS];
 
-       vif = ath6kl_vif_first(ar);
-       if (!vif)
-               return -EIO;
-
-       if (!ath6kl_cfg80211_ready(vif))
-               return -EIO;
-
-       if (!test_bit(CONNECTED, &vif->flags))
-               return -EINVAL;
-
-       /* Clear existing WOW patterns */
-       for (i = 0; i < WOW_MAX_FILTERS_PER_LIST; i++)
-               ath6kl_wmi_del_wow_pattern_cmd(ar->wmi, vif->fw_vif_idx,
-                                              WOW_LIST_ID, i);
-       /* Configure new WOW patterns */
+       /* Configure the patterns that we received from the user. */
        for (i = 0; i < wow->n_patterns; i++) {
 
                /*
@@ -1775,14 +1754,194 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
                 * matched from the first byte of received pkt in the firmware.
                 */
                ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi,
-                                       vif->fw_vif_idx, WOW_LIST_ID,
-                                       wow->patterns[i].pattern_len,
-                                       0 /* pattern offset */,
-                                       wow->patterns[i].pattern, mask);
+                               vif->fw_vif_idx, WOW_LIST_ID,
+                               wow->patterns[i].pattern_len,
+                               0 /* pattern offset */,
+                               wow->patterns[i].pattern, mask);
                if (ret)
                        return ret;
        }
 
+       if (wow->disconnect)
+               *filter |= WOW_FILTER_OPTION_NWK_DISASSOC;
+
+       if (wow->magic_pkt)
+               *filter |= WOW_FILTER_OPTION_MAGIC_PACKET;
+
+       if (wow->gtk_rekey_failure)
+               *filter |= WOW_FILTER_OPTION_GTK_ERROR;
+
+       if (wow->eap_identity_req)
+               *filter |= WOW_FILTER_OPTION_EAP_REQ;
+
+       if (wow->four_way_handshake)
+               *filter |= WOW_FILTER_OPTION_8021X_4WAYHS;
+
+       return 0;
+}
+
+static int ath6kl_wow_ap(struct ath6kl *ar, struct ath6kl_vif *vif)
+{
+       static const u8 unicst_pattern[] = { 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x08 };
+       static const u8 unicst_mask[] = { 0x01, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x7f };
+       u8 unicst_offset = 0;
+       static const u8 arp_pattern[] = { 0x08, 0x06 };
+       static const u8 arp_mask[] = { 0xff, 0xff };
+       u8 arp_offset = 20;
+       static const u8 discvr_pattern[] = { 0xe0, 0x00, 0x00, 0xf8 };
+       static const u8 discvr_mask[] = { 0xf0, 0x00, 0x00, 0xf8 };
+       u8 discvr_offset = 38;
+       static const u8 dhcp_pattern[] = { 0xff, 0xff, 0xff, 0xff,
+               0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x43 /* port 67 */ };
+       static const u8 dhcp_mask[] = { 0xff, 0xff, 0xff, 0xff,
+               0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0xff, 0xff /* port 67 */ };
+       u8 dhcp_offset = 0;
+       int ret;
+
+       /* Setup unicast IP, EAPOL-like and ARP pkt pattern */
+       ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi,
+                       vif->fw_vif_idx, WOW_LIST_ID,
+                       sizeof(unicst_pattern), unicst_offset,
+                       unicst_pattern, unicst_mask);
+       if (ret) {
+               ath6kl_err("failed to add WOW unicast IP pattern\n");
+               return ret;
+       }
+
+       /* Setup all ARP pkt pattern */
+       ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi,
+                       vif->fw_vif_idx, WOW_LIST_ID,
+                       sizeof(arp_pattern), arp_offset,
+                       arp_pattern, arp_mask);
+       if (ret) {
+               ath6kl_err("failed to add WOW ARP pattern\n");
+               return ret;
+       }
+
+       /*
+        * Setup multicast pattern for mDNS 224.0.0.251,
+        * SSDP 239.255.255.250 and LLMNR  224.0.0.252
+        */
+       ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi,
+                       vif->fw_vif_idx, WOW_LIST_ID,
+                       sizeof(discvr_pattern), discvr_offset,
+                       discvr_pattern, discvr_mask);
+       if (ret) {
+               ath6kl_err("failed to add WOW mDNS/SSDP/LLMNR pattern\n");
+               return ret;
+       }
+
+       /* Setup all DHCP broadcast pkt pattern */
+       ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi,
+                       vif->fw_vif_idx, WOW_LIST_ID,
+                       sizeof(dhcp_pattern), dhcp_offset,
+                       dhcp_pattern, dhcp_mask);
+       if (ret) {
+               ath6kl_err("failed to add WOW DHCP broadcast pattern\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static int ath6kl_wow_sta(struct ath6kl *ar, struct ath6kl_vif *vif)
+{
+       struct net_device *ndev = vif->ndev;
+       static const u8 discvr_pattern[] = { 0xe0, 0x00, 0x00, 0xf8 };
+       static const u8 discvr_mask[] = { 0xf0, 0x00, 0x00, 0xf8 };
+       u8 discvr_offset = 38;
+       u8 mac_mask[ETH_ALEN];
+       int ret;
+
+       /* Setup unicast pkt pattern */
+       memset(mac_mask, 0xff, ETH_ALEN);
+       ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi,
+                               vif->fw_vif_idx, WOW_LIST_ID,
+                               ETH_ALEN, 0, ndev->dev_addr,
+                               mac_mask);
+       if (ret) {
+               ath6kl_err("failed to add WOW unicast pattern\n");
+               return ret;
+       }
+
+       /*
+        * Setup multicast pattern for mDNS 224.0.0.251,
+        * SSDP 239.255.255.250 and LLMNR 224.0.0.252
+        */
+       if ((ndev->flags & IFF_ALLMULTI) ||
+           (ndev->flags & IFF_MULTICAST && netdev_mc_count(ndev) > 0)) {
+               ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi,
+                               vif->fw_vif_idx, WOW_LIST_ID,
+                               sizeof(discvr_pattern), discvr_offset,
+                               discvr_pattern, discvr_mask);
+               if (ret) {
+                       ath6kl_err("failed to add WOW mDNS/SSDP/LLMNR "
+                                  "pattern\n");
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
+{
+       struct in_device *in_dev;
+       struct in_ifaddr *ifa;
+       struct ath6kl_vif *vif;
+       int ret, left;
+       u32 filter = 0;
+       u16 i;
+       u8 index = 0;
+       __be32 ips[MAX_IP_ADDRS];
+
+       vif = ath6kl_vif_first(ar);
+       if (!vif)
+               return -EIO;
+
+       if (!ath6kl_cfg80211_ready(vif))
+               return -EIO;
+
+       if (!test_bit(CONNECTED, &vif->flags))
+               return -ENOTCONN;
+
+       if (wow && (wow->n_patterns > WOW_MAX_FILTERS_PER_LIST))
+               return -EINVAL;
+
+       /* Clear existing WOW patterns */
+       for (i = 0; i < WOW_MAX_FILTERS_PER_LIST; i++)
+               ath6kl_wmi_del_wow_pattern_cmd(ar->wmi, vif->fw_vif_idx,
+                                              WOW_LIST_ID, i);
+
+       /*
+        * Skip the default WOW pattern configuration
+        * if the driver receives any WOW patterns from
+        * the user.
+        */
+       if (wow)
+               ret = ath6kl_wow_usr(ar, vif, wow, &filter);
+       else if (vif->nw_type == AP_NETWORK)
+               ret = ath6kl_wow_ap(ar, vif);
+       else
+               ret = ath6kl_wow_sta(ar, vif);
+
+       if (ret)
+               return ret;
+
        /* Setup own IP addr for ARP agent. */
        in_dev = __in_dev_get_rtnl(vif->ndev);
        if (!in_dev)
@@ -1810,21 +1969,6 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
        }
 
 skip_arp:
-       if (wow->disconnect)
-               filter |= WOW_FILTER_OPTION_NWK_DISASSOC;
-
-       if (wow->magic_pkt)
-               filter |= WOW_FILTER_OPTION_MAGIC_PACKET;
-
-       if (wow->gtk_rekey_failure)
-               filter |= WOW_FILTER_OPTION_GTK_ERROR;
-
-       if (wow->eap_identity_req)
-               filter |= WOW_FILTER_OPTION_EAP_REQ;
-
-       if (wow->four_way_handshake)
-               filter |= WOW_FILTER_OPTION_8021X_4WAYHS;
-
        ret = ath6kl_wmi_set_wow_mode_cmd(ar->wmi, vif->fw_vif_idx,
                                          ATH6KL_WOW_MODE_ENABLE,
                                          filter,
@@ -1832,11 +1976,26 @@ skip_arp:
        if (ret)
                return ret;
 
+       clear_bit(HOST_SLEEP_MODE_CMD_PROCESSED, &vif->flags);
+
        ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
                                                 ATH6KL_HOST_MODE_ASLEEP);
        if (ret)
                return ret;
 
+       left = wait_event_interruptible_timeout(ar->event_wq,
+                       test_bit(HOST_SLEEP_MODE_CMD_PROCESSED, &vif->flags),
+                       WMI_TIMEOUT);
+       if (left == 0) {
+               ath6kl_warn("timeout, didn't get host sleep cmd "
+                           "processed event\n");
+               ret = -ETIMEDOUT;
+       } else if (left < 0) {
+               ath6kl_warn("error while waiting for host sleep cmd "
+                           "processed event %d\n", left);
+               ret = left;
+       }
+
        if (ar->tx_pending[ar->ctrl_ep]) {
                left = wait_event_interruptible_timeout(ar->event_wq,
                                ar->tx_pending[ar->ctrl_ep] == 0, WMI_TIMEOUT);
@@ -1940,6 +2099,7 @@ int ath6kl_cfg80211_suspend(struct ath6kl *ar,
 
        return 0;
 }
+EXPORT_SYMBOL(ath6kl_cfg80211_suspend);
 
 int ath6kl_cfg80211_resume(struct ath6kl *ar)
 {
@@ -1991,6 +2151,7 @@ int ath6kl_cfg80211_resume(struct ath6kl *ar)
 
        return 0;
 }
+EXPORT_SYMBOL(ath6kl_cfg80211_resume);
 
 #ifdef CONFIG_PM
 
@@ -2254,6 +2415,11 @@ static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
        p.dot11_auth_mode = vif->dot11_auth_mode;
        p.ch = cpu_to_le16(vif->next_chan);
 
+       /* Enable uAPSD support by default */
+       res = ath6kl_wmi_ap_set_apsd(ar->wmi, vif->fw_vif_idx, true);
+       if (res < 0)
+               return res;
+
        if (vif->wdev.iftype == NL80211_IFTYPE_P2P_GO) {
                p.nw_subtype = SUBTYPE_P2PGO;
        } else {
@@ -2689,122 +2855,9 @@ void ath6kl_cfg80211_stop_all(struct ath6kl *ar)
                ath6kl_cfg80211_stop(vif);
 }
 
-struct ath6kl *ath6kl_core_alloc(struct device *dev)
+static int ath6kl_cfg80211_vif_init(struct ath6kl_vif *vif)
 {
-       struct ath6kl *ar;
-       struct wiphy *wiphy;
-       u8 ctr;
-
-       /* create a new wiphy for use with cfg80211 */
-       wiphy = wiphy_new(&ath6kl_cfg80211_ops, sizeof(struct ath6kl));
-
-       if (!wiphy) {
-               ath6kl_err("couldn't allocate wiphy device\n");
-               return NULL;
-       }
-
-       ar = wiphy_priv(wiphy);
-       ar->p2p = !!ath6kl_p2p;
-       ar->wiphy = wiphy;
-       ar->dev = dev;
-
-       ar->vif_max = 1;
-
-       ar->max_norm_iface = 1;
-
-       spin_lock_init(&ar->lock);
-       spin_lock_init(&ar->mcastpsq_lock);
-       spin_lock_init(&ar->list_lock);
-
-       init_waitqueue_head(&ar->event_wq);
-       sema_init(&ar->sem, 1);
-
-       INIT_LIST_HEAD(&ar->amsdu_rx_buffer_queue);
-       INIT_LIST_HEAD(&ar->vif_list);
-
-       clear_bit(WMI_ENABLED, &ar->flag);
-       clear_bit(SKIP_SCAN, &ar->flag);
-       clear_bit(DESTROY_IN_PROGRESS, &ar->flag);
-
-       ar->listen_intvl_t = A_DEFAULT_LISTEN_INTERVAL;
-       ar->listen_intvl_b = 0;
-       ar->tx_pwr = 0;
-
-       ar->intra_bss = 1;
-       ar->lrssi_roam_threshold = DEF_LRSSI_ROAM_THRESHOLD;
-
-       ar->state = ATH6KL_STATE_OFF;
-
-       memset((u8 *)ar->sta_list, 0,
-              AP_MAX_NUM_STA * sizeof(struct ath6kl_sta));
-
-       /* Init the PS queues */
-       for (ctr = 0; ctr < AP_MAX_NUM_STA; ctr++) {
-               spin_lock_init(&ar->sta_list[ctr].psq_lock);
-               skb_queue_head_init(&ar->sta_list[ctr].psq);
-       }
-
-       skb_queue_head_init(&ar->mcastpsq);
-
-       memcpy(ar->ap_country_code, DEF_AP_COUNTRY_CODE, 3);
-
-       return ar;
-}
-
-int ath6kl_register_ieee80211_hw(struct ath6kl *ar)
-{
-       struct wiphy *wiphy = ar->wiphy;
-       int ret;
-
-       wiphy->mgmt_stypes = ath6kl_mgmt_stypes;
-
-       wiphy->max_remain_on_channel_duration = 5000;
-
-       /* set device pointer for wiphy */
-       set_wiphy_dev(wiphy, ar->dev);
-
-       wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
-                                BIT(NL80211_IFTYPE_ADHOC) |
-                                BIT(NL80211_IFTYPE_AP);
-       if (ar->p2p) {
-               wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_GO) |
-                                         BIT(NL80211_IFTYPE_P2P_CLIENT);
-       }
-
-       /* max num of ssids that can be probed during scanning */
-       wiphy->max_scan_ssids = MAX_PROBED_SSID_INDEX;
-       wiphy->max_scan_ie_len = 1000; /* FIX: what is correct limit? */
-       wiphy->bands[IEEE80211_BAND_2GHZ] = &ath6kl_band_2ghz;
-       wiphy->bands[IEEE80211_BAND_5GHZ] = &ath6kl_band_5ghz;
-       wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
-
-       wiphy->cipher_suites = cipher_suites;
-       wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
-
-       wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT |
-                             WIPHY_WOWLAN_DISCONNECT |
-                             WIPHY_WOWLAN_GTK_REKEY_FAILURE  |
-                             WIPHY_WOWLAN_SUPPORTS_GTK_REKEY |
-                             WIPHY_WOWLAN_EAP_IDENTITY_REQ   |
-                             WIPHY_WOWLAN_4WAY_HANDSHAKE;
-       wiphy->wowlan.n_patterns = WOW_MAX_FILTERS_PER_LIST;
-       wiphy->wowlan.pattern_min_len = 1;
-       wiphy->wowlan.pattern_max_len = WOW_PATTERN_SIZE;
-
-       wiphy->max_sched_scan_ssids = 10;
-
-       ret = wiphy_register(wiphy);
-       if (ret < 0) {
-               ath6kl_err("couldn't register wiphy device\n");
-               return ret;
-       }
-
-       return 0;
-}
-
-static int ath6kl_init_if_data(struct ath6kl_vif *vif)
-{
-       vif->aggr_cntxt = aggr_init(vif->ndev);
+       vif->aggr_cntxt = aggr_init(vif);
        if (!vif->aggr_cntxt) {
                ath6kl_err("failed to initialize aggr\n");
                return -ENOMEM;
@@ -2823,7 +2876,7 @@ static int ath6kl_init_if_data(struct ath6kl_vif *vif)
        return 0;
 }
 
-void ath6kl_deinit_if_data(struct ath6kl_vif *vif)
+void ath6kl_cfg80211_vif_cleanup(struct ath6kl_vif *vif)
 {
        struct ath6kl *ar = vif->ar;
        struct ath6kl_mc_filter *mc_filter, *tmp;
@@ -2876,8 +2929,7 @@ struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name,
 
        ath6kl_init_control_info(vif);
 
-       /* TODO: Pass interface specific pointer instead of ar */
-       if (ath6kl_init_if_data(vif))
+       if (ath6kl_cfg80211_vif_init(vif))
                goto err;
 
        if (register_netdevice(ndev))
@@ -2904,8 +2956,89 @@ err:
        return NULL;
 }
 
-void ath6kl_deinit_ieee80211_hw(struct ath6kl *ar)
+int ath6kl_cfg80211_init(struct ath6kl *ar)
+{
+       struct wiphy *wiphy = ar->wiphy;
+       int ret;
+
+       wiphy->mgmt_stypes = ath6kl_mgmt_stypes;
+
+       wiphy->max_remain_on_channel_duration = 5000;
+
+       /* set device pointer for wiphy */
+       set_wiphy_dev(wiphy, ar->dev);
+
+       wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
+                                BIT(NL80211_IFTYPE_ADHOC) |
+                                BIT(NL80211_IFTYPE_AP);
+       if (ar->p2p) {
+               wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_GO) |
+                                         BIT(NL80211_IFTYPE_P2P_CLIENT);
+       }
+
+       /* max num of ssids that can be probed during scanning */
+       wiphy->max_scan_ssids = MAX_PROBED_SSID_INDEX;
+       wiphy->max_scan_ie_len = 1000; /* FIX: what is correct limit? */
+       wiphy->bands[IEEE80211_BAND_2GHZ] = &ath6kl_band_2ghz;
+       wiphy->bands[IEEE80211_BAND_5GHZ] = &ath6kl_band_5ghz;
+       wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
+
+       wiphy->cipher_suites = cipher_suites;
+       wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
+
+       wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT |
+                             WIPHY_WOWLAN_DISCONNECT |
+                             WIPHY_WOWLAN_GTK_REKEY_FAILURE  |
+                             WIPHY_WOWLAN_SUPPORTS_GTK_REKEY |
+                             WIPHY_WOWLAN_EAP_IDENTITY_REQ   |
+                             WIPHY_WOWLAN_4WAY_HANDSHAKE;
+       wiphy->wowlan.n_patterns = WOW_MAX_FILTERS_PER_LIST;
+       wiphy->wowlan.pattern_min_len = 1;
+       wiphy->wowlan.pattern_max_len = WOW_PATTERN_SIZE;
+
+       wiphy->max_sched_scan_ssids = 10;
+
+       ret = wiphy_register(wiphy);
+       if (ret < 0) {
+               ath6kl_err("couldn't register wiphy device\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+void ath6kl_cfg80211_cleanup(struct ath6kl *ar)
 {
        wiphy_unregister(ar->wiphy);
+}
+
+struct ath6kl *ath6kl_cfg80211_create(void)
+{
+       struct ath6kl *ar;
+       struct wiphy *wiphy;
+
+       /* create a new wiphy for use with cfg80211 */
+       wiphy = wiphy_new(&ath6kl_cfg80211_ops, sizeof(struct ath6kl));
+
+       if (!wiphy) {
+               ath6kl_err("couldn't allocate wiphy device\n");
+               return NULL;
+       }
+
+       ar = wiphy_priv(wiphy);
+       ar->wiphy = wiphy;
+
+       return ar;
+}
+
+/* Note: ar variable must not be accessed after calling this! */
+void ath6kl_cfg80211_destroy(struct ath6kl *ar)
+{
+       int i;
+
+       for (i = 0; i < AP_MAX_NUM_STA; i++)
+               kfree(ar->sta_list[i].aggr_conn);
+
        wiphy_free(ar->wiphy);
 }
+
This page took 0.038326 seconds and 5 git commands to generate.