Commit ac4e4ce5 authored by Juuso Oikarinen's avatar Juuso Oikarinen Committed by John W. Linville

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: default avatarJuuso Oikarinen <juuso.oikarinen@nokia.com>
Reviewed-by: default avatarKalle Valo <kalle.valo@nokia.com>
Signed-off-by: default avatarLuciano Coelho <luciano.coelho@nokia.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 3b4be9e0
...@@ -337,6 +337,11 @@ struct wl1271 { ...@@ -337,6 +337,11 @@ struct wl1271 {
/* Pending TX frames */ /* Pending TX frames */
struct sk_buff *tx_frames[16]; struct sk_buff *tx_frames[16];
/* Security sequence number counters */
u8 tx_security_last_seq;
u16 tx_security_seq_16;
u32 tx_security_seq_32;
/* FW Rx counter */ /* FW Rx counter */
u32 rx_counter; u32 rx_counter;
......
...@@ -228,6 +228,10 @@ int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type, u8 dtim_interval, ...@@ -228,6 +228,10 @@ int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type, u8 dtim_interval,
join->ctrl |= wl->session_counter << WL1271_JOIN_CMD_TX_SESSION_OFFSET; join->ctrl |= wl->session_counter << WL1271_JOIN_CMD_TX_SESSION_OFFSET;
/* reset TX security counters */
wl->tx_security_last_seq = 0;
wl->tx_security_seq_16 = 0;
wl->tx_security_seq_32 = 0;
ret = wl1271_cmd_send(wl, CMD_START_JOIN, join, sizeof(*join)); ret = wl1271_cmd_send(wl, CMD_START_JOIN, join, sizeof(*join));
if (ret < 0) { if (ret < 0) {
...@@ -759,7 +763,8 @@ int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id) ...@@ -759,7 +763,8 @@ int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id)
} }
int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
u8 key_size, const u8 *key, const u8 *addr) u8 key_size, const u8 *key, const u8 *addr,
u32 tx_seq_32, u16 tx_seq_16)
{ {
struct wl1271_cmd_set_keys *cmd; struct wl1271_cmd_set_keys *cmd;
int ret = 0; int ret = 0;
...@@ -777,12 +782,14 @@ int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, ...@@ -777,12 +782,14 @@ int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
cmd->key_size = key_size; cmd->key_size = key_size;
cmd->key_type = key_type; cmd->key_type = key_type;
cmd->ac_seq_num16[0] = tx_seq_16;
cmd->ac_seq_num32[0] = tx_seq_32;
/* we have only one SSID profile */ /* we have only one SSID profile */
cmd->ssid_profile = 0; cmd->ssid_profile = 0;
cmd->id = id; cmd->id = id;
/* FIXME: this is from wl1251, needs to be checked */
if (key_type == KEY_TKIP) { if (key_type == KEY_TKIP) {
/* /*
* We get the key in the following form: * We get the key in the following form:
......
...@@ -49,7 +49,8 @@ int wl1271_cmd_build_ps_poll(struct wl1271 *wl, u16 aid); ...@@ -49,7 +49,8 @@ int wl1271_cmd_build_ps_poll(struct wl1271 *wl, u16 aid);
int wl1271_cmd_build_probe_req(struct wl1271 *wl, u8 *ssid, size_t ssid_len); int wl1271_cmd_build_probe_req(struct wl1271 *wl, u8 *ssid, size_t ssid_len);
int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id); int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id);
int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
u8 key_size, const u8 *key, const u8 *addr); u8 key_size, const u8 *key, const u8 *addr,
u32 tx_seq_32, u16 tx_seq_16);
enum wl1271_commands { enum wl1271_commands {
CMD_INTERROGATE = 1, /*use this to read information elements*/ CMD_INTERROGATE = 1, /*use this to read information elements*/
......
...@@ -592,6 +592,9 @@ static void wl1271_op_stop(struct ieee80211_hw *hw) ...@@ -592,6 +592,9 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
wl->tx_blocks_available = 0; wl->tx_blocks_available = 0;
wl->tx_results_count = 0; wl->tx_results_count = 0;
wl->tx_packets_count = 0; wl->tx_packets_count = 0;
wl->tx_security_last_seq = 0;
wl->tx_security_seq_16 = 0;
wl->tx_security_seq_32 = 0;
wl->time_offset = 0; wl->time_offset = 0;
wl->session_counter = 0; wl->session_counter = 0;
for (i = 0; i < NUM_TX_QUEUES; i++) 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,6 +826,8 @@ static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
struct wl1271 *wl = hw->priv; struct wl1271 *wl = hw->priv;
const u8 *addr; const u8 *addr;
int ret; int ret;
u32 tx_seq_32 = 0;
u16 tx_seq_16 = 0;
u8 key_type; u8 key_type;
static const u8 bcast_addr[ETH_ALEN] = 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,11 +866,15 @@ static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
key_type = KEY_TKIP; key_type = KEY_TKIP;
key_conf->hw_key_idx = key_conf->keyidx; key_conf->hw_key_idx = key_conf->keyidx;
tx_seq_32 = wl->tx_security_seq_32;
tx_seq_16 = wl->tx_security_seq_16;
break; break;
case ALG_CCMP: case ALG_CCMP:
key_type = KEY_AES; key_type = KEY_AES;
key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
tx_seq_32 = wl->tx_security_seq_32;
tx_seq_16 = wl->tx_security_seq_16;
break; break;
default: default:
wl1271_error("Unknown key algo 0x%x", key_conf->alg); 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,7 +888,7 @@ static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE, ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE,
key_conf->keyidx, key_type, key_conf->keyidx, key_type,
key_conf->keylen, key_conf->key, key_conf->keylen, key_conf->key,
addr); addr, tx_seq_32, tx_seq_16);
if (ret < 0) { if (ret < 0) {
wl1271_error("Could not add or replace key"); wl1271_error("Could not add or replace key");
goto out_sleep; goto out_sleep;
...@@ -890,7 +899,7 @@ static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, ...@@ -890,7 +899,7 @@ static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
ret = wl1271_cmd_set_key(wl, KEY_REMOVE, ret = wl1271_cmd_set_key(wl, KEY_REMOVE,
key_conf->keyidx, key_type, key_conf->keyidx, key_type,
key_conf->keylen, key_conf->key, key_conf->keylen, key_conf->key,
addr); addr, 0, 0);
if (ret < 0) { if (ret < 0) {
wl1271_error("Could not remove key"); wl1271_error("Could not remove key");
goto out_sleep; goto out_sleep;
......
...@@ -258,6 +258,7 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl, ...@@ -258,6 +258,7 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
struct ieee80211_tx_info *info; struct ieee80211_tx_info *info;
struct sk_buff *skb; struct sk_buff *skb;
u32 header_len; u32 header_len;
u16 seq;
int id = result->id; int id = result->id;
/* check for id legality */ /* check for id legality */
...@@ -284,6 +285,16 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl, ...@@ -284,6 +285,16 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
/* info->status.retry_count = result->ack_failures; */ /* info->status.retry_count = result->ack_failures; */
wl->stats.retry_count += result->ack_failures; wl->stats.retry_count += result->ack_failures;
/* update security sequence number */
seq = wl->tx_security_seq_16 +
(result->lsb_security_sequence_number -
wl->tx_security_last_seq);
wl->tx_security_last_seq = result->lsb_security_sequence_number;
if (seq < wl->tx_security_seq_16)
wl->tx_security_seq_32++;
wl->tx_security_seq_16 = seq;
/* get header len */ /* get header len */
if (info->control.hw_key && if (info->control.hw_key &&
info->control.hw_key->alg == ALG_TKIP) info->control.hw_key->alg == ALG_TKIP)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment