diff options
author | Max Stepanov <Max.Stepanov@intel.com> | 2013-08-27 12:56:13 -0400 |
---|---|---|
committer | Emmanuel Grumbach <emmanuel.grumbach@intel.com> | 2013-12-17 12:39:38 -0500 |
commit | e36e5433c98d0411af51683c53578e84dee42470 (patch) | |
tree | 204edc459a2218c98e410752d2785c66d24e188c | |
parent | 1f3b0ff8eccefb0a22398bb044fa12f7e3f6f058 (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.c | 39 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-fw-file.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-fw.h | 41 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h | 10 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/fw-api.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/mac80211.c | 13 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/rx.c | 6 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/sta.c | 8 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/tx.c | 3 |
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 | ||
325 | static 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 | ||
130 | struct iwl_ucode_tlv { | 131 | struct 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 | */ | ||
227 | struct 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 | */ | ||
245 | struct 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 | */ |
228 | struct iwl_fw { | 267 | struct 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 | ||
248 | static inline u8 iwl_fw_valid_tx_ant(const struct iwl_fw *fw) | 289 | static 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 | ||