xref: /OK3568_Linux_fs/kernel/drivers/net/wireless/rockchip_wlan/ssv6xxx/smac/sec_ccmp.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /*
2  * Copyright (c) 2015 South Silicon Valley Microelectronics Inc.
3  * Copyright (c) 2015 iComm Corporation
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12  * See the GNU General Public License for more details.
13  * You should have received a copy of the GNU General Public License
14  * along with this program. If not, see <http://www.gnu.org/licenses/>.
15  */
16 
17 #include <linux/kernel.h>
18 #include <linux/err.h>
19 #include <linux/init.h>
20 #include <linux/slab.h>
21 #include <linux/random.h>
22 #include <linux/skbuff.h>
23 #include <linux/netdevice.h>
24 #include <linux/if_ether.h>
25 #include <linux/if_arp.h>
26 #include <asm/string.h>
27 #include <linux/wireless.h>
28 #include <linux/ieee80211.h>
29 #include <linux/crypto.h>
30 #include <linux/module.h>
31 #include "sec.h"
32 #define PRINT_DEBUG 0
33 #define AES_BLOCK_LEN 16
34 #define CCMP_HDR_LEN 8
35 #define CCMP_MIC_LEN 8
36 #define CCMP_PN_LEN 6
37 #ifdef MULTI_THREAD_ENCRYPT
38 int prepare_mask = 0x0b0e0e0f;
39 #endif
40 struct lib80211_ccmp_data {
41  u8 key[CCMP_TK_LEN];
42  int key_set;
43  u8 tx_pn[CCMP_PN_LEN];
44  u8 rx_pn[CCMP_PN_LEN];
45 #ifdef MULTI_THREAD_ENCRYPT
46     u8 pre_rx_pn[CCMP_PN_LEN];
47 #endif
48  u32 dot11RSNAStatsCCMPFormatErrors;
49  u32 dot11RSNAStatsCCMPReplays;
50  u32 dot11RSNAStatsCCMPDecryptErrors;
51  int key_idx;
52  struct crypto_cipher *tfm;
53 #ifndef MULTI_THREAD_ENCRYPT
54  u8 tx_b0[AES_BLOCK_LEN], tx_b[AES_BLOCK_LEN],
55      tx_e[AES_BLOCK_LEN], tx_s0[AES_BLOCK_LEN];
56     u8 rx_b0[AES_BLOCK_LEN], rx_b[AES_BLOCK_LEN], rx_a[AES_BLOCK_LEN];
57 #else
58  u8 *tx_b0, *tx_b, *tx_e, *tx_s0;
59     u8 *rx_b0, *rx_b, *rx_a;
60 #endif
61 };
lib80211_ccmp_aes_encrypt(struct crypto_cipher * tfm,const u8 pt[16],u8 ct[16])62 static inline void lib80211_ccmp_aes_encrypt(struct crypto_cipher *tfm,
63            const u8 pt[16], u8 ct[16])
64 {
65  crypto_cipher_encrypt_one(tfm, ct, pt);
66 }
lib80211_ccmp_init(int key_idx)67 static void *lib80211_ccmp_init(int key_idx)
68 {
69  struct lib80211_ccmp_data *priv;
70  const char *cipher_name = "aes";
71 #ifdef MULTI_THREAD_ENCRYPT
72     unsigned int buf_size = num_present_cpus()*AES_BLOCK_LEN*sizeof(u8);
73 #endif
74  priv = kzalloc(sizeof(*priv), GFP_ATOMIC);
75  if (priv == NULL)
76   goto fail;
77  priv->key_idx = key_idx;
78  priv->tfm = crypto_alloc_cipher(cipher_name, 0, CRYPTO_ALG_ASYNC);
79  if (IS_ERR(priv->tfm)) {
80          printk(KERN_ERR "Failed to allocate cipher %s\n", cipher_name);
81   priv->tfm = NULL;
82   goto fail;
83  }
84  else
85  {
86      printk(KERN_ERR "Found %s in driver %s (M %s).\n",
87              priv->tfm->base.__crt_alg->cra_name,
88              priv->tfm->base.__crt_alg->cra_driver_name,
89              priv->tfm->base.__crt_alg->cra_module->name);
90  }
91 #ifdef MULTI_THREAD_ENCRYPT
92         priv->tx_b0 = priv->tx_b = priv->tx_e = priv->tx_s0 = NULL;
93         priv->tx_b0 = (u8 *)kzalloc(buf_size, GFP_ATOMIC);
94         priv->tx_b = (u8 *)kzalloc(buf_size, GFP_ATOMIC);
95         priv->tx_e = (u8 *)kzalloc(buf_size, GFP_ATOMIC);
96         priv->tx_s0 = (u8 *)kzalloc(buf_size, GFP_ATOMIC);
97         priv->rx_b0 = (u8 *)kzalloc(buf_size, GFP_ATOMIC);
98         priv->rx_b = (u8 *)kzalloc(buf_size, GFP_ATOMIC);
99         priv->rx_a = (u8 *)kzalloc(buf_size, GFP_ATOMIC);
100         if( (priv->tx_b0 == NULL) || (priv->tx_b == NULL) || (priv->tx_e == NULL) ||
101                 (priv->tx_s0 == NULL) ||(priv->rx_b0 == NULL) || (priv->rx_b == NULL) || (priv->rx_a == NULL) )
102         {
103             printk("#######fail to create memory for ccmp!!!\n");
104             goto fail;
105         }
106 #endif
107  return priv;
108       fail:
109  if (priv) {
110   if (priv->tfm)
111    crypto_free_cipher(priv->tfm);
112 #ifdef MULTI_THREAD_ENCRYPT
113         if(priv->tx_b0 != NULL)
114             kfree(priv->tx_b0);
115         if(priv->tx_b != NULL)
116             kfree(priv->tx_b);
117         if(priv->tx_e != NULL)
118             kfree(priv->tx_e);
119         if(priv->tx_s0 != NULL)
120             kfree(priv->tx_s0);
121         if(priv->rx_b0 != NULL)
122             kfree(priv->rx_b0);
123         if(priv->rx_b != NULL)
124             kfree(priv->rx_b);
125         if(priv->rx_a != NULL)
126             kfree(priv->rx_a);
127 #endif
128   kfree(priv);
129  }
130  return NULL;
131 }
lib80211_ccmp_deinit(void * priv)132 static void lib80211_ccmp_deinit(void *priv)
133 {
134  struct lib80211_ccmp_data *_priv = priv;
135  if (_priv && _priv->tfm)
136   crypto_free_cipher(_priv->tfm);
137 #ifdef MULTI_THREAD_ENCRYPT
138     if(_priv->tx_b0 != NULL)
139         kfree(_priv->tx_b0);
140     if(_priv->tx_b != NULL)
141         kfree(_priv->tx_b);
142     if(_priv->tx_e != NULL)
143         kfree(_priv->tx_e);
144     if(_priv->tx_s0 != NULL)
145         kfree(_priv->tx_s0);
146     if(_priv->rx_b0 != NULL)
147         kfree(_priv->rx_b0);
148     if(_priv->rx_b != NULL)
149         kfree(_priv->rx_b);
150     if(_priv->rx_a != NULL)
151         kfree(_priv->rx_a);
152 #endif
153  kfree(priv);
154 }
xor_block(u8 * b,u8 * a,size_t len)155 static inline void xor_block(u8 * b, u8 * a, size_t len)
156 {
157  int i;
158  for (i = 0; i < len; i++)
159   b[i] ^= a[i];
160 }
ccmp_init_blocks(struct crypto_cipher * tfm,struct ieee80211_hdr * hdr,u8 * pn,size_t dlen,u8 * b0,u8 * auth,u8 * s0)161 static void ccmp_init_blocks(struct crypto_cipher *tfm,
162         struct ieee80211_hdr *hdr,
163         u8 * pn, size_t dlen, u8 * b0, u8 * auth, u8 * s0)
164 {
165  u8 *pos, qc = 0;
166  size_t aad_len;
167  int a4_included, qc_included;
168  u8 aad[2 * AES_BLOCK_LEN];
169  a4_included = ieee80211_has_a4(hdr->frame_control);
170  qc_included = ieee80211_is_data_qos(hdr->frame_control);
171  aad_len = 22;
172  if (a4_included)
173   aad_len += 6;
174  if (qc_included) {
175   pos = (u8 *) & hdr->addr4;
176   if (a4_included)
177    pos += 6;
178   qc = *pos & 0x0f;
179   aad_len += 2;
180  }
181  b0[0] = 0x59;
182  b0[1] = qc;
183  memcpy(b0 + 2, hdr->addr2, ETH_ALEN);
184  memcpy(b0 + 8, pn, CCMP_PN_LEN);
185  b0[14] = (dlen >> 8) & 0xff;
186  b0[15] = dlen & 0xff;
187  pos = (u8 *) hdr;
188  aad[0] = 0;
189  aad[1] = aad_len & 0xff;
190  aad[2] = pos[0] & 0x8f;
191  aad[3] = pos[1] & 0xc7;
192  memcpy(aad + 4, hdr->addr1, 3 * ETH_ALEN);
193  pos = (u8 *) & hdr->seq_ctrl;
194  aad[22] = pos[0] & 0x0f;
195  aad[23] = 0;
196  memset(aad + 24, 0, 8);
197  if (a4_included)
198   memcpy(aad + 24, hdr->addr4, ETH_ALEN);
199  if (qc_included) {
200   aad[a4_included ? 30 : 24] = qc;
201  }
202  lib80211_ccmp_aes_encrypt(tfm, b0, auth);
203  xor_block(auth, aad, AES_BLOCK_LEN);
204  lib80211_ccmp_aes_encrypt(tfm, auth, auth);
205  xor_block(auth, &aad[AES_BLOCK_LEN], AES_BLOCK_LEN);
206  lib80211_ccmp_aes_encrypt(tfm, auth, auth);
207  b0[0] &= 0x07;
208  b0[14] = b0[15] = 0;
209  lib80211_ccmp_aes_encrypt(tfm, b0, s0);
210 }
lib80211_ccmp_hdr(struct sk_buff * skb,int hdr_len,u8 * aeskey,int keylen,void * priv)211 static int lib80211_ccmp_hdr(struct sk_buff *skb, int hdr_len,
212          u8 *aeskey, int keylen, void *priv)
213 {
214  struct lib80211_ccmp_data *key = priv;
215  int i;
216  u8 *pos;
217  if (skb_headroom(skb) < CCMP_HDR_LEN || skb->len < hdr_len)
218   return -1;
219  if (aeskey != NULL && keylen >= CCMP_TK_LEN)
220   memcpy(aeskey, key->key, CCMP_TK_LEN);
221  pos = skb_push(skb, CCMP_HDR_LEN);
222  memmove(pos, pos + CCMP_HDR_LEN, hdr_len);
223  pos += hdr_len;
224  i = CCMP_PN_LEN - 1;
225  while (i >= 0) {
226   key->tx_pn[i]++;
227   if (key->tx_pn[i] != 0)
228    break;
229   i--;
230  }
231  *pos++ = key->tx_pn[5];
232  *pos++ = key->tx_pn[4];
233  *pos++ = 0;
234  *pos++ = (key->key_idx << 6) | (1 << 5) ;
235  *pos++ = key->tx_pn[3];
236  *pos++ = key->tx_pn[2];
237  *pos++ = key->tx_pn[1];
238  *pos++ = key->tx_pn[0];
239  return CCMP_HDR_LEN;
240 }
lib80211_ccmp_encrypt(struct sk_buff * skb,int hdr_len,void * priv)241 static int lib80211_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
242 {
243  struct lib80211_ccmp_data *key = priv;
244  int data_len, i, blocks, last, len;
245  u8 *pos, *mic;
246  struct ieee80211_hdr *hdr;
247 #ifndef MULTI_THREAD_ENCRYPT
248  u8 *b0 = key->tx_b0;
249  u8 *b = key->tx_b;
250  u8 *e = key->tx_e;
251  u8 *s0 = key->tx_s0;
252  int ret;
253 #else
254  unsigned int offset = smp_processor_id()*AES_BLOCK_LEN*sizeof(u8);
255  u8 *b0 = (key->tx_b0 + offset);
256  u8 *b = (key->tx_b + offset);
257  u8 *e = (key->tx_e + offset);
258  u8 *s0 = (key->tx_s0 + offset);
259  u8 tmp_tx_pn[CCMP_PN_LEN], *ccmp_hdr_ptr = NULL;
260  void *mask_ptr = NULL;
261 #endif
262 #ifndef MULTI_THREAD_ENCRYPT
263  ret = skb_padto(skb, skb->len + CCMP_MIC_LEN);
264     if (ret)
265     {
266         printk(KERN_ERR "Failed to extand skb for CCMP encryption.");
267         return -1;
268     }
269  if (skb->len < hdr_len)
270   return -1;
271 #endif
272 #ifndef MULTI_THREAD_ENCRYPT
273     data_len = skb->len - hdr_len;
274  len = lib80211_ccmp_hdr(skb, hdr_len, NULL, 0, priv);
275  if (len < 0)
276   return -1;
277 #else
278  mask_ptr = (void *)((size_t)skb_end_pointer(skb) - sizeof(prepare_mask));
279  if(memcmp(mask_ptr, &prepare_mask, sizeof(prepare_mask)) != 0)
280  {
281   printk("no prepared skb\n");
282   return -1;
283  }
284  data_len = skb->len - (hdr_len + CCMP_HDR_LEN);
285  ccmp_hdr_ptr = (u8 *)(skb->data + hdr_len);
286  tmp_tx_pn[5] = ccmp_hdr_ptr[0];
287  tmp_tx_pn[4] = ccmp_hdr_ptr[1];
288  tmp_tx_pn[3] = ccmp_hdr_ptr[4];
289  tmp_tx_pn[2] = ccmp_hdr_ptr[5];
290  tmp_tx_pn[1] = ccmp_hdr_ptr[6];
291  tmp_tx_pn[0] = ccmp_hdr_ptr[7];
292 #endif
293  pos = skb->data + hdr_len + CCMP_HDR_LEN;
294  hdr = (struct ieee80211_hdr *)skb->data;
295 #ifndef MULTI_THREAD_ENCRYPT
296  ccmp_init_blocks(key->tfm, hdr, key->tx_pn, data_len, b0, b, s0);
297 #else
298  ccmp_init_blocks(key->tfm, hdr, tmp_tx_pn, data_len, b0, b, s0);
299 #endif
300  blocks = DIV_ROUND_UP(data_len, AES_BLOCK_LEN);
301  last = data_len % AES_BLOCK_LEN;
302  for (i = 1; i <= blocks; i++) {
303   len = (i == blocks && last) ? last : AES_BLOCK_LEN;
304   xor_block(b, pos, len);
305   lib80211_ccmp_aes_encrypt(key->tfm, b, b);
306   b0[14] = (i >> 8) & 0xff;
307   b0[15] = i & 0xff;
308   lib80211_ccmp_aes_encrypt(key->tfm, b0, e);
309   xor_block(pos, e, len);
310   pos += len;
311  }
312  mic = skb_put(skb, CCMP_MIC_LEN);
313  for (i = 0; i < CCMP_MIC_LEN; i++)
314   mic[i] = b[i] ^ s0[i];
315  return 0;
316 }
ccmp_replay_check(u8 * pn_n,u8 * pn_o)317 static inline int ccmp_replay_check(u8 *pn_n, u8 *pn_o)
318 {
319  u32 iv32_n, iv16_n;
320  u32 iv32_o, iv16_o;
321  iv32_n = (pn_n[0] << 24) | (pn_n[1] << 16) | (pn_n[2] << 8) | pn_n[3];
322  iv16_n = (pn_n[4] << 8) | pn_n[5];
323  iv32_o = (pn_o[0] << 24) | (pn_o[1] << 16) | (pn_o[2] << 8) | pn_o[3];
324  iv16_o = (pn_o[4] << 8) | pn_o[5];
325  if ((s32)iv32_n - (s32)iv32_o < 0 ||
326      (iv32_n == iv32_o && iv16_n <= iv16_o))
327   return 1;
328  return 0;
329 }
lib80211_ccmp_decrypt(struct sk_buff * skb,int hdr_len,void * priv)330 static int lib80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
331 {
332  struct lib80211_ccmp_data *key = priv;
333  u8 keyidx, *pos;
334  struct ieee80211_hdr *hdr;
335 #ifndef MULTI_THREAD_ENCRYPT
336  u8 *b0 = key->rx_b0;
337  u8 *b = key->rx_b;
338  u8 *a = key->rx_a;
339 #else
340     unsigned int offset = smp_processor_id()*AES_BLOCK_LEN*sizeof(u8);
341     u8 *b0 = (key->rx_b0 + offset);
342  u8 *b = (key->rx_b + offset);
343  u8 *a = (key->rx_a + offset);
344 #endif
345  u8 pn[6];
346  int i, blocks, last, len;
347  size_t data_len = skb->len - hdr_len - CCMP_HDR_LEN - CCMP_MIC_LEN;
348  u8 *mic = skb->data + skb->len - CCMP_MIC_LEN;
349 #ifndef MULTI_THREAD_ENCRYPT
350  if (skb->len < hdr_len + CCMP_HDR_LEN + CCMP_MIC_LEN) {
351   key->dot11RSNAStatsCCMPFormatErrors++;
352   return -1;
353  }
354 #endif
355  hdr = (struct ieee80211_hdr *)skb->data;
356  pos = skb->data + hdr_len;
357  keyidx = pos[3];
358 #ifndef MULTI_THREAD_ENCRYPT
359  if (!(keyidx & (1 << 5))) {
360   if (net_ratelimit()) {
361    printk(KERN_DEBUG "CCMP: received packet without ExtIV"
362           " flag from %pM (%02X)\n", hdr->addr2, keyidx);
363   }
364   key->dot11RSNAStatsCCMPFormatErrors++;
365   return -2;
366  }
367  keyidx >>= 6;
368  if (key->key_idx != keyidx) {
369   printk(KERN_DEBUG "CCMP: RX tkey->key_idx=%d frame "
370          "keyidx=%d priv=%p\n", key->key_idx, keyidx, priv);
371   return -6;
372  }
373  if (!key->key_set) {
374   if (net_ratelimit()) {
375    printk(KERN_DEBUG "CCMP: received packet from %pM"
376           " with keyid=%d that does not have a configured"
377           " key\n", hdr->addr2, keyidx);
378   }
379   return -3;
380  }
381 #endif
382  pn[0] = pos[7];
383  pn[1] = pos[6];
384  pn[2] = pos[5];
385  pn[3] = pos[4];
386  pn[4] = pos[1];
387  pn[5] = pos[0];
388  pos += 8;
389 #if 0
390  if (ccmp_replay_check(pn, key->rx_pn)) {
391 #ifdef CONFIG_LIB80211_DEBUG
392   if (net_ratelimit())
393         {
394    printk(KERN_DEBUG "CCMP: replay detected: STA=%pM "
395      "previous PN %02x%02x%02x%02x%02x%02x "
396      "received PN %02x%02x%02x%02x%02x%02x\n",
397      hdr->addr2,
398      key->rx_pn[0], key->rx_pn[1], key->rx_pn[2],
399      key->rx_pn[3], key->rx_pn[4], key->rx_pn[5],
400      pn[0], pn[1], pn[2], pn[3], pn[4], pn[5]);
401   }
402 #endif
403   key->dot11RSNAStatsCCMPReplays++;
404   return -4;
405  }
406 #endif
407  ccmp_init_blocks(key->tfm, hdr, pn, data_len, b0, a, b);
408  xor_block(mic, b, CCMP_MIC_LEN);
409  blocks = DIV_ROUND_UP(data_len, AES_BLOCK_LEN);
410  last = data_len % AES_BLOCK_LEN;
411  for (i = 1; i <= blocks; i++) {
412   len = (i == blocks && last) ? last : AES_BLOCK_LEN;
413   b0[14] = (i >> 8) & 0xff;
414   b0[15] = i & 0xff;
415   lib80211_ccmp_aes_encrypt(key->tfm, b0, b);
416   xor_block(pos, b, len);
417   xor_block(a, pos, len);
418   lib80211_ccmp_aes_encrypt(key->tfm, a, a);
419   pos += len;
420  }
421  if (memcmp(mic, a, CCMP_MIC_LEN) != 0) {
422   if (net_ratelimit()) {
423    printk(KERN_DEBUG "CCMP: decrypt failed: STA="
424           "%pM\n", hdr->addr2);
425   }
426   key->dot11RSNAStatsCCMPDecryptErrors++;
427   return -5;
428  }
429 #ifndef MULTI_THREAD_ENCRYPT
430  memcpy(key->rx_pn, pn, CCMP_PN_LEN);
431 #else
432     if (!ccmp_replay_check(pn, key->rx_pn))
433         memcpy(key->rx_pn, pn, CCMP_PN_LEN);
434 #endif
435  memmove(skb->data + CCMP_HDR_LEN, skb->data, hdr_len);
436  skb_pull(skb, CCMP_HDR_LEN);
437  skb_trim(skb, skb->len - CCMP_MIC_LEN);
438  return keyidx;
439 }
lib80211_ccmp_set_key(void * key,int len,u8 * seq,void * priv)440 static int lib80211_ccmp_set_key(void *key, int len, u8 * seq, void *priv)
441 {
442  struct lib80211_ccmp_data *data = priv;
443  int keyidx;
444  struct crypto_cipher *tfm = data->tfm;
445 #ifdef MULTI_THREAD_ENCRYPT
446  u8 *tx_b0 = data->tx_b0;
447  u8 *tx_b = data->tx_b;
448  u8 *tx_e = data->tx_e;
449  u8 *tx_s0 = data->tx_s0;
450     u8 *rx_b0 = data->rx_b0;
451  u8 *rx_b = data->rx_b;
452  u8 *rx_a = data->rx_a;
453 #endif
454  keyidx = data->key_idx;
455  memset(data, 0, sizeof(*data));
456  data->key_idx = keyidx;
457  data->tfm = tfm;
458  if (len == CCMP_TK_LEN) {
459   memcpy(data->key, key, CCMP_TK_LEN);
460   data->key_set = 1;
461   if (seq) {
462    data->rx_pn[0] = seq[5];
463    data->rx_pn[1] = seq[4];
464    data->rx_pn[2] = seq[3];
465    data->rx_pn[3] = seq[2];
466    data->rx_pn[4] = seq[1];
467    data->rx_pn[5] = seq[0];
468 #ifdef MULTI_THREAD_ENCRYPT
469             memcpy(data->pre_rx_pn, data->rx_pn, CCMP_PN_LEN);
470 #endif
471   }
472   crypto_cipher_setkey(data->tfm, data->key, CCMP_TK_LEN);
473 #ifdef MULTI_THREAD_ENCRYPT
474   data->tx_b0 = tx_b0;
475   data->tx_b = tx_b;
476   data->tx_e = tx_e;
477   data->tx_s0 = tx_s0;
478         data->rx_b0 = rx_b0;
479   data->rx_b = rx_b;
480   data->rx_a = rx_a;
481 #endif
482  } else if (len == 0)
483   data->key_set = 0;
484  else
485   return -1;
486  return 0;
487 }
lib80211_ccmp_get_key(void * key,int len,u8 * seq,void * priv)488 static int lib80211_ccmp_get_key(void *key, int len, u8 * seq, void *priv)
489 {
490  struct lib80211_ccmp_data *data = priv;
491  if (len < CCMP_TK_LEN)
492   return -1;
493  if (!data->key_set)
494   return 0;
495  memcpy(key, data->key, CCMP_TK_LEN);
496  if (seq) {
497   seq[0] = data->tx_pn[5];
498   seq[1] = data->tx_pn[4];
499   seq[2] = data->tx_pn[3];
500   seq[3] = data->tx_pn[2];
501   seq[4] = data->tx_pn[1];
502   seq[5] = data->tx_pn[0];
503  }
504  return CCMP_TK_LEN;
505 }
lib80211_ccmp_set_tx_pn(u8 * seq,void * priv)506 static int lib80211_ccmp_set_tx_pn(u8 * seq, void *priv)
507 {
508  struct lib80211_ccmp_data *data = priv;
509  if (seq) {
510   data->tx_pn[0] = seq[0];
511   data->tx_pn[1] = seq[1];
512   data->tx_pn[2] = seq[2];
513   data->tx_pn[3] = seq[3];
514   data->tx_pn[4] = seq[4];
515   data->tx_pn[5] = seq[5];
516  }
517  return 0;
518 }
lib80211_ccmp_print_stats(char * p,void * priv)519 static char *lib80211_ccmp_print_stats(char *p, void *priv)
520 {
521  struct lib80211_ccmp_data *ccmp = priv;
522  p += sprintf(p, "key[%d] alg=CCMP key_set=%d "
523        "tx_pn=%02x%02x%02x%02x%02x%02x "
524        "rx_pn=%02x%02x%02x%02x%02x%02x "
525        "format_errors=%d replays=%d decrypt_errors=%d\n",
526        ccmp->key_idx, ccmp->key_set,
527        ccmp->tx_pn[0], ccmp->tx_pn[1], ccmp->tx_pn[2],
528        ccmp->tx_pn[3], ccmp->tx_pn[4], ccmp->tx_pn[5],
529        ccmp->rx_pn[0], ccmp->rx_pn[1], ccmp->rx_pn[2],
530        ccmp->rx_pn[3], ccmp->rx_pn[4], ccmp->rx_pn[5],
531        ccmp->dot11RSNAStatsCCMPFormatErrors,
532        ccmp->dot11RSNAStatsCCMPReplays,
533        ccmp->dot11RSNAStatsCCMPDecryptErrors);
534  return p;
535 }
536 #ifdef MULTI_THREAD_ENCRYPT
lib80211_ccmp_encrypt_prepare(struct sk_buff * skb,int hdr_len,void * priv)537 static int lib80211_ccmp_encrypt_prepare (struct sk_buff * skb, int hdr_len, void *priv)
538 {
539     int data_len, len, ret;
540     void *ptr = NULL;
541     if (skb_tailroom(skb) < CCMP_MIC_LEN)
542     {
543         ret = skb_padto(skb, skb->len + CCMP_MIC_LEN);
544         if (ret != 0)
545         {
546             printk(KERN_ERR "Failed to extand skb for CCMP encryption, ret = %d.", ret);
547             return -1;
548         }
549     }
550     if (skb->len < hdr_len)
551   return -1;
552     data_len = skb->len - hdr_len;
553     len = lib80211_ccmp_hdr(skb, hdr_len, NULL, 0, priv);
554     if (len < 0)
555         return -1;
556     ptr = (void *)((size_t)skb_end_pointer(skb) - sizeof(prepare_mask));
557     memcpy(ptr, &prepare_mask, sizeof(prepare_mask));
558     return 0;
559 }
lib80211_ccmp_decrypt_prepare(struct sk_buff * skb,int hdr_len,void * priv)560 static int lib80211_ccmp_decrypt_prepare (struct sk_buff * skb, int hdr_len, void *priv)
561 {
562     struct lib80211_ccmp_data *key = priv;
563  u8 keyidx, *pos;
564  struct ieee80211_hdr *hdr;
565  u8 pn[6];
566  if (skb->len < hdr_len + CCMP_HDR_LEN + CCMP_MIC_LEN)
567     {
568   key->dot11RSNAStatsCCMPFormatErrors++;
569   return -1;
570  }
571  hdr = (struct ieee80211_hdr *)skb->data;
572  pos = skb->data + hdr_len;
573  keyidx = pos[3];
574  if (!(keyidx & (1 << 5)))
575     {
576         {
577    printk(KERN_DEBUG "CCMP: received packet without ExtIV"
578           " flag from %pM (%02X)\n", hdr->addr2, keyidx);
579   }
580   key->dot11RSNAStatsCCMPFormatErrors++;
581   return -2;
582  }
583  keyidx >>= 6;
584  if (key->key_idx != keyidx)
585     {
586   printk(KERN_DEBUG "CCMP: RX tkey->key_idx=%d frame "
587          "keyidx=%d priv=%p\n", key->key_idx, keyidx, priv);
588   return -6;
589  }
590  if (!key->key_set)
591     {
592         {
593    printk(KERN_DEBUG "CCMP: received packet from %pM"
594           " with keyid=%d that does not have a configured"
595           " key\n", hdr->addr2, keyidx);
596   }
597   return -3;
598  }
599  pn[0] = pos[7];
600  pn[1] = pos[6];
601  pn[2] = pos[5];
602  pn[3] = pos[4];
603  pn[4] = pos[1];
604  pn[5] = pos[0];
605 #if 0
606     if (ccmp_replay_check(pn, key->pre_rx_pn))
607     {
608 #if 1
609         {
610    printk(KERN_DEBUG "CCMP: replay detected: STA=%pM "
611      "previous PN %02x%02x%02x%02x%02x%02x "
612      "received PN %02x%02x%02x%02x%02x%02x\n",
613      hdr->addr2,
614      key->rx_pn[0], key->rx_pn[1], key->rx_pn[2],
615      key->rx_pn[3], key->rx_pn[4], key->rx_pn[5],
616      pn[0], pn[1], pn[2], pn[3], pn[4], pn[5]);
617   }
618 #endif
619   key->dot11RSNAStatsCCMPReplays++;
620   return -4;
621  }
622 #endif
623     memcpy(key->pre_rx_pn, pn, CCMP_PN_LEN);
624     return 0;
625 }
626 #endif
627 static struct ssv_crypto_ops ssv_crypt_ccmp = {
628  .name = "CCMP",
629  .init = lib80211_ccmp_init,
630  .deinit = lib80211_ccmp_deinit,
631  .encrypt_mpdu = lib80211_ccmp_encrypt,
632  .decrypt_mpdu = lib80211_ccmp_decrypt,
633  .encrypt_msdu = NULL,
634  .decrypt_msdu = NULL,
635  .set_tx_pn = lib80211_ccmp_set_tx_pn,
636  .set_key = lib80211_ccmp_set_key,
637  .get_key = lib80211_ccmp_get_key,
638  .print_stats = lib80211_ccmp_print_stats,
639  .extra_mpdu_prefix_len = CCMP_HDR_LEN,
640  .extra_mpdu_postfix_len = CCMP_MIC_LEN,
641 #ifdef MULTI_THREAD_ENCRYPT
642  .encrypt_prepare = lib80211_ccmp_encrypt_prepare,
643     .decrypt_prepare = lib80211_ccmp_decrypt_prepare,
644 #endif
645 };
get_crypto_ccmp_ops(void)646 struct ssv_crypto_ops *get_crypto_ccmp_ops(void)
647 {
648     return &ssv_crypt_ccmp;
649 }
650 #if 0
651 static inline int ccmp_replay_check(u8 *pn_n, u8 *pn_o)
652 {
653  u32 iv32_n, iv16_n;
654  u32 iv32_o, iv16_o;
655  iv32_n = (pn_n[5] << 24) | (pn_n[4] << 16) | (pn_n[3] << 8) | pn_n[2];
656  iv16_n = (pn_n[1] << 8) | pn_n[0];
657  iv32_o = (pn_o[5] << 24) | (pn_o[4] << 16) | (pn_o[3] << 8) | pn_o[2];
658  iv16_o = (pn_o[1] << 8) | pn_o[0];
659  if (((u32)iv32_n < (u32)iv32_o) ||
660      (iv32_n == iv32_o && iv16_n <= iv16_o))
661   return 1;
662  return 0;
663 }
664 static void ccmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *scratch, int encrypted)
665 {
666  u16 mask_fc;
667  u8 a4_included=0, mgmt=0;
668  u8 qos_tid;
669  u8 *b_0, *aad;
670  u16 data_len, len_a;
671  unsigned int hdrlen;
672  struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
673  mask_fc = hdr->frame_control;
674  b_0 = scratch + 3 * AES_BLOCK_LEN;
675  aad = scratch + 4 * AES_BLOCK_LEN;
676  if((mask_fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT)
677   mgmt = 1;
678  else
679   mgmt = 0;
680  mask_fc &= ~IEEE80211_FCTL_RETRY;
681  mask_fc &= ~IEEE80211_FCTL_PM;
682  mask_fc &= ~IEEE80211_FCTL_MOREDATA;
683  if (!mgmt)
684   mask_fc &= ~0x0070;
685  hdrlen = ieee80211_hdrlen(hdr->frame_control);
686  len_a = hdrlen - 2;
687  if( (mask_fc & (IEEE80211_FCTL_FROMDS|IEEE80211_FCTL_TODS)) == (IEEE80211_FCTL_FROMDS|IEEE80211_FCTL_TODS))
688   a4_included = 1;
689  else
690   a4_included = 0;
691  if (ieee80211_is_data_qos(hdr->frame_control))
692   qos_tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
693  else
694   qos_tid = 0;
695 #if 0
696  if ((mask_fc & (IEEE80211_FCTL_FTYPE | IEEE80211_STYPE_QOS_DATA)) == (IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_DATA))
697  {
698   if(a4_included)
699    qos_tid = (*((u8 *)ppkt + ppkt->hdr_offset+30)) & IEEE80211_QOS_CTL_TID_MASK;
700   else
701    qos_tid = (*((u8 *)ppkt + ppkt->hdr_offset+24)) & IEEE80211_QOS_CTL_TID_MASK;
702  }
703  else
704   qos_tid = 0;
705 #endif
706  data_len = skb->len - hdrlen;
707  if (encrypted)
708  {
709   data_len -= CCMP_MIC_LEN;
710   data_len -= CCMP_HDR_LEN;
711  }
712  b_0[0] = 0x59;
713  b_0[1] = qos_tid | (mgmt << 4);
714  memcpy(&b_0[2], hdr->addr2, ETH_ALEN);
715  memcpy(&b_0[8], pn, CCMP_PN_LEN);
716  put_unaligned_be16(data_len, &b_0[14]);
717  put_unaligned_be16(len_a, &aad[0]);
718  put_unaligned(mask_fc, (__le16 *)&aad[2]);
719  memcpy(&aad[4], &hdr->addr1, 3 * ETH_ALEN);
720  aad[22] = *((u8 *) &hdr->seq_ctrl) & 0x0f;
721  aad[23] = 0;
722  if (a4_included) {
723   memcpy(&aad[24], hdr->addr4, ETH_ALEN);
724   aad[30] = qos_tid;
725   aad[31] = 0;
726  } else {
727   memset(&aad[24], 0, ETH_ALEN + IEEE80211_QOS_CTL_LEN);
728   aad[24] = qos_tid;
729  }
730 }
731 static void ccmp_pn2hdr(u8 *hdr, int key_id, u8 *pn)
732 {
733 #if 0
734  hdr[0] = pn[0];
735  hdr[1] = pn[1];
736  hdr[2] = 0;
737  hdr[3] = 0x20 | (key_id << 6);
738  hdr[4] = pn[2];
739  hdr[5] = pn[3];
740  hdr[6] = pn[4];
741  hdr[7] = pn[5];
742 #endif
743     hdr[0] = pn[5];
744     hdr[1] = pn[4];
745     hdr[2] = 0;
746     hdr[3] = 0x20 | (key_id << 6);
747     hdr[4] = pn[3];
748     hdr[5] = pn[2];
749     hdr[6] = pn[1];
750     hdr[7] = pn[0];
751 }
752 #if 0
753 static void ccmp_hdr2pn(u8 *hdr, u8 *pn)
754 {
755  pn[0] = hdr[0];
756  pn[1] = hdr[1];
757  pn[2] = hdr[4];
758  pn[3] = hdr[5];
759  pn[4] = hdr[6];
760  pn[5] = hdr[7];
761 }
762 #endif
763 int ieee80211_crypto_ccmp_encrypt(struct sk_buff *skb, u8 *key, u8 keyidx, u8 *tx_pn)
764 {
765  u8 *data;
766  u32 data_len;
767  u8 crypto_buf[6 * AES_BLOCK_LEN];
768  struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
769     u32 hdrlen = ieee80211_hdrlen(hdr->frame_control);
770     u64 pn64;
771     u8 pn[6];
772     data_len = skb->len - hdrlen;
773  data = ((u8*)skb->data)+hdrlen;
774 #ifdef SECURITY_DUMP
775  fpga_dump(ppkt,"case-",key,16,0);
776 #endif
777 #if PRINT_DEBUG
778  printk("CCMP encrypt: PN =             0x%02x%02x%02x%02x%02x%02x\n",tx_pn[5],tx_pn[4],tx_pn[3],tx_pn[2],tx_pn[1],tx_pn[0]);
779 #endif
780     hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
781 #if 0
782  frame = (u16*)((u8 *)ppkt + ppkt->hdr_offset);
783  *frame |= IEEE80211_FCTL_PROTECTED;
784 #endif
785  pn64 = (*(u64*)tx_pn)++;
786  pn[5] = pn64;
787  pn[4] = pn64 >> 8;
788  pn[3] = pn64 >> 16;
789  pn[2] = pn64 >> 24;
790  pn[1] = pn64 >> 32;
791  pn[0] = pn64 >> 40;
792     ccmp_special_blocks(skb, pn, crypto_buf, 0);
793     data = skb_push(skb, CCMP_HDR_LEN);
794  memmove(data, data + CCMP_HDR_LEN, hdrlen);
795  ccmp_pn2hdr(data+hdrlen, keyidx, pn);
796  ieee80211_aes_ccm_encrypt(crypto_buf ,key , data+CCMP_HDR_LEN+hdrlen , data_len, skb_put(skb, CCMP_MIC_LEN));
797 #ifdef SECURITY_DUMP
798  fpga_dump(ppkt,"case-",key,16,1);
799 #endif
800  return true;
801 }
802 #endif
803