]>
Commit | Line | Data |
---|---|---|
95ea3627 ID |
1 | /* |
2 | Copyright (C) 2004 - 2007 rt2x00 SourceForge Project | |
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: rt2x00mac | |
23 | Abstract: rt2x00 generic mac80211 routines. | |
24 | */ | |
25 | ||
26 | /* | |
27 | * Set enviroment defines for rt2x00.h | |
28 | */ | |
29 | #define DRV_NAME "rt2x00lib" | |
30 | ||
31 | #include <linux/kernel.h> | |
32 | #include <linux/module.h> | |
33 | ||
34 | #include "rt2x00.h" | |
35 | #include "rt2x00lib.h" | |
36 | ||
37 | static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev, | |
38 | struct data_ring *ring, | |
39 | struct sk_buff *frag_skb, | |
40 | struct ieee80211_tx_control *control) | |
41 | { | |
42 | struct sk_buff *skb; | |
43 | int size; | |
44 | ||
45 | if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) | |
46 | size = sizeof(struct ieee80211_cts); | |
47 | else | |
48 | size = sizeof(struct ieee80211_rts); | |
49 | ||
50 | skb = dev_alloc_skb(size + rt2x00dev->hw->extra_tx_headroom); | |
51 | if (!skb) { | |
52 | WARNING(rt2x00dev, "Failed to create RTS/CTS frame.\n"); | |
53 | return NETDEV_TX_BUSY; | |
54 | } | |
55 | ||
56 | skb_reserve(skb, rt2x00dev->hw->extra_tx_headroom); | |
57 | skb_put(skb, size); | |
58 | ||
59 | if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) | |
60 | ieee80211_ctstoself_get(rt2x00dev->hw, rt2x00dev->interface.id, | |
61 | frag_skb->data, frag_skb->len, control, | |
62 | (struct ieee80211_cts *)(skb->data)); | |
63 | else | |
64 | ieee80211_rts_get(rt2x00dev->hw, rt2x00dev->interface.id, | |
65 | frag_skb->data, frag_skb->len, control, | |
66 | (struct ieee80211_rts *)(skb->data)); | |
67 | ||
68 | if (rt2x00dev->ops->lib->write_tx_data(rt2x00dev, ring, skb, control)) { | |
69 | WARNING(rt2x00dev, "Failed to send RTS/CTS frame.\n"); | |
70 | return NETDEV_TX_BUSY; | |
71 | } | |
72 | ||
73 | return NETDEV_TX_OK; | |
74 | } | |
75 | ||
76 | int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, | |
77 | struct ieee80211_tx_control *control) | |
78 | { | |
79 | struct rt2x00_dev *rt2x00dev = hw->priv; | |
80 | struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data; | |
81 | struct data_ring *ring; | |
82 | u16 frame_control; | |
83 | ||
84 | /* | |
85 | * Determine which ring to put packet on. | |
86 | */ | |
87 | ring = rt2x00lib_get_ring(rt2x00dev, control->queue); | |
88 | if (unlikely(!ring)) { | |
89 | ERROR(rt2x00dev, | |
90 | "Attempt to send packet over invalid queue %d.\n" | |
91 | "Please file bug report to %s.\n", | |
92 | control->queue, DRV_PROJECT); | |
93 | dev_kfree_skb_any(skb); | |
94 | return NETDEV_TX_OK; | |
95 | } | |
96 | ||
97 | /* | |
98 | * If CTS/RTS is required. and this frame is not CTS or RTS, | |
99 | * create and queue that frame first. But make sure we have | |
100 | * at least enough entries available to send this CTS/RTS | |
101 | * frame as well as the data frame. | |
102 | */ | |
103 | frame_control = le16_to_cpu(ieee80211hdr->frame_control); | |
104 | if (!is_rts_frame(frame_control) && !is_cts_frame(frame_control) && | |
105 | (control->flags & (IEEE80211_TXCTL_USE_RTS_CTS | | |
106 | IEEE80211_TXCTL_USE_CTS_PROTECT))) { | |
107 | if (rt2x00_ring_free(ring) <= 1) | |
108 | return NETDEV_TX_BUSY; | |
109 | ||
110 | if (rt2x00mac_tx_rts_cts(rt2x00dev, ring, skb, control)) | |
111 | return NETDEV_TX_BUSY; | |
112 | } | |
113 | ||
114 | if (rt2x00dev->ops->lib->write_tx_data(rt2x00dev, ring, skb, control)) | |
115 | return NETDEV_TX_BUSY; | |
116 | ||
117 | if (rt2x00dev->ops->lib->kick_tx_queue) | |
118 | rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, control->queue); | |
119 | ||
120 | return NETDEV_TX_OK; | |
121 | } | |
122 | EXPORT_SYMBOL_GPL(rt2x00mac_tx); | |
123 | ||
124 | int rt2x00mac_start(struct ieee80211_hw *hw) | |
125 | { | |
126 | struct rt2x00_dev *rt2x00dev = hw->priv; | |
127 | int status; | |
128 | ||
129 | if (test_bit(DEVICE_INITIALIZED, &rt2x00dev->flags)) | |
130 | return 0; | |
131 | ||
132 | /* | |
133 | * If this is the first interface which is added, | |
134 | * we should load the firmware now. | |
135 | */ | |
136 | if (test_bit(REQUIRE_FIRMWARE, &rt2x00dev->flags)) { | |
137 | status = rt2x00lib_load_firmware(rt2x00dev); | |
138 | if (status) | |
139 | return status; | |
140 | } | |
141 | ||
142 | /* | |
143 | * Initialize the device. | |
144 | */ | |
145 | status = rt2x00lib_initialize(rt2x00dev); | |
146 | if (status) | |
147 | return status; | |
148 | ||
149 | /* | |
150 | * Enable radio. | |
151 | */ | |
152 | status = rt2x00lib_enable_radio(rt2x00dev); | |
153 | if (status) { | |
154 | rt2x00lib_uninitialize(rt2x00dev); | |
155 | return status; | |
156 | } | |
157 | ||
158 | return 0; | |
159 | } | |
160 | EXPORT_SYMBOL_GPL(rt2x00mac_start); | |
161 | ||
162 | void rt2x00mac_stop(struct ieee80211_hw *hw) | |
163 | { | |
164 | struct rt2x00_dev *rt2x00dev = hw->priv; | |
165 | ||
166 | /* | |
167 | * Perhaps we can add something smarter here, | |
168 | * but for now just disabling the radio should do. | |
169 | */ | |
170 | rt2x00lib_disable_radio(rt2x00dev); | |
171 | } | |
172 | EXPORT_SYMBOL_GPL(rt2x00mac_stop); | |
173 | ||
174 | int rt2x00mac_add_interface(struct ieee80211_hw *hw, | |
175 | struct ieee80211_if_init_conf *conf) | |
176 | { | |
177 | struct rt2x00_dev *rt2x00dev = hw->priv; | |
178 | struct interface *intf = &rt2x00dev->interface; | |
179 | int retval; | |
180 | ||
181 | /* | |
182 | * We only support 1 non-monitor interface. | |
183 | */ | |
184 | if (conf->type != IEEE80211_IF_TYPE_MNTR && is_interface_present(intf)) | |
185 | return -ENOBUFS; | |
186 | ||
187 | /* | |
188 | * HACK: Placeholder until start/stop handler has been | |
189 | * added to the mac80211 callback functions structure. | |
190 | */ | |
191 | retval = rt2x00mac_start(hw); | |
192 | if (retval) | |
193 | return retval; | |
194 | ||
195 | /* | |
196 | * We support muliple monitor mode interfaces. | |
197 | * All we need to do is increase the monitor_count. | |
198 | */ | |
199 | if (conf->type == IEEE80211_IF_TYPE_MNTR) { | |
200 | intf->monitor_count++; | |
201 | } else { | |
202 | intf->id = conf->if_id; | |
203 | intf->type = conf->type; | |
204 | if (conf->type == IEEE80211_IF_TYPE_AP) | |
205 | memcpy(&intf->bssid, conf->mac_addr, ETH_ALEN); | |
206 | memcpy(&intf->mac, conf->mac_addr, ETH_ALEN); | |
207 | intf->filter = 0; | |
208 | } | |
209 | ||
210 | /* | |
211 | * Configure interface. | |
212 | * The MAC adddress must be configured after the device | |
213 | * has been initialized. Else the device can reset the | |
214 | * MAC registers. | |
215 | */ | |
216 | rt2x00lib_config_mac_addr(rt2x00dev, intf->mac); | |
217 | rt2x00lib_config_type(rt2x00dev, conf->type); | |
218 | rt2x00lib_config_packet_filter(rt2x00dev, intf->filter); | |
219 | ||
220 | return 0; | |
221 | } | |
222 | EXPORT_SYMBOL_GPL(rt2x00mac_add_interface); | |
223 | ||
224 | void rt2x00mac_remove_interface(struct ieee80211_hw *hw, | |
225 | struct ieee80211_if_init_conf *conf) | |
226 | { | |
227 | struct rt2x00_dev *rt2x00dev = hw->priv; | |
228 | struct interface *intf = &rt2x00dev->interface; | |
229 | ||
230 | /* | |
231 | * We only support 1 non-monitor interface. | |
232 | */ | |
233 | if (conf->type != IEEE80211_IF_TYPE_MNTR && !is_interface_present(intf)) | |
234 | return; | |
235 | ||
236 | /* | |
237 | * When removing an monitor interface, decrease monitor_count. | |
238 | * For non-monitor interfaces, all interface data needs to be reset. | |
239 | */ | |
240 | if (conf->type == IEEE80211_IF_TYPE_MNTR) { | |
241 | intf->monitor_count--; | |
242 | } else if (intf->type == conf->type) { | |
243 | intf->id = 0; | |
244 | intf->type = INVALID_INTERFACE; | |
245 | memset(&intf->bssid, 0x00, ETH_ALEN); | |
246 | memset(&intf->mac, 0x00, ETH_ALEN); | |
247 | intf->filter = 0; | |
248 | } | |
249 | ||
250 | /* | |
251 | * Make sure the bssid and mac address registers | |
252 | * are cleared to prevent false ACKing of frames. | |
253 | */ | |
254 | rt2x00lib_config_mac_addr(rt2x00dev, intf->mac); | |
255 | rt2x00lib_config_bssid(rt2x00dev, intf->bssid); | |
256 | rt2x00lib_config_type(rt2x00dev, intf->type); | |
257 | ||
258 | /* | |
259 | * HACK: Placeholder untill start/stop handler has been | |
260 | * added to the mac80211 callback functions structure. | |
261 | */ | |
262 | rt2x00mac_stop(hw); | |
263 | } | |
264 | EXPORT_SYMBOL_GPL(rt2x00mac_remove_interface); | |
265 | ||
266 | int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) | |
267 | { | |
268 | struct rt2x00_dev *rt2x00dev = hw->priv; | |
269 | ||
270 | /* | |
271 | * If the device is not initialized we shouldn't accept | |
272 | * any configuration changes. Mac80211 might be calling | |
273 | * this function while we are trying to remove the device | |
274 | * or perhaps suspending it. | |
275 | */ | |
276 | if (!test_bit(DEVICE_INITIALIZED, &rt2x00dev->flags)) | |
277 | return 0; | |
278 | ||
279 | /* | |
280 | * Check if we need to disable the radio, | |
281 | * if this is not the case, at least the RX must be disabled. | |
282 | */ | |
283 | if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) { | |
284 | if (!conf->radio_enabled) | |
285 | rt2x00lib_disable_radio(rt2x00dev); | |
286 | else | |
287 | rt2x00lib_toggle_rx(rt2x00dev, 0); | |
288 | } | |
289 | ||
290 | rt2x00lib_config(rt2x00dev, conf); | |
291 | ||
292 | /* | |
293 | * If promisc mode cannot be configured in irq context, | |
294 | * then it is now the time to configure it. | |
295 | */ | |
296 | if (test_bit(PACKET_FILTER_SCHEDULED, &rt2x00dev->flags)) | |
297 | rt2x00lib_config_packet_filter(rt2x00dev, | |
298 | rt2x00dev->interface.filter); | |
299 | ||
300 | /* | |
301 | * Reenable RX only if the radio should be on. | |
302 | */ | |
303 | if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) | |
304 | rt2x00lib_toggle_rx(rt2x00dev, 1); | |
305 | else if (conf->radio_enabled) | |
306 | return rt2x00lib_enable_radio(rt2x00dev); | |
307 | ||
308 | return 0; | |
309 | } | |
310 | EXPORT_SYMBOL_GPL(rt2x00mac_config); | |
311 | ||
312 | int rt2x00mac_config_interface(struct ieee80211_hw *hw, int if_id, | |
313 | struct ieee80211_if_conf *conf) | |
314 | { | |
315 | struct rt2x00_dev *rt2x00dev = hw->priv; | |
316 | struct interface *intf = &rt2x00dev->interface; | |
317 | int status; | |
318 | ||
319 | /* | |
320 | * If the device is not initialized we shouldn't accept | |
321 | * any configuration changes. Mac80211 might be calling | |
322 | * this function while we are trying to remove the device | |
323 | * or perhaps suspending it. | |
324 | */ | |
325 | if (!test_bit(DEVICE_INITIALIZED, &rt2x00dev->flags)) | |
326 | return 0; | |
327 | ||
328 | /* | |
329 | * Monitor mode does not need configuring. | |
330 | * If the given type does not match the configured type, | |
331 | * there has been a problem. | |
332 | */ | |
333 | if (conf->type == IEEE80211_IF_TYPE_MNTR) | |
334 | return 0; | |
335 | else if (conf->type != intf->type) | |
336 | return -EINVAL; | |
337 | ||
338 | /* | |
339 | * If the interface does not work in master mode, | |
340 | * then the bssid value in the interface structure | |
341 | * should now be set. | |
342 | */ | |
343 | if (conf->type != IEEE80211_IF_TYPE_AP) | |
344 | memcpy(&intf->bssid, conf->bssid, ETH_ALEN); | |
345 | rt2x00lib_config_bssid(rt2x00dev, intf->bssid); | |
346 | ||
347 | /* | |
348 | * We only need to initialize the beacon when master mode is enabled. | |
349 | */ | |
350 | if (conf->type != IEEE80211_IF_TYPE_AP || !conf->beacon) | |
351 | return 0; | |
352 | ||
353 | status = rt2x00dev->ops->hw->beacon_update(rt2x00dev->hw, | |
354 | conf->beacon, | |
355 | conf->beacon_control); | |
356 | if (status) | |
357 | dev_kfree_skb(conf->beacon); | |
358 | ||
359 | return status; | |
360 | } | |
361 | EXPORT_SYMBOL_GPL(rt2x00mac_config_interface); | |
362 | ||
363 | void rt2x00mac_set_multicast_list(struct ieee80211_hw *hw, | |
364 | unsigned short flags, int mc_count) | |
365 | { | |
366 | struct rt2x00_dev *rt2x00dev = hw->priv; | |
367 | ||
368 | /* | |
369 | * Check if the new state is different then the old state. | |
370 | */ | |
371 | if (rt2x00dev->interface.filter == flags) | |
372 | return; | |
373 | ||
374 | rt2x00dev->interface.filter = flags; | |
375 | ||
376 | /* | |
377 | * Raise the pending bit to indicate the | |
378 | * packet filter should be updated. | |
379 | */ | |
380 | __set_bit(PACKET_FILTER_PENDING, &rt2x00dev->flags); | |
381 | ||
382 | /* | |
383 | * Check if Packet filter actions are allowed in | |
384 | * atomic context. If not, raise the pending flag and | |
385 | * let it be. | |
386 | */ | |
387 | if (!test_bit(PACKET_FILTER_SCHEDULED, &rt2x00dev->flags) || | |
388 | !in_atomic()) | |
389 | rt2x00lib_config_packet_filter(rt2x00dev, flags); | |
390 | } | |
391 | EXPORT_SYMBOL_GPL(rt2x00mac_set_multicast_list); | |
392 | ||
393 | int rt2x00mac_get_stats(struct ieee80211_hw *hw, | |
394 | struct ieee80211_low_level_stats *stats) | |
395 | { | |
396 | struct rt2x00_dev *rt2x00dev = hw->priv; | |
397 | ||
398 | /* | |
399 | * The dot11ACKFailureCount, dot11RTSFailureCount and | |
400 | * dot11RTSSuccessCount are updated in interrupt time. | |
401 | * dot11FCSErrorCount is updated in the link tuner. | |
402 | */ | |
403 | memcpy(stats, &rt2x00dev->low_level_stats, sizeof(*stats)); | |
404 | ||
405 | return 0; | |
406 | } | |
407 | EXPORT_SYMBOL_GPL(rt2x00mac_get_stats); | |
408 | ||
409 | int rt2x00mac_get_tx_stats(struct ieee80211_hw *hw, | |
410 | struct ieee80211_tx_queue_stats *stats) | |
411 | { | |
412 | struct rt2x00_dev *rt2x00dev = hw->priv; | |
413 | unsigned int i; | |
414 | ||
415 | for (i = 0; i < hw->queues; i++) | |
416 | memcpy(&stats->data[i], &rt2x00dev->tx[i].stats, | |
417 | sizeof(rt2x00dev->tx[i].stats)); | |
418 | ||
419 | return 0; | |
420 | } | |
421 | EXPORT_SYMBOL_GPL(rt2x00mac_get_tx_stats); | |
422 | ||
423 | int rt2x00mac_conf_tx(struct ieee80211_hw *hw, int queue, | |
424 | const struct ieee80211_tx_queue_params *params) | |
425 | { | |
426 | struct rt2x00_dev *rt2x00dev = hw->priv; | |
427 | struct data_ring *ring; | |
428 | ||
429 | ring = rt2x00lib_get_ring(rt2x00dev, queue); | |
430 | if (unlikely(!ring)) | |
431 | return -EINVAL; | |
432 | ||
433 | /* | |
434 | * The passed variables are stored as real value ((2^n)-1). | |
435 | * Ralink registers require to know the bit number 'n'. | |
436 | */ | |
437 | if (params->cw_min) | |
438 | ring->tx_params.cw_min = fls(params->cw_min); | |
439 | else | |
440 | ring->tx_params.cw_min = 5; /* cw_min: 2^5 = 32. */ | |
441 | ||
442 | if (params->cw_max) | |
443 | ring->tx_params.cw_max = fls(params->cw_max); | |
444 | else | |
445 | ring->tx_params.cw_max = 10; /* cw_min: 2^10 = 1024. */ | |
446 | ||
447 | if (params->aifs) | |
448 | ring->tx_params.aifs = params->aifs; | |
449 | else | |
450 | ring->tx_params.aifs = 2; | |
451 | ||
452 | INFO(rt2x00dev, | |
453 | "Configured TX ring %d - CWmin: %d, CWmax: %d, Aifs: %d.\n", | |
454 | queue, ring->tx_params.cw_min, ring->tx_params.cw_max, | |
455 | ring->tx_params.aifs); | |
456 | ||
457 | return 0; | |
458 | } | |
459 | EXPORT_SYMBOL_GPL(rt2x00mac_conf_tx); |