mwifiex: add WPA2 support for AP
authorAvinash Patil <patila@marvell.com>
Wed, 9 May 2012 01:30:26 +0000 (18:30 -0700)
committerJohn W. Linville <linville@tuxdriver.com>
Wed, 16 May 2012 16:46:36 +0000 (12:46 -0400)
1. Support for parsing security related parameters from
   cfg80211_ap_settings in start_ap cfg80211 handler
2. Conversion of these security information into FW understandle TLVs
   and setting into FW thru sys_config command
3. key management is done on host. This ensures that FW forwards EAPOL
   key packets to host instead of processing on its own.

Signed-off-by: Avinash Patil <patila@marvell.com>
Signed-off-by: Kiran Divekar <dkiran@marvell.com>
Signed-off-by: Bing Zhao <bzhao@marvell.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/mwifiex/cfg80211.c
drivers/net/wireless/mwifiex/fw.h
drivers/net/wireless/mwifiex/ioctl.h
drivers/net/wireless/mwifiex/main.h
drivers/net/wireless/mwifiex/uap_cmd.c

index e7882e56950d9334a05251b1fac476cb47cedeff..6c343218d9f0fbc4d38c6e878326524e1e873834 100644 (file)
@@ -950,6 +950,9 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy,
        struct mwifiex_uap_bss_param *bss_cfg;
        struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
 
+       if (priv->bss_type != MWIFIEX_BSS_TYPE_UAP)
+               return -1;
+
        bss_cfg = kzalloc(sizeof(struct mwifiex_uap_bss_param), GFP_KERNEL);
        if (!bss_cfg)
                return -ENOMEM;
@@ -966,6 +969,12 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy,
                bss_cfg->ssid.ssid_len = params->ssid_len;
        }
 
