nexmon – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | diff -Naur linux-2.6.22_orig/drivers/net/wireless/zd1211rw/zd_mac.c linux-2.6.22/drivers/net/wireless/zd1211rw/zd_mac.c |
2 | --- linux-2.6.22_orig/drivers/net/wireless/zd1211rw/zd_mac.c 2007-08-09 15:37:14.000000000 +0200 |
||
3 | +++ linux-2.6.22/drivers/net/wireless/zd1211rw/zd_mac.c 2007-08-23 22:51:27.000000000 +0200 |
||
4 | @@ -156,8 +156,17 @@ |
||
5 | static int reset_mode(struct zd_mac *mac) |
||
6 | { |
||
7 | struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac); |
||
8 | - u32 filter = (ieee->iw_mode == IW_MODE_MONITOR) ? ~0 : STA_RX_FILTER; |
||
9 | - return zd_iowrite32(&mac->chip, CR_RX_FILTER, filter); |
||
10 | + struct zd_ioreq32 ioreqs[] = { |
||
11 | + { CR_RX_FILTER, STA_RX_FILTER }, |
||
12 | + { CR_SNIFFER_ON, 0U }, |
||
13 | + }; |
||
14 | + |
||
15 | + if (ieee->iw_mode == IW_MODE_MONITOR) { |
||
16 | + ioreqs[0].value = 0xffffffff; |
||
17 | + ioreqs[1].value = 0x1; |
||
18 | + } |
||
19 | + |
||
20 | + return zd_iowrite32a(&mac->chip, ioreqs, ARRAY_SIZE(ioreqs)); |
||
21 | } |
||
22 | |||
23 | int zd_mac_open(struct net_device *netdev) |
||
24 | @@ -192,7 +201,13 @@ |
||
25 | goto disable_rx; |
||
26 | |||
27 | housekeeping_enable(mac); |
||
28 | - ieee80211softmac_start(netdev); |
||
29 | + netif_carrier_on(netdev); |
||
30 | + ieee80211softmac_start(netdev); |
||
31 | + if(!netif_queue_stopped(netdev)) |
||
32 | + netif_start_queue(netdev); |
||
33 | + else |
||
34 | + netif_wake_queue(netdev); |
||
35 | + |
||
36 | return 0; |
||
37 | disable_rx: |
||
38 | zd_chip_disable_rx(chip); |
||
39 | @@ -825,6 +840,7 @@ |
||
40 | struct ieee80211_txb *txb, |
||
41 | int frag_num) |
||
42 | { |
||
43 | + struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac); |
||
44 | int r; |
||
45 | struct sk_buff *skb = txb->fragments[frag_num]; |
||
46 | struct ieee80211_hdr_4addr *hdr = |
||
47 | @@ -848,7 +864,10 @@ |
||
48 | |||
49 | cs->tx_length = cpu_to_le16(frag_len); |
||
50 | |||
51 | - cs_set_control(mac, cs, hdr); |
||
52 | + if(ieee->iw_mode == IW_MODE_MONITOR) |
||
53 | + cs->control = ZD_CS_MULTICAST; |
||
54 | + else |
||
55 | + cs_set_control(mac, cs, hdr); |
||
56 | |||
57 | packet_length = frag_len + sizeof(struct zd_ctrlset) + 10; |
||
58 | ZD_ASSERT(packet_length <= 0xffff); |
||
59 | @@ -904,7 +923,11 @@ |
||
60 | ieee->stats.tx_dropped++; |
||
61 | return r; |
||
62 | } |
||
63 | - r = zd_usb_tx(&mac->chip.usb, skb->data, skb->len); |
||
64 | + |
||
65 | + if(ieee->iw_mode == IW_MODE_MONITOR) |
||
66 | + r = zd_usb_tx_inject(&mac->chip.usb, skb->data, skb->len); |
||
67 | + else |
||
68 | + r = zd_usb_tx(&mac->chip.usb, skb->data, skb->len); |
||
69 | if (r) { |
||
70 | ieee->stats.tx_dropped++; |
||
71 | return r; |
||
72 | @@ -924,6 +947,8 @@ |
||
73 | u8 rt_rate; |
||
74 | u16 rt_channel; |
||
75 | u16 rt_chbitmask; |
||
76 | + u8 rt_antsignal; |
||
77 | + u8 rt_antnoise; |
||
78 | } __attribute__((packed)); |
||
79 | |||
80 | static void fill_rt_header(void *buffer, struct zd_mac *mac, |
||
81 | @@ -937,7 +962,9 @@ |
||
82 | hdr->rt_hdr.it_len = cpu_to_le16(sizeof(struct zd_rt_hdr)); |
||
83 | hdr->rt_hdr.it_present = cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) | |
||
84 | (1 << IEEE80211_RADIOTAP_CHANNEL) | |
||
85 | - (1 << IEEE80211_RADIOTAP_RATE)); |
||
86 | + (1 << IEEE80211_RADIOTAP_RATE) | |
||
87 | + (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | |
||
88 | + (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE)); |
||
89 | |||
90 | hdr->rt_flags = 0; |
||
91 | if (status->decryption_type & (ZD_RX_WEP64|ZD_RX_WEP128|ZD_RX_WEP256)) |
||
92 | @@ -951,6 +978,9 @@ |
||
93 | hdr->rt_chbitmask = cpu_to_le16(IEEE80211_CHAN_2GHZ | |
||
94 | ((status->frame_status & ZD_RX_FRAME_MODULATION_MASK) == |
||
95 | ZD_RX_OFDM ? IEEE80211_CHAN_OFDM : IEEE80211_CHAN_CCK)); |
||
96 | + |
||
97 | + hdr->rt_antsignal = status->signal_strength; |
||
98 | + hdr->rt_antnoise = stats->noise; |
||
99 | } |
||
100 | |||
101 | /* Returns 1 if the data packet is for us and 0 otherwise. */ |
||
102 | @@ -1057,7 +1087,8 @@ |
||
103 | const struct rx_status *status; |
||
104 | |||
105 | *pstatus = status = zd_tail(buffer, length, sizeof(struct rx_status)); |
||
106 | - if (status->frame_status & ZD_RX_ERROR) { |
||
107 | + if (status->frame_status & ZD_RX_ERROR |
||
108 | + || status->frame_status & ~0x21) { |
||
109 | struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac); |
||
110 | ieee->stats.rx_errors++; |
||
111 | if (status->frame_status & ZD_RX_TIMEOUT_ERROR) |
||
112 | diff -Naur linux-2.6.22_orig/drivers/net/wireless/zd1211rw/zd_mac.c~ linux-2.6.22/drivers/net/wireless/zd1211rw/zd_mac.c~ |
||
113 | --- linux-2.6.22_orig/drivers/net/wireless/zd1211rw/zd_mac.c~ 1970-01-01 01:00:00.000000000 +0100 |
||
114 | +++ linux-2.6.22/drivers/net/wireless/zd1211rw/zd_mac.c~ 2007-08-23 22:26:08.000000000 +0200 |
||
115 | @@ -0,0 +1,1352 @@ |
||
116 | +/* zd_mac.c |
||
117 | + * |
||
118 | + * This program is free software; you can redistribute it and/or modify |
||
119 | + * it under the terms of the GNU General Public License as published by |
||
120 | + * the Free Software Foundation; either version 2 of the License, or |
||
121 | + * (at your option) any later version. |
||
122 | + * |
||
123 | + * This program is distributed in the hope that it will be useful, |
||
124 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
125 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
126 | + * GNU General Public License for more details. |
||
127 | + * |
||
128 | + * You should have received a copy of the GNU General Public License |
||
129 | + * along with this program; if not, write to the Free Software |
||
130 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||
131 | + */ |
||
132 | + |
||
133 | +#include <linux/netdevice.h> |
||
134 | +#include <linux/etherdevice.h> |
||
135 | +#include <linux/wireless.h> |
||
136 | +#include <linux/usb.h> |
||
137 | +#include <linux/jiffies.h> |
||
138 | +#include <net/ieee80211_radiotap.h> |
||
139 | + |
||
140 | +#include "zd_def.h" |
||
141 | +#include "zd_chip.h" |
||
142 | +#include "zd_mac.h" |
||
143 | +#include "zd_ieee80211.h" |
||
144 | +#include "zd_netdev.h" |
||
145 | +#include "zd_rf.h" |
||
146 | +#include "zd_util.h" |
||
147 | + |
||
148 | +static void ieee_init(struct ieee80211_device *ieee); |
||
149 | +static void softmac_init(struct ieee80211softmac_device *sm); |
||
150 | +static void set_rts_cts_work(struct work_struct *work); |
||
151 | +static void set_basic_rates_work(struct work_struct *work); |
||
152 | + |
||
153 | +static void housekeeping_init(struct zd_mac *mac); |
||
154 | +static void housekeeping_enable(struct zd_mac *mac); |
||
155 | +static void housekeeping_disable(struct zd_mac *mac); |
||
156 | + |
||
157 | +static void set_multicast_hash_handler(struct work_struct *work); |
||
158 | + |
||
159 | +static void do_rx(unsigned long mac_ptr); |
||
160 | + |
||
161 | +int zd_mac_init(struct zd_mac *mac, |
||
162 | + struct net_device *netdev, |
||
163 | + struct usb_interface *intf) |
||
164 | +{ |
||
165 | + struct ieee80211_device *ieee = zd_netdev_ieee80211(netdev); |
||
166 | + |
||
167 | + memset(mac, 0, sizeof(*mac)); |
||
168 | + spin_lock_init(&mac->lock); |
||
169 | + mac->netdev = netdev; |
||
170 | + INIT_DELAYED_WORK(&mac->set_rts_cts_work, set_rts_cts_work); |
||
171 | + INIT_DELAYED_WORK(&mac->set_basic_rates_work, set_basic_rates_work); |
||
172 | + |
||
173 | + skb_queue_head_init(&mac->rx_queue); |
||
174 | + tasklet_init(&mac->rx_tasklet, do_rx, (unsigned long)mac); |
||
175 | + tasklet_disable(&mac->rx_tasklet); |
||
176 | + |
||
177 | + ieee_init(ieee); |
||
178 | + softmac_init(ieee80211_priv(netdev)); |
||
179 | + zd_chip_init(&mac->chip, netdev, intf); |
||
180 | + housekeeping_init(mac); |
||
181 | + INIT_WORK(&mac->set_multicast_hash_work, set_multicast_hash_handler); |
||
182 | + return 0; |
||
183 | +} |
||
184 | + |
||
185 | +static int reset_channel(struct zd_mac *mac) |
||
186 | +{ |
||
187 | + int r; |
||
188 | + unsigned long flags; |
||
189 | + const struct channel_range *range; |
||
190 | + |
||
191 | + spin_lock_irqsave(&mac->lock, flags); |
||
192 | + range = zd_channel_range(mac->regdomain); |
||
193 | + if (!range->start) { |
||
194 | + r = -EINVAL; |
||
195 | + goto out; |
||
196 | + } |
||
197 | + mac->requested_channel = range->start; |
||
198 | + r = 0; |
||
199 | +out: |
||
200 | + spin_unlock_irqrestore(&mac->lock, flags); |
||
201 | + return r; |
||
202 | +} |
||
203 | + |
||
204 | +int zd_mac_init_hw(struct zd_mac *mac, u8 device_type) |
||
205 | +{ |
||
206 | + int r; |
||
207 | + struct zd_chip *chip = &mac->chip; |
||
208 | + u8 addr[ETH_ALEN]; |
||
209 | + u8 default_regdomain; |
||
210 | + |
||
211 | + r = zd_chip_enable_int(chip); |
||
212 | + if (r) |
||
213 | + goto out; |
||
214 | + r = zd_chip_init_hw(chip, device_type); |
||
215 | + if (r) |
||
216 | + goto disable_int; |
||
217 | + |
||
218 | + zd_get_e2p_mac_addr(chip, addr); |
||
219 | + r = zd_write_mac_addr(chip, addr); |
||
220 | + if (r) |
||
221 | + goto disable_int; |
||
222 | + ZD_ASSERT(!irqs_disabled()); |
||
223 | + spin_lock_irq(&mac->lock); |
||
224 | + memcpy(mac->netdev->dev_addr, addr, ETH_ALEN); |
||
225 | + spin_unlock_irq(&mac->lock); |
||
226 | + |
||
227 | + r = zd_read_regdomain(chip, &default_regdomain); |
||
228 | + if (r) |
||
229 | + goto disable_int; |
||
230 | + if (!zd_regdomain_supported(default_regdomain)) { |
||
231 | + dev_dbg_f(zd_mac_dev(mac), |
||
232 | + "Regulatory Domain %#04x is not supported.\n", |
||
233 | + default_regdomain); |
||
234 | + r = -EINVAL; |
||
235 | + goto disable_int; |
||
236 | + } |
||
237 | + spin_lock_irq(&mac->lock); |
||
238 | + mac->regdomain = mac->default_regdomain = default_regdomain; |
||
239 | + spin_unlock_irq(&mac->lock); |
||
240 | + r = reset_channel(mac); |
||
241 | + if (r) |
||
242 | + goto disable_int; |
||
243 | + |
||
244 | + /* We must inform the device that we are doing encryption/decryption in |
||
245 | + * software at the moment. */ |
||
246 | + r = zd_set_encryption_type(chip, ENC_SNIFFER); |
||
247 | + if (r) |
||
248 | + goto disable_int; |
||
249 | + |
||
250 | + r = zd_geo_init(zd_mac_to_ieee80211(mac), mac->regdomain); |
||
251 | + if (r) |
||
252 | + goto disable_int; |
||
253 | + |
||
254 | + r = 0; |
||
255 | +disable_int: |
||
256 | + zd_chip_disable_int(chip); |
||
257 | +out: |
||
258 | + return r; |
||
259 | +} |
||
260 | + |
||
261 | +void zd_mac_clear(struct zd_mac *mac) |
||
262 | +{ |
||
263 | + flush_workqueue(zd_workqueue); |
||
264 | + skb_queue_purge(&mac->rx_queue); |
||
265 | + tasklet_kill(&mac->rx_tasklet); |
||
266 | + zd_chip_clear(&mac->chip); |
||
267 | + ZD_ASSERT(!spin_is_locked(&mac->lock)); |
||
268 | + ZD_MEMCLEAR(mac, sizeof(struct zd_mac)); |
||
269 | +} |
||
270 | + |
||
271 | +static int reset_mode(struct zd_mac *mac) |
||
272 | +{ |
||
273 | + struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac); |
||
274 | + u32 filter = (ieee->iw_mode == IW_MODE_MONITOR) ? ~0 : STA_RX_FILTER; |
||
275 | + return zd_iowrite32(&mac->chip, CR_RX_FILTER, filter); |
||
276 | +} |
||
277 | + |
||
278 | +int zd_mac_open(struct net_device *netdev) |
||
279 | +{ |
||
280 | + struct zd_mac *mac = zd_netdev_mac(netdev); |
||
281 | + struct zd_chip *chip = &mac->chip; |
||
282 | + int r; |
||
283 | + |
||
284 | + tasklet_enable(&mac->rx_tasklet); |
||
285 | + |
||
286 | + r = zd_chip_enable_int(chip); |
||
287 | + if (r < 0) |
||
288 | + goto out; |
||
289 | + |
||
290 | + r = zd_chip_set_basic_rates(chip, CR_RATES_80211B | CR_RATES_80211G); |
||
291 | + if (r < 0) |
||
292 | + goto disable_int; |
||
293 | + r = reset_mode(mac); |
||
294 | + if (r) |
||
295 | + goto disable_int; |
||
296 | + r = zd_chip_switch_radio_on(chip); |
||
297 | + if (r < 0) |
||
298 | + goto disable_int; |
||
299 | + r = zd_chip_set_channel(chip, mac->requested_channel); |
||
300 | + if (r < 0) |
||
301 | + goto disable_radio; |
||
302 | + r = zd_chip_enable_rx(chip); |
||
303 | + if (r < 0) |
||
304 | + goto disable_radio; |
||
305 | + r = zd_chip_enable_hwint(chip); |
||
306 | + if (r < 0) |
||
307 | + goto disable_rx; |
||
308 | + |
||
309 | + housekeeping_enable(mac); |
||
310 | + netif_carrier_on(netdev); |
||
311 | + ieee80211softmac_start(netdev); |
||
312 | + if(!netif_queue_stopped(netdev)) |
||
313 | + netif_start_queue(netdev); |
||
314 | + else |
||
315 | + netif_wake_queue(netdev); |
||
316 | + |
||
317 | + return 0; |
||
318 | +disable_rx: |
||
319 | + zd_chip_disable_rx(chip); |
||
320 | +disable_radio: |
||
321 | + zd_chip_switch_radio_off(chip); |
||
322 | +disable_int: |
||
323 | + zd_chip_disable_int(chip); |
||
324 | +out: |
||
325 | + return r; |
||
326 | +} |
||
327 | + |
||
328 | +int zd_mac_stop(struct net_device *netdev) |
||
329 | +{ |
||
330 | + struct zd_mac *mac = zd_netdev_mac(netdev); |
||
331 | + struct zd_chip *chip = &mac->chip; |
||
332 | + |
||
333 | + netif_stop_queue(netdev); |
||
334 | + |
||
335 | + /* |
||
336 | + * The order here deliberately is a little different from the open() |
||
337 | + * method, since we need to make sure there is no opportunity for RX |
||
338 | + * frames to be processed by softmac after we have stopped it. |
||
339 | + */ |
||
340 | + |
||
341 | + zd_chip_disable_rx(chip); |
||
342 | + skb_queue_purge(&mac->rx_queue); |
||
343 | + tasklet_disable(&mac->rx_tasklet); |
||
344 | + housekeeping_disable(mac); |
||
345 | + ieee80211softmac_stop(netdev); |
||
346 | + |
||
347 | + /* Ensure no work items are running or queued from this point */ |
||
348 | + cancel_delayed_work(&mac->set_rts_cts_work); |
||
349 | + cancel_delayed_work(&mac->set_basic_rates_work); |
||
350 | + flush_workqueue(zd_workqueue); |
||
351 | + mac->updating_rts_rate = 0; |
||
352 | + mac->updating_basic_rates = 0; |
||
353 | + |
||
354 | + zd_chip_disable_hwint(chip); |
||
355 | + zd_chip_switch_radio_off(chip); |
||
356 | + zd_chip_disable_int(chip); |
||
357 | + |
||
358 | + return 0; |
||
359 | +} |
||
360 | + |
||
361 | +int zd_mac_set_mac_address(struct net_device *netdev, void *p) |
||
362 | +{ |
||
363 | + int r; |
||
364 | + unsigned long flags; |
||
365 | + struct sockaddr *addr = p; |
||
366 | + struct zd_mac *mac = zd_netdev_mac(netdev); |
||
367 | + struct zd_chip *chip = &mac->chip; |
||
368 | + |
||
369 | + if (!is_valid_ether_addr(addr->sa_data)) |
||
370 | + return -EADDRNOTAVAIL; |
||
371 | + |
||
372 | + dev_dbg_f(zd_mac_dev(mac), |
||
373 | + "Setting MAC to " MAC_FMT "\n", MAC_ARG(addr->sa_data)); |
||
374 | + |
||
375 | + r = zd_write_mac_addr(chip, addr->sa_data); |
||
376 | + if (r) |
||
377 | + return r; |
||
378 | + |
||
379 | + spin_lock_irqsave(&mac->lock, flags); |
||
380 | + memcpy(netdev->dev_addr, addr->sa_data, ETH_ALEN); |
||
381 | + spin_unlock_irqrestore(&mac->lock, flags); |
||
382 | + |
||
383 | + return 0; |
||
384 | +} |
||
385 | + |
||
386 | +static void set_multicast_hash_handler(struct work_struct *work) |
||
387 | +{ |
||
388 | + struct zd_mac *mac = container_of(work, struct zd_mac, |
||
389 | + set_multicast_hash_work); |
||
390 | + struct zd_mc_hash hash; |
||
391 | + |
||
392 | + spin_lock_irq(&mac->lock); |
||
393 | + hash = mac->multicast_hash; |
||
394 | + spin_unlock_irq(&mac->lock); |
||
395 | + |
||
396 | + zd_chip_set_multicast_hash(&mac->chip, &hash); |
||
397 | +} |
||
398 | + |
||
399 | +void zd_mac_set_multicast_list(struct net_device *dev) |
||
400 | +{ |
||
401 | + struct zd_mc_hash hash; |
||
402 | + struct zd_mac *mac = zd_netdev_mac(dev); |
||
403 | + struct dev_mc_list *mc; |
||
404 | + unsigned long flags; |
||
405 | + |
||
406 | + if (dev->flags & (IFF_PROMISC|IFF_ALLMULTI)) { |
||
407 | + zd_mc_add_all(&hash); |
||
408 | + } else { |
||
409 | + zd_mc_clear(&hash); |
||
410 | + for (mc = dev->mc_list; mc; mc = mc->next) { |
||
411 | + dev_dbg_f(zd_mac_dev(mac), "mc addr " MAC_FMT "\n", |
||
412 | + MAC_ARG(mc->dmi_addr)); |
||
413 | + zd_mc_add_addr(&hash, mc->dmi_addr); |
||
414 | + } |
||
415 | + } |
||
416 | + |
||
417 | + spin_lock_irqsave(&mac->lock, flags); |
||
418 | + mac->multicast_hash = hash; |
||
419 | + spin_unlock_irqrestore(&mac->lock, flags); |
||
420 | + queue_work(zd_workqueue, &mac->set_multicast_hash_work); |
||
421 | +} |
||
422 | + |
||
423 | +int zd_mac_set_regdomain(struct zd_mac *mac, u8 regdomain) |
||
424 | +{ |
||
425 | + int r; |
||
426 | + u8 channel; |
||
427 | + |
||
428 | + ZD_ASSERT(!irqs_disabled()); |
||
429 | + spin_lock_irq(&mac->lock); |
||
430 | + if (regdomain == 0) { |
||
431 | + regdomain = mac->default_regdomain; |
||
432 | + } |
||
433 | + if (!zd_regdomain_supported(regdomain)) { |
||
434 | + spin_unlock_irq(&mac->lock); |
||
435 | + return -EINVAL; |
||
436 | + } |
||
437 | + mac->regdomain = regdomain; |
||
438 | + channel = mac->requested_channel; |
||
439 | + spin_unlock_irq(&mac->lock); |
||
440 | + |
||
441 | + r = zd_geo_init(zd_mac_to_ieee80211(mac), regdomain); |
||
442 | + if (r) |
||
443 | + return r; |
||
444 | + if (!zd_regdomain_supports_channel(regdomain, channel)) { |
||
445 | + r = reset_channel(mac); |
||
446 | + if (r) |
||
447 | + return r; |
||
448 | + } |
||
449 | + |
||
450 | + return 0; |
||
451 | +} |
||
452 | + |
||
453 | +u8 zd_mac_get_regdomain(struct zd_mac *mac) |
||
454 | +{ |
||
455 | + unsigned long flags; |
||
456 | + u8 regdomain; |
||
457 | + |
||
458 | + spin_lock_irqsave(&mac->lock, flags); |
||
459 | + regdomain = mac->regdomain; |
||
460 | + spin_unlock_irqrestore(&mac->lock, flags); |
||
461 | + return regdomain; |
||
462 | +} |
||
463 | + |
||
464 | +/* Fallback to lowest rate, if rate is unknown. */ |
||
465 | +static u8 rate_to_zd_rate(u8 rate) |
||
466 | +{ |
||
467 | + switch (rate) { |
||
468 | + case IEEE80211_CCK_RATE_2MB: |
||
469 | + return ZD_CCK_RATE_2M; |
||
470 | + case IEEE80211_CCK_RATE_5MB: |
||
471 | + return ZD_CCK_RATE_5_5M; |
||
472 | + case IEEE80211_CCK_RATE_11MB: |
||
473 | + return ZD_CCK_RATE_11M; |
||
474 | + case IEEE80211_OFDM_RATE_6MB: |
||
475 | + return ZD_OFDM_RATE_6M; |
||
476 | + case IEEE80211_OFDM_RATE_9MB: |
||
477 | + return ZD_OFDM_RATE_9M; |
||
478 | + case IEEE80211_OFDM_RATE_12MB: |
||
479 | + return ZD_OFDM_RATE_12M; |
||
480 | + case IEEE80211_OFDM_RATE_18MB: |
||
481 | + return ZD_OFDM_RATE_18M; |
||
482 | + case IEEE80211_OFDM_RATE_24MB: |
||
483 | + return ZD_OFDM_RATE_24M; |
||
484 | + case IEEE80211_OFDM_RATE_36MB: |
||
485 | + return ZD_OFDM_RATE_36M; |
||
486 | + case IEEE80211_OFDM_RATE_48MB: |
||
487 | + return ZD_OFDM_RATE_48M; |
||
488 | + case IEEE80211_OFDM_RATE_54MB: |
||
489 | + return ZD_OFDM_RATE_54M; |
||
490 | + } |
||
491 | + return ZD_CCK_RATE_1M; |
||
492 | +} |
||
493 | + |
||
494 | +static u16 rate_to_cr_rate(u8 rate) |
||
495 | +{ |
||
496 | + switch (rate) { |
||
497 | + case IEEE80211_CCK_RATE_2MB: |
||
498 | + return CR_RATE_1M; |
||
499 | + case IEEE80211_CCK_RATE_5MB: |
||
500 | + return CR_RATE_5_5M; |
||
501 | + case IEEE80211_CCK_RATE_11MB: |
||
502 | + return CR_RATE_11M; |
||
503 | + case IEEE80211_OFDM_RATE_6MB: |
||
504 | + return CR_RATE_6M; |
||
505 | + case IEEE80211_OFDM_RATE_9MB: |
||
506 | + return CR_RATE_9M; |
||
507 | + case IEEE80211_OFDM_RATE_12MB: |
||
508 | + return CR_RATE_12M; |
||
509 | + case IEEE80211_OFDM_RATE_18MB: |
||
510 | + return CR_RATE_18M; |
||
511 | + case IEEE80211_OFDM_RATE_24MB: |
||
512 | + return CR_RATE_24M; |
||
513 | + case IEEE80211_OFDM_RATE_36MB: |
||
514 | + return CR_RATE_36M; |
||
515 | + case IEEE80211_OFDM_RATE_48MB: |
||
516 | + return CR_RATE_48M; |
||
517 | + case IEEE80211_OFDM_RATE_54MB: |
||
518 | + return CR_RATE_54M; |
||
519 | + } |
||
520 | + return CR_RATE_1M; |
||
521 | +} |
||
522 | + |
||
523 | +static void try_enable_tx(struct zd_mac *mac) |
||
524 | +{ |
||
525 | + unsigned long flags; |
||
526 | + |
||
527 | + spin_lock_irqsave(&mac->lock, flags); |
||
528 | + if (mac->updating_rts_rate == 0 && mac->updating_basic_rates == 0) |
||
529 | + netif_wake_queue(mac->netdev); |
||
530 | + spin_unlock_irqrestore(&mac->lock, flags); |
||
531 | +} |
||
532 | + |
||
533 | +static void set_rts_cts_work(struct work_struct *work) |
||
534 | +{ |
||
535 | + struct zd_mac *mac = |
||
536 | + container_of(work, struct zd_mac, set_rts_cts_work.work); |
||
537 | + unsigned long flags; |
||
538 | + u8 rts_rate; |
||
539 | + unsigned int short_preamble; |
||
540 | + |
||
541 | + mutex_lock(&mac->chip.mutex); |
||
542 | + |
||
543 | + spin_lock_irqsave(&mac->lock, flags); |
||
544 | + mac->updating_rts_rate = 0; |
||
545 | + rts_rate = mac->rts_rate; |
||
546 | + short_preamble = mac->short_preamble; |
||
547 | + spin_unlock_irqrestore(&mac->lock, flags); |
||
548 | + |
||
549 | + zd_chip_set_rts_cts_rate_locked(&mac->chip, rts_rate, short_preamble); |
||
550 | + mutex_unlock(&mac->chip.mutex); |
||
551 | + |
||
552 | + try_enable_tx(mac); |
||
553 | +} |
||
554 | + |
||
555 | +static void set_basic_rates_work(struct work_struct *work) |
||
556 | +{ |
||
557 | + struct zd_mac *mac = |
||
558 | + container_of(work, struct zd_mac, set_basic_rates_work.work); |
||
559 | + unsigned long flags; |
||
560 | + u16 basic_rates; |
||
561 | + |
||
562 | + mutex_lock(&mac->chip.mutex); |
||
563 | + |
||
564 | + spin_lock_irqsave(&mac->lock, flags); |
||
565 | + mac->updating_basic_rates = 0; |
||
566 | + basic_rates = mac->basic_rates; |
||
567 | + spin_unlock_irqrestore(&mac->lock, flags); |
||
568 | + |
||
569 | + zd_chip_set_basic_rates_locked(&mac->chip, basic_rates); |
||
570 | + mutex_unlock(&mac->chip.mutex); |
||
571 | + |
||
572 | + try_enable_tx(mac); |
||
573 | +} |
||
574 | + |
||
575 | +static void bssinfo_change(struct net_device *netdev, u32 changes) |
||
576 | +{ |
||
577 | + struct zd_mac *mac = zd_netdev_mac(netdev); |
||
578 | + struct ieee80211softmac_device *softmac = ieee80211_priv(netdev); |
||
579 | + struct ieee80211softmac_bss_info *bssinfo = &softmac->bssinfo; |
||
580 | + int need_set_rts_cts = 0; |
||
581 | + int need_set_rates = 0; |
||
582 | + u16 basic_rates; |
||
583 | + unsigned long flags; |
||
584 | + |
||
585 | + dev_dbg_f(zd_mac_dev(mac), "changes: %x\n", changes); |
||
586 | + |
||
587 | + if (changes & IEEE80211SOFTMAC_BSSINFOCHG_SHORT_PREAMBLE) { |
||
588 | + spin_lock_irqsave(&mac->lock, flags); |
||
589 | + mac->short_preamble = bssinfo->short_preamble; |
||
590 | + spin_unlock_irqrestore(&mac->lock, flags); |
||
591 | + need_set_rts_cts = 1; |
||
592 | + } |
||
593 | + |
||
594 | + if (changes & IEEE80211SOFTMAC_BSSINFOCHG_RATES) { |
||
595 | + /* Set RTS rate to highest available basic rate */ |
||
596 | + u8 hi_rate = ieee80211softmac_highest_supported_rate(softmac, |
||
597 | + &bssinfo->supported_rates, 1); |
||
598 | + hi_rate = rate_to_zd_rate(hi_rate); |
||
599 | + |
||
600 | + spin_lock_irqsave(&mac->lock, flags); |
||
601 | + if (hi_rate != mac->rts_rate) { |
||
602 | + mac->rts_rate = hi_rate; |
||
603 | + need_set_rts_cts = 1; |
||
604 | + } |
||
605 | + spin_unlock_irqrestore(&mac->lock, flags); |
||
606 | + |
||
607 | + /* Set basic rates */ |
||
608 | + need_set_rates = 1; |
||
609 | + if (bssinfo->supported_rates.count == 0) { |
||
610 | + /* Allow the device to be flexible */ |
||
611 | + basic_rates = CR_RATES_80211B | CR_RATES_80211G; |
||
612 | + } else { |
||
613 | + int i = 0; |
||
614 | + basic_rates = 0; |
||
615 | + |
||
616 | + for (i = 0; i < bssinfo->supported_rates.count; i++) { |
||
617 | + u16 rate = bssinfo->supported_rates.rates[i]; |
||
618 | + if ((rate & IEEE80211_BASIC_RATE_MASK) == 0) |
||
619 | + continue; |
||
620 | + |
||
621 | + rate &= ~IEEE80211_BASIC_RATE_MASK; |
||
622 | + basic_rates |= rate_to_cr_rate(rate); |
||
623 | + } |
||
624 | + } |
||
625 | + spin_lock_irqsave(&mac->lock, flags); |
||
626 | + mac->basic_rates = basic_rates; |
||
627 | + spin_unlock_irqrestore(&mac->lock, flags); |
||
628 | + } |
||
629 | + |
||
630 | + /* Schedule any changes we made above */ |
||
631 | + |
||
632 | + spin_lock_irqsave(&mac->lock, flags); |
||
633 | + if (need_set_rts_cts && !mac->updating_rts_rate) { |
||
634 | + mac->updating_rts_rate = 1; |
||
635 | + netif_stop_queue(mac->netdev); |
||
636 | + queue_delayed_work(zd_workqueue, &mac->set_rts_cts_work, 0); |
||
637 | + } |
||
638 | + if (need_set_rates && !mac->updating_basic_rates) { |
||
639 | + mac->updating_basic_rates = 1; |
||
640 | + netif_stop_queue(mac->netdev); |
||
641 | + queue_delayed_work(zd_workqueue, &mac->set_basic_rates_work, |
||
642 | + 0); |
||
643 | + } |
||
644 | + spin_unlock_irqrestore(&mac->lock, flags); |
||
645 | +} |
||
646 | + |
||
647 | +static void set_channel(struct net_device *netdev, u8 channel) |
||
648 | +{ |
||
649 | + struct zd_mac *mac = zd_netdev_mac(netdev); |
||
650 | + |
||
651 | + dev_dbg_f(zd_mac_dev(mac), "channel %d\n", channel); |
||
652 | + |
||
653 | + zd_chip_set_channel(&mac->chip, channel); |
||
654 | +} |
||
655 | + |
||
656 | +int zd_mac_request_channel(struct zd_mac *mac, u8 channel) |
||
657 | +{ |
||
658 | + unsigned long lock_flags; |
||
659 | + struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac); |
||
660 | + |
||
661 | + if (ieee->iw_mode == IW_MODE_INFRA) |
||
662 | + return -EPERM; |
||
663 | + |
||
664 | + spin_lock_irqsave(&mac->lock, lock_flags); |
||
665 | + if (!zd_regdomain_supports_channel(mac->regdomain, channel)) { |
||
666 | + spin_unlock_irqrestore(&mac->lock, lock_flags); |
||
667 | + return -EINVAL; |
||
668 | + } |
||
669 | + mac->requested_channel = channel; |
||
670 | + spin_unlock_irqrestore(&mac->lock, lock_flags); |
||
671 | + if (netif_running(mac->netdev)) |
||
672 | + return zd_chip_set_channel(&mac->chip, channel); |
||
673 | + else |
||
674 | + return 0; |
||
675 | +} |
||
676 | + |
||
677 | +u8 zd_mac_get_channel(struct zd_mac *mac) |
||
678 | +{ |
||
679 | + u8 channel = zd_chip_get_channel(&mac->chip); |
||
680 | + |
||
681 | + dev_dbg_f(zd_mac_dev(mac), "channel %u\n", channel); |
||
682 | + return channel; |
||
683 | +} |
||
684 | + |
||
685 | +/* If wrong rate is given, we are falling back to the slowest rate: 1MBit/s */ |
||
686 | +static u8 zd_rate_typed(u8 zd_rate) |
||
687 | +{ |
||
688 | + static const u8 typed_rates[16] = { |
||
689 | + [ZD_CCK_RATE_1M] = ZD_CS_CCK|ZD_CCK_RATE_1M, |
||
690 | + [ZD_CCK_RATE_2M] = ZD_CS_CCK|ZD_CCK_RATE_2M, |
||
691 | + [ZD_CCK_RATE_5_5M] = ZD_CS_CCK|ZD_CCK_RATE_5_5M, |
||
692 | + [ZD_CCK_RATE_11M] = ZD_CS_CCK|ZD_CCK_RATE_11M, |
||
693 | + [ZD_OFDM_RATE_6M] = ZD_CS_OFDM|ZD_OFDM_RATE_6M, |
||
694 | + [ZD_OFDM_RATE_9M] = ZD_CS_OFDM|ZD_OFDM_RATE_9M, |
||
695 | + [ZD_OFDM_RATE_12M] = ZD_CS_OFDM|ZD_OFDM_RATE_12M, |
||
696 | + [ZD_OFDM_RATE_18M] = ZD_CS_OFDM|ZD_OFDM_RATE_18M, |
||
697 | + [ZD_OFDM_RATE_24M] = ZD_CS_OFDM|ZD_OFDM_RATE_24M, |
||
698 | + [ZD_OFDM_RATE_36M] = ZD_CS_OFDM|ZD_OFDM_RATE_36M, |
||
699 | + [ZD_OFDM_RATE_48M] = ZD_CS_OFDM|ZD_OFDM_RATE_48M, |
||
700 | + [ZD_OFDM_RATE_54M] = ZD_CS_OFDM|ZD_OFDM_RATE_54M, |
||
701 | + }; |
||
702 | + |
||
703 | + ZD_ASSERT(ZD_CS_RATE_MASK == 0x0f); |
||
704 | + return typed_rates[zd_rate & ZD_CS_RATE_MASK]; |
||
705 | +} |
||
706 | + |
||
707 | +int zd_mac_set_mode(struct zd_mac *mac, u32 mode) |
||
708 | +{ |
||
709 | + struct ieee80211_device *ieee; |
||
710 | + |
||
711 | + switch (mode) { |
||
712 | + case IW_MODE_AUTO: |
||
713 | + case IW_MODE_ADHOC: |
||
714 | + case IW_MODE_INFRA: |
||
715 | + mac->netdev->type = ARPHRD_ETHER; |
||
716 | + break; |
||
717 | + case IW_MODE_MONITOR: |
||
718 | + mac->netdev->type = ARPHRD_IEEE80211_RADIOTAP; |
||
719 | + break; |
||
720 | + default: |
||
721 | + dev_dbg_f(zd_mac_dev(mac), "wrong mode %u\n", mode); |
||
722 | + return -EINVAL; |
||
723 | + } |
||
724 | + |
||
725 | + ieee = zd_mac_to_ieee80211(mac); |
||
726 | + ZD_ASSERT(!irqs_disabled()); |
||
727 | + spin_lock_irq(&ieee->lock); |
||
728 | + ieee->iw_mode = mode; |
||
729 | + spin_unlock_irq(&ieee->lock); |
||
730 | + |
||
731 | + if (netif_running(mac->netdev)) |
||
732 | + return reset_mode(mac); |
||
733 | + |
||
734 | + return 0; |
||
735 | +} |
||
736 | + |
||
737 | +int zd_mac_get_mode(struct zd_mac *mac, u32 *mode) |
||
738 | +{ |
||
739 | + unsigned long flags; |
||
740 | + struct ieee80211_device *ieee; |
||
741 | + |
||
742 | + ieee = zd_mac_to_ieee80211(mac); |
||
743 | + spin_lock_irqsave(&ieee->lock, flags); |
||
744 | + *mode = ieee->iw_mode; |
||
745 | + spin_unlock_irqrestore(&ieee->lock, flags); |
||
746 | + return 0; |
||
747 | +} |
||
748 | + |
||
749 | +int zd_mac_get_range(struct zd_mac *mac, struct iw_range *range) |
||
750 | +{ |
||
751 | + int i; |
||
752 | + const struct channel_range *channel_range; |
||
753 | + u8 regdomain; |
||
754 | + |
||
755 | + memset(range, 0, sizeof(*range)); |
||
756 | + |
||
757 | + /* FIXME: Not so important and depends on the mode. For 802.11g |
||
758 | + * usually this value is used. It seems to be that Bit/s number is |
||
759 | + * given here. |
||
760 | + */ |
||
761 | + range->throughput = 27 * 1000 * 1000; |
||
762 | + |
||
763 | + range->max_qual.qual = 100; |
||
764 | + range->max_qual.level = 100; |
||
765 | + |
||
766 | + /* FIXME: Needs still to be tuned. */ |
||
767 | + range->avg_qual.qual = 71; |
||
768 | + range->avg_qual.level = 80; |
||
769 | + |
||
770 | + /* FIXME: depends on standard? */ |
||
771 | + range->min_rts = 256; |
||
772 | + range->max_rts = 2346; |
||
773 | + |
||
774 | + range->min_frag = MIN_FRAG_THRESHOLD; |
||
775 | + range->max_frag = MAX_FRAG_THRESHOLD; |
||
776 | + |
||
777 | + range->max_encoding_tokens = WEP_KEYS; |
||
778 | + range->num_encoding_sizes = 2; |
||
779 | + range->encoding_size[0] = 5; |
||
780 | + range->encoding_size[1] = WEP_KEY_LEN; |
||
781 | + |
||
782 | + range->we_version_compiled = WIRELESS_EXT; |
||
783 | + range->we_version_source = 20; |
||
784 | + |
||
785 | + range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | |
||
786 | + IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; |
||
787 | + |
||
788 | + ZD_ASSERT(!irqs_disabled()); |
||
789 | + spin_lock_irq(&mac->lock); |
||
790 | + regdomain = mac->regdomain; |
||
791 | + spin_unlock_irq(&mac->lock); |
||
792 | + channel_range = zd_channel_range(regdomain); |
||
793 | + |
||
794 | + range->num_channels = channel_range->end - channel_range->start; |
||
795 | + range->old_num_channels = range->num_channels; |
||
796 | + range->num_frequency = range->num_channels; |
||
797 | + range->old_num_frequency = range->num_frequency; |
||
798 | + |
||
799 | + for (i = 0; i < range->num_frequency; i++) { |
||
800 | + struct iw_freq *freq = &range->freq[i]; |
||
801 | + freq->i = channel_range->start + i; |
||
802 | + zd_channel_to_freq(freq, freq->i); |
||
803 | + } |
||
804 | + |
||
805 | + return 0; |
||
806 | +} |
||
807 | + |
||
808 | +static int zd_calc_tx_length_us(u8 *service, u8 zd_rate, u16 tx_length) |
||
809 | +{ |
||
810 | + static const u8 rate_divisor[] = { |
||
811 | + [ZD_CCK_RATE_1M] = 1, |
||
812 | + [ZD_CCK_RATE_2M] = 2, |
||
813 | + [ZD_CCK_RATE_5_5M] = 11, /* bits must be doubled */ |
||
814 | + [ZD_CCK_RATE_11M] = 11, |
||
815 | + [ZD_OFDM_RATE_6M] = 6, |
||
816 | + [ZD_OFDM_RATE_9M] = 9, |
||
817 | + [ZD_OFDM_RATE_12M] = 12, |
||
818 | + [ZD_OFDM_RATE_18M] = 18, |
||
819 | + [ZD_OFDM_RATE_24M] = 24, |
||
820 | + [ZD_OFDM_RATE_36M] = 36, |
||
821 | + [ZD_OFDM_RATE_48M] = 48, |
||
822 | + [ZD_OFDM_RATE_54M] = 54, |
||
823 | + }; |
||
824 | + |
||
825 | + u32 bits = (u32)tx_length * 8; |
||
826 | + u32 divisor; |
||
827 | + |
||
828 | + divisor = rate_divisor[zd_rate]; |
||
829 | + if (divisor == 0) |
||
830 | + return -EINVAL; |
||
831 | + |
||
832 | + switch (zd_rate) { |
||
833 | + case ZD_CCK_RATE_5_5M: |
||
834 | + bits = (2*bits) + 10; /* round up to the next integer */ |
||
835 | + break; |
||
836 | + case ZD_CCK_RATE_11M: |
||
837 | + if (service) { |
||
838 | + u32 t = bits % 11; |
||
839 | + *service &= ~ZD_PLCP_SERVICE_LENGTH_EXTENSION; |
||
840 | + if (0 < t && t <= 3) { |
||
841 | + *service |= ZD_PLCP_SERVICE_LENGTH_EXTENSION; |
||
842 | + } |
||
843 | + } |
||
844 | + bits += 10; /* round up to the next integer */ |
||
845 | + break; |
||
846 | + } |
||
847 | + |
||
848 | + return bits/divisor; |
||
849 | +} |
||
850 | + |
||
851 | +enum { |
||
852 | + R2M_SHORT_PREAMBLE = 0x01, |
||
853 | + R2M_11A = 0x02, |
||
854 | +}; |
||
855 | + |
||
856 | +static u8 zd_rate_to_modulation(u8 zd_rate, int flags) |
||
857 | +{ |
||
858 | + u8 modulation; |
||
859 | + |
||
860 | + modulation = zd_rate_typed(zd_rate); |
||
861 | + if (flags & R2M_SHORT_PREAMBLE) { |
||
862 | + switch (ZD_CS_RATE(modulation)) { |
||
863 | + case ZD_CCK_RATE_2M: |
||
864 | + case ZD_CCK_RATE_5_5M: |
||
865 | + case ZD_CCK_RATE_11M: |
||
866 | + modulation |= ZD_CS_CCK_PREA_SHORT; |
||
867 | + return modulation; |
||
868 | + } |
||
869 | + } |
||
870 | + if (flags & R2M_11A) { |
||
871 | + if (ZD_CS_TYPE(modulation) == ZD_CS_OFDM) |
||
872 | + modulation |= ZD_CS_OFDM_MODE_11A; |
||
873 | + } |
||
874 | + return modulation; |
||
875 | +} |
||
876 | + |
||
877 | +static void cs_set_modulation(struct zd_mac *mac, struct zd_ctrlset *cs, |
||
878 | + struct ieee80211_hdr_4addr *hdr) |
||
879 | +{ |
||
880 | + struct ieee80211softmac_device *softmac = ieee80211_priv(mac->netdev); |
||
881 | + u16 ftype = WLAN_FC_GET_TYPE(le16_to_cpu(hdr->frame_ctl)); |
||
882 | + u8 rate, zd_rate; |
||
883 | + int is_mgt = (ftype == IEEE80211_FTYPE_MGMT) != 0; |
||
884 | + int is_multicast = is_multicast_ether_addr(hdr->addr1); |
||
885 | + int short_preamble = ieee80211softmac_short_preamble_ok(softmac, |
||
886 | + is_multicast, is_mgt); |
||
887 | + int flags = 0; |
||
888 | + |
||
889 | + /* FIXME: 802.11a? */ |
||
890 | + rate = ieee80211softmac_suggest_txrate(softmac, is_multicast, is_mgt); |
||
891 | + |
||
892 | + if (short_preamble) |
||
893 | + flags |= R2M_SHORT_PREAMBLE; |
||
894 | + |
||
895 | + zd_rate = rate_to_zd_rate(rate); |
||
896 | + cs->modulation = zd_rate_to_modulation(zd_rate, flags); |
||
897 | +} |
||
898 | + |
||
899 | +static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs, |
||
900 | + struct ieee80211_hdr_4addr *header) |
||
901 | +{ |
||
902 | + struct ieee80211softmac_device *softmac = ieee80211_priv(mac->netdev); |
||
903 | + unsigned int tx_length = le16_to_cpu(cs->tx_length); |
||
904 | + u16 fctl = le16_to_cpu(header->frame_ctl); |
||
905 | + u16 ftype = WLAN_FC_GET_TYPE(fctl); |
||
906 | + u16 stype = WLAN_FC_GET_STYPE(fctl); |
||
907 | + |
||
908 | + /* |
||
909 | + * CONTROL TODO: |
||
910 | + * - if backoff needed, enable bit 0 |
||
911 | + * - if burst (backoff not needed) disable bit 0 |
||
912 | + */ |
||
913 | + |
||
914 | + cs->control = 0; |
||
915 | + |
||
916 | + /* First fragment */ |
||
917 | + if (WLAN_GET_SEQ_FRAG(le16_to_cpu(header->seq_ctl)) == 0) |
||
918 | + cs->control |= ZD_CS_NEED_RANDOM_BACKOFF; |
||
919 | + |
||
920 | + /* Multicast */ |
||
921 | + if (is_multicast_ether_addr(header->addr1)) |
||
922 | + cs->control |= ZD_CS_MULTICAST; |
||
923 | + |
||
924 | + /* PS-POLL */ |
||
925 | + if (stype == IEEE80211_STYPE_PSPOLL) |
||
926 | + cs->control |= ZD_CS_PS_POLL_FRAME; |
||
927 | + |
||
928 | + /* Unicast data frames over the threshold should have RTS */ |
||
929 | + if (!is_multicast_ether_addr(header->addr1) && |
||
930 | + ftype != IEEE80211_FTYPE_MGMT && |
||
931 | + tx_length > zd_netdev_ieee80211(mac->netdev)->rts) |
||
932 | + cs->control |= ZD_CS_RTS; |
||
933 | + |
||
934 | + /* Use CTS-to-self protection if required */ |
||
935 | + if (ZD_CS_TYPE(cs->modulation) == ZD_CS_OFDM && |
||
936 | + ieee80211softmac_protection_needed(softmac)) { |
||
937 | + /* FIXME: avoid sending RTS *and* self-CTS, is that correct? */ |
||
938 | + cs->control &= ~ZD_CS_RTS; |
||
939 | + cs->control |= ZD_CS_SELF_CTS; |
||
940 | + } |
||
941 | + |
||
942 | + /* FIXME: Management frame? */ |
||
943 | +} |
||
944 | + |
||
945 | +static int fill_ctrlset(struct zd_mac *mac, |
||
946 | + struct ieee80211_txb *txb, |
||
947 | + int frag_num) |
||
948 | +{ |
||
949 | + struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac); |
||
950 | + int r; |
||
951 | + struct sk_buff *skb = txb->fragments[frag_num]; |
||
952 | + struct ieee80211_hdr_4addr *hdr = |
||
953 | + (struct ieee80211_hdr_4addr *) skb->data; |
||
954 | + unsigned int frag_len = skb->len + IEEE80211_FCS_LEN; |
||
955 | + unsigned int next_frag_len; |
||
956 | + unsigned int packet_length; |
||
957 | + struct zd_ctrlset *cs = (struct zd_ctrlset *) |
||
958 | + skb_push(skb, sizeof(struct zd_ctrlset)); |
||
959 | + |
||
960 | + if (frag_num+1 < txb->nr_frags) { |
||
961 | + next_frag_len = txb->fragments[frag_num+1]->len + |
||
962 | + IEEE80211_FCS_LEN; |
||
963 | + } else { |
||
964 | + next_frag_len = 0; |
||
965 | + } |
||
966 | + ZD_ASSERT(frag_len <= 0xffff); |
||
967 | + ZD_ASSERT(next_frag_len <= 0xffff); |
||
968 | + |
||
969 | + cs_set_modulation(mac, cs, hdr); |
||
970 | + |
||
971 | + cs->tx_length = cpu_to_le16(frag_len); |
||
972 | + |
||
973 | + if(ieee->iw_mode == IW_MODE_MONITOR) |
||
974 | + cs->control = ZD_CS_MULTICAST; |
||
975 | + else |
||
976 | + cs_set_control(mac, cs, hdr); |
||
977 | + |
||
978 | + packet_length = frag_len + sizeof(struct zd_ctrlset) + 10; |
||
979 | + ZD_ASSERT(packet_length <= 0xffff); |
||
980 | + /* ZD1211B: Computing the length difference this way, gives us |
||
981 | + * flexibility to compute the packet length. |
||
982 | + */ |
||
983 | + cs->packet_length = cpu_to_le16(mac->chip.is_zd1211b ? |
||
984 | + packet_length - frag_len : packet_length); |
||
985 | + |
||
986 | + /* |
||
987 | + * CURRENT LENGTH: |
||
988 | + * - transmit frame length in microseconds |
||
989 | + * - seems to be derived from frame length |
||
990 | + * - see Cal_Us_Service() in zdinlinef.h |
||
991 | + * - if macp->bTxBurstEnable is enabled, then multiply by 4 |
||
992 | + * - bTxBurstEnable is never set in the vendor driver |
||
993 | + * |
||
994 | + * SERVICE: |
||
995 | + * - "for PLCP configuration" |
||
996 | + * - always 0 except in some situations at 802.11b 11M |
||
997 | + * - see line 53 of zdinlinef.h |
||
998 | + */ |
||
999 | + cs->service = 0; |
||
1000 | + r = zd_calc_tx_length_us(&cs->service, ZD_CS_RATE(cs->modulation), |
||
1001 | + le16_to_cpu(cs->tx_length)); |
||
1002 | + if (r < 0) |
||
1003 | + return r; |
||
1004 | + cs->current_length = cpu_to_le16(r); |
||
1005 | + |
||
1006 | + if (next_frag_len == 0) { |
||
1007 | + cs->next_frame_length = 0; |
||
1008 | + } else { |
||
1009 | + r = zd_calc_tx_length_us(NULL, ZD_CS_RATE(cs->modulation), |
||
1010 | + next_frag_len); |
||
1011 | + if (r < 0) |
||
1012 | + return r; |
||
1013 | + cs->next_frame_length = cpu_to_le16(r); |
||
1014 | + } |
||
1015 | + |
||
1016 | + return 0; |
||
1017 | +} |
||
1018 | + |
||
1019 | +static int zd_mac_tx(struct zd_mac *mac, struct ieee80211_txb *txb, int pri) |
||
1020 | +{ |
||
1021 | + int i, r; |
||
1022 | + struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac); |
||
1023 | + |
||
1024 | + for (i = 0; i < txb->nr_frags; i++) { |
||
1025 | + struct sk_buff *skb = txb->fragments[i]; |
||
1026 | + |
||
1027 | + r = fill_ctrlset(mac, txb, i); |
||
1028 | + if (r) { |
||
1029 | + ieee->stats.tx_dropped++; |
||
1030 | + return r; |
||
1031 | + } |
||
1032 | + |
||
1033 | + if(ieee->iw_mode == IW_MODE_MONITOR) |
||
1034 | + r = zd_usb_tx_inject(&mac->chip.usb, skb->data, skb->len); |
||
1035 | + else |
||
1036 | + r = zd_usb_tx(&mac->chip.usb, skb->data, skb->len); |
||
1037 | + if (r) { |
||
1038 | + ieee->stats.tx_dropped++; |
||
1039 | + return r; |
||
1040 | + } |
||
1041 | + } |
||
1042 | + |
||
1043 | + /* FIXME: shouldn't this be handled by the upper layers? */ |
||
1044 | + mac->netdev->trans_start = jiffies; |
||
1045 | + |
||
1046 | + ieee80211_txb_free(txb); |
||
1047 | + return 0; |
||
1048 | +} |
||
1049 | + |
||
1050 | +struct zd_rt_hdr { |
||
1051 | + struct ieee80211_radiotap_header rt_hdr; |
||
1052 | + u8 rt_flags; |
||
1053 | + u8 rt_rate; |
||
1054 | + u16 rt_channel; |
||
1055 | + u16 rt_chbitmask; |
||
1056 | + u8 rt_antsignal; |
||
1057 | + u8 rt_antnoise; |
||
1058 | +} __attribute__((packed)); |
||
1059 | + |
||
1060 | +static void fill_rt_header(void *buffer, struct zd_mac *mac, |
||
1061 | + const struct ieee80211_rx_stats *stats, |
||
1062 | + const struct rx_status *status) |
||
1063 | +{ |
||
1064 | + struct zd_rt_hdr *hdr = buffer; |
||
1065 | + |
||
1066 | + hdr->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION; |
||
1067 | + hdr->rt_hdr.it_pad = 0; |
||
1068 | + hdr->rt_hdr.it_len = cpu_to_le16(sizeof(struct zd_rt_hdr)); |
||
1069 | + hdr->rt_hdr.it_present = cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) | |
||
1070 | + (1 << IEEE80211_RADIOTAP_CHANNEL) | |
||
1071 | + (1 << IEEE80211_RADIOTAP_RATE) | |
||
1072 | + (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | |
||
1073 | + (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE)); |
||
1074 | + |
||
1075 | + hdr->rt_flags = 0; |
||
1076 | + if (status->decryption_type & (ZD_RX_WEP64|ZD_RX_WEP128|ZD_RX_WEP256)) |
||
1077 | + hdr->rt_flags |= IEEE80211_RADIOTAP_F_WEP; |
||
1078 | + |
||
1079 | + hdr->rt_rate = stats->rate / 5; |
||
1080 | + |
||
1081 | + /* FIXME: 802.11a */ |
||
1082 | + hdr->rt_channel = cpu_to_le16(ieee80211chan2mhz( |
||
1083 | + _zd_chip_get_channel(&mac->chip))); |
||
1084 | + hdr->rt_chbitmask = cpu_to_le16(IEEE80211_CHAN_2GHZ | |
||
1085 | + ((status->frame_status & ZD_RX_FRAME_MODULATION_MASK) == |
||
1086 | + ZD_RX_OFDM ? IEEE80211_CHAN_OFDM : IEEE80211_CHAN_CCK)); |
||
1087 | + |
||
1088 | + hdr->rt_antsignal = status->signal_strength; |
||
1089 | + hdr->rt_antnoise = stats->noise; |
||
1090 | +} |
||
1091 | + |
||
1092 | +/* Returns 1 if the data packet is for us and 0 otherwise. */ |
||
1093 | +static int is_data_packet_for_us(struct ieee80211_device *ieee, |
||
1094 | + struct ieee80211_hdr_4addr *hdr) |
||
1095 | +{ |
||
1096 | + struct net_device *netdev = ieee->dev; |
||
1097 | + u16 fc = le16_to_cpu(hdr->frame_ctl); |
||
1098 | + |
||
1099 | + ZD_ASSERT(WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA); |
||
1100 | + |
||
1101 | + switch (ieee->iw_mode) { |
||
1102 | + case IW_MODE_ADHOC: |
||
1103 | + if ((fc & (IEEE80211_FCTL_TODS|IEEE80211_FCTL_FROMDS)) != 0 || |
||
1104 | + compare_ether_addr(hdr->addr3, ieee->bssid) != 0) |
||
1105 | + return 0; |
||
1106 | + break; |
||
1107 | + case IW_MODE_AUTO: |
||
1108 | + case IW_MODE_INFRA: |
||
1109 | + if ((fc & (IEEE80211_FCTL_TODS|IEEE80211_FCTL_FROMDS)) != |
||
1110 | + IEEE80211_FCTL_FROMDS || |
||
1111 | + compare_ether_addr(hdr->addr2, ieee->bssid) != 0) |
||
1112 | + return 0; |
||
1113 | + break; |
||
1114 | + default: |
||
1115 | + ZD_ASSERT(ieee->iw_mode != IW_MODE_MONITOR); |
||
1116 | + return 0; |
||
1117 | + } |
||
1118 | + |
||
1119 | + return compare_ether_addr(hdr->addr1, netdev->dev_addr) == 0 || |
||
1120 | + (is_multicast_ether_addr(hdr->addr1) && |
||
1121 | + compare_ether_addr(hdr->addr3, netdev->dev_addr) != 0) || |
||
1122 | + (netdev->flags & IFF_PROMISC); |
||
1123 | +} |
||
1124 | + |
||
1125 | +/* Filters received packets. The function returns 1 if the packet should be |
||
1126 | + * forwarded to ieee80211_rx(). If the packet should be ignored the function |
||
1127 | + * returns 0. If an invalid packet is found the function returns -EINVAL. |
||
1128 | + * |
||
1129 | + * The function calls ieee80211_rx_mgt() directly. |
||
1130 | + * |
||
1131 | + * It has been based on ieee80211_rx_any. |
||
1132 | + */ |
||
1133 | +static int filter_rx(struct ieee80211_device *ieee, |
||
1134 | + const u8 *buffer, unsigned int length, |
||
1135 | + struct ieee80211_rx_stats *stats) |
||
1136 | +{ |
||
1137 | + struct ieee80211_hdr_4addr *hdr; |
||
1138 | + u16 fc; |
||
1139 | + |
||
1140 | + if (ieee->iw_mode == IW_MODE_MONITOR) |
||
1141 | + return 1; |
||
1142 | + |
||
1143 | + hdr = (struct ieee80211_hdr_4addr *)buffer; |
||
1144 | + fc = le16_to_cpu(hdr->frame_ctl); |
||
1145 | + if ((fc & IEEE80211_FCTL_VERS) != 0) |
||
1146 | + return -EINVAL; |
||
1147 | + |
||
1148 | + switch (WLAN_FC_GET_TYPE(fc)) { |
||
1149 | + case IEEE80211_FTYPE_MGMT: |
||
1150 | + if (length < sizeof(struct ieee80211_hdr_3addr)) |
||
1151 | + return -EINVAL; |
||
1152 | + ieee80211_rx_mgt(ieee, hdr, stats); |
||
1153 | + return 0; |
||
1154 | + case IEEE80211_FTYPE_CTL: |
||
1155 | + return 0; |
||
1156 | + case IEEE80211_FTYPE_DATA: |
||
1157 | + /* Ignore invalid short buffers */ |
||
1158 | + if (length < sizeof(struct ieee80211_hdr_3addr)) |
||
1159 | + return -EINVAL; |
||
1160 | + return is_data_packet_for_us(ieee, hdr); |
||
1161 | + } |
||
1162 | + |
||
1163 | + return -EINVAL; |
||
1164 | +} |
||
1165 | + |
||
1166 | +static void update_qual_rssi(struct zd_mac *mac, |
||
1167 | + const u8 *buffer, unsigned int length, |
||
1168 | + u8 qual_percent, u8 rssi_percent) |
||
1169 | +{ |
||
1170 | + unsigned long flags; |
||
1171 | + struct ieee80211_hdr_3addr *hdr; |
||
1172 | + int i; |
||
1173 | + |
||
1174 | + hdr = (struct ieee80211_hdr_3addr *)buffer; |
||
1175 | + if (length < offsetof(struct ieee80211_hdr_3addr, addr3)) |
||
1176 | + return; |
||
1177 | + if (compare_ether_addr(hdr->addr2, zd_mac_to_ieee80211(mac)->bssid) != 0) |
||
1178 | + return; |
||
1179 | + |
||
1180 | + spin_lock_irqsave(&mac->lock, flags); |
||
1181 | + i = mac->stats_count % ZD_MAC_STATS_BUFFER_SIZE; |
||
1182 | + mac->qual_buffer[i] = qual_percent; |
||
1183 | + mac->rssi_buffer[i] = rssi_percent; |
||
1184 | + mac->stats_count++; |
||
1185 | + spin_unlock_irqrestore(&mac->lock, flags); |
||
1186 | +} |
||
1187 | + |
||
1188 | +static int fill_rx_stats(struct ieee80211_rx_stats *stats, |
||
1189 | + const struct rx_status **pstatus, |
||
1190 | + struct zd_mac *mac, |
||
1191 | + const u8 *buffer, unsigned int length) |
||
1192 | +{ |
||
1193 | + const struct rx_status *status; |
||
1194 | + |
||
1195 | + *pstatus = status = zd_tail(buffer, length, sizeof(struct rx_status)); |
||
1196 | + if (status->frame_status & ZD_RX_ERROR |
||
1197 | + || status->frame_status & ~0x21) { |
||
1198 | + struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac); |
||
1199 | + ieee->stats.rx_errors++; |
||
1200 | + if (status->frame_status & ZD_RX_TIMEOUT_ERROR) |
||
1201 | + ieee->stats.rx_missed_errors++; |
||
1202 | + else if (status->frame_status & ZD_RX_FIFO_OVERRUN_ERROR) |
||
1203 | + ieee->stats.rx_fifo_errors++; |
||
1204 | + else if (status->frame_status & ZD_RX_DECRYPTION_ERROR) |
||
1205 | + ieee->ieee_stats.rx_discards_undecryptable++; |
||
1206 | + else if (status->frame_status & ZD_RX_CRC32_ERROR) { |
||
1207 | + ieee->stats.rx_crc_errors++; |
||
1208 | + ieee->ieee_stats.rx_fcs_errors++; |
||
1209 | + } |
||
1210 | + else if (status->frame_status & ZD_RX_CRC16_ERROR) |
||
1211 | + ieee->stats.rx_crc_errors++; |
||
1212 | + return -EINVAL; |
||
1213 | + } |
||
1214 | + |
||
1215 | + memset(stats, 0, sizeof(struct ieee80211_rx_stats)); |
||
1216 | + stats->len = length - (ZD_PLCP_HEADER_SIZE + IEEE80211_FCS_LEN + |
||
1217 | + + sizeof(struct rx_status)); |
||
1218 | + /* FIXME: 802.11a */ |
||
1219 | + stats->freq = IEEE80211_24GHZ_BAND; |
||
1220 | + stats->received_channel = _zd_chip_get_channel(&mac->chip); |
||
1221 | + stats->rssi = zd_rx_strength_percent(status->signal_strength); |
||
1222 | + stats->signal = zd_rx_qual_percent(buffer, |
||
1223 | + length - sizeof(struct rx_status), |
||
1224 | + status); |
||
1225 | + stats->mask = IEEE80211_STATMASK_RSSI | IEEE80211_STATMASK_SIGNAL; |
||
1226 | + stats->rate = zd_rx_rate(buffer, status); |
||
1227 | + if (stats->rate) |
||
1228 | + stats->mask |= IEEE80211_STATMASK_RATE; |
||
1229 | + |
||
1230 | + return 0; |
||
1231 | +} |
||
1232 | + |
||
1233 | +static void zd_mac_rx(struct zd_mac *mac, struct sk_buff *skb) |
||
1234 | +{ |
||
1235 | + int r; |
||
1236 | + struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac); |
||
1237 | + struct ieee80211_rx_stats stats; |
||
1238 | + const struct rx_status *status; |
||
1239 | + |
||
1240 | + if (skb->len < ZD_PLCP_HEADER_SIZE + IEEE80211_1ADDR_LEN + |
||
1241 | + IEEE80211_FCS_LEN + sizeof(struct rx_status)) |
||
1242 | + { |
||
1243 | + ieee->stats.rx_errors++; |
||
1244 | + ieee->stats.rx_length_errors++; |
||
1245 | + goto free_skb; |
||
1246 | + } |
||
1247 | + |
||
1248 | + r = fill_rx_stats(&stats, &status, mac, skb->data, skb->len); |
||
1249 | + if (r) { |
||
1250 | + /* Only packets with rx errors are included here. |
||
1251 | + * The error stats have already been set in fill_rx_stats. |
||
1252 | + */ |
||
1253 | + goto free_skb; |
||
1254 | + } |
||
1255 | + |
||
1256 | + __skb_pull(skb, ZD_PLCP_HEADER_SIZE); |
||
1257 | + __skb_trim(skb, skb->len - |
||
1258 | + (IEEE80211_FCS_LEN + sizeof(struct rx_status))); |
||
1259 | + |
||
1260 | + update_qual_rssi(mac, skb->data, skb->len, stats.signal, |
||
1261 | + status->signal_strength); |
||
1262 | + |
||
1263 | + r = filter_rx(ieee, skb->data, skb->len, &stats); |
||
1264 | + if (r <= 0) { |
||
1265 | + if (r < 0) { |
||
1266 | + ieee->stats.rx_errors++; |
||
1267 | + dev_dbg_f(zd_mac_dev(mac), "Error in packet.\n"); |
||
1268 | + } |
||
1269 | + goto free_skb; |
||
1270 | + } |
||
1271 | + |
||
1272 | + if (ieee->iw_mode == IW_MODE_MONITOR) |
||
1273 | + fill_rt_header(skb_push(skb, sizeof(struct zd_rt_hdr)), mac, |
||
1274 | + &stats, status); |
||
1275 | + |
||
1276 | + r = ieee80211_rx(ieee, skb, &stats); |
||
1277 | + if (r) |
||
1278 | + return; |
||
1279 | +free_skb: |
||
1280 | + /* We are always in a soft irq. */ |
||
1281 | + dev_kfree_skb(skb); |
||
1282 | +} |
||
1283 | + |
||
1284 | +static void do_rx(unsigned long mac_ptr) |
||
1285 | +{ |
||
1286 | + struct zd_mac *mac = (struct zd_mac *)mac_ptr; |
||
1287 | + struct sk_buff *skb; |
||
1288 | + |
||
1289 | + while ((skb = skb_dequeue(&mac->rx_queue)) != NULL) |
||
1290 | + zd_mac_rx(mac, skb); |
||
1291 | +} |
||
1292 | + |
||
1293 | +int zd_mac_rx_irq(struct zd_mac *mac, const u8 *buffer, unsigned int length) |
||
1294 | +{ |
||
1295 | + struct sk_buff *skb; |
||
1296 | + |
||
1297 | + skb = dev_alloc_skb(sizeof(struct zd_rt_hdr) + length); |
||
1298 | + if (!skb) { |
||
1299 | + struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac); |
||
1300 | + dev_warn(zd_mac_dev(mac), "Could not allocate skb.\n"); |
||
1301 | + ieee->stats.rx_dropped++; |
||
1302 | + return -ENOMEM; |
||
1303 | + } |
||
1304 | + skb_reserve(skb, sizeof(struct zd_rt_hdr)); |
||
1305 | + memcpy(__skb_put(skb, length), buffer, length); |
||
1306 | + skb_queue_tail(&mac->rx_queue, skb); |
||
1307 | + tasklet_schedule(&mac->rx_tasklet); |
||
1308 | + return 0; |
||
1309 | +} |
||
1310 | + |
||
1311 | +static int netdev_tx(struct ieee80211_txb *txb, struct net_device *netdev, |
||
1312 | + int pri) |
||
1313 | +{ |
||
1314 | + return zd_mac_tx(zd_netdev_mac(netdev), txb, pri); |
||
1315 | +} |
||
1316 | + |
||
1317 | +static void set_security(struct net_device *netdev, |
||
1318 | + struct ieee80211_security *sec) |
||
1319 | +{ |
||
1320 | + struct ieee80211_device *ieee = zd_netdev_ieee80211(netdev); |
||
1321 | + struct ieee80211_security *secinfo = &ieee->sec; |
||
1322 | + int keyidx; |
||
1323 | + |
||
1324 | + dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)), "\n"); |
||
1325 | + |
||
1326 | + for (keyidx = 0; keyidx<WEP_KEYS; keyidx++) |
||
1327 | + if (sec->flags & (1<<keyidx)) { |
||
1328 | + secinfo->encode_alg[keyidx] = sec->encode_alg[keyidx]; |
||
1329 | + secinfo->key_sizes[keyidx] = sec->key_sizes[keyidx]; |
||
1330 | + memcpy(secinfo->keys[keyidx], sec->keys[keyidx], |
||
1331 | + SCM_KEY_LEN); |
||
1332 | + } |
||
1333 | + |
||
1334 | + if (sec->flags & SEC_ACTIVE_KEY) { |
||
1335 | + secinfo->active_key = sec->active_key; |
||
1336 | + dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)), |
||
1337 | + " .active_key = %d\n", sec->active_key); |
||
1338 | + } |
||
1339 | + if (sec->flags & SEC_UNICAST_GROUP) { |
||
1340 | + secinfo->unicast_uses_group = sec->unicast_uses_group; |
||
1341 | + dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)), |
||
1342 | + " .unicast_uses_group = %d\n", |
||
1343 | + sec->unicast_uses_group); |
||
1344 | + } |
||
1345 | + if (sec->flags & SEC_LEVEL) { |
||
1346 | + secinfo->level = sec->level; |
||
1347 | + dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)), |
||
1348 | + " .level = %d\n", sec->level); |
||
1349 | + } |
||
1350 | + if (sec->flags & SEC_ENABLED) { |
||
1351 | + secinfo->enabled = sec->enabled; |
||
1352 | + dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)), |
||
1353 | + " .enabled = %d\n", sec->enabled); |
||
1354 | + } |
||
1355 | + if (sec->flags & SEC_ENCRYPT) { |
||
1356 | + secinfo->encrypt = sec->encrypt; |
||
1357 | + dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)), |
||
1358 | + " .encrypt = %d\n", sec->encrypt); |
||
1359 | + } |
||
1360 | + if (sec->flags & SEC_AUTH_MODE) { |
||
1361 | + secinfo->auth_mode = sec->auth_mode; |
||
1362 | + dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)), |
||
1363 | + " .auth_mode = %d\n", sec->auth_mode); |
||
1364 | + } |
||
1365 | +} |
||
1366 | + |
||
1367 | +static void ieee_init(struct ieee80211_device *ieee) |
||
1368 | +{ |
||
1369 | + ieee->mode = IEEE_B | IEEE_G; |
||
1370 | + ieee->freq_band = IEEE80211_24GHZ_BAND; |
||
1371 | + ieee->modulation = IEEE80211_OFDM_MODULATION | IEEE80211_CCK_MODULATION; |
||
1372 | + ieee->tx_headroom = sizeof(struct zd_ctrlset); |
||
1373 | + ieee->set_security = set_security; |
||
1374 | + ieee->hard_start_xmit = netdev_tx; |
||
1375 | + |
||
1376 | + /* Software encryption/decryption for now */ |
||
1377 | + ieee->host_build_iv = 0; |
||
1378 | + ieee->host_encrypt = 1; |
||
1379 | + ieee->host_decrypt = 1; |
||
1380 | + |
||
1381 | + /* FIXME: default to managed mode, until ieee80211 and zd1211rw can |
||
1382 | + * correctly support AUTO */ |
||
1383 | + ieee->iw_mode = IW_MODE_INFRA; |
||
1384 | +} |
||
1385 | + |
||
1386 | +static void softmac_init(struct ieee80211softmac_device *sm) |
||
1387 | +{ |
||
1388 | + sm->set_channel = set_channel; |
||
1389 | + sm->bssinfo_change = bssinfo_change; |
||
1390 | +} |
||
1391 | + |
||
1392 | +struct iw_statistics *zd_mac_get_wireless_stats(struct net_device *ndev) |
||
1393 | +{ |
||
1394 | + struct zd_mac *mac = zd_netdev_mac(ndev); |
||
1395 | + struct iw_statistics *iw_stats = &mac->iw_stats; |
||
1396 | + unsigned int i, count, qual_total, rssi_total; |
||
1397 | + |
||
1398 | + memset(iw_stats, 0, sizeof(struct iw_statistics)); |
||
1399 | + /* We are not setting the status, because ieee->state is not updated |
||
1400 | + * at all and this driver doesn't track authentication state. |
||
1401 | + */ |
||
1402 | + spin_lock_irq(&mac->lock); |
||
1403 | + count = mac->stats_count < ZD_MAC_STATS_BUFFER_SIZE ? |
||
1404 | + mac->stats_count : ZD_MAC_STATS_BUFFER_SIZE; |
||
1405 | + qual_total = rssi_total = 0; |
||
1406 | + for (i = 0; i < count; i++) { |
||
1407 | + qual_total += mac->qual_buffer[i]; |
||
1408 | + rssi_total += mac->rssi_buffer[i]; |
||
1409 | + } |
||
1410 | + spin_unlock_irq(&mac->lock); |
||
1411 | + iw_stats->qual.updated = IW_QUAL_NOISE_INVALID; |
||
1412 | + if (count > 0) { |
||
1413 | + iw_stats->qual.qual = qual_total / count; |
||
1414 | + iw_stats->qual.level = rssi_total / count; |
||
1415 | + iw_stats->qual.updated |= |
||
1416 | + IW_QUAL_QUAL_UPDATED|IW_QUAL_LEVEL_UPDATED; |
||
1417 | + } else { |
||
1418 | + iw_stats->qual.updated |= |
||
1419 | + IW_QUAL_QUAL_INVALID|IW_QUAL_LEVEL_INVALID; |
||
1420 | + } |
||
1421 | + /* TODO: update counter */ |
||
1422 | + return iw_stats; |
||
1423 | +} |
||
1424 | + |
||
1425 | +#define LINK_LED_WORK_DELAY HZ |
||
1426 | + |
||
1427 | +static void link_led_handler(struct work_struct *work) |
||
1428 | +{ |
||
1429 | + struct zd_mac *mac = |
||
1430 | + container_of(work, struct zd_mac, housekeeping.link_led_work.work); |
||
1431 | + struct zd_chip *chip = &mac->chip; |
||
1432 | + struct ieee80211softmac_device *sm = ieee80211_priv(mac->netdev); |
||
1433 | + int is_associated; |
||
1434 | + int r; |
||
1435 | + |
||
1436 | + spin_lock_irq(&mac->lock); |
||
1437 | + is_associated = sm->associnfo.associated != 0; |
||
1438 | + spin_unlock_irq(&mac->lock); |
||
1439 | + |
||
1440 | + r = zd_chip_control_leds(chip, |
||
1441 | + is_associated ? LED_ASSOCIATED : LED_SCANNING); |
||
1442 | + if (r) |
||
1443 | + dev_err(zd_mac_dev(mac), "zd_chip_control_leds error %d\n", r); |
||
1444 | + |
||
1445 | + queue_delayed_work(zd_workqueue, &mac->housekeeping.link_led_work, |
||
1446 | + LINK_LED_WORK_DELAY); |
||
1447 | +} |
||
1448 | + |
||
1449 | +static void housekeeping_init(struct zd_mac *mac) |
||
1450 | +{ |
||
1451 | + INIT_DELAYED_WORK(&mac->housekeeping.link_led_work, link_led_handler); |
||
1452 | +} |
||
1453 | + |
||
1454 | +static void housekeeping_enable(struct zd_mac *mac) |
||
1455 | +{ |
||
1456 | + dev_dbg_f(zd_mac_dev(mac), "\n"); |
||
1457 | + queue_delayed_work(zd_workqueue, &mac->housekeeping.link_led_work, |
||
1458 | + 0); |
||
1459 | +} |
||
1460 | + |
||
1461 | +static void housekeeping_disable(struct zd_mac *mac) |
||
1462 | +{ |
||
1463 | + dev_dbg_f(zd_mac_dev(mac), "\n"); |
||
1464 | + cancel_rearming_delayed_workqueue(zd_workqueue, |
||
1465 | + &mac->housekeeping.link_led_work); |
||
1466 | + zd_chip_control_leds(&mac->chip, LED_OFF); |
||
1467 | +} |
||
1468 | diff -Naur linux-2.6.22_orig/drivers/net/wireless/zd1211rw/zd_usb.c linux-2.6.22/drivers/net/wireless/zd1211rw/zd_usb.c |
||
1469 | --- linux-2.6.22_orig/drivers/net/wireless/zd1211rw/zd_usb.c 2007-08-09 15:37:14.000000000 +0200 |
||
1470 | +++ linux-2.6.22/drivers/net/wireless/zd1211rw/zd_usb.c 2007-08-23 22:26:08.000000000 +0200 |
||
1471 | @@ -781,6 +781,46 @@ |
||
1472 | return r; |
||
1473 | } |
||
1474 | |||
1475 | +/* Puts the frame on the USB endpoint. It doesn't wait for |
||
1476 | + * completion. The frame must contain the control set. |
||
1477 | + */ |
||
1478 | +int zd_usb_tx_inject(struct zd_usb *usb, const u8 *frame, unsigned int length) |
||
1479 | +{ |
||
1480 | + int r; |
||
1481 | + struct usb_device *udev = zd_usb_to_usbdev(usb); |
||
1482 | + struct urb *urb; |
||
1483 | + void *buffer; |
||
1484 | + |
||
1485 | + urb = usb_alloc_urb(0, GFP_ATOMIC); |
||
1486 | + if (!urb) { |
||
1487 | + r = -ENOMEM; |
||
1488 | + goto out; |
||
1489 | + } |
||
1490 | + |
||
1491 | + buffer = usb_buffer_alloc(zd_usb_to_usbdev(usb), length, GFP_ATOMIC, |
||
1492 | + &urb->transfer_dma); |
||
1493 | + if (!buffer) { |
||
1494 | + r = -ENOMEM; |
||
1495 | + goto error_free_urb; |
||
1496 | + } |
||
1497 | + memcpy(buffer, frame, length); |
||
1498 | + |
||
1499 | + usb_fill_bulk_urb(urb, udev, usb_sndbulkpipe(udev, EP_DATA_OUT), |
||
1500 | + buffer, length, tx_urb_complete, NULL); |
||
1501 | + |
||
1502 | + r = usb_submit_urb(urb, GFP_ATOMIC); |
||
1503 | + if (r) |
||
1504 | + goto error; |
||
1505 | + return 0; |
||
1506 | +error: |
||
1507 | + usb_buffer_free(zd_usb_to_usbdev(usb), length, buffer, |
||
1508 | + urb->transfer_dma); |
||
1509 | +error_free_urb: |
||
1510 | + usb_free_urb(urb); |
||
1511 | +out: |
||
1512 | + return r; |
||
1513 | +} |
||
1514 | + |
||
1515 | static inline void init_usb_interrupt(struct zd_usb *usb) |
||
1516 | { |
||
1517 | struct zd_usb_interrupt *intr = &usb->intr; |
||
1518 | diff -Naur linux-2.6.22_orig/drivers/net/wireless/zd1211rw/zd_usb.h linux-2.6.22/drivers/net/wireless/zd1211rw/zd_usb.h |
||
1519 | --- linux-2.6.22_orig/drivers/net/wireless/zd1211rw/zd_usb.h 2007-08-09 15:37:14.000000000 +0200 |
||
1520 | +++ linux-2.6.22/drivers/net/wireless/zd1211rw/zd_usb.h 2007-08-23 22:26:08.000000000 +0200 |
||
1521 | @@ -221,6 +221,7 @@ |
||
1522 | void zd_usb_disable_rx(struct zd_usb *usb); |
||
1523 | |||
1524 | int zd_usb_tx(struct zd_usb *usb, const u8 *frame, unsigned int length); |
||
1525 | +int zd_usb_tx_inject(struct zd_usb *usb, const u8 *frame, unsigned int length); |
||
1526 | |||
1527 | int zd_usb_ioread16v(struct zd_usb *usb, u16 *values, |
||
1528 | const zd_addr_t *addresses, unsigned int count); |