diff options
Diffstat (limited to 'net/mac80211/tkip.c')
-rw-r--r-- | net/mac80211/tkip.c | 115 |
1 files changed, 66 insertions, 49 deletions
diff --git a/net/mac80211/tkip.c b/net/mac80211/tkip.c index 757e4eb2baf..f49d00a4c7f 100644 --- a/net/mac80211/tkip.c +++ b/net/mac80211/tkip.c | |||
@@ -101,6 +101,7 @@ static void tkip_mixing_phase1(const u8 *tk, struct tkip_ctx *ctx, | |||
101 | p1k[4] += tkipS(p1k[3] ^ get_unaligned_le16(tk + 0 + j)) + i; | 101 | p1k[4] += tkipS(p1k[3] ^ get_unaligned_le16(tk + 0 + j)) + i; |
102 | } | 102 | } |
103 | ctx->state = TKIP_STATE_PHASE1_DONE; | 103 | ctx->state = TKIP_STATE_PHASE1_DONE; |
104 | ctx->p1k_iv32 = tsc_IV32; | ||
104 | } | 105 | } |
105 | 106 | ||
106 | static void tkip_mixing_phase2(const u8 *tk, struct tkip_ctx *ctx, | 107 | static void tkip_mixing_phase2(const u8 *tk, struct tkip_ctx *ctx, |
@@ -140,60 +141,80 @@ static void tkip_mixing_phase2(const u8 *tk, struct tkip_ctx *ctx, | |||
140 | /* Add TKIP IV and Ext. IV at @pos. @iv0, @iv1, and @iv2 are the first octets | 141 | /* Add TKIP IV and Ext. IV at @pos. @iv0, @iv1, and @iv2 are the first octets |
141 | * of the IV. Returns pointer to the octet following IVs (i.e., beginning of | 142 | * of the IV. Returns pointer to the octet following IVs (i.e., beginning of |
142 | * the packet payload). */ | 143 | * the packet payload). */ |
143 | u8 *ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key, u16 iv16) | 144 | u8 *ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key) |
144 | { | 145 | { |
145 | pos = write_tkip_iv(pos, iv16); | 146 | lockdep_assert_held(&key->u.tkip.txlock); |
147 | |||
148 | pos = write_tkip_iv(pos, key->u.tkip.tx.iv16); | ||
146 | *pos++ = (key->conf.keyidx << 6) | (1 << 5) /* Ext IV */; | 149 | *pos++ = (key->conf.keyidx << 6) | (1 << 5) /* Ext IV */; |
147 | put_unaligned_le32(key->u.tkip.tx.iv32, pos); | 150 | put_unaligned_le32(key->u.tkip.tx.iv32, pos); |
148 | return pos + 4; | 151 | return pos + 4; |
149 | } | 152 | } |
150 | 153 | ||
151 | void ieee80211_get_tkip_key(struct ieee80211_key_conf *keyconf, | 154 | static void ieee80211_compute_tkip_p1k(struct ieee80211_key *key, u32 iv32) |
152 | struct sk_buff *skb, enum ieee80211_tkip_key_type type, | ||
153 | u8 *outkey) | ||
154 | { | 155 | { |
155 | struct ieee80211_key *key = (struct ieee80211_key *) | 156 | struct ieee80211_sub_if_data *sdata = key->sdata; |
156 | container_of(keyconf, struct ieee80211_key, conf); | 157 | struct tkip_ctx *ctx = &key->u.tkip.tx; |
157 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | 158 | const u8 *tk = &key->conf.key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY]; |
158 | u8 *data; | ||
159 | const u8 *tk; | ||
160 | struct tkip_ctx *ctx; | ||
161 | u16 iv16; | ||
162 | u32 iv32; | ||
163 | 159 | ||
164 | data = (u8 *)hdr + ieee80211_hdrlen(hdr->frame_control); | 160 | lockdep_assert_held(&key->u.tkip.txlock); |
165 | iv16 = data[2] | (data[0] << 8); | 161 | |
166 | iv32 = get_unaligned_le32(&data[4]); | 162 | /* |
163 | * Update the P1K when the IV32 is different from the value it | ||
164 | * had when we last computed it (or when not initialised yet). | ||
165 | * This might flip-flop back and forth if packets are processed | ||
166 | * out-of-order due to the different ACs, but then we have to | ||
167 | * just compute the P1K more often. | ||
168 | */ | ||
169 | if (ctx->p1k_iv32 != iv32 || ctx->state == TKIP_STATE_NOT_INIT) | ||
170 | tkip_mixing_phase1(tk, ctx, sdata->vif.addr, iv32); | ||
171 | } | ||
167 | 172 | ||
168 | tk = &key->conf.key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY]; | 173 | void ieee80211_get_tkip_p1k_iv(struct ieee80211_key_conf *keyconf, |
169 | ctx = &key->u.tkip.tx; | 174 | u32 iv32, u16 *p1k) |
175 | { | ||
176 | struct ieee80211_key *key = (struct ieee80211_key *) | ||
177 | container_of(keyconf, struct ieee80211_key, conf); | ||
178 | struct tkip_ctx *ctx = &key->u.tkip.tx; | ||
179 | unsigned long flags; | ||
170 | 180 | ||
171 | #ifdef CONFIG_MAC80211_TKIP_DEBUG | 181 | spin_lock_irqsave(&key->u.tkip.txlock, flags); |
172 | printk(KERN_DEBUG "TKIP encrypt: iv16 = 0x%04x, iv32 = 0x%08x\n", | 182 | ieee80211_compute_tkip_p1k(key, iv32); |
173 | iv16, iv32); | 183 | memcpy(p1k, ctx->p1k, sizeof(ctx->p1k)); |
174 | 184 | spin_unlock_irqrestore(&key->u.tkip.txlock, flags); | |
175 | if (iv32 != ctx->iv32) { | 185 | } |
176 | printk(KERN_DEBUG "skb: iv32 = 0x%08x key: iv32 = 0x%08x\n", | 186 | EXPORT_SYMBOL(ieee80211_get_tkip_p1k_iv); |
177 | iv32, ctx->iv32); | ||
178 | printk(KERN_DEBUG "Wrap around of iv16 in the middle of a " | ||
179 | "fragmented packet\n"); | ||
180 | } | ||
181 | #endif | ||
182 | 187 | ||
183 | /* Update the p1k only when the iv16 in the packet wraps around, this | 188 | void ieee80211_get_tkip_rx_p1k(struct ieee80211_key_conf *keyconf, |
184 | * might occur after the wrap around of iv16 in the key in case of | 189 | const u8 *ta, u32 iv32, u16 *p1k) |
185 | * fragmented packets. */ | 190 | { |
186 | if (iv16 == 0 || ctx->state == TKIP_STATE_NOT_INIT) | 191 | const u8 *tk = &keyconf->key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY]; |
187 | tkip_mixing_phase1(tk, ctx, hdr->addr2, iv32); | 192 | struct tkip_ctx ctx; |
188 | 193 | ||
189 | if (type == IEEE80211_TKIP_P1_KEY) { | 194 | tkip_mixing_phase1(tk, &ctx, ta, iv32); |
190 | memcpy(outkey, ctx->p1k, sizeof(u16) * 5); | 195 | memcpy(p1k, ctx.p1k, sizeof(ctx.p1k)); |
191 | return; | 196 | } |
192 | } | 197 | EXPORT_SYMBOL(ieee80211_get_tkip_rx_p1k); |
193 | 198 | ||
194 | tkip_mixing_phase2(tk, ctx, iv16, outkey); | 199 | void ieee80211_get_tkip_p2k(struct ieee80211_key_conf *keyconf, |
200 | struct sk_buff *skb, u8 *p2k) | ||
201 | { | ||
202 | struct ieee80211_key *key = (struct ieee80211_key *) | ||
203 | container_of(keyconf, struct ieee80211_key, conf); | ||
204 | const u8 *tk = &key->conf.key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY]; | ||
205 | struct tkip_ctx *ctx = &key->u.tkip.tx; | ||
206 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | ||
207 | const u8 *data = (u8 *)hdr + ieee80211_hdrlen(hdr->frame_control); | ||
208 | u32 iv32 = get_unaligned_le32(&data[4]); | ||
209 | u16 iv16 = data[2] | (data[0] << 8); | ||
210 | unsigned long flags; | ||
211 | |||
212 | spin_lock_irqsave(&key->u.tkip.txlock, flags); | ||
213 | ieee80211_compute_tkip_p1k(key, iv32); | ||
214 | tkip_mixing_phase2(tk, ctx, iv16, p2k); | ||
215 | spin_unlock_irqrestore(&key->u.tkip.txlock, flags); | ||
195 | } | 216 | } |
196 | EXPORT_SYMBOL(ieee80211_get_tkip_key); | 217 | EXPORT_SYMBOL(ieee80211_get_tkip_p2k); |
197 | 218 | ||
198 | /* | 219 | /* |
199 | * Encrypt packet payload with TKIP using @key. @pos is a pointer to the | 220 | * Encrypt packet payload with TKIP using @key. @pos is a pointer to the |
@@ -204,19 +225,15 @@ EXPORT_SYMBOL(ieee80211_get_tkip_key); | |||
204 | */ | 225 | */ |
205 | int ieee80211_tkip_encrypt_data(struct crypto_cipher *tfm, | 226 | int ieee80211_tkip_encrypt_data(struct crypto_cipher *tfm, |
206 | struct ieee80211_key *key, | 227 | struct ieee80211_key *key, |
207 | u8 *pos, size_t payload_len, u8 *ta) | 228 | struct sk_buff *skb, |
229 | u8 *payload, size_t payload_len) | ||
208 | { | 230 | { |
209 | u8 rc4key[16]; | 231 | u8 rc4key[16]; |
210 | struct tkip_ctx *ctx = &key->u.tkip.tx; | ||
211 | const u8 *tk = &key->conf.key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY]; | ||
212 | |||
213 | /* Calculate per-packet key */ | ||
214 | if (ctx->iv16 == 0 || ctx->state == TKIP_STATE_NOT_INIT) | ||
215 | tkip_mixing_phase1(tk, ctx, ta, ctx->iv32); | ||
216 | 232 | ||
217 | tkip_mixing_phase2(tk, ctx, ctx->iv16, rc4key); | 233 | ieee80211_get_tkip_p2k(&key->conf, skb, rc4key); |
218 | 234 | ||
219 | return ieee80211_wep_encrypt_data(tfm, rc4key, 16, pos, payload_len); | 235 | return ieee80211_wep_encrypt_data(tfm, rc4key, 16, |
236 | payload, payload_len); | ||
220 | } | 237 | } |
221 | 238 | ||
222 | /* Decrypt packet payload with TKIP using @key. @pos is a pointer to the | 239 | /* Decrypt packet payload with TKIP using @key. @pos is a pointer to the |