diff options
Diffstat (limited to 'drivers/net/wireless/rt2x00/rt2x00mac.c')
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00mac.c | 152 |
1 files changed, 101 insertions, 51 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index f08c151ee4ba..65a2bcd18aa1 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c | |||
@@ -52,11 +52,11 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev, | |||
52 | skb_put(skb, size); | 52 | skb_put(skb, size); |
53 | 53 | ||
54 | if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) | 54 | if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) |
55 | ieee80211_ctstoself_get(rt2x00dev->hw, rt2x00dev->interface.id, | 55 | ieee80211_ctstoself_get(rt2x00dev->hw, control->vif, |
56 | frag_skb->data, frag_skb->len, control, | 56 | frag_skb->data, frag_skb->len, control, |
57 | (struct ieee80211_cts *)(skb->data)); | 57 | (struct ieee80211_cts *)(skb->data)); |
58 | else | 58 | else |
59 | ieee80211_rts_get(rt2x00dev->hw, rt2x00dev->interface.id, | 59 | ieee80211_rts_get(rt2x00dev->hw, control->vif, |
60 | frag_skb->data, frag_skb->len, control, | 60 | frag_skb->data, frag_skb->len, control, |
61 | (struct ieee80211_rts *)(skb->data)); | 61 | (struct ieee80211_rts *)(skb->data)); |
62 | 62 | ||
@@ -162,19 +162,67 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw, | |||
162 | struct ieee80211_if_init_conf *conf) | 162 | struct ieee80211_if_init_conf *conf) |
163 | { | 163 | { |
164 | struct rt2x00_dev *rt2x00dev = hw->priv; | 164 | struct rt2x00_dev *rt2x00dev = hw->priv; |
165 | struct interface *intf = &rt2x00dev->interface; | 165 | struct rt2x00_intf *intf = vif_to_intf(conf->vif); |
166 | struct data_queue *queue = | ||
167 | rt2x00queue_get_queue(rt2x00dev, IEEE80211_TX_QUEUE_BEACON); | ||
168 | struct queue_entry *entry = NULL; | ||
169 | unsigned int i; | ||
166 | 170 | ||
167 | /* | 171 | /* |
168 | * Don't allow interfaces to be added while | 172 | * Don't allow interfaces to be added |
169 | * either the device has disappeared or when | 173 | * the device has disappeared. |
170 | * another interface is already present. | ||
171 | */ | 174 | */ |
172 | if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags) || | 175 | if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags) || |
173 | is_interface_present(intf)) | 176 | !test_bit(DEVICE_STARTED, &rt2x00dev->flags)) |
177 | return -ENODEV; | ||
178 | |||
179 | /* | ||
180 | * When we don't support mixed interfaces (a combination | ||
181 | * of sta and ap virtual interfaces) then we can only | ||
182 | * add this interface when the rival interface count is 0. | ||
183 | */ | ||
184 | if (!test_bit(DRIVER_SUPPORT_MIXED_INTERFACES, &rt2x00dev->flags) && | ||
185 | ((conf->type == IEEE80211_IF_TYPE_AP && rt2x00dev->intf_sta_count) || | ||
186 | (conf->type != IEEE80211_IF_TYPE_AP && rt2x00dev->intf_ap_count))) | ||
187 | return -ENOBUFS; | ||
188 | |||
189 | /* | ||
190 | * Check if we exceeded the maximum amount of supported interfaces. | ||
191 | */ | ||
192 | if ((conf->type == IEEE80211_IF_TYPE_AP && | ||
193 | rt2x00dev->intf_ap_count >= rt2x00dev->ops->max_ap_intf) || | ||
194 | (conf->type != IEEE80211_IF_TYPE_AP && | ||
195 | rt2x00dev->intf_sta_count >= rt2x00dev->ops->max_sta_intf)) | ||
196 | return -ENOBUFS; | ||
197 | |||
198 | /* | ||
199 | * Loop through all beacon queues to find a free | ||
200 | * entry. Since there are as much beacon entries | ||
201 | * as the maximum interfaces, this search shouldn't | ||
202 | * fail. | ||
203 | */ | ||
204 | for (i = 0; i < queue->limit; i++) { | ||
205 | entry = &queue->entries[i]; | ||
206 | if (!__test_and_set_bit(ENTRY_BCN_ASSIGNED, &entry->flags)) | ||
207 | break; | ||
208 | } | ||
209 | |||
210 | if (unlikely(i == queue->limit)) | ||
174 | return -ENOBUFS; | 211 | return -ENOBUFS; |
175 | 212 | ||
176 | intf->id = conf->vif; | 213 | /* |
177 | intf->type = conf->type; | 214 | * We are now absolutely sure the interface can be created, |
215 | * increase interface count and start initialization. | ||
216 | */ | ||
217 | |||
218 | if (conf->type == IEEE80211_IF_TYPE_AP) | ||
219 | rt2x00dev->intf_ap_count++; | ||
220 | else | ||
221 | rt2x00dev->intf_sta_count++; | ||
222 | |||
223 | spin_lock_init(&intf->lock); | ||
224 | intf->beacon = entry; | ||
225 | |||
178 | if (conf->type == IEEE80211_IF_TYPE_AP) | 226 | if (conf->type == IEEE80211_IF_TYPE_AP) |
179 | memcpy(&intf->bssid, conf->mac_addr, ETH_ALEN); | 227 | memcpy(&intf->bssid, conf->mac_addr, ETH_ALEN); |
180 | memcpy(&intf->mac, conf->mac_addr, ETH_ALEN); | 228 | memcpy(&intf->mac, conf->mac_addr, ETH_ALEN); |
@@ -184,8 +232,7 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw, | |||
184 | * has been initialized. Otherwise the device can reset | 232 | * has been initialized. Otherwise the device can reset |
185 | * the MAC registers. | 233 | * the MAC registers. |
186 | */ | 234 | */ |
187 | rt2x00lib_config_mac_addr(rt2x00dev, intf->mac); | 235 | rt2x00lib_config_intf(rt2x00dev, intf, conf->type, intf->mac, NULL); |
188 | rt2x00lib_config_type(rt2x00dev, conf->type); | ||
189 | 236 | ||
190 | return 0; | 237 | return 0; |
191 | } | 238 | } |
@@ -195,7 +242,7 @@ void rt2x00mac_remove_interface(struct ieee80211_hw *hw, | |||
195 | struct ieee80211_if_init_conf *conf) | 242 | struct ieee80211_if_init_conf *conf) |
196 | { | 243 | { |
197 | struct rt2x00_dev *rt2x00dev = hw->priv; | 244 | struct rt2x00_dev *rt2x00dev = hw->priv; |
198 | struct interface *intf = &rt2x00dev->interface; | 245 | struct rt2x00_intf *intf = vif_to_intf(conf->vif); |
199 | 246 | ||
200 | /* | 247 | /* |
201 | * Don't allow interfaces to be remove while | 248 | * Don't allow interfaces to be remove while |
@@ -203,21 +250,27 @@ void rt2x00mac_remove_interface(struct ieee80211_hw *hw, | |||
203 | * no interface is present. | 250 | * no interface is present. |
204 | */ | 251 | */ |
205 | if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags) || | 252 | if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags) || |
206 | !is_interface_present(intf)) | 253 | (conf->type == IEEE80211_IF_TYPE_AP && !rt2x00dev->intf_ap_count) || |
254 | (conf->type != IEEE80211_IF_TYPE_AP && !rt2x00dev->intf_sta_count)) | ||
207 | return; | 255 | return; |
208 | 256 | ||
209 | intf->id = NULL; | 257 | if (conf->type == IEEE80211_IF_TYPE_AP) |
210 | intf->type = IEEE80211_IF_TYPE_INVALID; | 258 | rt2x00dev->intf_ap_count--; |
211 | memset(&intf->bssid, 0x00, ETH_ALEN); | 259 | else |
212 | memset(&intf->mac, 0x00, ETH_ALEN); | 260 | rt2x00dev->intf_sta_count--; |
261 | |||
262 | /* | ||
263 | * Release beacon entry so it is available for | ||
264 | * new interfaces again. | ||
265 | */ | ||
266 | __clear_bit(ENTRY_BCN_ASSIGNED, &intf->beacon->flags); | ||
213 | 267 | ||
214 | /* | 268 | /* |
215 | * Make sure the bssid and mac address registers | 269 | * Make sure the bssid and mac address registers |
216 | * are cleared to prevent false ACKing of frames. | 270 | * are cleared to prevent false ACKing of frames. |
217 | */ | 271 | */ |
218 | rt2x00lib_config_mac_addr(rt2x00dev, intf->mac); | 272 | rt2x00lib_config_intf(rt2x00dev, intf, |
219 | rt2x00lib_config_bssid(rt2x00dev, intf->bssid); | 273 | IEEE80211_IF_TYPE_INVALID, NULL, NULL); |
220 | rt2x00lib_config_type(rt2x00dev, intf->type); | ||
221 | } | 274 | } |
222 | EXPORT_SYMBOL_GPL(rt2x00mac_remove_interface); | 275 | EXPORT_SYMBOL_GPL(rt2x00mac_remove_interface); |
223 | 276 | ||
@@ -262,7 +315,7 @@ int rt2x00mac_config_interface(struct ieee80211_hw *hw, | |||
262 | struct ieee80211_if_conf *conf) | 315 | struct ieee80211_if_conf *conf) |
263 | { | 316 | { |
264 | struct rt2x00_dev *rt2x00dev = hw->priv; | 317 | struct rt2x00_dev *rt2x00dev = hw->priv; |
265 | struct interface *intf = &rt2x00dev->interface; | 318 | struct rt2x00_intf *intf = vif_to_intf(vif); |
266 | int status; | 319 | int status; |
267 | 320 | ||
268 | /* | 321 | /* |
@@ -272,12 +325,7 @@ int rt2x00mac_config_interface(struct ieee80211_hw *hw, | |||
272 | if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags)) | 325 | if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags)) |
273 | return 0; | 326 | return 0; |
274 | 327 | ||
275 | /* | 328 | spin_lock(&intf->lock); |
276 | * If the given type does not match the configured type, | ||
277 | * there has been a problem. | ||
278 | */ | ||
279 | if (conf->type != intf->type) | ||
280 | return -EINVAL; | ||
281 | 329 | ||
282 | /* | 330 | /* |
283 | * If the interface does not work in master mode, | 331 | * If the interface does not work in master mode, |
@@ -286,7 +334,9 @@ int rt2x00mac_config_interface(struct ieee80211_hw *hw, | |||
286 | */ | 334 | */ |
287 | if (conf->type != IEEE80211_IF_TYPE_AP) | 335 | if (conf->type != IEEE80211_IF_TYPE_AP) |
288 | memcpy(&intf->bssid, conf->bssid, ETH_ALEN); | 336 | memcpy(&intf->bssid, conf->bssid, ETH_ALEN); |
289 | rt2x00lib_config_bssid(rt2x00dev, intf->bssid); | 337 | rt2x00lib_config_intf(rt2x00dev, intf, conf->type, NULL, intf->bssid); |
338 | |||
339 | spin_unlock(&intf->lock); | ||
290 | 340 | ||
291 | /* | 341 | /* |
292 | * We only need to initialize the beacon when master mode is enabled. | 342 | * We only need to initialize the beacon when master mode is enabled. |
@@ -342,35 +392,35 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, | |||
342 | u32 changes) | 392 | u32 changes) |
343 | { | 393 | { |
344 | struct rt2x00_dev *rt2x00dev = hw->priv; | 394 | struct rt2x00_dev *rt2x00dev = hw->priv; |
345 | int short_preamble; | 395 | struct rt2x00_intf *intf = vif_to_intf(vif); |
346 | int ack_timeout; | ||
347 | int ack_consume_time; | ||
348 | int difs; | ||
349 | int preamble; | ||
350 | 396 | ||
351 | /* | 397 | /* |
352 | * We only support changing preamble mode. | 398 | * When the association status has changed we must reset the link |
399 | * tuner counter. This is because some drivers determine if they | ||
400 | * should perform link tuning based on the number of seconds | ||
401 | * while associated or not associated. | ||
353 | */ | 402 | */ |
354 | if (!(changes & BSS_CHANGED_ERP_PREAMBLE)) | 403 | if (changes & BSS_CHANGED_ASSOC) { |
355 | return; | 404 | rt2x00dev->link.count = 0; |
356 | |||
357 | short_preamble = bss_conf->use_short_preamble; | ||
358 | preamble = bss_conf->use_short_preamble ? | ||
359 | SHORT_PREAMBLE : PREAMBLE; | ||
360 | 405 | ||
361 | difs = (hw->conf.flags & IEEE80211_CONF_SHORT_SLOT_TIME) ? | 406 | if (bss_conf->assoc) |
362 | SHORT_DIFS : DIFS; | 407 | rt2x00dev->intf_associated++; |
363 | ack_timeout = difs + PLCP + preamble + get_duration(ACK_SIZE, 10); | 408 | else |
364 | 409 | rt2x00dev->intf_associated--; | |
365 | ack_consume_time = SIFS + PLCP + preamble + get_duration(ACK_SIZE, 10); | 410 | } |
366 | 411 | ||
367 | if (short_preamble) | 412 | /* |
368 | __set_bit(CONFIG_SHORT_PREAMBLE, &rt2x00dev->flags); | 413 | * When the preamble mode has changed, we should perform additional |
369 | else | 414 | * configuration steps. For all other changes we are already done. |
370 | __clear_bit(CONFIG_SHORT_PREAMBLE, &rt2x00dev->flags); | 415 | */ |
416 | if (changes & BSS_CHANGED_ERP_PREAMBLE) { | ||
417 | rt2x00lib_config_preamble(rt2x00dev, intf, | ||
418 | bss_conf->use_short_preamble); | ||
371 | 419 | ||
372 | rt2x00dev->ops->lib->config_preamble(rt2x00dev, short_preamble, | 420 | spin_lock(&intf->lock); |
373 | ack_timeout, ack_consume_time); | 421 | memcpy(&intf->conf, bss_conf, sizeof(*bss_conf)); |
422 | spin_unlock(&intf->lock); | ||
423 | } | ||
374 | } | 424 | } |
375 | EXPORT_SYMBOL_GPL(rt2x00mac_bss_info_changed); | 425 | EXPORT_SYMBOL_GPL(rt2x00mac_bss_info_changed); |
376 | 426 | ||