diff options
author | Juuso Oikarinen <juuso.oikarinen@nokia.com> | 2009-10-08 14:56:19 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-10-27 16:47:48 -0400 |
commit | ac4e4ce54eb9cb4963a1d3d91fc65536d882ffb2 (patch) | |
tree | 7ce830794c7029ab65ecb00562e48d00acc98d87 /drivers | |
parent | 3b4be9e08abd8c390d13001f5dd55f64afa5ab93 (diff) |
wl1271: Security sequence number handling for TX (for WPA)
Add security sequence number handling to the driver TX data path needed
by WPA.
Signed-off-by: Juuso Oikarinen <juuso.oikarinen@nokia.com>
Reviewed-by: Kalle Valo <kalle.valo@nokia.com>
Signed-off-by: Luciano Coelho <luciano.coelho@nokia.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271.h | 5 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271_cmd.c | 11 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271_cmd.h | 3 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271_main.c | 13 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271_tx.c | 11 |
5 files changed, 38 insertions, 5 deletions
diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h index 55818f94017b..e575dcc9df27 100644 --- a/drivers/net/wireless/wl12xx/wl1271.h +++ b/drivers/net/wireless/wl12xx/wl1271.h | |||
@@ -337,6 +337,11 @@ struct wl1271 { | |||
337 | /* Pending TX frames */ | 337 | /* Pending TX frames */ |
338 | struct sk_buff *tx_frames[16]; | 338 | struct sk_buff *tx_frames[16]; |
339 | 339 | ||
340 | /* Security sequence number counters */ | ||
341 | u8 tx_security_last_seq; | ||
342 | u16 tx_security_seq_16; | ||
343 | u32 tx_security_seq_32; | ||
344 | |||
340 | /* FW Rx counter */ | 345 | /* FW Rx counter */ |
341 | u32 rx_counter; | 346 | u32 rx_counter; |
342 | 347 | ||
diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c index 2a4351ff54dc..1ee1b2b4dfa2 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c | |||
@@ -228,6 +228,10 @@ int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type, u8 dtim_interval, | |||
228 | 228 | ||
229 | join->ctrl |= wl->session_counter << WL1271_JOIN_CMD_TX_SESSION_OFFSET; | 229 | join->ctrl |= wl->session_counter << WL1271_JOIN_CMD_TX_SESSION_OFFSET; |
230 | 230 | ||
231 | /* reset TX security counters */ | ||
232 | wl->tx_security_last_seq = 0; | ||
233 | wl->tx_security_seq_16 = 0; | ||
234 | wl->tx_security_seq_32 = 0; | ||
231 | 235 | ||
232 | ret = wl1271_cmd_send(wl, CMD_START_JOIN, join, sizeof(*join)); | 236 | ret = wl1271_cmd_send(wl, CMD_START_JOIN, join, sizeof(*join)); |
233 | if (ret < 0) { | 237 | if (ret < 0) { |
@@ -759,7 +763,8 @@ out: | |||
759 | } | 763 | } |
760 | 764 | ||
761 | int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, | 765 | int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, |
762 | u8 key_size, const u8 *key, const u8 *addr) | 766 | u8 key_size, const u8 *key, const u8 *addr, |
767 | u32 tx_seq_32, u16 tx_seq_16) | ||
763 | { | 768 | { |
764 | struct wl1271_cmd_set_keys *cmd; | 769 | struct wl1271_cmd_set_keys *cmd; |
765 | int ret = 0; | 770 | int ret = 0; |
@@ -777,12 +782,14 @@ int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, | |||
777 | cmd->key_size = key_size; | 782 | cmd->key_size = key_size; |
778 | cmd->key_type = key_type; | 783 | cmd->key_type = key_type; |
779 | 784 | ||
785 | cmd->ac_seq_num16[0] = tx_seq_16; | ||
786 | cmd->ac_seq_num32[0] = tx_seq_32; | ||
787 | |||
780 | /* we have only one SSID profile */ | 788 | /* we have only one SSID profile */ |
781 | cmd->ssid_profile = 0; | 789 | cmd->ssid_profile = 0; |
782 | 790 | ||
783 | cmd->id = id; | 791 | cmd->id = id; |
784 | 792 | ||
785 | /* FIXME: this is from wl1251, needs to be checked */ | ||
786 | if (key_type == KEY_TKIP) { | 793 | if (key_type == KEY_TKIP) { |
787 | /* | 794 | /* |
788 | * We get the key in the following form: | 795 | * We get the key in the following form: |
diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.h b/drivers/net/wireless/wl12xx/wl1271_cmd.h index 951a8447a516..7c4d3aaaa819 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.h +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.h | |||
@@ -49,7 +49,8 @@ int wl1271_cmd_build_ps_poll(struct wl1271 *wl, u16 aid); | |||
49 | int wl1271_cmd_build_probe_req(struct wl1271 *wl, u8 *ssid, size_t ssid_len); | 49 | int wl1271_cmd_build_probe_req(struct wl1271 *wl, u8 *ssid, size_t ssid_len); |
50 | int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id); | 50 | int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id); |
51 | int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, | 51 | int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, |
52 | u8 key_size, const u8 *key, const u8 *addr); | 52 | u8 key_size, const u8 *key, const u8 *addr, |
53 | u32 tx_seq_32, u16 tx_seq_16); | ||
53 | 54 | ||
54 | enum wl1271_commands { | 55 | enum wl1271_commands { |
55 | CMD_INTERROGATE = 1, /*use this to read information elements*/ | 56 | CMD_INTERROGATE = 1, /*use this to read information elements*/ |
diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 27298b19d5bd..bedd19b57499 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c | |||
@@ -592,6 +592,9 @@ static void wl1271_op_stop(struct ieee80211_hw *hw) | |||
592 | wl->tx_blocks_available = 0; | 592 | wl->tx_blocks_available = 0; |
593 | wl->tx_results_count = 0; | 593 | wl->tx_results_count = 0; |
594 | wl->tx_packets_count = 0; | 594 | wl->tx_packets_count = 0; |
595 | wl->tx_security_last_seq = 0; | ||
596 | wl->tx_security_seq_16 = 0; | ||
597 | wl->tx_security_seq_32 = 0; | ||
595 | wl->time_offset = 0; | 598 | wl->time_offset = 0; |
596 | wl->session_counter = 0; | 599 | wl->session_counter = 0; |
597 | for (i = 0; i < NUM_TX_QUEUES; i++) | 600 | for (i = 0; i < NUM_TX_QUEUES; i++) |
@@ -823,6 +826,8 @@ static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, | |||
823 | struct wl1271 *wl = hw->priv; | 826 | struct wl1271 *wl = hw->priv; |
824 | const u8 *addr; | 827 | const u8 *addr; |
825 | int ret; | 828 | int ret; |
829 | u32 tx_seq_32 = 0; | ||
830 | u16 tx_seq_16 = 0; | ||
826 | u8 key_type; | 831 | u8 key_type; |
827 | 832 | ||
828 | static const u8 bcast_addr[ETH_ALEN] = | 833 | static const u8 bcast_addr[ETH_ALEN] = |
@@ -861,11 +866,15 @@ static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, | |||
861 | key_type = KEY_TKIP; | 866 | key_type = KEY_TKIP; |
862 | 867 | ||
863 | key_conf->hw_key_idx = key_conf->keyidx; | 868 | key_conf->hw_key_idx = key_conf->keyidx; |
869 | tx_seq_32 = wl->tx_security_seq_32; | ||
870 | tx_seq_16 = wl->tx_security_seq_16; | ||
864 | break; | 871 | break; |
865 | case ALG_CCMP: | 872 | case ALG_CCMP: |
866 | key_type = KEY_AES; | 873 | key_type = KEY_AES; |
867 | 874 | ||
868 | key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; | 875 | key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; |
876 | tx_seq_32 = wl->tx_security_seq_32; | ||
877 | tx_seq_16 = wl->tx_security_seq_16; | ||
869 | break; | 878 | break; |
870 | default: | 879 | default: |
871 | wl1271_error("Unknown key algo 0x%x", key_conf->alg); | 880 | wl1271_error("Unknown key algo 0x%x", key_conf->alg); |
@@ -879,7 +888,7 @@ static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, | |||
879 | ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE, | 888 | ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE, |
880 | key_conf->keyidx, key_type, | 889 | key_conf->keyidx, key_type, |
881 | key_conf->keylen, key_conf->key, | 890 | key_conf->keylen, key_conf->key, |
882 | addr); | 891 | addr, tx_seq_32, tx_seq_16); |
883 | if (ret < 0) { | 892 | if (ret < 0) { |
884 | wl1271_error("Could not add or replace key"); | 893 | wl1271_error("Could not add or replace key"); |
885 | goto out_sleep; | 894 | goto out_sleep; |
@@ -890,7 +899,7 @@ static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, | |||
890 | ret = wl1271_cmd_set_key(wl, KEY_REMOVE, | 899 | ret = wl1271_cmd_set_key(wl, KEY_REMOVE, |
891 | key_conf->keyidx, key_type, | 900 | key_conf->keyidx, key_type, |
892 | key_conf->keylen, key_conf->key, | 901 | key_conf->keylen, key_conf->key, |
893 | addr); | 902 | addr, 0, 0); |
894 | if (ret < 0) { | 903 | if (ret < 0) { |
895 | wl1271_error("Could not remove key"); | 904 | wl1271_error("Could not remove key"); |
896 | goto out_sleep; | 905 | goto out_sleep; |
diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.c b/drivers/net/wireless/wl12xx/wl1271_tx.c index 0c19688f4405..162f0267a20b 100644 --- a/drivers/net/wireless/wl12xx/wl1271_tx.c +++ b/drivers/net/wireless/wl12xx/wl1271_tx.c | |||
@@ -258,6 +258,7 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl, | |||
258 | struct ieee80211_tx_info *info; | 258 | struct ieee80211_tx_info *info; |
259 | struct sk_buff *skb; | 259 | struct sk_buff *skb; |
260 | u32 header_len; | 260 | u32 header_len; |
261 | u16 seq; | ||
261 | int id = result->id; | 262 | int id = result->id; |
262 | 263 | ||
263 | /* check for id legality */ | 264 | /* check for id legality */ |
@@ -284,6 +285,16 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl, | |||
284 | /* info->status.retry_count = result->ack_failures; */ | 285 | /* info->status.retry_count = result->ack_failures; */ |
285 | wl->stats.retry_count += result->ack_failures; | 286 | wl->stats.retry_count += result->ack_failures; |
286 | 287 | ||
288 | /* update security sequence number */ | ||
289 | seq = wl->tx_security_seq_16 + | ||
290 | (result->lsb_security_sequence_number - | ||
291 | wl->tx_security_last_seq); | ||
292 | wl->tx_security_last_seq = result->lsb_security_sequence_number; | ||
293 | |||
294 | if (seq < wl->tx_security_seq_16) | ||
295 | wl->tx_security_seq_32++; | ||
296 | wl->tx_security_seq_16 = seq; | ||
297 | |||
287 | /* get header len */ | 298 | /* get header len */ |
288 | if (info->control.hw_key && | 299 | if (info->control.hw_key && |
289 | info->control.hw_key->alg == ALG_TKIP) | 300 | info->control.hw_key->alg == ALG_TKIP) |