[PATCH] Update mac80211 and make b43 driver build and load on targets other than...
[openwrt.git] / package / mac80211 / patches / 300-rt2x00_hw_encryption.patch
1 From: Ivo van Doorn <IvDoorn@gmail.com>
2 Date: Thu, 20 Nov 2008 22:29:36 +0000 (+0100)
3 Subject: rt2x00: Implement HW encryption (rt2500usb)
4 X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Fivd%2Frt2x00.git;a=commitdiff_plain;h=52fe465ab5eb6aeead5ac8d91dd70e363d0560b7
5
6 rt2x00: Implement HW encryption (rt2500usb)
7
8 rt2500usb supports hardware encryption.
9 rt2500usb supports up to 4 shared and pairwise keys.
10
11 Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
12 ---
13
14 diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
15 index 10cb46a..620ac65 100644
16 --- a/drivers/net/wireless/rt2x00/rt2500usb.c
17 +++ b/drivers/net/wireless/rt2x00/rt2500usb.c
18 @@ -36,6 +36,13 @@
19  #include "rt2500usb.h"
20  
21  /*
22 + * Allow hardware encryption to be disabled.
23 + */
24 +static int modparam_nohwcrypt = 0;
25 +module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
26 +MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
27 +
28 +/*
29   * Register access.
30   * All access to the CSR registers will go through the methods
31   * rt2500usb_register_read and rt2500usb_register_write.
32 @@ -323,6 +330,85 @@ static void rt2500usb_init_led(struct rt2x00_dev *rt2x00dev,
33  /*
34   * Configuration handlers.
35   */
36 +
37 +/*
38 + * rt2500usb does not differentiate between shared and pairwise
39 + * keys, so we should use the same function for both key types.
40 + */
41 +static int rt2500usb_config_key(struct rt2x00_dev *rt2x00dev,
42 +                               struct rt2x00lib_crypto *crypto,
43 +                               struct ieee80211_key_conf *key)
44 +{
45 +       int timeout;
46 +       u32 mask;
47 +       u16 reg;
48 +
49 +       /* Support up to 4 keys */
50 +       if (key->hw_key_idx >= 4)
51 +               return -ENOSPC;
52 +
53 +       if (crypto->cmd == SET_KEY) {
54 +               /*
55 +                * Pairwise key will always be entry 0, but this
56 +                * could collide with a shared key on the same
57 +                * position...
58 +                */
59 +               mask = TXRX_CSR0_KEY_ID.bit_mask;
60 +
61 +               rt2500usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
62 +
63 +               if ((reg & mask) && (reg & mask) == mask)
64 +                       return -ENOSPC;
65 +
66 +               reg = rt2x00_get_field16(reg, TXRX_CSR0_KEY_ID);
67 +
68 +               key->hw_key_idx += reg ? ffz(reg) : 0;
69 +
70 +               /*
71 +                * The encryption key doesn't fit within the CSR cache,
72 +                * this means we should allocate it seperately and use
73 +                * rt2x00usb_vendor_request() to send the key to the hardware.
74 +                */
75 +               reg = KEY_ENTRY(key->hw_key_idx);
76 +               timeout = REGISTER_TIMEOUT32(sizeof(crypto->key));
77 +               rt2x00usb_vendor_request_large_buff(rt2x00dev, USB_MULTI_WRITE,
78 +                                                   USB_VENDOR_REQUEST_OUT, reg,
79 +                                                   crypto->key,
80 +                                                   sizeof(crypto->key),
81 +                                                   timeout);
82 +
83 +               /*
84 +                * The driver does not support the IV/EIV generation
85 +                * in hardware. However it doesn't support the IV/EIV
86 +                * inside the ieee80211 frame either, but requires it
87 +                * to be provided seperately for the descriptor.
88 +                * rt2x00lib will cut the IV/EIV data out of all frames
89 +                * given to us by mac80211, but we must tell mac80211
90 +                * to generate the IV/EIV data.
91 +                */
92 +               key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
93 +               key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
94 +       }
95 +
96 +       /*
97 +        * TXRX_CSR0_KEY_ID contains only single-bit fields to indicate
98 +        * a particular key is valid.
99 +        */
100 +       rt2500usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
101 +       rt2x00_set_field16(&reg, TXRX_CSR0_ALGORITHM, crypto->cipher);
102 +       rt2x00_set_field16(&reg, TXRX_CSR0_IV_OFFSET, IEEE80211_HEADER);
103 +
104 +       mask = rt2x00_get_field16(reg, TXRX_CSR0_KEY_ID);
105 +       if (crypto->cmd == SET_KEY)
106 +               mask |= 1 << key->hw_key_idx;
107 +       else if (crypto->cmd == DISABLE_KEY)
108 +               mask &= ~(1 << key->hw_key_idx);
109 +       rt2x00_set_field16(&reg, TXRX_CSR0_KEY_ID, mask);
110 +       rt2500usb_register_write(rt2x00dev, TXRX_CSR0, reg);
111 +
112 +       return 0;
113 +}
114 +
115  static void rt2500usb_config_filter(struct rt2x00_dev *rt2x00dev,
116                                     const unsigned int filter_flags)
117  {
118 @@ -844,7 +930,7 @@ static int rt2500usb_init_registers(struct rt2x00_dev *rt2x00dev)
119  
120         rt2500usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
121         rt2x00_set_field16(&reg, TXRX_CSR0_IV_OFFSET, IEEE80211_HEADER);
122 -       rt2x00_set_field16(&reg, TXRX_CSR0_KEY_ID, 0xff);
123 +       rt2x00_set_field16(&reg, TXRX_CSR0_KEY_ID, 0);
124         rt2500usb_register_write(rt2x00dev, TXRX_CSR0, reg);
125  
126         rt2500usb_register_read(rt2x00dev, MAC_CSR18, &reg);
127 @@ -1066,7 +1152,7 @@ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
128          * Start writing the descriptor words.
129          */
130         rt2x00_desc_read(txd, 1, &word);
131 -       rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, IEEE80211_HEADER);
132 +       rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, txdesc->iv_offset);
133         rt2x00_set_field32(&word, TXD_W1_AIFS, txdesc->aifs);
134         rt2x00_set_field32(&word, TXD_W1_CWMIN, txdesc->cw_min);
135         rt2x00_set_field32(&word, TXD_W1_CWMAX, txdesc->cw_max);
136 @@ -1079,6 +1165,11 @@ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
137         rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_HIGH, txdesc->length_high);
138         rt2x00_desc_write(txd, 2, word);
139  
140 +       if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags)) {
141 +               _rt2x00_desc_write(txd, 3, skbdesc->iv);
142 +               _rt2x00_desc_write(txd, 4, skbdesc->eiv);
143 +       }
144 +
145         rt2x00_desc_read(txd, 0, &word);
146         rt2x00_set_field32(&word, TXD_W0_RETRY_LIMIT, txdesc->retry_limit);
147         rt2x00_set_field32(&word, TXD_W0_MORE_FRAG,
148 @@ -1093,7 +1184,8 @@ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
149                            test_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags));
150         rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs);
151         rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skb->len);
152 -       rt2x00_set_field32(&word, TXD_W0_CIPHER, CIPHER_NONE);
153 +       rt2x00_set_field32(&word, TXD_W0_CIPHER, txdesc->cipher);
154 +       rt2x00_set_field32(&word, TXD_W0_KEY_ID, txdesc->key_idx);
155         rt2x00_desc_write(txd, 0, word);
156  }
157  
158 @@ -1204,6 +1296,7 @@ static void rt2500usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
159  static void rt2500usb_fill_rxdone(struct queue_entry *entry,
160                                   struct rxdone_entry_desc *rxdesc)
161  {
162 +       struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
163         struct queue_entry_priv_usb *entry_priv = entry->priv_data;
164         struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
165         __le32 *rxd =
166 @@ -1231,6 +1324,31 @@ static void rt2500usb_fill_rxdone(struct queue_entry *entry,
167         if (rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR))
168                 rxdesc->flags |= RX_FLAG_FAILED_PLCP_CRC;
169  
170 +       if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) {
171 +               rxdesc->cipher = rt2x00_get_field32(word0, RXD_W0_CIPHER);
172 +               if (rt2x00_get_field32(word0, RXD_W0_CIPHER_ERROR))
173 +                       rxdesc->cipher_status = RX_CRYPTO_FAIL_KEY;
174 +       }
175 +
176 +       if (rxdesc->cipher != CIPHER_NONE) {
177 +               _rt2x00_desc_read(rxd, 2, &rxdesc->iv);
178 +               _rt2x00_desc_read(rxd, 3, &rxdesc->eiv);
179 +               /* ICV is located at the end of frame */
180 +
181 +               /*
182 +                * Hardware has stripped IV/EIV data from 802.11 frame during
183 +                * decryption. It has provided the data seperately but rt2x00lib
184 +                * should decide if it should be reinserted.
185 +                */
186 +               rxdesc->flags |= RX_FLAG_IV_STRIPPED;
187 +               if (rxdesc->cipher != CIPHER_TKIP)
188 +                       rxdesc->flags |= RX_FLAG_MMIC_STRIPPED;
189 +               if (rxdesc->cipher_status == RX_CRYPTO_SUCCESS)
190 +                       rxdesc->flags |= RX_FLAG_DECRYPTED;
191 +               else if (rxdesc->cipher_status == RX_CRYPTO_FAIL_MIC)
192 +                       rxdesc->flags |= RX_FLAG_MMIC_ERROR;
193 +       }
194 +
195         /*
196          * Obtain the status about this packet.
197          * When frame was received with an OFDM bitrate,
198 @@ -1238,8 +1356,8 @@ static void rt2500usb_fill_rxdone(struct queue_entry *entry,
199          * a CCK bitrate the signal is the rate in 100kbit/s.
200          */
201         rxdesc->signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL);
202 -       rxdesc->rssi = rt2x00_get_field32(word1, RXD_W1_RSSI) -
203 -           entry->queue->rt2x00dev->rssi_offset;
204 +       rxdesc->rssi =
205 +           rt2x00_get_field32(word1, RXD_W1_RSSI) - rt2x00dev->rssi_offset;
206         rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
207  
208         if (rt2x00_get_field32(word0, RXD_W0_OFDM))
209 @@ -1729,6 +1847,8 @@ static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev)
210         __set_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags);
211         __set_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags);
212         __set_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags);
213 +       if (!modparam_nohwcrypt)
214 +               __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags);
215         __set_bit(CONFIG_DISABLE_LINK_TUNING, &rt2x00dev->flags);
216  
217         /*
218 @@ -1748,6 +1868,7 @@ static const struct ieee80211_ops rt2500usb_mac80211_ops = {
219         .config                 = rt2x00mac_config,
220         .config_interface       = rt2x00mac_config_interface,
221         .configure_filter       = rt2x00mac_configure_filter,
222 +       .set_key                = rt2x00mac_set_key,
223         .get_stats              = rt2x00mac_get_stats,
224         .bss_info_changed       = rt2x00mac_bss_info_changed,
225         .conf_tx                = rt2x00mac_conf_tx,
226 @@ -1769,6 +1890,8 @@ static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = {
227         .get_tx_data_len        = rt2500usb_get_tx_data_len,
228         .kick_tx_queue          = rt2500usb_kick_tx_queue,
229         .fill_rxdone            = rt2500usb_fill_rxdone,
230 +       .config_shared_key      = rt2500usb_config_key,
231 +       .config_pairwise_key    = rt2500usb_config_key,
232         .config_filter          = rt2500usb_config_filter,
233         .config_intf            = rt2500usb_config_intf,
234         .config_erp             = rt2500usb_config_erp,
235 diff --git a/drivers/net/wireless/rt2x00/rt2500usb.h b/drivers/net/wireless/rt2x00/rt2500usb.h
236 index dbb5d68..4347dfd 100644
237 --- a/drivers/net/wireless/rt2x00/rt2500usb.h
238 +++ b/drivers/net/wireless/rt2x00/rt2500usb.h
239 @@ -447,6 +447,9 @@
240  #define SEC_CSR30                      0x04bc
241  #define SEC_CSR31                      0x04be
242  
243 +#define KEY_ENTRY(__idx) \
244 +       ( SEC_CSR0 + ((__idx) * 16) )
245 +
246  /*
247   * PHY control registers.
248   */