blob: e6c7c0c477789ee34b449fed1d668b0186916cf0 [file] [log] [blame]
From 186f818bcf09ecd1290309d38844a349124c1386 Mon Sep 17 00:00:00 2001
From: Shijie Zhang <shijiez@qca.qualcomm.com>
Date: Mon, 20 May 2013 14:00:08 +0800
Subject: [PATCH] LinuxWapiCcxReleaseAth6kl:compat-wireless: add 11w support
add optional support from wpa_supplicant to host driver for
linux packages Signed-off-by: Shijie Zhang
<shijiez@qca.qualcomm.com>
---
config.mk | 1 +
drivers/net/wireless/ath/ath6kl/cfg80211.c | 103 +++++++++++++++++++++++--
drivers/net/wireless/ath/ath6kl/common.h | 3 +
drivers/net/wireless/ath/ath6kl/core.h | 10 +++
drivers/net/wireless/ath/ath6kl/debugfs_pri.c | 97 +++++++++++++++++++++++
drivers/net/wireless/ath/ath6kl/main.c | 14 ++++
drivers/net/wireless/ath/ath6kl/wmi.c | 90 +++++++++++++++++++++
drivers/net/wireless/ath/ath6kl/wmi.h | 44 +++++++++++
include/linux/ieee80211.h | 5 ++
include/linux/nl80211.h | 8 +-
include/net/cfg80211.h | 6 +-
net/mac80211/ieee80211_i.h | 6 +-
net/mac80211/mlme.c | 12 ++-
net/wireless/core.h | 4 +-
net/wireless/mlme.c | 8 +-
net/wireless/nl80211.c | 31 +++++---
net/wireless/sme.c | 4 +-
17 files changed, 405 insertions(+), 41 deletions(-)
diff --git a/config.mk b/config.mk
index 5567d90..daad171 100644
--- a/config.mk
+++ b/config.mk
@@ -617,6 +617,7 @@ CONFIG_ATH6KL_SDIO=m
CONFIG_ATH6KL_USB=m
CONFIG_ATH6KL_DEBUG=y
CONFIG_ATH6KL_REGDOMAIN=y
+CONFIG_SUPPORT_11W=y
endif #CONFIG_COMPAT_KERNEL_2_6_27
ifndef CONFIG_COMPAT_KERNEL_2_6_29
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index 7e8c827..8bcd06e 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -279,7 +279,24 @@ static void ath6kl_set_key_mgmt(struct ath6kl_vif *vif, u32 key_mgmt)
vif->auth_mode = WPA_AUTH_CCKM;
else if (vif->auth_mode == WPA2_AUTH)
vif->auth_mode = WPA2_AUTH_CCKM;
+#ifdef CONFIG_SUPPORT_11W
+ } else if (key_mgmt == WLAN_AKM_SUITE_8021X_SHA256) {
+ if (vif->auth_mode == WPA_AUTH){
+ ath6kl_err("%s: auth_mode %x not supported key_mgmt %x\n", __func__, vif->auth_mode,key_mgmt);
+ return ;
+ }
+ else if (vif->auth_mode == WPA2_AUTH)
+ vif->auth_mode = WPA2_AUTH_SHA256;
+ } else if (key_mgmt == WLAN_AKM_SUITE_PSK_SHA256) {
+ if (vif->auth_mode == WPA_AUTH){
+ ath6kl_err("%s: auth_mode %x not supported key_mgmt %x\n", __func__, vif->auth_mode,key_mgmt);
+ return ;
+ }
+ else if (vif->auth_mode == WPA2_AUTH)
+ vif->auth_mode = WPA2_PSK_AUTH_SHA256;
+#endif
} else if (key_mgmt != WLAN_AKM_SUITE_8021X) {
+
vif->auth_mode = NONE_AUTH;
}
}
@@ -530,6 +547,21 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
if (sme->bssid && !is_broadcast_ether_addr(sme->bssid))
memcpy(vif->req_bssid, sme->bssid, sizeof(vif->req_bssid));
+#ifdef CONFIG_SUPPORT_11W
+ {
+ u16 rsn_cap = 0;
+
+ ath6kl_err("ath6kl_cfg80211_connect: sme->mfp = %d\n", sme->mfp);
+ if ( sme->mfp == NL80211_MFP_REQUIRED ) {
+ rsn_cap = 0xc0;
+ }else if ( sme->mfp == NL80211_MFP_OPTIONAL ) {
+ rsn_cap = 0x80;
+ }
+ ath6kl_wmi_set_rsn_cap_cmd(ar->wmi, vif->fw_vif_idx, rsn_cap);
+ }
+#endif
+
+
ath6kl_set_wpa_version(vif, sme->crypto.wpa_versions);
status = ath6kl_set_auth_type(vif, sme->auth_type);
@@ -1132,6 +1164,9 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
int seq_len;
u8 key_usage;
u8 key_type;
+#ifdef CONFIG_SUPPORT_11W
+ u8 max_key_index;
+#endif
if (!ath6kl_cfg80211_ready(vif))
return -EIO;
@@ -1143,10 +1178,19 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
params->key);
}
+
+#ifdef CONFIG_SUPPORT_11W
+ if (WLAN_CIPHER_SUITE_AES_CMAC == params->cipher)
+ max_key_index = WMI_MAX_SUPPORT_11W_KEY_INDEX;
+ else
+ max_key_index = WMI_MAX_KEY_INDEX;
+ if (key_index > max_key_index) {
+#else
if (key_index > WMI_MAX_KEY_INDEX) {
+#endif
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
- "%s: key index %d out of bounds\n", __func__,
- key_index);
+ "%s: key index %d out of bounds\n", __func__,
+ key_index);
return -ENOENT;
}
@@ -1191,6 +1235,12 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
key_type = WAPI_CRYPT;
break;
+#ifdef CONFIG_SUPPORT_11W
+ case WLAN_CIPHER_SUITE_AES_CMAC:
+ key_type = AES_128_CMAC_CRYPT;
+ break;
+#endif
+
default:
return -ENOTSUPP;
}
@@ -1240,11 +1290,24 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
return 0;
}
- return ath6kl_wmi_addkey_cmd(ar->wmi, vif->fw_vif_idx, key_index,
- key_type, key_usage, key->key_len,
- key->seq, key->seq_len, key->key,
- KEY_OP_INIT_VAL,
- (u8 *) mac_addr, SYNC_BOTH_WMIFLAG);
+#ifdef CONFIG_SUPPORT_11W
+ if (AES_128_CMAC_CRYPT == key_type){
+ return ath6kl_wmi_addigtk_cmd(ar->wmi, vif->fw_vif_idx, key_index,
+ key_type, key_usage, key->key_len,
+ key->seq, key->seq_len, key->key,
+ KEY_OP_INIT_VAL,
+ (u8 *) mac_addr, SYNC_BOTH_WMIFLAG);
+ }else {
+#endif
+ return ath6kl_wmi_addkey_cmd(ar->wmi, vif->fw_vif_idx, key_index,
+ key_type, key_usage, key->key_len,
+ key->seq, key->seq_len, key->key,
+ KEY_OP_INIT_VAL,
+ (u8 *) mac_addr, SYNC_BOTH_WMIFLAG);
+#ifdef CONFIG_SUPPORT_11W
+ }
+#endif
+
}
static int ath6kl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
@@ -1259,7 +1322,12 @@ static int ath6kl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
if (!ath6kl_cfg80211_ready(vif))
return -EIO;
+#ifdef CONFIG_SUPPORT_11W
+ if (key_index > WMI_MAX_SUPPORT_11W_KEY_INDEX) {
+#else
if (key_index > WMI_MAX_KEY_INDEX) {
+#endif
+
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
"%s: key index %d out of bounds\n", __func__,
key_index);
@@ -1711,6 +1779,9 @@ static const u32 cipher_suites[] = {
WLAN_CIPHER_SUITE_CCMP,
CCKM_KRK_CIPHER_SUITE,
WLAN_CIPHER_SUITE_SMS4,
+#ifdef CONFIG_SUPPORT_11W
+ WLAN_CIPHER_SUITE_AES_CMAC,
+#endif
};
static bool is_rate_legacy(s32 rate)
@@ -2789,6 +2860,20 @@ static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2)
p.auth_mode |= WPA2_PSK_AUTH;
break;
+#ifdef CONFIG_SUPPORT_11W
+ case WLAN_AKM_SUITE_8021X_SHA256:
+ if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1)
+ ath6kl_err("WLAN_AKM_SUITE_8021X_SHA256 is not supported in wpa_versions %x\n",info->crypto.wpa_versions);
+ if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2)
+ p.auth_mode |= WPA2_AUTH_SHA256;
+ break;
+ case WLAN_AKM_SUITE_PSK_SHA256:
+ if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1)
+ ath6kl_err("WLAN_AKM_SUITE_PSK_SHA256 is not supported in wpa_versions %x\n",info->crypto.wpa_versions);
+ if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2)
+ p.auth_mode |= WPA2_PSK_AUTH_SHA256;
+ break;
+#endif
}
}
if (p.auth_mode == 0)
@@ -2858,7 +2943,11 @@ static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
* advertise the same in beacon/probe response. Send
* the complete RSN IE capability field to firmware
*/
+#ifdef CONFIG_SUPPORT_11W
+ if ((p.auth_mode & (WPA2_AUTH | WPA2_PSK_AUTH | WPA2_AUTH_SHA256 | WPA2_PSK_AUTH_SHA256)) && (info->tail) &&
+#else
if ((p.auth_mode & (WPA2_AUTH | WPA2_PSK_AUTH)) && (info->tail) &&
+#endif
test_bit(ATH6KL_FW_CAPABILITY_RSN_CAP_OVERRIDE,
ar->fw_capabilities)) {
rsn_capb = 0;
diff --git a/drivers/net/wireless/ath/ath6kl/common.h b/drivers/net/wireless/ath/ath6kl/common.h
index f78c59c..622063d 100644
--- a/drivers/net/wireless/ath/ath6kl/common.h
+++ b/drivers/net/wireless/ath/ath6kl/common.h
@@ -73,6 +73,9 @@ enum crypto_type {
TKIP_CRYPT = 0x04,
AES_CRYPT = 0x08,
WAPI_CRYPT = 0x10,
+#ifdef CONFIG_SUPPORT_11W
+ AES_128_CMAC_CRYPT = 0x20,
+#endif
};
struct htc_endpoint_credit_dist;
diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h
index 1a97a1f..ac240df 100644
--- a/drivers/net/wireless/ath/ath6kl/core.h
+++ b/drivers/net/wireless/ath/ath6kl/core.h
@@ -599,7 +599,11 @@ struct ath6kl_vif {
u16 ch_hint;
u16 bss_ch;
struct ath6kl_wep_key wep_key_list[WMI_MAX_KEY_INDEX + 1];
+#ifdef CONFIG_SUPPORT_11W
+ struct ath6kl_key keys[WMI_MAX_SUPPORT_11W_KEY_INDEX + 1];
+#else
struct ath6kl_key keys[WMI_MAX_KEY_INDEX + 1];
+#endif
struct aggr_info *aggr_cntxt;
struct ath6kl_htcap htcap[IEEE80211_NUM_BANDS];
@@ -628,6 +632,9 @@ struct ath6kl_vif {
struct wmi_connect_cmd profile;
u16 rsn_capab;
+#ifdef CONFIG_SUPPORT_11W
+ u16 rsn_cap; /* for 802.11w */
+#endif
struct list_head mc_filter;
};
@@ -914,6 +921,9 @@ void ath6kl_tkip_micerr_event(struct ath6kl_vif *vif, u8 keyid, bool ismcast);
void ath6kl_txpwr_rx_evt(void *devt, u8 tx_pwr);
void ath6kl_scan_complete_evt(struct ath6kl_vif *vif, int status);
void ath6kl_tgt_stats_event(struct ath6kl_vif *vif, u8 *ptr, u32 len);
+#ifdef CONFIG_SUPPORT_11W
+void ath6kl_get_rsn_cap_event(struct ath6kl_vif *vif, u16 rsn_cap);
+#endif
void ath6kl_indicate_tx_activity(void *devt, u8 traffic_class, bool active);
enum htc_endpoint_id ath6kl_ac2_endpoint_id(void *devt, u8 ac);
diff --git a/drivers/net/wireless/ath/ath6kl/debugfs_pri.c b/drivers/net/wireless/ath/ath6kl/debugfs_pri.c
index 79a4746..34682be 100644
--- a/drivers/net/wireless/ath/ath6kl/debugfs_pri.c
+++ b/drivers/net/wireless/ath/ath6kl/debugfs_pri.c
@@ -195,6 +195,99 @@ static const struct file_operations fops_bmisstime = {
.llseek = default_llseek,
};
+#ifdef CONFIG_SUPPORT_11W
+static ssize_t ath6kl_rsn_cap_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath6kl *ar = file->private_data;
+ struct ath6kl_vif *vif;
+ u16 rsn_cap;
+ char buf[32];
+ ssize_t len;
+ int ret;
+
+ if (WARN_ON(!test_bit(WMI_READY, &ar->flag)))
+ return -EIO;
+
+ vif = ath6kl_vif_first(ar);
+ if (!vif)
+ return -EIO;
+
+ len = min(count, sizeof(buf) - 1);
+ if (copy_from_user(buf, user_buf, len))
+ return -EFAULT;
+
+ buf[len] = '\0';
+ if (kstrtou16(buf, 0, &rsn_cap))
+ return -EINVAL;
+
+ vif->rsn_cap = rsn_cap;
+
+ ret = ath6kl_wmi_set_rsn_cap_cmd(ar->wmi, vif->fw_vif_idx,
+ vif->rsn_cap);
+ if (ret) {
+ ath6kl_err("failed to set rsn cap:%d\n", ret);
+ return ret;
+ }
+
+ return count;
+}
+
+static ssize_t ath6kl_rsn_cap_read(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath6kl *ar = file->private_data;
+ struct ath6kl_vif *vif;
+ char buf[32];
+ long left;
+ int ret;
+ ssize_t len;
+
+ if (WARN_ON(!test_bit(WMI_READY, &ar->flag)))
+ return -EIO;
+
+ vif = ath6kl_vif_first(ar);
+ if (!vif)
+ return -EIO;
+
+ if (down_interruptible(&ar->sem)) {
+ return -EBUSY;
+ }
+
+ set_bit(STATS_UPDATE_PEND, &vif->flags);
+
+ ret = ath6kl_wmi_get_rsn_cap_cmd(ar->wmi, vif->fw_vif_idx);
+ if (ret) {
+ up(&ar->sem);
+ ath6kl_err("ath6kl_wmi_get_rsn_cap_cmd failed:%d \n", ret);
+ return -EIO;
+ }
+
+ left = wait_event_interruptible_timeout(ar->event_wq,
+ !test_bit(STATS_UPDATE_PEND,
+ &vif->flags), WMI_TIMEOUT);
+
+ up(&ar->sem);
+
+ if (left <= 0) {
+ ath6kl_err("wait_event_interruptible_timeout\n");
+ return -ETIMEDOUT;
+ }
+
+ len = scnprintf(buf, sizeof(buf), "%u\n", vif->rsn_cap);
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_rsn_cap = {
+ .open = ath6kl_debugfs_open_pri,
+ .read = ath6kl_rsn_cap_read,
+ .write = ath6kl_rsn_cap_write,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+#endif
+
int ath6kl_init_debugfs_pri(struct ath6kl *ar)
{
debugfs_create_file("inactivity_period", S_IWUSR, ar->debugfs_phy, ar,
@@ -202,6 +295,10 @@ int ath6kl_init_debugfs_pri(struct ath6kl *ar)
debugfs_create_file("bmiss_time", S_IRUSR | S_IWUSR, ar->debugfs_phy,
ar, &fops_bmisstime);
+#ifdef CONFIG_SUPPORT_11W
+ debugfs_create_file("rsn_cap", S_IRUSR | S_IWUSR, ar->debugfs_phy, ar,
+ &fops_rsn_cap);
+#endif
return 0;
}
diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c
index 3280f05..21cc7a9 100644
--- a/drivers/net/wireless/ath/ath6kl/main.c
+++ b/drivers/net/wireless/ath/ath6kl/main.c
@@ -910,6 +910,20 @@ void ath6kl_tgt_stats_event(struct ath6kl_vif *vif, u8 *ptr, u32 len)
}
}
+#ifdef CONFIG_SUPPORT_11W
+void ath6kl_get_rsn_cap_event(struct ath6kl_vif *vif, u16 rsn_cap)
+{
+ struct ath6kl *ar = vif->ar;
+
+ vif->rsn_cap = rsn_cap;
+
+ if (test_bit(STATS_UPDATE_PEND, &vif->flags)) {
+ clear_bit(STATS_UPDATE_PEND, &vif->flags);
+ wake_up(&ar->event_wq);
+ }
+}
+#endif
+
void ath6kl_wakeup_event(void *dev)
{
struct ath6kl *ar = (struct ath6kl *) dev;
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c
index 8aebf56..49cb0af 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.c
+++ b/drivers/net/wireless/ath/ath6kl/wmi.c
@@ -1338,6 +1338,22 @@ static int ath6kl_wmi_stats_event_rx(struct wmi *wmi, u8 *datap, int len,
return 0;
}
+#ifdef CONFIG_SUPPORT_11W
+static int ath6kl_wmi_get_rsn_cap_rx(struct wmi *wmi, u8 *datap, int len,
+ struct ath6kl_vif *vif)
+{
+ struct wmi_rsn_cap_cmd *reply;
+
+ if (len < sizeof(struct wmi_rsn_cap_cmd))
+ return -EINVAL;
+
+ reply = (struct wmi_rsn_cap_cmd *) datap;
+ ath6kl_get_rsn_cap_event(vif, le16_to_cpu(reply->rsn_cap));
+
+ return 0;
+}
+#endif
+
static u8 ath6kl_wmi_get_upper_threshold(s16 rssi,
struct sq_threshold_params *sq_thresh,
u32 size)
@@ -2198,6 +2214,32 @@ int ath6kl_wmi_bmisstime_cmd(struct wmi *wmi, u8 if_idx,
return ret;
}
+#ifdef CONFIG_SUPPORT_11W
+int ath6kl_wmi_set_rsn_cap_cmd(struct wmi *wmi, u8 if_idx,
+ u16 rsn_cap)
+{
+ struct sk_buff *skb;
+ struct wmi_rsn_cap_cmd *cmd;
+ int ret;
+
+ skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+ if (!skb)
+ return -ENOMEM;
+
+ cmd = (struct wmi_rsn_cap_cmd *) skb->data;
+ cmd->rsn_cap = cpu_to_le16(rsn_cap);
+
+ ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_RSN_CAP_CMDID,
+ NO_SYNC_WMIFLAG);
+ return ret;
+}
+
+int ath6kl_wmi_get_rsn_cap_cmd(struct wmi *wmi, u8 if_idx)
+{
+ return ath6kl_wmi_simple_cmd(wmi, if_idx, WMI_GET_RSN_CAP_CMDID);
+}
+#endif
+
int ath6kl_wmi_powermode_cmd(struct wmi *wmi, u8 if_idx, u8 pwr_mode)
{
struct sk_buff *skb;
@@ -2313,6 +2355,48 @@ int ath6kl_wmi_addkey_cmd(struct wmi *wmi, u8 if_idx, u8 key_index,
return ret;
}
+#ifdef CONFIG_SUPPORT_11W
+int ath6kl_wmi_addigtk_cmd(struct wmi *wmi, u8 if_idx, u8 key_index,
+ enum crypto_type key_type,
+ u8 key_usage, u8 key_len,
+ u8 *key_rsc, unsigned int key_rsc_len,
+ u8 *key_material,
+ u8 key_op_ctrl, u8 *mac_addr,
+ enum wmi_sync_flag sync_flag)
+{
+ struct sk_buff *skb;
+ struct wmi_add_igtk_key_cmd *cmd;
+ int ret;
+
+ ath6kl_dbg(ATH6KL_DBG_WMI, "addigtk cmd: key_index=%u key_type=%d "
+ "key_usage=%d key_len=%d key_op_ctrl=%d\n",
+ key_index, key_type, key_usage, key_len, key_op_ctrl);
+
+ if ((key_index > WMI_MAX_SUPPORT_11W_KEY_INDEX) || (key_len > WMI_MAX_KEY_LEN) ||
+ (key_material == NULL) || key_rsc_len > 6)
+ return -EINVAL;
+
+ if ((WEP_CRYPT != key_type) && (NULL == key_rsc))
+ return -EINVAL;
+
+ skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+ if (!skb)
+ return -ENOMEM;
+
+ cmd = (struct wmi_add_igtk_key_cmd *) skb->data;
+ cmd->key_index = key_index;
+ cmd->key_len = key_len;
+ memcpy(cmd->key, key_material, key_len);
+ if (key_rsc != NULL)
+ memcpy(cmd->key_rsc, key_rsc, key_rsc_len);
+
+ ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_IGTK_CMDID,
+ sync_flag);
+
+ return ret;
+}
+#endif
+
int ath6kl_wmi_add_krk_cmd(struct wmi *wmi, u8 if_idx, u8 *krk)
{
struct sk_buff *skb;
@@ -3940,6 +4024,12 @@ static int ath6kl_wmi_proc_events_vif(struct net_device *dev, struct wmi *wmi,
ret = ath6kl_wmi_neighbor_report_event_rx(wmi, datap, len,
vif);
break;
+#ifdef CONFIG_SUPPORT_11W
+ case WMI_GET_RSN_CAP_EVENTID:
+ ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_SCAN_COMPLETE_EVENTID\n");
+ ret = ath6kl_wmi_get_rsn_cap_rx(wmi, datap, len, vif);
+ break;
+#endif
case WMI_SCAN_COMPLETE_EVENTID:
ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_SCAN_COMPLETE_EVENTID\n");
ret = ath6kl_wmi_scan_complete_rx(wmi, datap, len, vif);
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h
index da3612c..661e8ad 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.h
+++ b/drivers/net/wireless/ath/ath6kl/wmi.h
@@ -685,10 +685,18 @@ enum auth_mode {
WPA2_PSK_AUTH = 0x10,
WPA_AUTH_CCKM = 0x20,
WPA2_AUTH_CCKM = 0x40,
+#ifdef CONFIG_SUPPORT_11W
+ WPA2_AUTH_SHA256 = 0x80,
+ WPA2_PSK_AUTH_SHA256 = 0x81,
+#endif
};
#define WMI_MAX_KEY_INDEX 3
+#ifdef CONFIG_SUPPORT_11W
+#define WMI_MAX_SUPPORT_11W_KEY_INDEX 5
+#endif
+
#define WMI_MAX_KEY_LEN 32
/*
@@ -797,6 +805,18 @@ struct wmi_delete_cipher_key_cmd {
u8 key_index;
} __packed;
+#ifdef CONFIG_SUPPORT_11W
+struct wmi_add_igtk_key_cmd {
+ u8 key_index;
+
+ u8 key_len;
+
+ u8 key_rsc[6];/* key replay sequence counter */
+
+ u8 key[WMI_MAX_KEY_LEN];
+} __packed;
+#endif
+
#define WMI_KRK_LEN 16
/* WMI_ADD_KRK_CMDID */
@@ -2159,6 +2179,16 @@ struct wmi_txe_notify_event {
__le32 pkts;
} __packed;
+#ifdef CONFIG_SUPPORT_11W
+#define RSN_CAP_PREAUTH 0x01
+#define RSN_CAP_MFPR 0x40
+#define RSN_CAP_MFPC 0x80
+
+struct wmi_rsn_cap_cmd {
+ __le16 rsn_cap;
+} __packed;
+#endif
+
/* WMI_SET_AKMP_PARAMS_CMD */
struct wmi_pmkid {
@@ -2656,6 +2686,16 @@ int ath6kl_wmi_addkey_cmd(struct wmi *wmi, u8 if_idx, u8 key_index,
u8 *key_material,
u8 key_op_ctrl, u8 *mac_addr,
enum wmi_sync_flag sync_flag);
+#ifdef CONFIG_SUPPORT_11W
+int ath6kl_wmi_addigtk_cmd(struct wmi *wmi, u8 if_idx, u8 key_index,
+ enum crypto_type key_type,
+ u8 key_usage, u8 key_len,
+ u8 *key_rsc, unsigned int key_rsc_len,
+ u8 *key_material,
+ u8 key_op_ctrl, u8 *mac_addr,
+ enum wmi_sync_flag sync_flag);
+#endif
+
int ath6kl_wmi_add_krk_cmd(struct wmi *wmi, u8 if_idx, u8 *krk);
int ath6kl_wmi_deletekey_cmd(struct wmi *wmi, u8 if_idx, u8 key_index);
int ath6kl_wmi_setpmkid_cmd(struct wmi *wmi, u8 if_idx, const u8 *bssid,
@@ -2665,6 +2705,10 @@ int ath6kl_wmi_get_tx_pwr_cmd(struct wmi *wmi, u8 if_idx);
int ath6kl_wmi_get_roam_tbl_cmd(struct wmi *wmi);
int ath6kl_wmi_set_wmm_txop(struct wmi *wmi, u8 if_idx, enum wmi_txop_cfg cfg);
+#ifdef CONFIG_SUPPORT_11W
+int ath6kl_wmi_get_rsn_cap_cmd(struct wmi *wmi, u8 if_idx);
+int ath6kl_wmi_set_rsn_cap_cmd(struct wmi *wmi, u8 if_idx, u16 rsn_cap);
+#endif
int ath6kl_wmi_set_keepalive_cmd(struct wmi *wmi, u8 if_idx,
u8 keep_alive_intvl);
int ath6kl_wmi_set_htcap_cmd(struct wmi *wmi, u8 if_idx,
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 66cedf6..8f680c8 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -1566,6 +1566,11 @@ enum ieee80211_sa_query_action {
#define WLAN_MAX_KEY_LEN 32
+#ifdef CONFIG_SUPPORT_11W
+#define WLAN_AKM_SUITE_8021X_SHA256 0x000FAC05
+#define WLAN_AKM_SUITE_PSK_SHA256 0x000FAC06
+#endif
+
#define WLAN_PMKID_LEN 16
#define WLAN_OUI_WFA 0x506f9a
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 85e5051..d9854f4 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -363,8 +363,8 @@
* requests to connect to a specified network but without separating
* auth and assoc steps. For this, you need to specify the SSID in a
* %NL80211_ATTR_SSID attribute, and can optionally specify the association
- * IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_MAC,
- * %NL80211_ATTR_WIPHY_FREQ, %NL80211_ATTR_CONTROL_PORT,
+ * IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_USE_MFP,
+ * %NL80211_ATTR_MAC, %NL80211_ATTR_WIPHY_FREQ, %NL80211_ATTR_CONTROL_PORT,
* %NL80211_ATTR_CONTROL_PORT_ETHERTYPE and
* %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT.
* Background scan period can optionally be
@@ -914,7 +914,7 @@ enum nl80211_commands {
* @NL80211_ATTR_USE_MFP: Whether management frame protection (IEEE 802.11w) is
* used for the association (&enum nl80211_mfp, represented as a u32);
* this attribute can be used
- * with %NL80211_CMD_ASSOCIATE request
+ * with %NL80211_CMD_ASSOCIATE and %NL80211_CMD_CONNECT requests
*
* @NL80211_ATTR_STA_FLAGS2: Attribute containing a
* &struct nl80211_sta_flag_update.
@@ -2380,10 +2380,12 @@ enum nl80211_key_type {
* enum nl80211_mfp - Management frame protection state
* @NL80211_MFP_NO: Management frame protection not used
* @NL80211_MFP_REQUIRED: Management frame protection required
+ * @NL80211_MFP_OPTIONAL: Management frame protection enabled, but not required
*/
enum nl80211_mfp {
NL80211_MFP_NO,
NL80211_MFP_REQUIRED,
+ NL80211_MFP_OPTIONAL,
};
enum nl80211_wpa_versions {
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index a98830b..f9e658b 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1056,7 +1056,7 @@ struct cfg80211_auth_request {
* @bss: The BSS to associate with.
* @ie: Extra IEs to add to (Re)Association Request frame or %NULL
* @ie_len: Length of ie buffer in octets
- * @use_mfp: Use management frame protection (IEEE 802.11w) in this association
+ * @mfp: indicate whether management frame protection is used
* @crypto: crypto settings
* @prev_bssid: previous BSSID, if not %NULL use reassociate frame
*/
@@ -1065,7 +1065,7 @@ struct cfg80211_assoc_request {
const u8 *ie, *prev_bssid;
size_t ie_len;
struct cfg80211_crypto_settings crypto;
- bool use_mfp;
+ enum nl80211_mfp mfp;
};
/**
@@ -1160,6 +1160,7 @@ struct cfg80211_ibss_params {
* @ie: IEs for association request
* @ie_len: Length of assoc_ie in octets
* @privacy: indicates whether privacy-enabled APs should be used
+ * @mfp: indicate whether management frame protection is used
* @crypto: crypto settings
* @key_len: length of WEP key for shared key authentication
* @key_idx: index of WEP key for shared key authentication
@@ -1176,6 +1177,7 @@ struct cfg80211_connect_params {
u8 *ie;
size_t ie_len;
bool privacy;
+ enum nl80211_mfp mfp;
struct cfg80211_crypto_settings crypto;
const u8 *key;
u8 key_len, key_idx;
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index a01e37f..9292440 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -406,11 +406,7 @@ struct ieee80211_if_managed {
bool beacon_crc_valid;
u32 beacon_crc;
- enum {
- IEEE80211_MFP_DISABLED,
- IEEE80211_MFP_OPTIONAL,
- IEEE80211_MFP_REQUIRED
- } mfp; /* management frame protection */
+ enum nl80211_mfp mfp; /* management frame protection */
int wmm_last_param_set;
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 9d1fb85..8838816 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -2704,13 +2704,11 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
else
wk->type = IEEE80211_WORK_ASSOC;
- if (req->use_mfp) {
- ifmgd->mfp = IEEE80211_MFP_REQUIRED;
- ifmgd->flags |= IEEE80211_STA_MFP_ENABLED;
- } else {
- ifmgd->mfp = IEEE80211_MFP_DISABLED;
- ifmgd->flags &= ~IEEE80211_STA_MFP_ENABLED;
- }
+ ifmgd->mfp = req->mfp;
+ if (req->mfp != NL80211_MFP_NO)
+ ifmgd->flags |= IEEE80211_STA_MFP_ENABLED;
+ else
+ ifmgd->flags &= ~IEEE80211_STA_MFP_ENABLED;
if (req->crypto.control_port)
ifmgd->flags |= IEEE80211_STA_CONTROL_PORT;
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 11ff6bb..61c92d3 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -339,13 +339,13 @@ int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
struct ieee80211_channel *chan,
const u8 *bssid, const u8 *prev_bssid,
const u8 *ssid, int ssid_len,
- const u8 *ie, int ie_len, bool use_mfp,
+ const u8 *ie, int ie_len, enum nl80211_mfp mfp,
struct cfg80211_crypto_settings *crypt);
int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
struct net_device *dev, struct ieee80211_channel *chan,
const u8 *bssid, const u8 *prev_bssid,
const u8 *ssid, int ssid_len,
- const u8 *ie, int ie_len, bool use_mfp,
+ const u8 *ie, int ie_len, enum nl80211_mfp mfp,
struct cfg80211_crypto_settings *crypt);
int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
struct net_device *dev, const u8 *bssid,
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index 4d74154..25abf54 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -506,7 +506,7 @@ int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
struct ieee80211_channel *chan,
const u8 *bssid, const u8 *prev_bssid,
const u8 *ssid, int ssid_len,
- const u8 *ie, int ie_len, bool use_mfp,
+ const u8 *ie, int ie_len, enum nl80211_mfp mfp,
struct cfg80211_crypto_settings *crypt)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
@@ -535,7 +535,7 @@ int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
req.ie = ie;
req.ie_len = ie_len;
memcpy(&req.crypto, crypt, sizeof(req.crypto));
- req.use_mfp = use_mfp;
+ req.mfp = mfp;
req.prev_bssid = prev_bssid;
req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
@@ -573,7 +573,7 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
struct ieee80211_channel *chan,
const u8 *bssid, const u8 *prev_bssid,
const u8 *ssid, int ssid_len,
- const u8 *ie, int ie_len, bool use_mfp,
+ const u8 *ie, int ie_len, enum nl80211_mfp mfp,
struct cfg80211_crypto_settings *crypt)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
@@ -581,7 +581,7 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
wdev_lock(wdev);
err = __cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid,
- ssid, ssid_len, ie, ie_len, use_mfp, crypt);
+ ssid, ssid_len, ie, ie_len, mfp, crypt);
wdev_unlock(wdev);
return err;
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 896d19b..0e69a75 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -4493,7 +4493,7 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
struct ieee80211_channel *chan;
const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL;
int err, ssid_len, ie_len = 0;
- bool use_mfp = false;
+ enum nl80211_mfp mfp;
if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
return -EINVAL;
@@ -4525,14 +4525,15 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
}
- if (info->attrs[NL80211_ATTR_USE_MFP]) {
- enum nl80211_mfp mfp =
- nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]);
- if (mfp == NL80211_MFP_REQUIRED)
- use_mfp = true;
- else if (mfp != NL80211_MFP_NO)
- return -EINVAL;
- }
+ if (info->attrs[NL80211_ATTR_USE_MFP]) {
+ mfp = nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]);
+ if (mfp != NL80211_MFP_REQUIRED &&
+ mfp != NL80211_MFP_OPTIONAL &&
+ mfp != NL80211_MFP_NO)
+ return -EINVAL;
+ }else{
+ mfp = NL80211_MFP_NO;
+ }
if (info->attrs[NL80211_ATTR_PREV_BSSID])
prev_bssid = nla_data(info->attrs[NL80211_ATTR_PREV_BSSID]);
@@ -4540,7 +4541,7 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
err = nl80211_crypto_settings(rdev, info, &crypto, 1);
if (!err)
err = cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid,
- ssid, ssid_len, ie, ie_len, use_mfp,
+ ssid, ssid_len, ie, ie_len, mfp,
&crypto);
return err;
@@ -5022,6 +5023,16 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
connect.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
}
+ if (info->attrs[NL80211_ATTR_USE_MFP]) {
+ connect.mfp = nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]);
+ if (connect.mfp != NL80211_MFP_REQUIRED &&
+ connect.mfp != NL80211_MFP_OPTIONAL &&
+ connect.mfp != NL80211_MFP_NO)
+ return -EINVAL;
+ } else {
+ connect.mfp = NL80211_MFP_NO;
+ }
+
if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
connect.channel =
ieee80211_get_channel(wiphy,
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index 38d3248..f02e0bc 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -190,7 +190,9 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev)
prev_bssid,
params->ssid, params->ssid_len,
params->ie, params->ie_len,
- false, &params->crypto);
+ params->mfp,
+ &params->crypto);
+
if (err)
__cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid,
NULL, 0,
--
1.7.9.5