+       if (mwifiex_set_secure_params(priv, bss_cfg, params)) {
+               kfree(bss_cfg);
+               wiphy_err(wiphy, "Failed to parse secuirty parameters!\n");
+               return -1;
+       }
+
        if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_UAP_BSS_STOP,
                                  HostCmd_ACT_GEN_SET, 0, NULL)) {
                wiphy_err(wiphy, "Failed to stop the BSS\n");
index 77f82fc811e23dfcae244dd981b49efe282e27d9..57fd0ca6e42812b74249a9fc40ee6f2aa4f0b54f 100644 (file)
@@ -111,6 +111,9 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
 #define TLV_TYPE_UAP_BEACON_PERIOD  (PROPRIETARY_TLV_BASE_ID + 44)
 #define TLV_TYPE_UAP_DTIM_PERIOD    (PROPRIETARY_TLV_BASE_ID + 45)
 #define TLV_TYPE_UAP_RTS_THRESHOLD  (PROPRIETARY_TLV_BASE_ID + 51)
+#define TLV_TYPE_UAP_WPA_PASSPHRASE (PROPRIETARY_TLV_BASE_ID + 60)
+#define TLV_TYPE_UAP_ENCRY_PROTOCOL (PROPRIETARY_TLV_BASE_ID + 64)
+#define TLV_TYPE_UAP_AKMP           (PROPRIETARY_TLV_BASE_ID + 65)
 #define TLV_TYPE_UAP_FRAG_THRESHOLD (PROPRIETARY_TLV_BASE_ID + 70)
 #define TLV_TYPE_RATE_DROP_CONTROL  (PROPRIETARY_TLV_BASE_ID + 82)
 #define TLV_TYPE_RATE_SCOPE         (PROPRIETARY_TLV_BASE_ID + 83)
@@ -121,6 +124,8 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
 #define TLV_TYPE_MGMT_IE            (PROPRIETARY_TLV_BASE_ID + 105)
 #define TLV_TYPE_AUTO_DS_PARAM      (PROPRIETARY_TLV_BASE_ID + 113)
 #define TLV_TYPE_PS_PARAM           (PROPRIETARY_TLV_BASE_ID + 114)
+#define TLV_TYPE_PWK_CIPHER         (PROPRIETARY_TLV_BASE_ID + 145)
+#define TLV_TYPE_GWK_CIPHER         (PROPRIETARY_TLV_BASE_ID + 146)
 
 #define MWIFIEX_TX_DATA_BUF_SIZE_2K        2048
 
@@ -235,6 +240,19 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
 #define HostCmd_CMD_SET_BSS_MODE                      0x00f7
 #define HostCmd_CMD_PCIE_DESC_DETAILS                 0x00fa
 
+#define PROTOCOL_NO_SECURITY        0x01
+#define PROTOCOL_STATIC_WEP         0x02
+#define PROTOCOL_WPA                0x08
+#define PROTOCOL_WPA2               0x20
+#define PROTOCOL_WPA2_MIXED         0x28
+#define PROTOCOL_EAP                0x40
+#define KEY_MGMT_NONE               0x04
+#define KEY_MGMT_PSK                0x02
+#define KEY_MGMT_EAP                0x01
+#define CIPHER_TKIP                 0x04
+#define CIPHER_AES_CCMP             0x08
+#define VALID_CIPHER_BITMAP         0x0c
+
 enum ENH_PS_MODES {
        EN_PS = 1,
        DIS_PS = 2,
@@ -1139,6 +1157,41 @@ struct host_cmd_ds_sys_config {
        __le16 action;
        u8 tlv[0];
 };
+
+struct host_cmd_tlv_akmp {
+       struct host_cmd_tlv tlv;
+       __le16 key_mgmt;
+       __le16 key_mgmt_operation;
+} __packed;
+
+struct host_cmd_tlv_pwk_cipher {
+       struct host_cmd_tlv tlv;
+       __le16 proto;
+       u8 cipher;
+       u8 reserved;
+} __packed;
+
+struct host_cmd_tlv_gwk_cipher {
+       struct host_cmd_tlv tlv;
+       u8 cipher;
+       u8 reserved;
+} __packed;
+
+struct host_cmd_tlv_passphrase {
+       struct host_cmd_tlv tlv;
+       u8 passphrase[0];
+} __packed;
+
+struct host_cmd_tlv_auth_type {
+       struct host_cmd_tlv tlv;
+       u8 auth_type;
+} __packed;
+
+struct host_cmd_tlv_encrypt_protocol {
+       struct host_cmd_tlv tlv;
+       __le16 proto;
+} __packed;
+
 struct host_cmd_tlv_ssid {
        struct host_cmd_tlv tlv;
        u8 ssid[0];
index 99a7168022d08a039bc9b00dbdada955c3375d24..eb14f558b118e518311b45581de125048ea42778 100644 (file)
@@ -62,6 +62,17 @@ enum {
        BAND_AN = 16,
 };
 
+#define MWIFIEX_WPA_PASSHPHRASE_LEN 64
+struct wpa_param {
+       u8 pairwise_cipher_wpa;
+       u8 pairwise_cipher_wpa2;
+       u8 group_cipher;
+       u32 length;
+       u8 passphrase[MWIFIEX_WPA_PASSHPHRASE_LEN];
+};
+
+#define KEY_MGMT_ON_HOST        0x03
+#define MWIFIEX_AUTH_MODE_AUTO  0xFF
 #define BAND_CONFIG_MANUAL      0x00
 struct mwifiex_uap_bss_param {
        u8 channel;
@@ -74,6 +85,11 @@ struct mwifiex_uap_bss_param {
        u8 radio_ctl;
        u8 dtim_period;
        u16 beacon_period;
+       u16 auth_mode;
+       u16 protocol;
+       u16 key_mgmt;
+       u16 key_mgmt_operation;
+       struct wpa_param wpa_cfg;
 };
 
 enum {
index b0a8338d2c8a0ab3a07ecd5d78bceedb9efcbc55..824bd436c3ae1509df3f88c67fe465fc88217d33 100644 (file)
@@ -826,6 +826,9 @@ int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv,
 int is_command_pending(struct mwifiex_adapter *adapter);
 void mwifiex_init_priv_params(struct mwifiex_private *priv,
                                                struct net_device *dev);
+int mwifiex_set_secure_params(struct mwifiex_private *priv,
+                             struct mwifiex_uap_bss_param *bss_config,
+                             struct cfg80211_ap_settings *params);
 
 /*
  * This function checks if the queuing is RA based or not.
index 66047cff7eb77963945d5bb964061ab41a7c3bfb..0cfe88849e942982e72f9b89787f68e4b78280f1 100644 (file)
 
 #include "main.h"
 
+/* This function parses security related parameters from cfg80211_ap_settings
+ * and sets into FW understandable bss_config structure.
+ */
+int mwifiex_set_secure_params(struct mwifiex_private *priv,
+                             struct mwifiex_uap_bss_param *bss_config,
+                             struct cfg80211_ap_settings *params) {
+       int i;
+
+       switch (params->auth_type) {
+       case NL80211_AUTHTYPE_OPEN_SYSTEM:
+               bss_config->auth_mode = WLAN_AUTH_OPEN;
+               break;
+       case NL80211_AUTHTYPE_SHARED_KEY:
+               bss_config->auth_mode = WLAN_AUTH_SHARED_KEY;
+               break;
+       case NL80211_AUTHTYPE_NETWORK_EAP:
+               bss_config->auth_mode = WLAN_AUTH_LEAP;
+               break;
+       default:
+               bss_config->auth_mode = MWIFIEX_AUTH_MODE_AUTO;
+               break;
+       }
+
+       bss_config->key_mgmt_operation |= KEY_MGMT_ON_HOST;
+
+       for (i = 0; i < params->crypto.n_akm_suites; i++) {
+               switch (params->crypto.akm_suites[i]) {
+               case WLAN_AKM_SUITE_8021X:
+                       if (params->crypto.wpa_versions &
+                           NL80211_WPA_VERSION_1) {
+                               bss_config->protocol = PROTOCOL_WPA;
+                               bss_config->key_mgmt = KEY_MGMT_EAP;
+                       }
+                       if (params->crypto.wpa_versions &
+                           NL80211_WPA_VERSION_2) {
+                               bss_config->protocol = PROTOCOL_WPA2;
+                               bss_config->key_mgmt = KEY_MGMT_EAP;
+                       }
+                       break;
+               case WLAN_AKM_SUITE_PSK:
+                       if (params->crypto.wpa_versions &
+                           NL80211_WPA_VERSION_1) {
+                               bss_config->protocol = PROTOCOL_WPA;
+                               bss_config->key_mgmt = KEY_MGMT_PSK;
+                       }
+                       if (params->crypto.wpa_versions &
+                           NL80211_WPA_VERSION_2) {
+                               bss_config->protocol = PROTOCOL_WPA2;
+                               bss_config->key_mgmt = KEY_MGMT_PSK;
+                       }
+                       break;
+               default:
+                       break;
+               }
+       }
+       for (i = 0; i < params->crypto.n_ciphers_pairwise; i++) {
+               switch (params->crypto.ciphers_pairwise[i]) {
+               case WLAN_CIPHER_SUITE_WEP40:
+               case WLAN_CIPHER_SUITE_WEP104:
+                       break;
+               case WLAN_CIPHER_SUITE_TKIP:
+                       bss_config->wpa_cfg.pairwise_cipher_wpa = CIPHER_TKIP;
+                       break;
+               case WLAN_CIPHER_SUITE_CCMP:
+                       bss_config->wpa_cfg.pairwise_cipher_wpa2 =
+                                                               CIPHER_AES_CCMP;
+               default:
+                       break;
+               }
+       }
+
+       switch (params->crypto.cipher_group) {
+       case WLAN_CIPHER_SUITE_WEP40:
+       case WLAN_CIPHER_SUITE_WEP104:
+               break;
+       case WLAN_CIPHER_SUITE_TKIP:
+               bss_config->wpa_cfg.group_cipher = CIPHER_TKIP;
+               break;
+       case WLAN_CIPHER_SUITE_CCMP:
+               bss_config->wpa_cfg.group_cipher = CIPHER_AES_CCMP;
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
 /* This function initializes some of mwifiex_uap_bss_param variables.
  * This helps FW in ignoring invalid values. These values may or may not
  * be get updated to valid ones at later stage.
  */
 void mwifiex_set_sys_config_invalid_data(struct mwifiex_uap_bss_param *config)
 {
+       config->bcast_ssid_ctl = 0x7F;
+       config->radio_ctl = 0x7F;
+       config->dtim_period = 0x7F;
+       config->beacon_period = 0x7FFF;
+       config->auth_mode = 0x7F;
        config->rts_threshold = 0x7FFF;
        config->frag_threshold = 0x7FFF;
        config->retry_limit = 0x7F;
@@ -45,6 +138,12 @@ static int mwifiex_cmd_uap_sys_config(struct host_cmd_ds_command *cmd,
        struct host_cmd_tlv_frag_threshold *frag_threshold;
        struct host_cmd_tlv_rts_threshold *rts_threshold;
        struct host_cmd_tlv_retry_limit *retry_limit;
+       struct host_cmd_tlv_pwk_cipher *pwk_cipher;
+       struct host_cmd_tlv_gwk_cipher *gwk_cipher;
+       struct host_cmd_tlv_encrypt_protocol *encrypt_protocol;
+       struct host_cmd_tlv_auth_type *auth_type;
+       struct host_cmd_tlv_passphrase *passphrase;
+       struct host_cmd_tlv_akmp *tlv_akmp;
        struct mwifiex_uap_bss_param *bss_cfg = cmd_buf;
        u16 cmd_size;
 
@@ -131,6 +230,94 @@ static int mwifiex_cmd_uap_sys_config(struct host_cmd_ds_command *cmd,
                cmd_size += sizeof(struct host_cmd_tlv_retry_limit);
                tlv += sizeof(struct host_cmd_tlv_retry_limit);
        }
+       if ((bss_cfg->protocol & PROTOCOL_WPA) ||
+           (bss_cfg->protocol & PROTOCOL_WPA2) ||
+           (bss_cfg->protocol & PROTOCOL_EAP)) {
+               tlv_akmp = (struct host_cmd_tlv_akmp *)tlv;
+               tlv_akmp->tlv.type = cpu_to_le16(TLV_TYPE_UAP_AKMP);
+               tlv_akmp->tlv.len =
+                   cpu_to_le16(sizeof(struct host_cmd_tlv_akmp) -
+                               sizeof(struct host_cmd_tlv));
+               tlv_akmp->key_mgmt_operation =
+                       cpu_to_le16(bss_cfg->key_mgmt_operation);
+               tlv_akmp->key_mgmt = cpu_to_le16(bss_cfg->key_mgmt);
+               cmd_size += sizeof(struct host_cmd_tlv_akmp);
+               tlv += sizeof(struct host_cmd_tlv_akmp);
+
+               if (bss_cfg->wpa_cfg.pairwise_cipher_wpa &
+                               VALID_CIPHER_BITMAP) {
+                       pwk_cipher = (struct host_cmd_tlv_pwk_cipher *)tlv;
+                       pwk_cipher->tlv.type =
+                               cpu_to_le16(TLV_TYPE_PWK_CIPHER);
+                       pwk_cipher->tlv.len = cpu_to_le16(
+                               sizeof(struct host_cmd_tlv_pwk_cipher) -
+                               sizeof(struct host_cmd_tlv));
+                       pwk_cipher->proto = cpu_to_le16(PROTOCOL_WPA);
+                       pwk_cipher->cipher =
+                               bss_cfg->wpa_cfg.pairwise_cipher_wpa;
+                       cmd_size += sizeof(struct host_cmd_tlv_pwk_cipher);
+                       tlv += sizeof(struct host_cmd_tlv_pwk_cipher);
+               }
+               if (bss_cfg->wpa_cfg.pairwise_cipher_wpa2 &
+                               VALID_CIPHER_BITMAP) {
+                       pwk_cipher = (struct host_cmd_tlv_pwk_cipher *)tlv;
+                       pwk_cipher->tlv.type = cpu_to_le16(TLV_TYPE_PWK_CIPHER);
+                       pwk_cipher->tlv.len = cpu_to_le16(
+                               sizeof(struct host_cmd_tlv_pwk_cipher) -
+                               sizeof(struct host_cmd_tlv));
+                       pwk_cipher->proto = cpu_to_le16(PROTOCOL_WPA2);
+                       pwk_cipher->cipher =
+                               bss_cfg->wpa_cfg.pairwise_cipher_wpa2;
+                       cmd_size += sizeof(struct host_cmd_tlv_pwk_cipher);
+                       tlv += sizeof(struct host_cmd_tlv_pwk_cipher);
+               }
+               if (bss_cfg->wpa_cfg.group_cipher & VALID_CIPHER_BITMAP) {
+                       gwk_cipher = (struct host_cmd_tlv_gwk_cipher *)tlv;
+                       gwk_cipher->tlv.type = cpu_to_le16(TLV_TYPE_GWK_CIPHER);
+                       gwk_cipher->tlv.len = cpu_to_le16(
+                               sizeof(struct host_cmd_tlv_gwk_cipher) -
+                               sizeof(struct host_cmd_tlv));
+                       gwk_cipher->cipher = bss_cfg->wpa_cfg.group_cipher;
+                       cmd_size += sizeof(struct host_cmd_tlv_gwk_cipher);
+                       tlv += sizeof(struct host_cmd_tlv_gwk_cipher);
+               }
+               if (bss_cfg->wpa_cfg.length) {
+                       passphrase = (struct host_cmd_tlv_passphrase *)tlv;
+                       passphrase->tlv.type =
+                               cpu_to_le16(TLV_TYPE_UAP_WPA_PASSPHRASE);
+                       passphrase->tlv.len =
+                               cpu_to_le16(bss_cfg->wpa_cfg.length);
+                       memcpy(passphrase->passphrase,
+                              bss_cfg->wpa_cfg.passphrase,
+                              bss_cfg->wpa_cfg.length);
+                       cmd_size += sizeof(struct host_cmd_tlv) +
+                                   bss_cfg->wpa_cfg.length;
+                       tlv += sizeof(struct host_cmd_tlv) +
+                              bss_cfg->wpa_cfg.length;
+               }
+       }
+       if ((bss_cfg->auth_mode <= WLAN_AUTH_SHARED_KEY) ||
+           (bss_cfg->auth_mode == MWIFIEX_AUTH_MODE_AUTO)) {
+               auth_type = (struct host_cmd_tlv_auth_type *)tlv;
+               auth_type->tlv.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE);
+               auth_type->tlv.len =
+                       cpu_to_le16(sizeof(struct host_cmd_tlv_auth_type) -
+                       sizeof(struct host_cmd_tlv));
+               auth_type->auth_type = (u8)bss_cfg->auth_mode;
+               cmd_size += sizeof(struct host_cmd_tlv_auth_type);
+               tlv += sizeof(struct host_cmd_tlv_auth_type);
+       }
+       if (bss_cfg->protocol) {
+               encrypt_protocol = (struct host_cmd_tlv_encrypt_protocol *)tlv;
+               encrypt_protocol->tlv.type =
+                       cpu_to_le16(TLV_TYPE_UAP_ENCRY_PROTOCOL);
+               encrypt_protocol->tlv.len =
+                       cpu_to_le16(sizeof(struct host_cmd_tlv_encrypt_protocol)
+                       - sizeof(struct host_cmd_tlv));
+               encrypt_protocol->proto = cpu_to_le16(bss_cfg->protocol);
+               cmd_size += sizeof(struct host_cmd_tlv_encrypt_protocol);
+               tlv += sizeof(struct host_cmd_tlv_encrypt_protocol);
+       }
 
        cmd->size = cpu_to_le16(cmd_size);
        return 0;