wl1271: Security sequence number handling for TX (for WPA)
authorJuuso Oikarinen <juuso.oikarinen@nokia.com>
Thu, 8 Oct 2009 18:56:19 +0000 (21:56 +0300)
committerJohn W. Linville <linville@tuxdriver.com>
Tue, 27 Oct 2009 20:47:48 +0000 (16:47 -0400)
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>
drivers/net/wireless/wl12xx/wl1271.h
drivers/net/wireless/wl12xx/wl1271_cmd.c
drivers/net/wireless/wl12xx/wl1271_cmd.h
drivers/net/wireless/wl12xx/wl1271_main.c
drivers/net/wireless/wl12xx/wl1271_tx.c

index 55818f9..e575dcc 100644 (file)
@@ -337,6 +337,11 @@ struct wl1271 {
        /* Pending TX frames */
        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 */
        u32 rx_counter;
 
index 2a4351f..1ee1b2b 100644 (file)
@@ -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;
 
+       /* 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));
        if (ret < 0) {
@@ -759,7 +763,8 @@ out:
 }
 
 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;
        int ret = 0;
@@ -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_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 */
        cmd->ssid_profile = 0;
 
        cmd->id = id;
 
-       /* FIXME: this is from wl1251, needs to be checked */
        if (key_type == KEY_TKIP) {
                /*
                 * We get the key in the following form:
index 951a844..7c4d3aa 100644 (file)
@@ -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_set_default_wep_key(struct wl1271 *wl, u8 id);
 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 {
        CMD_INTERROGATE     = 1,    /*use this to read information elements*/
index 27298b1..bedd19b 100644 (file)
@@ -592,6 +592,9 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
        wl->tx_blocks_available = 0;
        wl->tx_results_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->session_counter = 0;
        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,
        struct wl1271 *wl = hw->priv;
        const u8 *addr;
        int ret;
+       u32 tx_seq_32 = 0;
+       u16 tx_seq_16 = 0;
        u8 key_type;
 
        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,
                key_type = KEY_TKIP;
 
                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;
        case ALG_CCMP:
                key_type = KEY_AES;
 
                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;
        default:
                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,
                ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE,
                                         key_conf->keyidx, key_type,
                                         key_conf->keylen, key_conf->key,
-                                        addr);
+                                        addr, tx_seq_32, tx_seq_16);
                if (ret < 0) {
                        wl1271_error("Could not add or replace key");
                        goto out_sleep;
@@ -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,
                                         key_conf->keyidx, key_type,
                                         key_conf->keylen, key_conf->key,
-                                        addr);
+                                        addr, 0, 0);
                if (ret < 0) {
                        wl1271_error("Could not remove key");
                        goto out_sleep;
index 0c19688..162f026 100644 (file)
@@ -258,6 +258,7 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
        struct ieee80211_tx_info *info;
        struct sk_buff *skb;
        u32 header_len;
+       u16 seq;
        int id = result->id;
 
        /* check for id legality */
@@ -284,6 +285,16 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
        /* info->status.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 */
        if (info->control.hw_key &&
            info->control.hw_key->alg == ALG_TKIP)