aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMax Stepanov <Max.Stepanov@intel.com>2013-08-27 12:56:13 -0400
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>2013-12-17 12:39:38 -0500
commite36e5433c98d0411af51683c53578e84dee42470 (patch)
tree204edc459a2218c98e410752d2785c66d24e188c
parent1f3b0ff8eccefb0a22398bb044fa12f7e3f6f058 (diff)
iwlwifi: mvm: add a generic cipher scheme support
This patch adds a cipher scheme support to extend a set of the supported ciphers. The driver reads a cipher scheme list TLV from FW image and passes it to mac80211 on hw registration. After the cipher schemes are registered the driver handles key installation and Tx/Rx calls related to the new ciphers. Signed-off-by: Max Stepanov <Max.Stepanov@intel.com> Reviewed-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-drv.c39
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-fw-file.h1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-fw.h41
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h10
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h1
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api.h1
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mac80211.c13
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/rx.c6
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/sta.c8
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/tx.c3
10 files changed, 115 insertions, 8 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c
index ff570027e9dd..4bebfb58fc7b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-drv.c
+++ b/drivers/net/wireless/iwlwifi/iwl-drv.c
@@ -322,6 +322,41 @@ static void set_sec_offset(struct iwl_firmware_pieces *pieces,
322 pieces->img[type].sec[sec].offset = offset; 322 pieces->img[type].sec[sec].offset = offset;
323} 323}
324 324
325static int iwl_store_cscheme(struct iwl_fw *fw, const u8 *data, const u32 len)
326{
327 int i, j;
328 struct iwl_fw_cscheme_list *l = (struct iwl_fw_cscheme_list *)data;
329 struct iwl_fw_cipher_scheme *fwcs;
330 struct ieee80211_cipher_scheme *cs;
331 u32 cipher;
332
333 if (len < sizeof(*l) ||
334 len < sizeof(l->size) + l->size * sizeof(l->cs[0]))
335 return -EINVAL;
336
337 for (i = 0, j = 0; i < IWL_UCODE_MAX_CS && i < l->size; i++) {
338 fwcs = &l->cs[j];
339 cipher = le32_to_cpu(fwcs->cipher);
340
341 /* we skip schemes with zero cipher suite selector */
342 if (!cipher)
343 continue;
344
345 cs = &fw->cs[j++];
346 cs->cipher = cipher;
347 cs->iftype = BIT(NL80211_IFTYPE_STATION);
348 cs->hdr_len = fwcs->hdr_len;
349 cs->pn_len = fwcs->pn_len;
350 cs->pn_off = fwcs->pn_off;
351 cs->key_idx_off = fwcs->key_idx_off;
352 cs->key_idx_mask = fwcs->key_idx_mask;
353 cs->key_idx_shift = fwcs->key_idx_shift;
354 cs->mic_len = fwcs->mic_len;
355 }
356
357 return 0;
358}
359
325/* 360/*
326 * Gets uCode section from tlv. 361 * Gets uCode section from tlv.
327 */ 362 */
@@ -729,6 +764,10 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
729 return -EINVAL; 764 return -EINVAL;
730 } 765 }
731 break; 766 break;
767 case IWL_UCODE_TLV_CSCHEME:
768 if (iwl_store_cscheme(&drv->fw, tlv_data, tlv_len))
769 goto invalid_tlv_len;
770 break;
732 default: 771 default:
733 IWL_DEBUG_INFO(drv, "unknown TLV: %d\n", tlv_type); 772 IWL_DEBUG_INFO(drv, "unknown TLV: %d\n", tlv_type);
734 break; 773 break;
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h
index 6c6c35c5228c..4f95734b2811 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h
@@ -125,6 +125,7 @@ enum iwl_ucode_tlv_type {
125 IWL_UCODE_TLV_SECURE_SEC_INIT = 25, 125 IWL_UCODE_TLV_SECURE_SEC_INIT = 25,
126 IWL_UCODE_TLV_SECURE_SEC_WOWLAN = 26, 126 IWL_UCODE_TLV_SECURE_SEC_WOWLAN = 26,
127 IWL_UCODE_TLV_NUM_OF_CPU = 27, 127 IWL_UCODE_TLV_NUM_OF_CPU = 27,
128 IWL_UCODE_TLV_CSCHEME = 28,
128}; 129};
129 130
130struct iwl_ucode_tlv { 131struct iwl_ucode_tlv {
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h
index 75db087120c3..b2a4c1d51c0e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw.h
@@ -209,6 +209,44 @@ enum iwl_fw_phy_cfg {
209 FW_PHY_CFG_RX_CHAIN = 0xf << FW_PHY_CFG_RX_CHAIN_POS, 209 FW_PHY_CFG_RX_CHAIN = 0xf << FW_PHY_CFG_RX_CHAIN_POS,
210}; 210};
211 211
212#define IWL_UCODE_MAX_CS 1
213
214/**
215 * struct iwl_fw_cipher_scheme - a cipher scheme supported by FW.
216 * @cipher: a cipher suite selector
217 * @flags: cipher scheme flags (currently reserved for a future use)
218 * @hdr_len: a size of MPDU security header
219 * @pn_len: a size of PN
220 * @pn_off: an offset of pn from the beginning of the security header
221 * @key_idx_off: an offset of key index byte in the security header
222 * @key_idx_mask: a bit mask of key_idx bits
223 * @key_idx_shift: bit shift needed to get key_idx
224 * @mic_len: mic length in bytes
225 * @hw_cipher: a HW cipher index used in host commands
226 */
227struct iwl_fw_cipher_scheme {
228 __le32 cipher;
229 u8 flags;
230 u8 hdr_len;
231 u8 pn_len;
232 u8 pn_off;
233 u8 key_idx_off;
234 u8 key_idx_mask;
235 u8 key_idx_shift;
236 u8 mic_len;
237 u8 hw_cipher;
238} __packed;
239
240/**
241 * struct iwl_fw_cscheme_list - a cipher scheme list
242 * @size: a number of entries
243 * @cs: cipher scheme entries
244 */
245struct iwl_fw_cscheme_list {
246 u8 size;
247 struct iwl_fw_cipher_scheme cs[];
248} __packed;
249
212/** 250/**
213 * struct iwl_fw - variables associated with the firmware 251 * struct iwl_fw - variables associated with the firmware
214 * 252 *
@@ -224,6 +262,7 @@ enum iwl_fw_phy_cfg {
224 * @inst_evtlog_size: event log size for runtime ucode. 262 * @inst_evtlog_size: event log size for runtime ucode.
225 * @inst_errlog_ptr: error log offfset for runtime ucode. 263 * @inst_errlog_ptr: error log offfset for runtime ucode.
226 * @mvm_fw: indicates this is MVM firmware 264 * @mvm_fw: indicates this is MVM firmware
265 * @cipher_scheme: optional external cipher scheme.
227 */ 266 */
228struct iwl_fw { 267struct iwl_fw {
229 u32 ucode_ver; 268 u32 ucode_ver;
@@ -243,6 +282,8 @@ struct iwl_fw {
243 u32 phy_config; 282 u32 phy_config;
244 283
245 bool mvm_fw; 284 bool mvm_fw;
285
286 struct ieee80211_cipher_scheme cs[IWL_UCODE_MAX_CS];
246}; 287};
247 288
248static inline u8 iwl_fw_valid_tx_ant(const struct iwl_fw *fw) 289static inline u8 iwl_fw_valid_tx_ant(const struct iwl_fw *fw)
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h
index 4aca5933a65d..8c73ba74b6fd 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h
@@ -138,7 +138,14 @@ enum iwl_sta_flags {
138 138
139/** 139/**
140 * enum iwl_sta_key_flag - key flags for the ADD_STA host command 140 * enum iwl_sta_key_flag - key flags for the ADD_STA host command
141 * @STA_KEY_FLG_EN_MSK: mask for encryption algorithm 141 * @STA_KEY_FLG_NO_ENC: no encryption
142 * @STA_KEY_FLG_WEP: WEP encryption algorithm
143 * @STA_KEY_FLG_CCM: CCMP encryption algorithm
144 * @STA_KEY_FLG_TKIP: TKIP encryption algorithm
145 * @STA_KEY_FLG_EXT: extended cipher algorithm (depends on the FW support)
146 * @STA_KEY_FLG_CMAC: CMAC encryption algorithm
147 * @STA_KEY_FLG_ENC_UNKNOWN: unknown encryption algorithm
148 * @STA_KEY_FLG_EN_MSK: mask for encryption algorithmi value
142 * @STA_KEY_FLG_WEP_KEY_MAP: wep is either a group key (0 - legacy WEP) or from 149 * @STA_KEY_FLG_WEP_KEY_MAP: wep is either a group key (0 - legacy WEP) or from
143 * station info array (1 - n 1X mode) 150 * station info array (1 - n 1X mode)
144 * @STA_KEY_FLG_KEYID_MSK: the index of the key 151 * @STA_KEY_FLG_KEYID_MSK: the index of the key
@@ -152,6 +159,7 @@ enum iwl_sta_key_flag {
152 STA_KEY_FLG_WEP = (1 << 0), 159 STA_KEY_FLG_WEP = (1 << 0),
153 STA_KEY_FLG_CCM = (2 << 0), 160 STA_KEY_FLG_CCM = (2 << 0),
154 STA_KEY_FLG_TKIP = (3 << 0), 161 STA_KEY_FLG_TKIP = (3 << 0),
162 STA_KEY_FLG_EXT = (4 << 0),
155 STA_KEY_FLG_CMAC = (6 << 0), 163 STA_KEY_FLG_CMAC = (6 << 0),
156 STA_KEY_FLG_ENC_UNKNOWN = (7 << 0), 164 STA_KEY_FLG_ENC_UNKNOWN = (7 << 0),
157 STA_KEY_FLG_EN_MSK = (7 << 0), 165 STA_KEY_FLG_EN_MSK = (7 << 0),
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h
index d606197bde8f..22864671d66c 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h
@@ -132,6 +132,7 @@ enum iwl_tx_flags {
132#define TX_CMD_SEC_WEP 0x01 132#define TX_CMD_SEC_WEP 0x01
133#define TX_CMD_SEC_CCM 0x02 133#define TX_CMD_SEC_CCM 0x02
134#define TX_CMD_SEC_TKIP 0x03 134#define TX_CMD_SEC_TKIP 0x03
135#define TX_CMD_SEC_EXT 0x04
135#define TX_CMD_SEC_MSK 0x07 136#define TX_CMD_SEC_MSK 0x07
136#define TX_CMD_SEC_WEP_KEY_IDX_POS 6 137#define TX_CMD_SEC_WEP_KEY_IDX_POS 6
137#define TX_CMD_SEC_WEP_KEY_IDX_MSK 0xc0 138#define TX_CMD_SEC_WEP_KEY_IDX_MSK 0xc0
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h
index 3af413386ad9..c9cfaadc40a2 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h
@@ -1053,6 +1053,7 @@ enum iwl_mvm_rx_status {
1053 RX_MPDU_RES_STATUS_SEC_WEP_ENC = (1 << 8), 1053 RX_MPDU_RES_STATUS_SEC_WEP_ENC = (1 << 8),
1054 RX_MPDU_RES_STATUS_SEC_CCM_ENC = (2 << 8), 1054 RX_MPDU_RES_STATUS_SEC_CCM_ENC = (2 << 8),
1055 RX_MPDU_RES_STATUS_SEC_TKIP_ENC = (3 << 8), 1055 RX_MPDU_RES_STATUS_SEC_TKIP_ENC = (3 << 8),
1056 RX_MPDU_RES_STATUS_SEC_EXT_ENC = (4 << 8),
1056 RX_MPDU_RES_STATUS_SEC_CCM_CMAC_ENC = (6 << 8), 1057 RX_MPDU_RES_STATUS_SEC_CCM_CMAC_ENC = (6 << 8),
1057 RX_MPDU_RES_STATUS_SEC_ENC_ERR = (7 << 8), 1058 RX_MPDU_RES_STATUS_SEC_ENC_ERR = (7 << 8),
1058 RX_MPDU_RES_STATUS_SEC_ENC_MSK = (7 << 8), 1059 RX_MPDU_RES_STATUS_SEC_ENC_MSK = (7 << 8),
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
index f0f8b2c7ebef..8a99ecc2c588 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
@@ -261,6 +261,12 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
261 261
262 mvm->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD; 262 mvm->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD;
263 263
264 /* currently FW API supports only one optional cipher scheme */
265 if (mvm->fw->cs && mvm->fw->cs->cipher) {
266 mvm->hw->n_cipher_schemes = 1;
267 mvm->hw->cipher_schemes = mvm->fw->cs;
268 }
269
264#ifdef CONFIG_PM_SLEEP 270#ifdef CONFIG_PM_SLEEP
265 if (mvm->fw->img[IWL_UCODE_WOWLAN].sec[0].len && 271 if (mvm->fw->img[IWL_UCODE_WOWLAN].sec[0].len &&
266 mvm->trans->ops->d3_suspend && 272 mvm->trans->ops->d3_suspend &&
@@ -1342,7 +1348,12 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
1342 */ 1348 */
1343 return 0; 1349 return 0;
1344 default: 1350 default:
1345 return -EOPNOTSUPP; 1351 /* currently FW supports only one optional cipher scheme */
1352 if (hw->n_cipher_schemes &&
1353 hw->cipher_schemes->cipher == key->cipher)
1354 key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE;
1355 else
1356 return -EOPNOTSUPP;
1346 } 1357 }
1347 1358
1348 mutex_lock(&mvm->mutex); 1359 mutex_lock(&mvm->mutex);
diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c
index 3a1f3982109d..454341cc3b27 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rx.c
+++ b/drivers/net/wireless/iwlwifi/mvm/rx.c
@@ -251,6 +251,12 @@ static u32 iwl_mvm_set_mac80211_rx_flag(struct iwl_mvm *mvm,
251 stats->flag |= RX_FLAG_DECRYPTED; 251 stats->flag |= RX_FLAG_DECRYPTED;
252 return 0; 252 return 0;
253 253
254 case RX_MPDU_RES_STATUS_SEC_EXT_ENC:
255 if (!(rx_pkt_status & RX_MPDU_RES_STATUS_MIC_OK))
256 return -1;
257 stats->flag |= RX_FLAG_DECRYPTED;
258 return 0;
259
254 default: 260 default:
255 IWL_ERR(mvm, "Unhandled alg: 0x%x\n", rx_pkt_status); 261 IWL_ERR(mvm, "Unhandled alg: 0x%x\n", rx_pkt_status);
256 } 262 }
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c
index 7a5b7473eafa..4ea00da54b05 100644
--- a/drivers/net/wireless/iwlwifi/mvm/sta.c
+++ b/drivers/net/wireless/iwlwifi/mvm/sta.c
@@ -1123,8 +1123,8 @@ static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm,
1123 memcpy(cmd.key, keyconf->key, keyconf->keylen); 1123 memcpy(cmd.key, keyconf->key, keyconf->keylen);
1124 break; 1124 break;
1125 default: 1125 default:
1126 WARN_ON(1); 1126 key_flags |= cpu_to_le16(STA_KEY_FLG_EXT);
1127 return -EINVAL; 1127 memcpy(cmd.key, keyconf->key, keyconf->keylen);
1128 } 1128 }
1129 1129
1130 if (!(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE)) 1130 if (!(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE))
@@ -1288,8 +1288,8 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
1288 0, NULL, CMD_SYNC); 1288 0, NULL, CMD_SYNC);
1289 break; 1289 break;
1290 default: 1290 default:
1291 IWL_ERR(mvm, "Unknown cipher %x\n", keyconf->cipher); 1291 ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf,
1292 ret = -EINVAL; 1292 sta_id, 0, NULL, CMD_SYNC);
1293 } 1293 }
1294 1294
1295 if (ret) 1295 if (ret)
diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c
index d87649ac88e1..735f86da7985 100644
--- a/drivers/net/wireless/iwlwifi/mvm/tx.c
+++ b/drivers/net/wireless/iwlwifi/mvm/tx.c
@@ -253,8 +253,7 @@ static void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm,
253 memcpy(&tx_cmd->key[3], keyconf->key, keyconf->keylen); 253 memcpy(&tx_cmd->key[3], keyconf->key, keyconf->keylen);
254 break; 254 break;
255 default: 255 default:
256 IWL_ERR(mvm, "Unknown encode cipher %x\n", keyconf->cipher); 256 tx_cmd->sec_ctl |= TX_CMD_SEC_EXT;
257 break;
258 } 257 }
259} 258}
260 259