Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
rt2x00crypto.c
Go to the documentation of this file.
1 /*
2  Copyright (C) 2004 - 2009 Ivo van Doorn <[email protected]>
3  <http://rt2x00.serialmonkey.com>
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 2 of the License, or
8  (at your option) any later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program; if not, write to the
17  Free Software Foundation, Inc.,
18  59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19  */
20 
21 /*
22  Module: rt2x00lib
23  Abstract: rt2x00 crypto specific routines.
24  */
25 
26 #include <linux/kernel.h>
27 #include <linux/module.h>
28 
29 #include "rt2x00.h"
30 #include "rt2x00lib.h"
31 
33 {
34  switch (key->cipher) {
36  return CIPHER_WEP64;
38  return CIPHER_WEP128;
40  return CIPHER_TKIP;
42  return CIPHER_AES;
43  default:
44  return CIPHER_NONE;
45  }
46 }
47 
49  struct sk_buff *skb,
50  struct txentry_desc *txdesc)
51 {
52  struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
53  struct ieee80211_key_conf *hw_key = tx_info->control.hw_key;
54 
55  if (!test_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags) || !hw_key)
56  return;
57 
59 
60  txdesc->cipher = rt2x00crypto_key_to_cipher(hw_key);
61 
62  if (hw_key->flags & IEEE80211_KEY_FLAG_PAIRWISE)
64 
65  txdesc->key_idx = hw_key->hw_key_idx;
66  txdesc->iv_offset = txdesc->header_length;
67  txdesc->iv_len = hw_key->iv_len;
68 
69  if (!(hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV))
71 
72  if (!(hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_MMIC))
74 }
75 
76 unsigned int rt2x00crypto_tx_overhead(struct rt2x00_dev *rt2x00dev,
77  struct sk_buff *skb)
78 {
79  struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
80  struct ieee80211_key_conf *key = tx_info->control.hw_key;
81  unsigned int overhead = 0;
82 
83  if (!test_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags) || !key)
84  return overhead;
85 
86  /*
87  * Extend frame length to include IV/EIV/ICV/MMIC,
88  * note that these lengths should only be added when
89  * mac80211 does not generate it.
90  */
91  overhead += key->icv_len;
92 
94  overhead += key->iv_len;
95 
97  if (key->cipher == WLAN_CIPHER_SUITE_TKIP)
98  overhead += 8;
99  }
100 
101  return overhead;
102 }
103 
105 {
106  struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
107 
108  if (unlikely(!txdesc->iv_len))
109  return;
110 
111  /* Copy IV/EIV data */
112  memcpy(skbdesc->iv, skb->data + txdesc->iv_offset, txdesc->iv_len);
113 }
114 
116 {
117  struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
118 
119  if (unlikely(!txdesc->iv_len))
120  return;
121 
122  /* Copy IV/EIV data */
123  memcpy(skbdesc->iv, skb->data + txdesc->iv_offset, txdesc->iv_len);
124 
125  /* Move ieee80211 header */
126  memmove(skb->data + txdesc->iv_len, skb->data, txdesc->iv_offset);
127 
128  /* Pull buffer to correct size */
129  skb_pull(skb, txdesc->iv_len);
130  txdesc->length -= txdesc->iv_len;
131 
132  /* IV/EIV data has officially been stripped */
133  skbdesc->flags |= SKBDESC_IV_STRIPPED;
134 }
135 
137 {
138  struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
139  const unsigned int iv_len =
140  ((!!(skbdesc->iv[0])) * 4) + ((!!(skbdesc->iv[1])) * 4);
141 
142  if (!(skbdesc->flags & SKBDESC_IV_STRIPPED))
143  return;
144 
145  skb_push(skb, iv_len);
146 
147  /* Move ieee80211 header */
148  memmove(skb->data, skb->data + iv_len, header_length);
149 
150  /* Copy IV/EIV data */
151  memcpy(skb->data + header_length, skbdesc->iv, iv_len);
152 
153  /* IV/EIV data has returned into the frame */
154  skbdesc->flags &= ~SKBDESC_IV_STRIPPED;
155 }
156 
158  unsigned int header_length,
159  struct rxdone_entry_desc *rxdesc)
160 {
161  unsigned int payload_len = rxdesc->size - header_length;
162  unsigned int align = ALIGN_SIZE(skb, header_length);
163  unsigned int iv_len;
164  unsigned int icv_len;
165  unsigned int transfer = 0;
166 
167  /*
168  * WEP64/WEP128: Provides IV & ICV
169  * TKIP: Provides IV/EIV & ICV
170  * AES: Provies IV/EIV & ICV
171  */
172  switch (rxdesc->cipher) {
173  case CIPHER_WEP64:
174  case CIPHER_WEP128:
175  iv_len = 4;
176  icv_len = 4;
177  break;
178  case CIPHER_TKIP:
179  iv_len = 8;
180  icv_len = 4;
181  break;
182  case CIPHER_AES:
183  iv_len = 8;
184  icv_len = 8;
185  break;
186  default:
187  /* Unsupport type */
188  return;
189  }
190 
191  /*
192  * Make room for new data. There are 2 possibilities
193  * either the alignment is already present between
194  * the 802.11 header and payload. In that case we
195  * we have to move the header less then the iv_len
196  * since we can use the already available l2pad bytes
197  * for the iv data.
198  * When the alignment must be added manually we must
199  * move the header more then iv_len since we must
200  * make room for the payload move as well.
201  */
202  if (rxdesc->dev_flags & RXDONE_L2PAD) {
203  skb_push(skb, iv_len - align);
204  skb_put(skb, icv_len);
205 
206  /* Move ieee80211 header */
207  memmove(skb->data + transfer,
208  skb->data + transfer + (iv_len - align),
209  header_length);
210  transfer += header_length;
211  } else {
212  skb_push(skb, iv_len + align);
213  if (align < icv_len)
214  skb_put(skb, icv_len - align);
215  else if (align > icv_len)
216  skb_trim(skb, rxdesc->size + iv_len + icv_len);
217 
218  /* Move ieee80211 header */
219  memmove(skb->data + transfer,
220  skb->data + transfer + iv_len + align,
221  header_length);
222  transfer += header_length;
223  }
224 
225  /* Copy IV/EIV data */
226  memcpy(skb->data + transfer, rxdesc->iv, iv_len);
227  transfer += iv_len;
228 
229  /*
230  * Move payload for alignment purposes. Note that
231  * this is only needed when no l2 padding is present.
232  */
233  if (!(rxdesc->dev_flags & RXDONE_L2PAD)) {
234  memmove(skb->data + transfer,
235  skb->data + transfer + align,
236  payload_len);
237  }
238 
239  /*
240  * NOTE: Always count the payload as transferred,
241  * even when alignment was set to zero. This is required
242  * for determining the correct offset for the ICV data.
243  */
244  transfer += payload_len;
245 
246  /*
247  * Copy ICV data
248  * AES appends 8 bytes, we can't fill the upper
249  * 4 bytes, but mac80211 doesn't care about what
250  * we provide here anyway and strips it immediately.
251  */
252  memcpy(skb->data + transfer, &rxdesc->icv, 4);
253  transfer += icv_len;
254 
255  /* IV/EIV/ICV has been inserted into frame */
256  rxdesc->size = transfer;
257  rxdesc->flags &= ~RX_FLAG_IV_STRIPPED;
258 }