diff options
Diffstat (limited to 'net/mac80211')
31 files changed, 1212 insertions, 512 deletions
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index 96ddb72760b9..8d249d705980 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig | |||
@@ -225,6 +225,17 @@ config MAC80211_VERBOSE_MHWMP_DEBUG | |||
225 | 225 | ||
226 | Do not select this option. | 226 | Do not select this option. |
227 | 227 | ||
228 | config MAC80211_VERBOSE_MESH_SYNC_DEBUG | ||
229 | bool "Verbose mesh mesh synchronization debugging" | ||
230 | depends on MAC80211_DEBUG_MENU | ||
231 | depends on MAC80211_MESH | ||
232 | ---help--- | ||
233 | Selecting this option causes mac80211 to print out very verbose mesh | ||
234 | synchronization debugging messages (when mac80211 is taking part in a | ||
235 | mesh network). | ||
236 | |||
237 | Do not select this option. | ||
238 | |||
228 | config MAC80211_VERBOSE_TDLS_DEBUG | 239 | config MAC80211_VERBOSE_TDLS_DEBUG |
229 | bool "Verbose TDLS debugging" | 240 | bool "Verbose TDLS debugging" |
230 | depends on MAC80211_DEBUG_MENU | 241 | depends on MAC80211_DEBUG_MENU |
diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile index 1be7a454aa77..3e9d931bba35 100644 --- a/net/mac80211/Makefile +++ b/net/mac80211/Makefile | |||
@@ -38,7 +38,8 @@ mac80211-$(CONFIG_MAC80211_MESH) += \ | |||
38 | mesh.o \ | 38 | mesh.o \ |
39 | mesh_pathtbl.o \ | 39 | mesh_pathtbl.o \ |
40 | mesh_plink.o \ | 40 | mesh_plink.o \ |
41 | mesh_hwmp.o | 41 | mesh_hwmp.o \ |
42 | mesh_sync.o | ||
42 | 43 | ||
43 | mac80211-$(CONFIG_PM) += pm.o | 44 | mac80211-$(CONFIG_PM) += pm.o |
44 | 45 | ||
diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c index 64d3ce5ea1a0..a070d4f460ea 100644 --- a/net/mac80211/agg-rx.c +++ b/net/mac80211/agg-rx.c | |||
@@ -142,6 +142,18 @@ static void sta_rx_agg_session_timer_expired(unsigned long data) | |||
142 | u8 *timer_to_id = ptid - *ptid; | 142 | u8 *timer_to_id = ptid - *ptid; |
143 | struct sta_info *sta = container_of(timer_to_id, struct sta_info, | 143 | struct sta_info *sta = container_of(timer_to_id, struct sta_info, |
144 | timer_to_tid[0]); | 144 | timer_to_tid[0]); |
145 | struct tid_ampdu_rx *tid_rx; | ||
146 | unsigned long timeout; | ||
147 | |||
148 | tid_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[*ptid]); | ||
149 | if (!tid_rx) | ||
150 | return; | ||
151 | |||
152 | timeout = tid_rx->last_rx + TU_TO_JIFFIES(tid_rx->timeout); | ||
153 | if (time_is_after_jiffies(timeout)) { | ||
154 | mod_timer(&tid_rx->session_timer, timeout); | ||
155 | return; | ||
156 | } | ||
145 | 157 | ||
146 | #ifdef CONFIG_MAC80211_HT_DEBUG | 158 | #ifdef CONFIG_MAC80211_HT_DEBUG |
147 | printk(KERN_DEBUG "rx session timer expired on tid %d\n", (u16)*ptid); | 159 | printk(KERN_DEBUG "rx session timer expired on tid %d\n", (u16)*ptid); |
@@ -291,7 +303,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, | |||
291 | /* rx timer */ | 303 | /* rx timer */ |
292 | tid_agg_rx->session_timer.function = sta_rx_agg_session_timer_expired; | 304 | tid_agg_rx->session_timer.function = sta_rx_agg_session_timer_expired; |
293 | tid_agg_rx->session_timer.data = (unsigned long)&sta->timer_to_tid[tid]; | 305 | tid_agg_rx->session_timer.data = (unsigned long)&sta->timer_to_tid[tid]; |
294 | init_timer(&tid_agg_rx->session_timer); | 306 | init_timer_deferrable(&tid_agg_rx->session_timer); |
295 | 307 | ||
296 | /* rx reorder timer */ | 308 | /* rx reorder timer */ |
297 | tid_agg_rx->reorder_timer.function = sta_rx_agg_reorder_timer_expired; | 309 | tid_agg_rx->reorder_timer.function = sta_rx_agg_reorder_timer_expired; |
@@ -335,8 +347,10 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, | |||
335 | /* activate it for RX */ | 347 | /* activate it for RX */ |
336 | rcu_assign_pointer(sta->ampdu_mlme.tid_rx[tid], tid_agg_rx); | 348 | rcu_assign_pointer(sta->ampdu_mlme.tid_rx[tid], tid_agg_rx); |
337 | 349 | ||
338 | if (timeout) | 350 | if (timeout) { |
339 | mod_timer(&tid_agg_rx->session_timer, TU_TO_EXP_TIME(timeout)); | 351 | mod_timer(&tid_agg_rx->session_timer, TU_TO_EXP_TIME(timeout)); |
352 | tid_agg_rx->last_rx = jiffies; | ||
353 | } | ||
340 | 354 | ||
341 | end: | 355 | end: |
342 | mutex_unlock(&sta->ampdu_mlme.mtx); | 356 | mutex_unlock(&sta->ampdu_mlme.mtx); |
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index 76be61744198..5b7053c58732 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c | |||
@@ -286,25 +286,25 @@ static inline int ieee80211_ac_from_tid(int tid) | |||
286 | * a global "agg_queue_stop" refcount. | 286 | * a global "agg_queue_stop" refcount. |
287 | */ | 287 | */ |
288 | static void __acquires(agg_queue) | 288 | static void __acquires(agg_queue) |
289 | ieee80211_stop_queue_agg(struct ieee80211_local *local, int tid) | 289 | ieee80211_stop_queue_agg(struct ieee80211_sub_if_data *sdata, int tid) |
290 | { | 290 | { |
291 | int queue = ieee80211_ac_from_tid(tid); | 291 | int queue = sdata->vif.hw_queue[ieee80211_ac_from_tid(tid)]; |
292 | 292 | ||
293 | if (atomic_inc_return(&local->agg_queue_stop[queue]) == 1) | 293 | if (atomic_inc_return(&sdata->local->agg_queue_stop[queue]) == 1) |
294 | ieee80211_stop_queue_by_reason( | 294 | ieee80211_stop_queue_by_reason( |
295 | &local->hw, queue, | 295 | &sdata->local->hw, queue, |
296 | IEEE80211_QUEUE_STOP_REASON_AGGREGATION); | 296 | IEEE80211_QUEUE_STOP_REASON_AGGREGATION); |
297 | __acquire(agg_queue); | 297 | __acquire(agg_queue); |
298 | } | 298 | } |
299 | 299 | ||
300 | static void __releases(agg_queue) | 300 | static void __releases(agg_queue) |
301 | ieee80211_wake_queue_agg(struct ieee80211_local *local, int tid) | 301 | ieee80211_wake_queue_agg(struct ieee80211_sub_if_data *sdata, int tid) |
302 | { | 302 | { |
303 | int queue = ieee80211_ac_from_tid(tid); | 303 | int queue = sdata->vif.hw_queue[ieee80211_ac_from_tid(tid)]; |
304 | 304 | ||
305 | if (atomic_dec_return(&local->agg_queue_stop[queue]) == 0) | 305 | if (atomic_dec_return(&sdata->local->agg_queue_stop[queue]) == 0) |
306 | ieee80211_wake_queue_by_reason( | 306 | ieee80211_wake_queue_by_reason( |
307 | &local->hw, queue, | 307 | &sdata->local->hw, queue, |
308 | IEEE80211_QUEUE_STOP_REASON_AGGREGATION); | 308 | IEEE80211_QUEUE_STOP_REASON_AGGREGATION); |
309 | __release(agg_queue); | 309 | __release(agg_queue); |
310 | } | 310 | } |
@@ -314,13 +314,14 @@ ieee80211_wake_queue_agg(struct ieee80211_local *local, int tid) | |||
314 | * requires a call to ieee80211_agg_splice_finish later | 314 | * requires a call to ieee80211_agg_splice_finish later |
315 | */ | 315 | */ |
316 | static void __acquires(agg_queue) | 316 | static void __acquires(agg_queue) |
317 | ieee80211_agg_splice_packets(struct ieee80211_local *local, | 317 | ieee80211_agg_splice_packets(struct ieee80211_sub_if_data *sdata, |
318 | struct tid_ampdu_tx *tid_tx, u16 tid) | 318 | struct tid_ampdu_tx *tid_tx, u16 tid) |
319 | { | 319 | { |
320 | int queue = ieee80211_ac_from_tid(tid); | 320 | struct ieee80211_local *local = sdata->local; |
321 | int queue = sdata->vif.hw_queue[ieee80211_ac_from_tid(tid)]; | ||
321 | unsigned long flags; | 322 | unsigned long flags; |
322 | 323 | ||
323 | ieee80211_stop_queue_agg(local, tid); | 324 | ieee80211_stop_queue_agg(sdata, tid); |
324 | 325 | ||
325 | if (WARN(!tid_tx, "TID %d gone but expected when splicing aggregates" | 326 | if (WARN(!tid_tx, "TID %d gone but expected when splicing aggregates" |
326 | " from the pending queue\n", tid)) | 327 | " from the pending queue\n", tid)) |
@@ -336,9 +337,9 @@ ieee80211_agg_splice_packets(struct ieee80211_local *local, | |||
336 | } | 337 | } |
337 | 338 | ||
338 | static void __releases(agg_queue) | 339 | static void __releases(agg_queue) |
339 | ieee80211_agg_splice_finish(struct ieee80211_local *local, u16 tid) | 340 | ieee80211_agg_splice_finish(struct ieee80211_sub_if_data *sdata, u16 tid) |
340 | { | 341 | { |
341 | ieee80211_wake_queue_agg(local, tid); | 342 | ieee80211_wake_queue_agg(sdata, tid); |
342 | } | 343 | } |
343 | 344 | ||
344 | void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid) | 345 | void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid) |
@@ -376,9 +377,9 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid) | |||
376 | " tid %d\n", tid); | 377 | " tid %d\n", tid); |
377 | #endif | 378 | #endif |
378 | spin_lock_bh(&sta->lock); | 379 | spin_lock_bh(&sta->lock); |
379 | ieee80211_agg_splice_packets(local, tid_tx, tid); | 380 | ieee80211_agg_splice_packets(sdata, tid_tx, tid); |
380 | ieee80211_assign_tid_tx(sta, tid, NULL); | 381 | ieee80211_assign_tid_tx(sta, tid, NULL); |
381 | ieee80211_agg_splice_finish(local, tid); | 382 | ieee80211_agg_splice_finish(sdata, tid); |
382 | spin_unlock_bh(&sta->lock); | 383 | spin_unlock_bh(&sta->lock); |
383 | 384 | ||
384 | kfree_rcu(tid_tx, rcu_head); | 385 | kfree_rcu(tid_tx, rcu_head); |
@@ -417,6 +418,18 @@ static void sta_tx_agg_session_timer_expired(unsigned long data) | |||
417 | u8 *timer_to_id = ptid - *ptid; | 418 | u8 *timer_to_id = ptid - *ptid; |
418 | struct sta_info *sta = container_of(timer_to_id, struct sta_info, | 419 | struct sta_info *sta = container_of(timer_to_id, struct sta_info, |
419 | timer_to_tid[0]); | 420 | timer_to_tid[0]); |
421 | struct tid_ampdu_tx *tid_tx; | ||
422 | unsigned long timeout; | ||
423 | |||
424 | tid_tx = rcu_dereference_protected_tid_tx(sta, *ptid); | ||
425 | if (!tid_tx) | ||
426 | return; | ||
427 | |||
428 | timeout = tid_tx->last_tx + TU_TO_JIFFIES(tid_tx->timeout); | ||
429 | if (time_is_after_jiffies(timeout)) { | ||
430 | mod_timer(&tid_tx->session_timer, timeout); | ||
431 | return; | ||
432 | } | ||
420 | 433 | ||
421 | #ifdef CONFIG_MAC80211_HT_DEBUG | 434 | #ifdef CONFIG_MAC80211_HT_DEBUG |
422 | printk(KERN_DEBUG "tx session timer expired on tid %d\n", (u16)*ptid); | 435 | printk(KERN_DEBUG "tx session timer expired on tid %d\n", (u16)*ptid); |
@@ -542,7 +555,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid, | |||
542 | /* tx timer */ | 555 | /* tx timer */ |
543 | tid_tx->session_timer.function = sta_tx_agg_session_timer_expired; | 556 | tid_tx->session_timer.function = sta_tx_agg_session_timer_expired; |
544 | tid_tx->session_timer.data = (unsigned long)&sta->timer_to_tid[tid]; | 557 | tid_tx->session_timer.data = (unsigned long)&sta->timer_to_tid[tid]; |
545 | init_timer(&tid_tx->session_timer); | 558 | init_timer_deferrable(&tid_tx->session_timer); |
546 | 559 | ||
547 | /* assign a dialog token */ | 560 | /* assign a dialog token */ |
548 | sta->ampdu_mlme.dialog_token_allocator++; | 561 | sta->ampdu_mlme.dialog_token_allocator++; |
@@ -586,14 +599,14 @@ static void ieee80211_agg_tx_operational(struct ieee80211_local *local, | |||
586 | */ | 599 | */ |
587 | spin_lock_bh(&sta->lock); | 600 | spin_lock_bh(&sta->lock); |
588 | 601 | ||
589 | ieee80211_agg_splice_packets(local, tid_tx, tid); | 602 | ieee80211_agg_splice_packets(sta->sdata, tid_tx, tid); |
590 | /* | 603 | /* |
591 | * Now mark as operational. This will be visible | 604 | * Now mark as operational. This will be visible |
592 | * in the TX path, and lets it go lock-free in | 605 | * in the TX path, and lets it go lock-free in |
593 | * the common case. | 606 | * the common case. |
594 | */ | 607 | */ |
595 | set_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state); | 608 | set_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state); |
596 | ieee80211_agg_splice_finish(local, tid); | 609 | ieee80211_agg_splice_finish(sta->sdata, tid); |
597 | 610 | ||
598 | spin_unlock_bh(&sta->lock); | 611 | spin_unlock_bh(&sta->lock); |
599 | } | 612 | } |
@@ -778,12 +791,12 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid) | |||
778 | * more. | 791 | * more. |
779 | */ | 792 | */ |
780 | 793 | ||
781 | ieee80211_agg_splice_packets(local, tid_tx, tid); | 794 | ieee80211_agg_splice_packets(sta->sdata, tid_tx, tid); |
782 | 795 | ||
783 | /* future packets must not find the tid_tx struct any more */ | 796 | /* future packets must not find the tid_tx struct any more */ |
784 | ieee80211_assign_tid_tx(sta, tid, NULL); | 797 | ieee80211_assign_tid_tx(sta, tid, NULL); |
785 | 798 | ||
786 | ieee80211_agg_splice_finish(local, tid); | 799 | ieee80211_agg_splice_finish(sta->sdata, tid); |
787 | 800 | ||
788 | kfree_rcu(tid_tx, rcu_head); | 801 | kfree_rcu(tid_tx, rcu_head); |
789 | 802 | ||
@@ -884,9 +897,11 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local, | |||
884 | 897 | ||
885 | sta->ampdu_mlme.addba_req_num[tid] = 0; | 898 | sta->ampdu_mlme.addba_req_num[tid] = 0; |
886 | 899 | ||
887 | if (tid_tx->timeout) | 900 | if (tid_tx->timeout) { |
888 | mod_timer(&tid_tx->session_timer, | 901 | mod_timer(&tid_tx->session_timer, |
889 | TU_TO_EXP_TIME(tid_tx->timeout)); | 902 | TU_TO_EXP_TIME(tid_tx->timeout)); |
903 | tid_tx->last_tx = jiffies; | ||
904 | } | ||
890 | 905 | ||
891 | } else { | 906 | } else { |
892 | ___ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_INITIATOR, | 907 | ___ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_INITIATOR, |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 677d65929780..355735491252 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -412,6 +412,10 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) | |||
412 | sinfo->llid = le16_to_cpu(sta->llid); | 412 | sinfo->llid = le16_to_cpu(sta->llid); |
413 | sinfo->plid = le16_to_cpu(sta->plid); | 413 | sinfo->plid = le16_to_cpu(sta->plid); |
414 | sinfo->plink_state = sta->plink_state; | 414 | sinfo->plink_state = sta->plink_state; |
415 | if (test_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN)) { | ||
416 | sinfo->filled |= STATION_INFO_T_OFFSET; | ||
417 | sinfo->t_offset = sta->t_offset; | ||
418 | } | ||
415 | #endif | 419 | #endif |
416 | } | 420 | } |
417 | 421 | ||
@@ -640,6 +644,10 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, | |||
640 | 644 | ||
641 | ieee80211_bss_info_change_notify(sdata, changed); | 645 | ieee80211_bss_info_change_notify(sdata, changed); |
642 | 646 | ||
647 | netif_carrier_on(dev); | ||
648 | list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) | ||
649 | netif_carrier_on(vlan->dev); | ||
650 | |||
643 | return 0; | 651 | return 0; |
644 | } | 652 | } |
645 | 653 | ||
@@ -665,7 +673,7 @@ static int ieee80211_change_beacon(struct wiphy *wiphy, struct net_device *dev, | |||
665 | 673 | ||
666 | static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) | 674 | static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) |
667 | { | 675 | { |
668 | struct ieee80211_sub_if_data *sdata; | 676 | struct ieee80211_sub_if_data *sdata, *vlan; |
669 | struct beacon_data *old; | 677 | struct beacon_data *old; |
670 | 678 | ||
671 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 679 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
@@ -674,6 +682,10 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) | |||
674 | if (!old) | 682 | if (!old) |
675 | return -ENOENT; | 683 | return -ENOENT; |
676 | 684 | ||
685 | list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) | ||
686 | netif_carrier_off(vlan->dev); | ||
687 | netif_carrier_off(dev); | ||
688 | |||
677 | RCU_INIT_POINTER(sdata->u.ap.beacon, NULL); | 689 | RCU_INIT_POINTER(sdata->u.ap.beacon, NULL); |
678 | 690 | ||
679 | kfree_rcu(old, rcu_head); | 691 | kfree_rcu(old, rcu_head); |
@@ -1235,6 +1247,7 @@ static int copy_mesh_setup(struct ieee80211_if_mesh *ifmsh, | |||
1235 | /* now copy the rest of the setup parameters */ | 1247 | /* now copy the rest of the setup parameters */ |
1236 | ifmsh->mesh_id_len = setup->mesh_id_len; | 1248 | ifmsh->mesh_id_len = setup->mesh_id_len; |
1237 | memcpy(ifmsh->mesh_id, setup->mesh_id, ifmsh->mesh_id_len); | 1249 | memcpy(ifmsh->mesh_id, setup->mesh_id, ifmsh->mesh_id_len); |
1250 | ifmsh->mesh_sp_id = setup->sync_method; | ||
1238 | ifmsh->mesh_pp_id = setup->path_sel_proto; | 1251 | ifmsh->mesh_pp_id = setup->path_sel_proto; |
1239 | ifmsh->mesh_pm_id = setup->path_metric; | 1252 | ifmsh->mesh_pm_id = setup->path_metric; |
1240 | ifmsh->security = IEEE80211_MESH_SEC_NONE; | 1253 | ifmsh->security = IEEE80211_MESH_SEC_NONE; |
@@ -1279,6 +1292,9 @@ static int ieee80211_update_mesh_config(struct wiphy *wiphy, | |||
1279 | conf->dot11MeshTTL = nconf->element_ttl; | 1292 | conf->dot11MeshTTL = nconf->element_ttl; |
1280 | if (_chg_mesh_attr(NL80211_MESHCONF_AUTO_OPEN_PLINKS, mask)) | 1293 | if (_chg_mesh_attr(NL80211_MESHCONF_AUTO_OPEN_PLINKS, mask)) |
1281 | conf->auto_open_plinks = nconf->auto_open_plinks; | 1294 | conf->auto_open_plinks = nconf->auto_open_plinks; |
1295 | if (_chg_mesh_attr(NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR, mask)) | ||
1296 | conf->dot11MeshNbrOffsetMaxNeighbor = | ||
1297 | nconf->dot11MeshNbrOffsetMaxNeighbor; | ||
1282 | if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES, mask)) | 1298 | if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES, mask)) |
1283 | conf->dot11MeshHWMPmaxPREQretries = | 1299 | conf->dot11MeshHWMPmaxPREQretries = |
1284 | nconf->dot11MeshHWMPmaxPREQretries; | 1300 | nconf->dot11MeshHWMPmaxPREQretries; |
@@ -1437,6 +1453,9 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy, | |||
1437 | if (!local->ops->conf_tx) | 1453 | if (!local->ops->conf_tx) |
1438 | return -EOPNOTSUPP; | 1454 | return -EOPNOTSUPP; |
1439 | 1455 | ||
1456 | if (local->hw.queues < IEEE80211_NUM_ACS) | ||
1457 | return -EOPNOTSUPP; | ||
1458 | |||
1440 | memset(&p, 0, sizeof(p)); | 1459 | memset(&p, 0, sizeof(p)); |
1441 | p.aifs = params->aifs; | 1460 | p.aifs = params->aifs; |
1442 | p.cw_max = params->cwmax; | 1461 | p.cw_max = params->cwmax; |
@@ -1449,14 +1468,11 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy, | |||
1449 | */ | 1468 | */ |
1450 | p.uapsd = false; | 1469 | p.uapsd = false; |
1451 | 1470 | ||
1452 | if (params->queue >= local->hw.queues) | 1471 | sdata->tx_conf[params->ac] = p; |
1453 | return -EINVAL; | 1472 | if (drv_conf_tx(local, sdata, params->ac, &p)) { |
1454 | |||
1455 | sdata->tx_conf[params->queue] = p; | ||
1456 | if (drv_conf_tx(local, sdata, params->queue, &p)) { | ||
1457 | wiphy_debug(local->hw.wiphy, | 1473 | wiphy_debug(local->hw.wiphy, |
1458 | "failed to set TX queue parameters for queue %d\n", | 1474 | "failed to set TX queue parameters for AC %d\n", |
1459 | params->queue); | 1475 | params->ac); |
1460 | return -EINVAL; | 1476 | return -EINVAL; |
1461 | } | 1477 | } |
1462 | 1478 | ||
@@ -2090,6 +2106,10 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, | |||
2090 | 2106 | ||
2091 | IEEE80211_SKB_CB(skb)->flags = flags; | 2107 | IEEE80211_SKB_CB(skb)->flags = flags; |
2092 | 2108 | ||
2109 | if (flags & IEEE80211_TX_CTL_TX_OFFCHAN) | ||
2110 | IEEE80211_SKB_CB(skb)->hw_queue = | ||
2111 | local->hw.offchannel_tx_hw_queue; | ||
2112 | |||
2093 | skb->dev = sdata->dev; | 2113 | skb->dev = sdata->dev; |
2094 | 2114 | ||
2095 | *cookie = (unsigned long) skb; | 2115 | *cookie = (unsigned long) skb; |
@@ -2131,6 +2151,8 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, | |||
2131 | /* modify cookie to prevent API mismatches */ | 2151 | /* modify cookie to prevent API mismatches */ |
2132 | *cookie ^= 2; | 2152 | *cookie ^= 2; |
2133 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_TX_OFFCHAN; | 2153 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_TX_OFFCHAN; |
2154 | IEEE80211_SKB_CB(skb)->hw_queue = | ||
2155 | local->hw.offchannel_tx_hw_queue; | ||
2134 | local->hw_roc_skb = skb; | 2156 | local->hw_roc_skb = skb; |
2135 | local->hw_roc_skb_for_status = skb; | 2157 | local->hw_roc_skb_for_status = skb; |
2136 | mutex_unlock(&local->mtx); | 2158 | mutex_unlock(&local->mtx); |
@@ -2350,8 +2372,8 @@ ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev, | |||
2350 | tf->u.setup_req.capability = | 2372 | tf->u.setup_req.capability = |
2351 | cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); | 2373 | cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); |
2352 | 2374 | ||
2353 | ieee80211_add_srates_ie(&sdata->vif, skb); | 2375 | ieee80211_add_srates_ie(&sdata->vif, skb, false); |
2354 | ieee80211_add_ext_srates_ie(&sdata->vif, skb); | 2376 | ieee80211_add_ext_srates_ie(&sdata->vif, skb, false); |
2355 | ieee80211_tdls_add_ext_capab(skb); | 2377 | ieee80211_tdls_add_ext_capab(skb); |
2356 | break; | 2378 | break; |
2357 | case WLAN_TDLS_SETUP_RESPONSE: | 2379 | case WLAN_TDLS_SETUP_RESPONSE: |
@@ -2364,8 +2386,8 @@ ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev, | |||
2364 | tf->u.setup_resp.capability = | 2386 | tf->u.setup_resp.capability = |
2365 | cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); | 2387 | cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); |
2366 | 2388 | ||
2367 | ieee80211_add_srates_ie(&sdata->vif, skb); | 2389 | ieee80211_add_srates_ie(&sdata->vif, skb, false); |
2368 | ieee80211_add_ext_srates_ie(&sdata->vif, skb); | 2390 | ieee80211_add_ext_srates_ie(&sdata->vif, skb, false); |
2369 | ieee80211_tdls_add_ext_capab(skb); | 2391 | ieee80211_tdls_add_ext_capab(skb); |
2370 | break; | 2392 | break; |
2371 | case WLAN_TDLS_SETUP_CONFIRM: | 2393 | case WLAN_TDLS_SETUP_CONFIRM: |
@@ -2425,8 +2447,8 @@ ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev, | |||
2425 | mgmt->u.action.u.tdls_discover_resp.capability = | 2447 | mgmt->u.action.u.tdls_discover_resp.capability = |
2426 | cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); | 2448 | cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); |
2427 | 2449 | ||
2428 | ieee80211_add_srates_ie(&sdata->vif, skb); | 2450 | ieee80211_add_srates_ie(&sdata->vif, skb, false); |
2429 | ieee80211_add_ext_srates_ie(&sdata->vif, skb); | 2451 | ieee80211_add_ext_srates_ie(&sdata->vif, skb, false); |
2430 | ieee80211_tdls_add_ext_capab(skb); | 2452 | ieee80211_tdls_add_ext_capab(skb); |
2431 | break; | 2453 | break; |
2432 | default: | 2454 | default: |
@@ -2673,6 +2695,13 @@ ieee80211_wiphy_get_channel(struct wiphy *wiphy) | |||
2673 | return local->oper_channel; | 2695 | return local->oper_channel; |
2674 | } | 2696 | } |
2675 | 2697 | ||
2698 | #ifdef CONFIG_PM | ||
2699 | static void ieee80211_set_wakeup(struct wiphy *wiphy, bool enabled) | ||
2700 | { | ||
2701 | drv_set_wakeup(wiphy_priv(wiphy), enabled); | ||
2702 | } | ||
2703 | #endif | ||
2704 | |||
2676 | struct cfg80211_ops mac80211_config_ops = { | 2705 | struct cfg80211_ops mac80211_config_ops = { |
2677 | .add_virtual_intf = ieee80211_add_iface, | 2706 | .add_virtual_intf = ieee80211_add_iface, |
2678 | .del_virtual_intf = ieee80211_del_iface, | 2707 | .del_virtual_intf = ieee80211_del_iface, |
@@ -2741,4 +2770,7 @@ struct cfg80211_ops mac80211_config_ops = { | |||
2741 | .probe_client = ieee80211_probe_client, | 2770 | .probe_client = ieee80211_probe_client, |
2742 | .get_channel = ieee80211_wiphy_get_channel, | 2771 | .get_channel = ieee80211_wiphy_get_channel, |
2743 | .set_noack_map = ieee80211_set_noack_map, | 2772 | .set_noack_map = ieee80211_set_noack_map, |
2773 | #ifdef CONFIG_PM | ||
2774 | .set_wakeup = ieee80211_set_wakeup, | ||
2775 | #endif | ||
2744 | }; | 2776 | }; |
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index e00ce8c3e28e..c76cf7230c7d 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c | |||
@@ -135,29 +135,3 @@ bool ieee80211_set_channel_type(struct ieee80211_local *local, | |||
135 | 135 | ||
136 | return result; | 136 | return result; |
137 | } | 137 | } |
138 | |||
139 | /* | ||
140 | * ieee80211_get_tx_channel_type returns the channel type we should | ||
141 | * use for packet transmission, given the channel capability and | ||
142 | * whatever regulatory flags we have been given. | ||
143 | */ | ||
144 | enum nl80211_channel_type ieee80211_get_tx_channel_type( | ||
145 | struct ieee80211_local *local, | ||
146 | enum nl80211_channel_type channel_type) | ||
147 | { | ||
148 | switch (channel_type) { | ||
149 | case NL80211_CHAN_HT40PLUS: | ||
150 | if (local->hw.conf.channel->flags & | ||
151 | IEEE80211_CHAN_NO_HT40PLUS) | ||
152 | return NL80211_CHAN_HT20; | ||
153 | break; | ||
154 | case NL80211_CHAN_HT40MINUS: | ||
155 | if (local->hw.conf.channel->flags & | ||
156 | IEEE80211_CHAN_NO_HT40MINUS) | ||
157 | return NL80211_CHAN_HT20; | ||
158 | break; | ||
159 | default: | ||
160 | break; | ||
161 | } | ||
162 | return channel_type; | ||
163 | } | ||
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 30f99c344847..e7af5227e322 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c | |||
@@ -424,6 +424,7 @@ static ssize_t ieee80211_if_parse_tsf( | |||
424 | struct ieee80211_local *local = sdata->local; | 424 | struct ieee80211_local *local = sdata->local; |
425 | unsigned long long tsf; | 425 | unsigned long long tsf; |
426 | int ret; | 426 | int ret; |
427 | int tsf_is_delta = 0; | ||
427 | 428 | ||
428 | if (strncmp(buf, "reset", 5) == 0) { | 429 | if (strncmp(buf, "reset", 5) == 0) { |
429 | if (local->ops->reset_tsf) { | 430 | if (local->ops->reset_tsf) { |
@@ -431,9 +432,20 @@ static ssize_t ieee80211_if_parse_tsf( | |||
431 | wiphy_info(local->hw.wiphy, "debugfs reset TSF\n"); | 432 | wiphy_info(local->hw.wiphy, "debugfs reset TSF\n"); |
432 | } | 433 | } |
433 | } else { | 434 | } else { |
435 | if (buflen > 10 && buf[1] == '=') { | ||
436 | if (buf[0] == '+') | ||
437 | tsf_is_delta = 1; | ||
438 | else if (buf[0] == '-') | ||
439 | tsf_is_delta = -1; | ||
440 | else | ||
441 | return -EINVAL; | ||
442 | buf += 2; | ||
443 | } | ||
434 | ret = kstrtoull(buf, 10, &tsf); | 444 | ret = kstrtoull(buf, 10, &tsf); |
435 | if (ret < 0) | 445 | if (ret < 0) |
436 | return -EINVAL; | 446 | return -EINVAL; |
447 | if (tsf_is_delta) | ||
448 | tsf = drv_get_tsf(local, sdata) + tsf_is_delta * tsf; | ||
437 | if (local->ops->set_tsf) { | 449 | if (local->ops->set_tsf) { |
438 | drv_set_tsf(local, sdata, tsf); | 450 | drv_set_tsf(local, sdata, tsf); |
439 | wiphy_info(local->hw.wiphy, | 451 | wiphy_info(local->hw.wiphy, |
@@ -499,26 +511,23 @@ IEEE80211_IF_FILE(dot11MeshForwarding, u.mesh.mshcfg.dot11MeshForwarding, DEC); | |||
499 | IEEE80211_IF_FILE(rssi_threshold, u.mesh.mshcfg.rssi_threshold, DEC); | 511 | IEEE80211_IF_FILE(rssi_threshold, u.mesh.mshcfg.rssi_threshold, DEC); |
500 | #endif | 512 | #endif |
501 | 513 | ||
502 | |||
503 | #define DEBUGFS_ADD(name) \ | ||
504 | debugfs_create_file(#name, 0400, sdata->debugfs.dir, \ | ||
505 | sdata, &name##_ops); | ||
506 | |||
507 | #define DEBUGFS_ADD_MODE(name, mode) \ | 514 | #define DEBUGFS_ADD_MODE(name, mode) \ |
508 | debugfs_create_file(#name, mode, sdata->debugfs.dir, \ | 515 | debugfs_create_file(#name, mode, sdata->debugfs.dir, \ |
509 | sdata, &name##_ops); | 516 | sdata, &name##_ops); |
510 | 517 | ||
511 | static void add_sta_files(struct ieee80211_sub_if_data *sdata) | 518 | #define DEBUGFS_ADD(name) DEBUGFS_ADD_MODE(name, 0400) |
519 | |||
520 | static void add_common_files(struct ieee80211_sub_if_data *sdata) | ||
512 | { | 521 | { |
513 | DEBUGFS_ADD(drop_unencrypted); | 522 | DEBUGFS_ADD(drop_unencrypted); |
514 | DEBUGFS_ADD(flags); | ||
515 | DEBUGFS_ADD(state); | ||
516 | DEBUGFS_ADD(channel_type); | ||
517 | DEBUGFS_ADD(rc_rateidx_mask_2ghz); | 523 | DEBUGFS_ADD(rc_rateidx_mask_2ghz); |
518 | DEBUGFS_ADD(rc_rateidx_mask_5ghz); | 524 | DEBUGFS_ADD(rc_rateidx_mask_5ghz); |
519 | DEBUGFS_ADD(rc_rateidx_mcs_mask_2ghz); | 525 | DEBUGFS_ADD(rc_rateidx_mcs_mask_2ghz); |
520 | DEBUGFS_ADD(rc_rateidx_mcs_mask_5ghz); | 526 | DEBUGFS_ADD(rc_rateidx_mcs_mask_5ghz); |
527 | } | ||
521 | 528 | ||
529 | static void add_sta_files(struct ieee80211_sub_if_data *sdata) | ||
530 | { | ||
522 | DEBUGFS_ADD(bssid); | 531 | DEBUGFS_ADD(bssid); |
523 | DEBUGFS_ADD(aid); | 532 | DEBUGFS_ADD(aid); |
524 | DEBUGFS_ADD(last_beacon); | 533 | DEBUGFS_ADD(last_beacon); |
@@ -531,15 +540,6 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata) | |||
531 | 540 | ||
532 | static void add_ap_files(struct ieee80211_sub_if_data *sdata) | 541 | static void add_ap_files(struct ieee80211_sub_if_data *sdata) |
533 | { | 542 | { |
534 | DEBUGFS_ADD(drop_unencrypted); | ||
535 | DEBUGFS_ADD(flags); | ||
536 | DEBUGFS_ADD(state); | ||
537 | DEBUGFS_ADD(channel_type); | ||
538 | DEBUGFS_ADD(rc_rateidx_mask_2ghz); | ||
539 | DEBUGFS_ADD(rc_rateidx_mask_5ghz); | ||
540 | DEBUGFS_ADD(rc_rateidx_mcs_mask_2ghz); | ||
541 | DEBUGFS_ADD(rc_rateidx_mcs_mask_5ghz); | ||
542 | |||
543 | DEBUGFS_ADD(num_sta_authorized); | 543 | DEBUGFS_ADD(num_sta_authorized); |
544 | DEBUGFS_ADD(num_sta_ps); | 544 | DEBUGFS_ADD(num_sta_ps); |
545 | DEBUGFS_ADD(dtim_count); | 545 | DEBUGFS_ADD(dtim_count); |
@@ -549,48 +549,14 @@ static void add_ap_files(struct ieee80211_sub_if_data *sdata) | |||
549 | 549 | ||
550 | static void add_ibss_files(struct ieee80211_sub_if_data *sdata) | 550 | static void add_ibss_files(struct ieee80211_sub_if_data *sdata) |
551 | { | 551 | { |
552 | DEBUGFS_ADD(channel_type); | ||
553 | DEBUGFS_ADD(rc_rateidx_mask_2ghz); | ||
554 | DEBUGFS_ADD(rc_rateidx_mask_5ghz); | ||
555 | DEBUGFS_ADD(rc_rateidx_mcs_mask_2ghz); | ||
556 | DEBUGFS_ADD(rc_rateidx_mcs_mask_5ghz); | ||
557 | |||
558 | DEBUGFS_ADD_MODE(tsf, 0600); | 552 | DEBUGFS_ADD_MODE(tsf, 0600); |
559 | } | 553 | } |
560 | 554 | ||
561 | static void add_wds_files(struct ieee80211_sub_if_data *sdata) | 555 | static void add_wds_files(struct ieee80211_sub_if_data *sdata) |
562 | { | 556 | { |
563 | DEBUGFS_ADD(drop_unencrypted); | ||
564 | DEBUGFS_ADD(flags); | ||
565 | DEBUGFS_ADD(state); | ||
566 | DEBUGFS_ADD(channel_type); | ||
567 | DEBUGFS_ADD(rc_rateidx_mask_2ghz); | ||
568 | DEBUGFS_ADD(rc_rateidx_mask_5ghz); | ||
569 | DEBUGFS_ADD(rc_rateidx_mcs_mask_2ghz); | ||
570 | DEBUGFS_ADD(rc_rateidx_mcs_mask_5ghz); | ||
571 | |||
572 | DEBUGFS_ADD(peer); | 557 | DEBUGFS_ADD(peer); |
573 | } | 558 | } |
574 | 559 | ||
575 | static void add_vlan_files(struct ieee80211_sub_if_data *sdata) | ||
576 | { | ||
577 | DEBUGFS_ADD(drop_unencrypted); | ||
578 | DEBUGFS_ADD(flags); | ||
579 | DEBUGFS_ADD(state); | ||
580 | DEBUGFS_ADD(channel_type); | ||
581 | DEBUGFS_ADD(rc_rateidx_mask_2ghz); | ||
582 | DEBUGFS_ADD(rc_rateidx_mask_5ghz); | ||
583 | DEBUGFS_ADD(rc_rateidx_mcs_mask_2ghz); | ||
584 | DEBUGFS_ADD(rc_rateidx_mcs_mask_5ghz); | ||
585 | } | ||
586 | |||
587 | static void add_monitor_files(struct ieee80211_sub_if_data *sdata) | ||
588 | { | ||
589 | DEBUGFS_ADD(flags); | ||
590 | DEBUGFS_ADD(state); | ||
591 | DEBUGFS_ADD(channel_type); | ||
592 | } | ||
593 | |||
594 | #ifdef CONFIG_MAC80211_MESH | 560 | #ifdef CONFIG_MAC80211_MESH |
595 | 561 | ||
596 | static void add_mesh_files(struct ieee80211_sub_if_data *sdata) | 562 | static void add_mesh_files(struct ieee80211_sub_if_data *sdata) |
@@ -651,6 +617,13 @@ static void add_files(struct ieee80211_sub_if_data *sdata) | |||
651 | if (!sdata->debugfs.dir) | 617 | if (!sdata->debugfs.dir) |
652 | return; | 618 | return; |
653 | 619 | ||
620 | DEBUGFS_ADD(flags); | ||
621 | DEBUGFS_ADD(state); | ||
622 | DEBUGFS_ADD(channel_type); | ||
623 | |||
624 | if (sdata->vif.type != NL80211_IFTYPE_MONITOR) | ||
625 | add_common_files(sdata); | ||
626 | |||
654 | switch (sdata->vif.type) { | 627 | switch (sdata->vif.type) { |
655 | case NL80211_IFTYPE_MESH_POINT: | 628 | case NL80211_IFTYPE_MESH_POINT: |
656 | #ifdef CONFIG_MAC80211_MESH | 629 | #ifdef CONFIG_MAC80211_MESH |
@@ -671,12 +644,6 @@ static void add_files(struct ieee80211_sub_if_data *sdata) | |||
671 | case NL80211_IFTYPE_WDS: | 644 | case NL80211_IFTYPE_WDS: |
672 | add_wds_files(sdata); | 645 | add_wds_files(sdata); |
673 | break; | 646 | break; |
674 | case NL80211_IFTYPE_MONITOR: | ||
675 | add_monitor_files(sdata); | ||
676 | break; | ||
677 | case NL80211_IFTYPE_AP_VLAN: | ||
678 | add_vlan_files(sdata); | ||
679 | break; | ||
680 | default: | 647 | default: |
681 | break; | 648 | break; |
682 | } | 649 | } |
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 832b2da5e4cd..5ccec2c1e9f6 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c | |||
@@ -63,7 +63,7 @@ static ssize_t sta_flags_read(struct file *file, char __user *userbuf, | |||
63 | test_sta_flag(sta, WLAN_STA_##flg) ? #flg "\n" : "" | 63 | test_sta_flag(sta, WLAN_STA_##flg) ? #flg "\n" : "" |
64 | 64 | ||
65 | int res = scnprintf(buf, sizeof(buf), | 65 | int res = scnprintf(buf, sizeof(buf), |
66 | "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", | 66 | "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", |
67 | TEST(AUTH), TEST(ASSOC), TEST(PS_STA), | 67 | TEST(AUTH), TEST(ASSOC), TEST(PS_STA), |
68 | TEST(PS_DRIVER), TEST(AUTHORIZED), | 68 | TEST(PS_DRIVER), TEST(AUTHORIZED), |
69 | TEST(SHORT_PREAMBLE), | 69 | TEST(SHORT_PREAMBLE), |
@@ -71,7 +71,8 @@ static ssize_t sta_flags_read(struct file *file, char __user *userbuf, | |||
71 | TEST(MFP), TEST(BLOCK_BA), TEST(PSPOLL), | 71 | TEST(MFP), TEST(BLOCK_BA), TEST(PSPOLL), |
72 | TEST(UAPSD), TEST(SP), TEST(TDLS_PEER), | 72 | TEST(UAPSD), TEST(SP), TEST(TDLS_PEER), |
73 | TEST(TDLS_PEER_AUTH), TEST(4ADDR_EVENT), | 73 | TEST(TDLS_PEER_AUTH), TEST(4ADDR_EVENT), |
74 | TEST(INSERTED), TEST(RATE_CONTROL)); | 74 | TEST(INSERTED), TEST(RATE_CONTROL), |
75 | TEST(TOFFSET_KNOWN)); | ||
75 | #undef TEST | 76 | #undef TEST |
76 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); | 77 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); |
77 | } | 78 | } |
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index af4691fed645..4a0e559cb26b 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h | |||
@@ -7,7 +7,9 @@ | |||
7 | 7 | ||
8 | static inline void check_sdata_in_driver(struct ieee80211_sub_if_data *sdata) | 8 | static inline void check_sdata_in_driver(struct ieee80211_sub_if_data *sdata) |
9 | { | 9 | { |
10 | WARN_ON(!(sdata->flags & IEEE80211_SDATA_IN_DRIVER)); | 10 | WARN(!(sdata->flags & IEEE80211_SDATA_IN_DRIVER), |
11 | "%s: Failed check-sdata-in-driver check, flags: 0x%x\n", | ||
12 | sdata->dev->name, sdata->flags); | ||
11 | } | 13 | } |
12 | 14 | ||
13 | static inline struct ieee80211_sub_if_data * | 15 | static inline struct ieee80211_sub_if_data * |
@@ -89,6 +91,19 @@ static inline int drv_resume(struct ieee80211_local *local) | |||
89 | trace_drv_return_int(local, ret); | 91 | trace_drv_return_int(local, ret); |
90 | return ret; | 92 | return ret; |
91 | } | 93 | } |
94 | |||
95 | static inline void drv_set_wakeup(struct ieee80211_local *local, | ||
96 | bool enabled) | ||
97 | { | ||
98 | might_sleep(); | ||
99 | |||
100 | if (!local->ops->set_wakeup) | ||
101 | return; | ||
102 | |||
103 | trace_drv_set_wakeup(local, enabled); | ||
104 | local->ops->set_wakeup(&local->hw, enabled); | ||
105 | trace_drv_return_void(local); | ||
106 | } | ||
92 | #endif | 107 | #endif |
93 | 108 | ||
94 | static inline int drv_add_interface(struct ieee80211_local *local, | 109 | static inline int drv_add_interface(struct ieee80211_local *local, |
@@ -99,7 +114,8 @@ static inline int drv_add_interface(struct ieee80211_local *local, | |||
99 | might_sleep(); | 114 | might_sleep(); |
100 | 115 | ||
101 | if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_AP_VLAN || | 116 | if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_AP_VLAN || |
102 | sdata->vif.type == NL80211_IFTYPE_MONITOR)) | 117 | (sdata->vif.type == NL80211_IFTYPE_MONITOR && |
118 | !(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF)))) | ||
103 | return -EINVAL; | 119 | return -EINVAL; |
104 | 120 | ||
105 | trace_drv_add_interface(local, sdata); | 121 | trace_drv_add_interface(local, sdata); |
@@ -474,8 +490,23 @@ int drv_sta_state(struct ieee80211_local *local, | |||
474 | return ret; | 490 | return ret; |
475 | } | 491 | } |
476 | 492 | ||
493 | static inline void drv_sta_rc_update(struct ieee80211_local *local, | ||
494 | struct ieee80211_sub_if_data *sdata, | ||
495 | struct ieee80211_sta *sta, u32 changed) | ||
496 | { | ||
497 | sdata = get_bss_sdata(sdata); | ||
498 | check_sdata_in_driver(sdata); | ||
499 | |||
500 | trace_drv_sta_rc_update(local, sdata, sta, changed); | ||
501 | if (local->ops->sta_rc_update) | ||
502 | local->ops->sta_rc_update(&local->hw, &sdata->vif, | ||
503 | sta, changed); | ||
504 | |||
505 | trace_drv_return_void(local); | ||
506 | } | ||
507 | |||
477 | static inline int drv_conf_tx(struct ieee80211_local *local, | 508 | static inline int drv_conf_tx(struct ieee80211_local *local, |
478 | struct ieee80211_sub_if_data *sdata, u16 queue, | 509 | struct ieee80211_sub_if_data *sdata, u16 ac, |
479 | const struct ieee80211_tx_queue_params *params) | 510 | const struct ieee80211_tx_queue_params *params) |
480 | { | 511 | { |
481 | int ret = -EOPNOTSUPP; | 512 | int ret = -EOPNOTSUPP; |
@@ -484,10 +515,10 @@ static inline int drv_conf_tx(struct ieee80211_local *local, | |||
484 | 515 | ||
485 | check_sdata_in_driver(sdata); | 516 | check_sdata_in_driver(sdata); |
486 | 517 | ||
487 | trace_drv_conf_tx(local, sdata, queue, params); | 518 | trace_drv_conf_tx(local, sdata, ac, params); |
488 | if (local->ops->conf_tx) | 519 | if (local->ops->conf_tx) |
489 | ret = local->ops->conf_tx(&local->hw, &sdata->vif, | 520 | ret = local->ops->conf_tx(&local->hw, &sdata->vif, |
490 | queue, params); | 521 | ac, params); |
491 | trace_drv_return_int(local, ret); | 522 | trace_drv_return_int(local, ret); |
492 | return ret; | 523 | return ret; |
493 | } | 524 | } |
diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h index 21d6f5290a1c..7c0754bed61b 100644 --- a/net/mac80211/driver-trace.h +++ b/net/mac80211/driver-trace.h | |||
@@ -171,6 +171,20 @@ DEFINE_EVENT(local_only_evt, drv_resume, | |||
171 | TP_ARGS(local) | 171 | TP_ARGS(local) |
172 | ); | 172 | ); |
173 | 173 | ||
174 | TRACE_EVENT(drv_set_wakeup, | ||
175 | TP_PROTO(struct ieee80211_local *local, bool enabled), | ||
176 | TP_ARGS(local, enabled), | ||
177 | TP_STRUCT__entry( | ||
178 | LOCAL_ENTRY | ||
179 | __field(bool, enabled) | ||
180 | ), | ||
181 | TP_fast_assign( | ||
182 | LOCAL_ASSIGN; | ||
183 | __entry->enabled = enabled; | ||
184 | ), | ||
185 | TP_printk(LOCAL_PR_FMT " enabled:%d", LOCAL_PR_ARG, __entry->enabled) | ||
186 | ); | ||
187 | |||
174 | DEFINE_EVENT(local_only_evt, drv_stop, | 188 | DEFINE_EVENT(local_only_evt, drv_stop, |
175 | TP_PROTO(struct ieee80211_local *local), | 189 | TP_PROTO(struct ieee80211_local *local), |
176 | TP_ARGS(local) | 190 | TP_ARGS(local) |
@@ -624,6 +638,34 @@ TRACE_EVENT(drv_sta_state, | |||
624 | ) | 638 | ) |
625 | ); | 639 | ); |
626 | 640 | ||
641 | TRACE_EVENT(drv_sta_rc_update, | ||
642 | TP_PROTO(struct ieee80211_local *local, | ||
643 | struct ieee80211_sub_if_data *sdata, | ||
644 | struct ieee80211_sta *sta, | ||
645 | u32 changed), | ||
646 | |||
647 | TP_ARGS(local, sdata, sta, changed), | ||
648 | |||
649 | TP_STRUCT__entry( | ||
650 | LOCAL_ENTRY | ||
651 | VIF_ENTRY | ||
652 | STA_ENTRY | ||
653 | __field(u32, changed) | ||
654 | ), | ||
655 | |||
656 | TP_fast_assign( | ||
657 | LOCAL_ASSIGN; | ||
658 | VIF_ASSIGN; | ||
659 | STA_ASSIGN; | ||
660 | __entry->changed = changed; | ||
661 | ), | ||
662 | |||
663 | TP_printk( | ||
664 | LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " changed: 0x%x", | ||
665 | LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->changed | ||
666 | ) | ||
667 | ); | ||
668 | |||
627 | TRACE_EVENT(drv_sta_add, | 669 | TRACE_EVENT(drv_sta_add, |
628 | TP_PROTO(struct ieee80211_local *local, | 670 | TP_PROTO(struct ieee80211_local *local, |
629 | struct ieee80211_sub_if_data *sdata, | 671 | struct ieee80211_sub_if_data *sdata, |
@@ -677,15 +719,14 @@ TRACE_EVENT(drv_sta_remove, | |||
677 | TRACE_EVENT(drv_conf_tx, | 719 | TRACE_EVENT(drv_conf_tx, |
678 | TP_PROTO(struct ieee80211_local *local, | 720 | TP_PROTO(struct ieee80211_local *local, |
679 | struct ieee80211_sub_if_data *sdata, | 721 | struct ieee80211_sub_if_data *sdata, |
680 | u16 queue, | 722 | u16 ac, const struct ieee80211_tx_queue_params *params), |
681 | const struct ieee80211_tx_queue_params *params), | ||
682 | 723 | ||
683 | TP_ARGS(local, sdata, queue, params), | 724 | TP_ARGS(local, sdata, ac, params), |
684 | 725 | ||
685 | TP_STRUCT__entry( | 726 | TP_STRUCT__entry( |
686 | LOCAL_ENTRY | 727 | LOCAL_ENTRY |
687 | VIF_ENTRY | 728 | VIF_ENTRY |
688 | __field(u16, queue) | 729 | __field(u16, ac) |
689 | __field(u16, txop) | 730 | __field(u16, txop) |
690 | __field(u16, cw_min) | 731 | __field(u16, cw_min) |
691 | __field(u16, cw_max) | 732 | __field(u16, cw_max) |
@@ -696,7 +737,7 @@ TRACE_EVENT(drv_conf_tx, | |||
696 | TP_fast_assign( | 737 | TP_fast_assign( |
697 | LOCAL_ASSIGN; | 738 | LOCAL_ASSIGN; |
698 | VIF_ASSIGN; | 739 | VIF_ASSIGN; |
699 | __entry->queue = queue; | 740 | __entry->ac = ac; |
700 | __entry->txop = params->txop; | 741 | __entry->txop = params->txop; |
701 | __entry->cw_max = params->cw_max; | 742 | __entry->cw_max = params->cw_max; |
702 | __entry->cw_min = params->cw_min; | 743 | __entry->cw_min = params->cw_min; |
@@ -705,8 +746,8 @@ TRACE_EVENT(drv_conf_tx, | |||
705 | ), | 746 | ), |
706 | 747 | ||
707 | TP_printk( | 748 | TP_printk( |
708 | LOCAL_PR_FMT VIF_PR_FMT " queue:%d", | 749 | LOCAL_PR_FMT VIF_PR_FMT " AC:%d", |
709 | LOCAL_PR_ARG, VIF_PR_ARG, __entry->queue | 750 | LOCAL_PR_ARG, VIF_PR_ARG, __entry->ac |
710 | ) | 751 | ) |
711 | ); | 752 | ); |
712 | 753 | ||
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index f25fff7607d8..9b603366943c 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c | |||
@@ -19,15 +19,6 @@ | |||
19 | #include "ieee80211_i.h" | 19 | #include "ieee80211_i.h" |
20 | #include "rate.h" | 20 | #include "rate.h" |
21 | 21 | ||
22 | bool ieee80111_cfg_override_disables_ht40(struct ieee80211_sub_if_data *sdata) | ||
23 | { | ||
24 | const __le16 flg = cpu_to_le16(IEEE80211_HT_CAP_SUP_WIDTH_20_40); | ||
25 | if ((sdata->u.mgd.ht_capa_mask.cap_info & flg) && | ||
26 | !(sdata->u.mgd.ht_capa.cap_info & flg)) | ||
27 | return true; | ||
28 | return false; | ||
29 | } | ||
30 | |||
31 | static void __check_htcap_disable(struct ieee80211_sub_if_data *sdata, | 22 | static void __check_htcap_disable(struct ieee80211_sub_if_data *sdata, |
32 | struct ieee80211_sta_ht_cap *ht_cap, | 23 | struct ieee80211_sta_ht_cap *ht_cap, |
33 | u16 flag) | 24 | u16 flag) |
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 33fd8d9f714e..49a207980338 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c | |||
@@ -160,16 +160,14 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
160 | if (channel_type && sband->ht_cap.ht_supported) { | 160 | if (channel_type && sband->ht_cap.ht_supported) { |
161 | pos = skb_put(skb, 4 + | 161 | pos = skb_put(skb, 4 + |
162 | sizeof(struct ieee80211_ht_cap) + | 162 | sizeof(struct ieee80211_ht_cap) + |
163 | sizeof(struct ieee80211_ht_info)); | 163 | sizeof(struct ieee80211_ht_operation)); |
164 | pos = ieee80211_ie_build_ht_cap(pos, &sband->ht_cap, | 164 | pos = ieee80211_ie_build_ht_cap(pos, &sband->ht_cap, |
165 | sband->ht_cap.cap); | 165 | sband->ht_cap.cap); |
166 | pos = ieee80211_ie_build_ht_info(pos, | 166 | pos = ieee80211_ie_build_ht_oper(pos, &sband->ht_cap, |
167 | &sband->ht_cap, | 167 | chan, channel_type); |
168 | chan, | ||
169 | channel_type); | ||
170 | } | 168 | } |
171 | 169 | ||
172 | if (local->hw.queues >= 4) { | 170 | if (local->hw.queues >= IEEE80211_NUM_ACS) { |
173 | pos = skb_put(skb, 9); | 171 | pos = skb_put(skb, 9); |
174 | *pos++ = WLAN_EID_VENDOR_SPECIFIC; | 172 | *pos++ = WLAN_EID_VENDOR_SPECIFIC; |
175 | *pos++ = 7; /* len */ | 173 | *pos++ = 7; /* len */ |
@@ -410,7 +408,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
410 | 408 | ||
411 | if (elems->supp_rates) { | 409 | if (elems->supp_rates) { |
412 | supp_rates = ieee80211_sta_get_rates(local, elems, | 410 | supp_rates = ieee80211_sta_get_rates(local, elems, |
413 | band); | 411 | band, NULL); |
414 | if (sta) { | 412 | if (sta) { |
415 | u32 prev_rates; | 413 | u32 prev_rates; |
416 | 414 | ||
@@ -441,13 +439,13 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
441 | if (sta && elems->wmm_info) | 439 | if (sta && elems->wmm_info) |
442 | set_sta_flag(sta, WLAN_STA_WME); | 440 | set_sta_flag(sta, WLAN_STA_WME); |
443 | 441 | ||
444 | if (sta && elems->ht_info_elem && elems->ht_cap_elem && | 442 | if (sta && elems->ht_operation && elems->ht_cap_elem && |
445 | sdata->u.ibss.channel_type != NL80211_CHAN_NO_HT) { | 443 | sdata->u.ibss.channel_type != NL80211_CHAN_NO_HT) { |
446 | /* we both use HT */ | 444 | /* we both use HT */ |
447 | struct ieee80211_sta_ht_cap sta_ht_cap_new; | 445 | struct ieee80211_sta_ht_cap sta_ht_cap_new; |
448 | enum nl80211_channel_type channel_type = | 446 | enum nl80211_channel_type channel_type = |
449 | ieee80211_ht_info_to_channel_type( | 447 | ieee80211_ht_oper_to_channel_type( |
450 | elems->ht_info_elem); | 448 | elems->ht_operation); |
451 | 449 | ||
452 | ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, | 450 | ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, |
453 | elems->ht_cap_elem, | 451 | elems->ht_cap_elem, |
@@ -560,7 +558,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
560 | sdata->name, mgmt->bssid); | 558 | sdata->name, mgmt->bssid); |
561 | #endif | 559 | #endif |
562 | ieee80211_sta_join_ibss(sdata, bss); | 560 | ieee80211_sta_join_ibss(sdata, bss); |
563 | supp_rates = ieee80211_sta_get_rates(local, elems, band); | 561 | supp_rates = ieee80211_sta_get_rates(local, elems, band, NULL); |
564 | ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, | 562 | ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, |
565 | supp_rates, true); | 563 | supp_rates, true); |
566 | rcu_read_unlock(); | 564 | rcu_read_unlock(); |
@@ -1063,7 +1061,7 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, | |||
1063 | 4 /* IBSS params */ + | 1061 | 4 /* IBSS params */ + |
1064 | 2 + (IEEE80211_MAX_SUPP_RATES - 8) + | 1062 | 2 + (IEEE80211_MAX_SUPP_RATES - 8) + |
1065 | 2 + sizeof(struct ieee80211_ht_cap) + | 1063 | 2 + sizeof(struct ieee80211_ht_cap) + |
1066 | 2 + sizeof(struct ieee80211_ht_info) + | 1064 | 2 + sizeof(struct ieee80211_ht_operation) + |
1067 | params->ie_len); | 1065 | params->ie_len); |
1068 | if (!skb) | 1066 | if (!skb) |
1069 | return -ENOMEM; | 1067 | return -ENOMEM; |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index d9798a307f20..4be11ea3dfc4 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -52,7 +52,8 @@ struct ieee80211_local; | |||
52 | * increased memory use (about 2 kB of RAM per entry). */ | 52 | * increased memory use (about 2 kB of RAM per entry). */ |
53 | #define IEEE80211_FRAGMENT_MAX 4 | 53 | #define IEEE80211_FRAGMENT_MAX 4 |
54 | 54 | ||
55 | #define TU_TO_EXP_TIME(x) (jiffies + usecs_to_jiffies((x) * 1024)) | 55 | #define TU_TO_JIFFIES(x) (usecs_to_jiffies((x) * 1024)) |
56 | #define TU_TO_EXP_TIME(x) (jiffies + TU_TO_JIFFIES(x)) | ||
56 | 57 | ||
57 | #define IEEE80211_DEFAULT_UAPSD_QUEUES \ | 58 | #define IEEE80211_DEFAULT_UAPSD_QUEUES \ |
58 | (IEEE80211_WMM_IE_STA_QOSINFO_AC_BK | \ | 59 | (IEEE80211_WMM_IE_STA_QOSINFO_AC_BK | \ |
@@ -378,6 +379,7 @@ enum ieee80211_sta_flags { | |||
378 | IEEE80211_STA_UAPSD_ENABLED = BIT(7), | 379 | IEEE80211_STA_UAPSD_ENABLED = BIT(7), |
379 | IEEE80211_STA_NULLFUNC_ACKED = BIT(8), | 380 | IEEE80211_STA_NULLFUNC_ACKED = BIT(8), |
380 | IEEE80211_STA_RESET_SIGNAL_AVE = BIT(9), | 381 | IEEE80211_STA_RESET_SIGNAL_AVE = BIT(9), |
382 | IEEE80211_STA_DISABLE_40MHZ = BIT(10), | ||
381 | }; | 383 | }; |
382 | 384 | ||
383 | struct ieee80211_mgd_auth_data { | 385 | struct ieee80211_mgd_auth_data { |
@@ -397,7 +399,7 @@ struct ieee80211_mgd_auth_data { | |||
397 | struct ieee80211_mgd_assoc_data { | 399 | struct ieee80211_mgd_assoc_data { |
398 | struct cfg80211_bss *bss; | 400 | struct cfg80211_bss *bss; |
399 | const u8 *supp_rates; | 401 | const u8 *supp_rates; |
400 | const u8 *ht_information_ie; | 402 | const u8 *ht_operation_ie; |
401 | 403 | ||
402 | unsigned long timeout; | 404 | unsigned long timeout; |
403 | int tries; | 405 | int tries; |
@@ -552,6 +554,24 @@ struct ieee80211_if_ibss { | |||
552 | } state; | 554 | } state; |
553 | }; | 555 | }; |
554 | 556 | ||
557 | /** | ||
558 | * struct ieee80211_mesh_sync_ops - Extensible synchronization framework interface | ||
559 | * | ||
560 | * these declarations define the interface, which enables | ||
561 | * vendor-specific mesh synchronization | ||
562 | * | ||
563 | */ | ||
564 | struct ieee802_11_elems; | ||
565 | struct ieee80211_mesh_sync_ops { | ||
566 | void (*rx_bcn_presp)(struct ieee80211_sub_if_data *sdata, | ||
567 | u16 stype, | ||
568 | struct ieee80211_mgmt *mgmt, | ||
569 | struct ieee802_11_elems *elems, | ||
570 | struct ieee80211_rx_status *rx_status); | ||
571 | void (*adjust_tbtt)(struct ieee80211_sub_if_data *sdata); | ||
572 | /* add other framework functions here */ | ||
573 | }; | ||
574 | |||
555 | struct ieee80211_if_mesh { | 575 | struct ieee80211_if_mesh { |
556 | struct timer_list housekeeping_timer; | 576 | struct timer_list housekeeping_timer; |
557 | struct timer_list mesh_path_timer; | 577 | struct timer_list mesh_path_timer; |
@@ -600,6 +620,11 @@ struct ieee80211_if_mesh { | |||
600 | IEEE80211_MESH_SEC_AUTHED = 0x1, | 620 | IEEE80211_MESH_SEC_AUTHED = 0x1, |
601 | IEEE80211_MESH_SEC_SECURED = 0x2, | 621 | IEEE80211_MESH_SEC_SECURED = 0x2, |
602 | } security; | 622 | } security; |
623 | /* Extensible Synchronization Framework */ | ||
624 | struct ieee80211_mesh_sync_ops *sync_ops; | ||
625 | s64 sync_offset_clockdrift_max; | ||
626 | spinlock_t sync_offset_lock; | ||
627 | bool adjusting_tbtt; | ||
603 | }; | 628 | }; |
604 | 629 | ||
605 | #ifdef CONFIG_MAC80211_MESH | 630 | #ifdef CONFIG_MAC80211_MESH |
@@ -666,12 +691,6 @@ struct ieee80211_sub_if_data { | |||
666 | 691 | ||
667 | char name[IFNAMSIZ]; | 692 | char name[IFNAMSIZ]; |
668 | 693 | ||
669 | /* | ||
670 | * keep track of whether the HT opmode (stored in | ||
671 | * vif.bss_info.ht_operation_mode) is valid. | ||
672 | */ | ||
673 | bool ht_opmode_valid; | ||
674 | |||
675 | /* to detect idle changes */ | 694 | /* to detect idle changes */ |
676 | bool old_idle; | 695 | bool old_idle; |
677 | 696 | ||
@@ -691,7 +710,7 @@ struct ieee80211_sub_if_data { | |||
691 | __be16 control_port_protocol; | 710 | __be16 control_port_protocol; |
692 | bool control_port_no_encrypt; | 711 | bool control_port_no_encrypt; |
693 | 712 | ||
694 | struct ieee80211_tx_queue_params tx_conf[IEEE80211_MAX_QUEUES]; | 713 | struct ieee80211_tx_queue_params tx_conf[IEEE80211_NUM_ACS]; |
695 | 714 | ||
696 | struct work_struct work; | 715 | struct work_struct work; |
697 | struct sk_buff_head skb_queue; | 716 | struct sk_buff_head skb_queue; |
@@ -761,7 +780,6 @@ enum queue_stop_reason { | |||
761 | IEEE80211_QUEUE_STOP_REASON_AGGREGATION, | 780 | IEEE80211_QUEUE_STOP_REASON_AGGREGATION, |
762 | IEEE80211_QUEUE_STOP_REASON_SUSPEND, | 781 | IEEE80211_QUEUE_STOP_REASON_SUSPEND, |
763 | IEEE80211_QUEUE_STOP_REASON_SKB_ADD, | 782 | IEEE80211_QUEUE_STOP_REASON_SKB_ADD, |
764 | IEEE80211_QUEUE_STOP_REASON_CHTYPE_CHANGE, | ||
765 | }; | 783 | }; |
766 | 784 | ||
767 | #ifdef CONFIG_MAC80211_LEDS | 785 | #ifdef CONFIG_MAC80211_LEDS |
@@ -1082,6 +1100,9 @@ struct ieee80211_local { | |||
1082 | struct net_device napi_dev; | 1100 | struct net_device napi_dev; |
1083 | 1101 | ||
1084 | struct napi_struct napi; | 1102 | struct napi_struct napi; |
1103 | |||
1104 | /* virtual monitor interface */ | ||
1105 | struct ieee80211_sub_if_data __rcu *monitor_sdata; | ||
1085 | }; | 1106 | }; |
1086 | 1107 | ||
1087 | static inline struct ieee80211_sub_if_data * | 1108 | static inline struct ieee80211_sub_if_data * |
@@ -1117,7 +1138,7 @@ struct ieee802_11_elems { | |||
1117 | u8 *wmm_info; | 1138 | u8 *wmm_info; |
1118 | u8 *wmm_param; | 1139 | u8 *wmm_param; |
1119 | struct ieee80211_ht_cap *ht_cap_elem; | 1140 | struct ieee80211_ht_cap *ht_cap_elem; |
1120 | struct ieee80211_ht_info *ht_info_elem; | 1141 | struct ieee80211_ht_operation *ht_operation; |
1121 | struct ieee80211_meshconf_ie *mesh_config; | 1142 | struct ieee80211_meshconf_ie *mesh_config; |
1122 | u8 *mesh_id; | 1143 | u8 *mesh_id; |
1123 | u8 *peering; | 1144 | u8 *peering; |
@@ -1299,7 +1320,6 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1299 | struct net_device *dev); | 1320 | struct net_device *dev); |
1300 | 1321 | ||
1301 | /* HT */ | 1322 | /* HT */ |
1302 | bool ieee80111_cfg_override_disables_ht40(struct ieee80211_sub_if_data *sdata); | ||
1303 | void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata, | 1323 | void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata, |
1304 | struct ieee80211_sta_ht_cap *ht_cap); | 1324 | struct ieee80211_sta_ht_cap *ht_cap); |
1305 | void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, | 1325 | void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, |
@@ -1429,13 +1449,17 @@ void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue, | |||
1429 | enum queue_stop_reason reason); | 1449 | enum queue_stop_reason reason); |
1430 | void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue, | 1450 | void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue, |
1431 | enum queue_stop_reason reason); | 1451 | enum queue_stop_reason reason); |
1452 | void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue); | ||
1432 | void ieee80211_add_pending_skb(struct ieee80211_local *local, | 1453 | void ieee80211_add_pending_skb(struct ieee80211_local *local, |
1433 | struct sk_buff *skb); | 1454 | struct sk_buff *skb); |
1434 | void ieee80211_add_pending_skbs(struct ieee80211_local *local, | ||
1435 | struct sk_buff_head *skbs); | ||
1436 | void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local, | 1455 | void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local, |
1437 | struct sk_buff_head *skbs, | 1456 | struct sk_buff_head *skbs, |
1438 | void (*fn)(void *data), void *data); | 1457 | void (*fn)(void *data), void *data); |
1458 | static inline void ieee80211_add_pending_skbs(struct ieee80211_local *local, | ||
1459 | struct sk_buff_head *skbs) | ||
1460 | { | ||
1461 | ieee80211_add_pending_skbs_fn(local, skbs, NULL, NULL); | ||
1462 | } | ||
1439 | 1463 | ||
1440 | void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, | 1464 | void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, |
1441 | u16 transaction, u16 auth_alg, | 1465 | u16 transaction, u16 auth_alg, |
@@ -1460,7 +1484,7 @@ void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, | |||
1460 | const u8 *supp_rates); | 1484 | const u8 *supp_rates); |
1461 | u32 ieee80211_sta_get_rates(struct ieee80211_local *local, | 1485 | u32 ieee80211_sta_get_rates(struct ieee80211_local *local, |
1462 | struct ieee802_11_elems *elems, | 1486 | struct ieee802_11_elems *elems, |
1463 | enum ieee80211_band band); | 1487 | enum ieee80211_band band, u32 *basic_rates); |
1464 | int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata, | 1488 | int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata, |
1465 | enum ieee80211_smps_mode smps_mode); | 1489 | enum ieee80211_smps_mode smps_mode); |
1466 | void ieee80211_recalc_smps(struct ieee80211_local *local); | 1490 | void ieee80211_recalc_smps(struct ieee80211_local *local); |
@@ -1470,10 +1494,9 @@ size_t ieee80211_ie_split(const u8 *ies, size_t ielen, | |||
1470 | size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset); | 1494 | size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset); |
1471 | u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, | 1495 | u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, |
1472 | u16 cap); | 1496 | u16 cap); |
1473 | u8 *ieee80211_ie_build_ht_info(u8 *pos, | 1497 | u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, |
1474 | struct ieee80211_sta_ht_cap *ht_cap, | 1498 | struct ieee80211_channel *channel, |
1475 | struct ieee80211_channel *channel, | 1499 | enum nl80211_channel_type channel_type); |
1476 | enum nl80211_channel_type channel_type); | ||
1477 | 1500 | ||
1478 | /* internal work items */ | 1501 | /* internal work items */ |
1479 | void ieee80211_work_init(struct ieee80211_local *local); | 1502 | void ieee80211_work_init(struct ieee80211_local *local); |
@@ -1501,10 +1524,7 @@ bool ieee80211_set_channel_type(struct ieee80211_local *local, | |||
1501 | struct ieee80211_sub_if_data *sdata, | 1524 | struct ieee80211_sub_if_data *sdata, |
1502 | enum nl80211_channel_type chantype); | 1525 | enum nl80211_channel_type chantype); |
1503 | enum nl80211_channel_type | 1526 | enum nl80211_channel_type |
1504 | ieee80211_ht_info_to_channel_type(struct ieee80211_ht_info *ht_info); | 1527 | ieee80211_ht_oper_to_channel_type(struct ieee80211_ht_operation *ht_oper); |
1505 | enum nl80211_channel_type ieee80211_get_tx_channel_type( | ||
1506 | struct ieee80211_local *local, | ||
1507 | enum nl80211_channel_type channel_type); | ||
1508 | 1528 | ||
1509 | #ifdef CONFIG_MAC80211_NOINLINE | 1529 | #ifdef CONFIG_MAC80211_NOINLINE |
1510 | #define debug_noinline noinline | 1530 | #define debug_noinline noinline |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 401c01f0731e..6e85faed053d 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -149,6 +149,34 @@ static int ieee80211_check_concurrent_iface(struct ieee80211_sub_if_data *sdata, | |||
149 | return 0; | 149 | return 0; |
150 | } | 150 | } |
151 | 151 | ||
152 | static int ieee80211_check_queues(struct ieee80211_sub_if_data *sdata) | ||
153 | { | ||
154 | int n_queues = sdata->local->hw.queues; | ||
155 | int i; | ||
156 | |||
157 | for (i = 0; i < IEEE80211_NUM_ACS; i++) { | ||
158 | if (WARN_ON_ONCE(sdata->vif.hw_queue[i] == | ||
159 | IEEE80211_INVAL_HW_QUEUE)) | ||
160 | return -EINVAL; | ||
161 | if (WARN_ON_ONCE(sdata->vif.hw_queue[i] >= | ||
162 | n_queues)) | ||
163 | return -EINVAL; | ||
164 | } | ||
165 | |||
166 | if (sdata->vif.type != NL80211_IFTYPE_AP) { | ||
167 | sdata->vif.cab_queue = IEEE80211_INVAL_HW_QUEUE; | ||
168 | return 0; | ||
169 | } | ||
170 | |||
171 | if (WARN_ON_ONCE(sdata->vif.cab_queue == IEEE80211_INVAL_HW_QUEUE)) | ||
172 | return -EINVAL; | ||
173 | |||
174 | if (WARN_ON_ONCE(sdata->vif.cab_queue >= n_queues)) | ||
175 | return -EINVAL; | ||
176 | |||
177 | return 0; | ||
178 | } | ||
179 | |||
152 | void ieee80211_adjust_monitor_flags(struct ieee80211_sub_if_data *sdata, | 180 | void ieee80211_adjust_monitor_flags(struct ieee80211_sub_if_data *sdata, |
153 | const int offset) | 181 | const int offset) |
154 | { | 182 | { |
@@ -169,6 +197,81 @@ void ieee80211_adjust_monitor_flags(struct ieee80211_sub_if_data *sdata, | |||
169 | #undef ADJUST | 197 | #undef ADJUST |
170 | } | 198 | } |
171 | 199 | ||
200 | static void ieee80211_set_default_queues(struct ieee80211_sub_if_data *sdata) | ||
201 | { | ||
202 | struct ieee80211_local *local = sdata->local; | ||
203 | int i; | ||
204 | |||
205 | for (i = 0; i < IEEE80211_NUM_ACS; i++) { | ||
206 | if (local->hw.flags & IEEE80211_HW_QUEUE_CONTROL) | ||
207 | sdata->vif.hw_queue[i] = IEEE80211_INVAL_HW_QUEUE; | ||
208 | else | ||
209 | sdata->vif.hw_queue[i] = i; | ||
210 | } | ||
211 | sdata->vif.cab_queue = IEEE80211_INVAL_HW_QUEUE; | ||
212 | } | ||
213 | |||
214 | static int ieee80211_add_virtual_monitor(struct ieee80211_local *local) | ||
215 | { | ||
216 | struct ieee80211_sub_if_data *sdata; | ||
217 | int ret; | ||
218 | |||
219 | if (!(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF)) | ||
220 | return 0; | ||
221 | |||
222 | if (local->monitor_sdata) | ||
223 | return 0; | ||
224 | |||
225 | sdata = kzalloc(sizeof(*sdata) + local->hw.vif_data_size, GFP_KERNEL); | ||
226 | if (!sdata) | ||
227 | return -ENOMEM; | ||
228 | |||
229 | /* set up data */ | ||
230 | sdata->local = local; | ||
231 | sdata->vif.type = NL80211_IFTYPE_MONITOR; | ||
232 | snprintf(sdata->name, IFNAMSIZ, "%s-monitor", | ||
233 | wiphy_name(local->hw.wiphy)); | ||
234 | |||
235 | ieee80211_set_default_queues(sdata); | ||
236 | |||
237 | ret = drv_add_interface(local, sdata); | ||
238 | if (WARN_ON(ret)) { | ||
239 | /* ok .. stupid driver, it asked for this! */ | ||
240 | kfree(sdata); | ||
241 | return ret; | ||
242 | } | ||
243 | |||
244 | ret = ieee80211_check_queues(sdata); | ||
245 | if (ret) { | ||
246 | kfree(sdata); | ||
247 | return ret; | ||
248 | } | ||
249 | |||
250 | rcu_assign_pointer(local->monitor_sdata, sdata); | ||
251 | |||
252 | return 0; | ||
253 | } | ||
254 | |||
255 | static void ieee80211_del_virtual_monitor(struct ieee80211_local *local) | ||
256 | { | ||
257 | struct ieee80211_sub_if_data *sdata; | ||
258 | |||
259 | if (!(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF)) | ||
260 | return; | ||
261 | |||
262 | sdata = rtnl_dereference(local->monitor_sdata); | ||
263 | |||
264 | if (!sdata) | ||
265 | return; | ||
266 | |||
267 | rcu_assign_pointer(local->monitor_sdata, NULL); | ||
268 | synchronize_net(); | ||
269 | |||
270 | drv_remove_interface(local, sdata); | ||
271 | |||
272 | kfree(sdata); | ||
273 | } | ||
274 | |||
172 | /* | 275 | /* |
173 | * NOTE: Be very careful when changing this function, it must NOT return | 276 | * NOTE: Be very careful when changing this function, it must NOT return |
174 | * an error on interface type changes that have been pre-checked, so most | 277 | * an error on interface type changes that have been pre-checked, so most |
@@ -246,15 +349,18 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up) | |||
246 | memcpy(dev->perm_addr, dev->dev_addr, ETH_ALEN); | 349 | memcpy(dev->perm_addr, dev->dev_addr, ETH_ALEN); |
247 | 350 | ||
248 | if (!is_valid_ether_addr(dev->dev_addr)) { | 351 | if (!is_valid_ether_addr(dev->dev_addr)) { |
249 | if (!local->open_count) | 352 | res = -EADDRNOTAVAIL; |
250 | drv_stop(local); | 353 | goto err_stop; |
251 | return -EADDRNOTAVAIL; | ||
252 | } | 354 | } |
253 | } | 355 | } |
254 | 356 | ||
255 | switch (sdata->vif.type) { | 357 | switch (sdata->vif.type) { |
256 | case NL80211_IFTYPE_AP_VLAN: | 358 | case NL80211_IFTYPE_AP_VLAN: |
257 | /* no need to tell driver */ | 359 | /* no need to tell driver, but set carrier */ |
360 | if (rtnl_dereference(sdata->bss->beacon)) | ||
361 | netif_carrier_on(dev); | ||
362 | else | ||
363 | netif_carrier_off(dev); | ||
258 | break; | 364 | break; |
259 | case NL80211_IFTYPE_MONITOR: | 365 | case NL80211_IFTYPE_MONITOR: |
260 | if (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) { | 366 | if (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) { |
@@ -262,6 +368,12 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up) | |||
262 | break; | 368 | break; |
263 | } | 369 | } |
264 | 370 | ||
371 | if (local->monitors == 0 && local->open_count == 0) { | ||
372 | res = ieee80211_add_virtual_monitor(local); | ||
373 | if (res) | ||
374 | goto err_stop; | ||
375 | } | ||
376 | |||
265 | /* must be before the call to ieee80211_configure_filter */ | 377 | /* must be before the call to ieee80211_configure_filter */ |
266 | local->monitors++; | 378 | local->monitors++; |
267 | if (local->monitors == 1) { | 379 | if (local->monitors == 1) { |
@@ -276,9 +388,14 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up) | |||
276 | break; | 388 | break; |
277 | default: | 389 | default: |
278 | if (coming_up) { | 390 | if (coming_up) { |
391 | ieee80211_del_virtual_monitor(local); | ||
392 | |||
279 | res = drv_add_interface(local, sdata); | 393 | res = drv_add_interface(local, sdata); |
280 | if (res) | 394 | if (res) |
281 | goto err_stop; | 395 | goto err_stop; |
396 | res = ieee80211_check_queues(sdata); | ||
397 | if (res) | ||
398 | goto err_del_interface; | ||
282 | } | 399 | } |
283 | 400 | ||
284 | if (sdata->vif.type == NL80211_IFTYPE_AP) { | 401 | if (sdata->vif.type == NL80211_IFTYPE_AP) { |
@@ -294,7 +411,8 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up) | |||
294 | ieee80211_bss_info_change_notify(sdata, changed); | 411 | ieee80211_bss_info_change_notify(sdata, changed); |
295 | 412 | ||
296 | if (sdata->vif.type == NL80211_IFTYPE_STATION || | 413 | if (sdata->vif.type == NL80211_IFTYPE_STATION || |
297 | sdata->vif.type == NL80211_IFTYPE_ADHOC) | 414 | sdata->vif.type == NL80211_IFTYPE_ADHOC || |
415 | sdata->vif.type == NL80211_IFTYPE_AP) | ||
298 | netif_carrier_off(dev); | 416 | netif_carrier_off(dev); |
299 | else | 417 | else |
300 | netif_carrier_on(dev); | 418 | netif_carrier_on(dev); |
@@ -366,6 +484,7 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up) | |||
366 | sdata->bss = NULL; | 484 | sdata->bss = NULL; |
367 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 485 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
368 | list_del(&sdata->u.vlan.list); | 486 | list_del(&sdata->u.vlan.list); |
487 | /* might already be clear but that doesn't matter */ | ||
369 | clear_bit(SDATA_STATE_RUNNING, &sdata->state); | 488 | clear_bit(SDATA_STATE_RUNNING, &sdata->state); |
370 | return res; | 489 | return res; |
371 | } | 490 | } |
@@ -506,6 +625,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
506 | if (local->monitors == 0) { | 625 | if (local->monitors == 0) { |
507 | local->hw.conf.flags &= ~IEEE80211_CONF_MONITOR; | 626 | local->hw.conf.flags &= ~IEEE80211_CONF_MONITOR; |
508 | hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR; | 627 | hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR; |
628 | ieee80211_del_virtual_monitor(local); | ||
509 | } | 629 | } |
510 | 630 | ||
511 | ieee80211_adjust_monitor_flags(sdata, -1); | 631 | ieee80211_adjust_monitor_flags(sdata, -1); |
@@ -579,6 +699,9 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
579 | } | 699 | } |
580 | } | 700 | } |
581 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | 701 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); |
702 | |||
703 | if (local->monitors == local->open_count && local->monitors > 0) | ||
704 | ieee80211_add_virtual_monitor(local); | ||
582 | } | 705 | } |
583 | 706 | ||
584 | static int ieee80211_stop(struct net_device *dev) | 707 | static int ieee80211_stop(struct net_device *dev) |
@@ -676,7 +799,7 @@ static u16 ieee80211_monitor_select_queue(struct net_device *dev, | |||
676 | struct ieee80211_hdr *hdr; | 799 | struct ieee80211_hdr *hdr; |
677 | struct ieee80211_radiotap_header *rtap = (void *)skb->data; | 800 | struct ieee80211_radiotap_header *rtap = (void *)skb->data; |
678 | 801 | ||
679 | if (local->hw.queues < 4) | 802 | if (local->hw.queues < IEEE80211_NUM_ACS) |
680 | return 0; | 803 | return 0; |
681 | 804 | ||
682 | if (skb->len < 4 || | 805 | if (skb->len < 4 || |
@@ -970,6 +1093,13 @@ static int ieee80211_runtime_change_iftype(struct ieee80211_sub_if_data *sdata, | |||
970 | if (ret) | 1093 | if (ret) |
971 | type = sdata->vif.type; | 1094 | type = sdata->vif.type; |
972 | 1095 | ||
1096 | /* | ||
1097 | * Ignore return value here, there's not much we can do since | ||
1098 | * the driver changed the interface type internally already. | ||
1099 | * The warnings will hopefully make driver authors fix it :-) | ||
1100 | */ | ||
1101 | ieee80211_check_queues(sdata); | ||
1102 | |||
973 | ieee80211_setup_sdata(sdata, type); | 1103 | ieee80211_setup_sdata(sdata, type); |
974 | 1104 | ||
975 | err = ieee80211_do_open(sdata->dev, false); | 1105 | err = ieee80211_do_open(sdata->dev, false); |
@@ -1133,11 +1263,15 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, | |||
1133 | struct net_device *ndev; | 1263 | struct net_device *ndev; |
1134 | struct ieee80211_sub_if_data *sdata = NULL; | 1264 | struct ieee80211_sub_if_data *sdata = NULL; |
1135 | int ret, i; | 1265 | int ret, i; |
1266 | int txqs = 1; | ||
1136 | 1267 | ||
1137 | ASSERT_RTNL(); | 1268 | ASSERT_RTNL(); |
1138 | 1269 | ||
1270 | if (local->hw.queues >= IEEE80211_NUM_ACS) | ||
1271 | txqs = IEEE80211_NUM_ACS; | ||
1272 | |||
1139 | ndev = alloc_netdev_mqs(sizeof(*sdata) + local->hw.vif_data_size, | 1273 | ndev = alloc_netdev_mqs(sizeof(*sdata) + local->hw.vif_data_size, |
1140 | name, ieee80211_if_setup, local->hw.queues, 1); | 1274 | name, ieee80211_if_setup, txqs, 1); |
1141 | if (!ndev) | 1275 | if (!ndev) |
1142 | return -ENOMEM; | 1276 | return -ENOMEM; |
1143 | dev_net_set(ndev, wiphy_net(local->hw.wiphy)); | 1277 | dev_net_set(ndev, wiphy_net(local->hw.wiphy)); |
@@ -1192,6 +1326,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, | |||
1192 | sizeof(sdata->rc_rateidx_mcs_mask[i])); | 1326 | sizeof(sdata->rc_rateidx_mcs_mask[i])); |
1193 | } | 1327 | } |
1194 | 1328 | ||
1329 | ieee80211_set_default_queues(sdata); | ||
1330 | |||
1195 | /* setup type-dependent data */ | 1331 | /* setup type-dependent data */ |
1196 | ieee80211_setup_sdata(sdata, type); | 1332 | ieee80211_setup_sdata(sdata, type); |
1197 | 1333 | ||
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 16336480c631..ac79d5e8e0d0 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -557,8 +557,10 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
557 | WIPHY_FLAG_4ADDR_AP | | 557 | WIPHY_FLAG_4ADDR_AP | |
558 | WIPHY_FLAG_4ADDR_STATION | | 558 | WIPHY_FLAG_4ADDR_STATION | |
559 | WIPHY_FLAG_REPORTS_OBSS | | 559 | WIPHY_FLAG_REPORTS_OBSS | |
560 | WIPHY_FLAG_OFFCHAN_TX | | 560 | WIPHY_FLAG_OFFCHAN_TX; |
561 | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; | 561 | |
562 | if (ops->remain_on_channel) | ||
563 | wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; | ||
562 | 564 | ||
563 | wiphy->features = NL80211_FEATURE_SK_TX_STATUS | | 565 | wiphy->features = NL80211_FEATURE_SK_TX_STATUS | |
564 | NL80211_FEATURE_HT_IBSS; | 566 | NL80211_FEATURE_HT_IBSS; |
@@ -589,6 +591,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
589 | local->hw.max_report_rates = 0; | 591 | local->hw.max_report_rates = 0; |
590 | local->hw.max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF; | 592 | local->hw.max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF; |
591 | local->hw.max_tx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF; | 593 | local->hw.max_tx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF; |
594 | local->hw.offchannel_tx_hw_queue = IEEE80211_INVAL_HW_QUEUE; | ||
592 | local->hw.conf.long_frame_max_tx_count = wiphy->retry_long; | 595 | local->hw.conf.long_frame_max_tx_count = wiphy->retry_long; |
593 | local->hw.conf.short_frame_max_tx_count = wiphy->retry_short; | 596 | local->hw.conf.short_frame_max_tx_count = wiphy->retry_short; |
594 | local->user_power_level = -1; | 597 | local->user_power_level = -1; |
@@ -685,6 +688,11 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
685 | WLAN_CIPHER_SUITE_AES_CMAC | 688 | WLAN_CIPHER_SUITE_AES_CMAC |
686 | }; | 689 | }; |
687 | 690 | ||
691 | if (hw->flags & IEEE80211_HW_QUEUE_CONTROL && | ||
692 | (local->hw.offchannel_tx_hw_queue == IEEE80211_INVAL_HW_QUEUE || | ||
693 | local->hw.offchannel_tx_hw_queue >= local->hw.queues)) | ||
694 | return -EINVAL; | ||
695 | |||
688 | if ((hw->wiphy->wowlan.flags || hw->wiphy->wowlan.n_patterns) | 696 | if ((hw->wiphy->wowlan.flags || hw->wiphy->wowlan.n_patterns) |
689 | #ifdef CONFIG_PM | 697 | #ifdef CONFIG_PM |
690 | && (!local->ops->suspend || !local->ops->resume) | 698 | && (!local->ops->suspend || !local->ops->resume) |
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index e5fbb7cf3562..133c118526fb 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c | |||
@@ -13,9 +13,6 @@ | |||
13 | #include "ieee80211_i.h" | 13 | #include "ieee80211_i.h" |
14 | #include "mesh.h" | 14 | #include "mesh.h" |
15 | 15 | ||
16 | #define MESHCONF_CAPAB_ACCEPT_PLINKS 0x01 | ||
17 | #define MESHCONF_CAPAB_FORWARDING 0x08 | ||
18 | |||
19 | #define TMR_RUNNING_HK 0 | 16 | #define TMR_RUNNING_HK 0 |
20 | #define TMR_RUNNING_MP 1 | 17 | #define TMR_RUNNING_MP 1 |
21 | #define TMR_RUNNING_MPR 2 | 18 | #define TMR_RUNNING_MPR 2 |
@@ -69,11 +66,13 @@ static void ieee80211_mesh_housekeeping_timer(unsigned long data) | |||
69 | * | 66 | * |
70 | * @ie: information elements of a management frame from the mesh peer | 67 | * @ie: information elements of a management frame from the mesh peer |
71 | * @sdata: local mesh subif | 68 | * @sdata: local mesh subif |
69 | * @basic_rates: BSSBasicRateSet of the peer candidate | ||
72 | * | 70 | * |
73 | * This function checks if the mesh configuration of a mesh point matches the | 71 | * This function checks if the mesh configuration of a mesh point matches the |
74 | * local mesh configuration, i.e. if both nodes belong to the same mesh network. | 72 | * local mesh configuration, i.e. if both nodes belong to the same mesh network. |
75 | */ | 73 | */ |
76 | bool mesh_matches_local(struct ieee802_11_elems *ie, struct ieee80211_sub_if_data *sdata) | 74 | bool mesh_matches_local(struct ieee802_11_elems *ie, |
75 | struct ieee80211_sub_if_data *sdata, u32 basic_rates) | ||
77 | { | 76 | { |
78 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 77 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
79 | struct ieee80211_local *local = sdata->local; | 78 | struct ieee80211_local *local = sdata->local; |
@@ -97,10 +96,13 @@ bool mesh_matches_local(struct ieee802_11_elems *ie, struct ieee80211_sub_if_dat | |||
97 | (ifmsh->mesh_auth_id == ie->mesh_config->meshconf_auth))) | 96 | (ifmsh->mesh_auth_id == ie->mesh_config->meshconf_auth))) |
98 | goto mismatch; | 97 | goto mismatch; |
99 | 98 | ||
99 | if (sdata->vif.bss_conf.basic_rates != basic_rates) | ||
100 | goto mismatch; | ||
101 | |||
100 | /* disallow peering with mismatched channel types for now */ | 102 | /* disallow peering with mismatched channel types for now */ |
101 | if (ie->ht_info_elem && | 103 | if (ie->ht_operation && |
102 | (local->_oper_channel_type != | 104 | (local->_oper_channel_type != |
103 | ieee80211_ht_info_to_channel_type(ie->ht_info_elem))) | 105 | ieee80211_ht_oper_to_channel_type(ie->ht_operation))) |
104 | goto mismatch; | 106 | goto mismatch; |
105 | 107 | ||
106 | return true; | 108 | return true; |
@@ -251,8 +253,10 @@ mesh_add_meshconf_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) | |||
251 | /* Mesh capability */ | 253 | /* Mesh capability */ |
252 | ifmsh->accepting_plinks = mesh_plink_availables(sdata); | 254 | ifmsh->accepting_plinks = mesh_plink_availables(sdata); |
253 | *pos = MESHCONF_CAPAB_FORWARDING; | 255 | *pos = MESHCONF_CAPAB_FORWARDING; |
254 | *pos++ |= ifmsh->accepting_plinks ? | 256 | *pos |= ifmsh->accepting_plinks ? |
255 | MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00; | 257 | MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00; |
258 | *pos++ |= ifmsh->adjusting_tbtt ? | ||
259 | MESHCONF_CAPAB_TBTT_ADJUSTING : 0x00; | ||
256 | *pos++ = 0x00; | 260 | *pos++ = 0x00; |
257 | 261 | ||
258 | return 0; | 262 | return 0; |
@@ -371,7 +375,7 @@ int mesh_add_ht_cap_ie(struct sk_buff *skb, | |||
371 | return 0; | 375 | return 0; |
372 | } | 376 | } |
373 | 377 | ||
374 | int mesh_add_ht_info_ie(struct sk_buff *skb, | 378 | int mesh_add_ht_oper_ie(struct sk_buff *skb, |
375 | struct ieee80211_sub_if_data *sdata) | 379 | struct ieee80211_sub_if_data *sdata) |
376 | { | 380 | { |
377 | struct ieee80211_local *local = sdata->local; | 381 | struct ieee80211_local *local = sdata->local; |
@@ -385,11 +389,11 @@ int mesh_add_ht_info_ie(struct sk_buff *skb, | |||
385 | if (!ht_cap->ht_supported || channel_type == NL80211_CHAN_NO_HT) | 389 | if (!ht_cap->ht_supported || channel_type == NL80211_CHAN_NO_HT) |
386 | return 0; | 390 | return 0; |
387 | 391 | ||
388 | if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_ht_info)) | 392 | if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_ht_operation)) |
389 | return -ENOMEM; | 393 | return -ENOMEM; |
390 | 394 | ||
391 | pos = skb_put(skb, 2 + sizeof(struct ieee80211_ht_info)); | 395 | pos = skb_put(skb, 2 + sizeof(struct ieee80211_ht_operation)); |
392 | ieee80211_ie_build_ht_info(pos, ht_cap, channel, channel_type); | 396 | ieee80211_ie_build_ht_oper(pos, ht_cap, channel, channel_type); |
393 | 397 | ||
394 | return 0; | 398 | return 0; |
395 | } | 399 | } |
@@ -573,14 +577,21 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) | |||
573 | ieee80211_configure_filter(local); | 577 | ieee80211_configure_filter(local); |
574 | 578 | ||
575 | ifmsh->mesh_cc_id = 0; /* Disabled */ | 579 | ifmsh->mesh_cc_id = 0; /* Disabled */ |
576 | ifmsh->mesh_sp_id = 0; /* Neighbor Offset */ | ||
577 | ifmsh->mesh_auth_id = 0; /* Disabled */ | 580 | ifmsh->mesh_auth_id = 0; /* Disabled */ |
581 | /* register sync ops from extensible synchronization framework */ | ||
582 | ifmsh->sync_ops = ieee80211_mesh_sync_ops_get(ifmsh->mesh_sp_id); | ||
583 | ifmsh->adjusting_tbtt = false; | ||
584 | ifmsh->sync_offset_clockdrift_max = 0; | ||
578 | set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags); | 585 | set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags); |
579 | ieee80211_mesh_root_setup(ifmsh); | 586 | ieee80211_mesh_root_setup(ifmsh); |
580 | ieee80211_queue_work(&local->hw, &sdata->work); | 587 | ieee80211_queue_work(&local->hw, &sdata->work); |
581 | sdata->vif.bss_conf.beacon_int = MESH_DEFAULT_BEACON_INTERVAL; | 588 | sdata->vif.bss_conf.beacon_int = MESH_DEFAULT_BEACON_INTERVAL; |
589 | sdata->vif.bss_conf.basic_rates = | ||
590 | ieee80211_mandatory_rates(sdata->local, | ||
591 | sdata->local->hw.conf.channel->band); | ||
582 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON | | 592 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON | |
583 | BSS_CHANGED_BEACON_ENABLED | | 593 | BSS_CHANGED_BEACON_ENABLED | |
594 | BSS_CHANGED_BASIC_RATES | | ||
584 | BSS_CHANGED_BEACON_INT); | 595 | BSS_CHANGED_BEACON_INT); |
585 | } | 596 | } |
586 | 597 | ||
@@ -616,9 +627,10 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, | |||
616 | struct ieee80211_rx_status *rx_status) | 627 | struct ieee80211_rx_status *rx_status) |
617 | { | 628 | { |
618 | struct ieee80211_local *local = sdata->local; | 629 | struct ieee80211_local *local = sdata->local; |
630 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||
619 | struct ieee802_11_elems elems; | 631 | struct ieee802_11_elems elems; |
620 | struct ieee80211_channel *channel; | 632 | struct ieee80211_channel *channel; |
621 | u32 supp_rates = 0; | 633 | u32 supp_rates = 0, basic_rates = 0; |
622 | size_t baselen; | 634 | size_t baselen; |
623 | int freq; | 635 | int freq; |
624 | enum ieee80211_band band = rx_status->band; | 636 | enum ieee80211_band band = rx_status->band; |
@@ -649,11 +661,16 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, | |||
649 | if (!channel || channel->flags & IEEE80211_CHAN_DISABLED) | 661 | if (!channel || channel->flags & IEEE80211_CHAN_DISABLED) |
650 | return; | 662 | return; |
651 | 663 | ||
664 | supp_rates = ieee80211_sta_get_rates(local, &elems, | ||
665 | band, &basic_rates); | ||
666 | |||
652 | if (elems.mesh_id && elems.mesh_config && | 667 | if (elems.mesh_id && elems.mesh_config && |
653 | mesh_matches_local(&elems, sdata)) { | 668 | mesh_matches_local(&elems, sdata, basic_rates)) |
654 | supp_rates = ieee80211_sta_get_rates(local, &elems, band); | ||
655 | mesh_neighbour_update(mgmt->sa, supp_rates, sdata, &elems); | 669 | mesh_neighbour_update(mgmt->sa, supp_rates, sdata, &elems); |
656 | } | 670 | |
671 | if (ifmsh->sync_ops) | ||
672 | ifmsh->sync_ops->rx_bcn_presp(sdata, | ||
673 | stype, mgmt, &elems, rx_status); | ||
657 | } | 674 | } |
658 | 675 | ||
659 | static void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata, | 676 | static void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata, |
@@ -721,6 +738,9 @@ void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata) | |||
721 | 738 | ||
722 | if (test_and_clear_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags)) | 739 | if (test_and_clear_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags)) |
723 | ieee80211_mesh_rootpath(sdata); | 740 | ieee80211_mesh_rootpath(sdata); |
741 | |||
742 | if (test_and_clear_bit(MESH_WORK_DRIFT_ADJUST, &ifmsh->wrkq_flags)) | ||
743 | mesh_sync_adjust_tbtt(sdata); | ||
724 | } | 744 | } |
725 | 745 | ||
726 | void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local) | 746 | void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local) |
@@ -761,4 +781,5 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata) | |||
761 | (unsigned long) sdata); | 781 | (unsigned long) sdata); |
762 | INIT_LIST_HEAD(&ifmsh->preq_queue.list); | 782 | INIT_LIST_HEAD(&ifmsh->preq_queue.list); |
763 | spin_lock_init(&ifmsh->mesh_preq_queue_lock); | 783 | spin_lock_init(&ifmsh->mesh_preq_queue_lock); |
784 | spin_lock_init(&ifmsh->sync_offset_lock); | ||
764 | } | 785 | } |
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index 8d53b71378e3..4ad738988801 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h | |||
@@ -19,6 +19,20 @@ | |||
19 | /* Data structures */ | 19 | /* Data structures */ |
20 | 20 | ||
21 | /** | 21 | /** |
22 | * enum mesh_config_capab_flags - mesh config IE capability flags | ||
23 | * | ||
24 | * @MESHCONF_CAPAB_ACCEPT_PLINKS: STA is willing to establish | ||
25 | * additional mesh peerings with other mesh STAs | ||
26 | * @MESHCONF_CAPAB_FORWARDING: the STA forwards MSDUs | ||
27 | * @MESHCONF_CAPAB_TBTT_ADJUSTING: TBTT adjustment procedure is ongoing | ||
28 | */ | ||
29 | enum mesh_config_capab_flags { | ||
30 | MESHCONF_CAPAB_ACCEPT_PLINKS = BIT(0), | ||
31 | MESHCONF_CAPAB_FORWARDING = BIT(3), | ||
32 | MESHCONF_CAPAB_TBTT_ADJUSTING = BIT(5), | ||
33 | }; | ||
34 | |||
35 | /** | ||
22 | * enum mesh_path_flags - mac80211 mesh path flags | 36 | * enum mesh_path_flags - mac80211 mesh path flags |
23 | * | 37 | * |
24 | * | 38 | * |
@@ -56,12 +70,15 @@ enum mesh_path_flags { | |||
56 | * @MESH_WORK_GROW_MPP_TABLE: the mesh portals table is full and needs to | 70 | * @MESH_WORK_GROW_MPP_TABLE: the mesh portals table is full and needs to |
57 | * grow | 71 | * grow |
58 | * @MESH_WORK_ROOT: the mesh root station needs to send a frame | 72 | * @MESH_WORK_ROOT: the mesh root station needs to send a frame |
73 | * @MESH_WORK_DRIFT_ADJUST: time to compensate for clock drift relative to other | ||
74 | * mesh nodes | ||
59 | */ | 75 | */ |
60 | enum mesh_deferred_task_flags { | 76 | enum mesh_deferred_task_flags { |
61 | MESH_WORK_HOUSEKEEPING, | 77 | MESH_WORK_HOUSEKEEPING, |
62 | MESH_WORK_GROW_MPATH_TABLE, | 78 | MESH_WORK_GROW_MPATH_TABLE, |
63 | MESH_WORK_GROW_MPP_TABLE, | 79 | MESH_WORK_GROW_MPP_TABLE, |
64 | MESH_WORK_ROOT, | 80 | MESH_WORK_ROOT, |
81 | MESH_WORK_DRIFT_ADJUST, | ||
65 | }; | 82 | }; |
66 | 83 | ||
67 | /** | 84 | /** |
@@ -86,6 +103,7 @@ enum mesh_deferred_task_flags { | |||
86 | * mpath itself. No need to take this lock when adding or removing | 103 | * mpath itself. No need to take this lock when adding or removing |
87 | * an mpath to a hash bucket on a path table. | 104 | * an mpath to a hash bucket on a path table. |
88 | * @rann_snd_addr: the RANN sender address | 105 | * @rann_snd_addr: the RANN sender address |
106 | * @rann_metric: the aggregated path metric towards the root node | ||
89 | * @is_root: the destination station of this path is a root node | 107 | * @is_root: the destination station of this path is a root node |
90 | * @is_gate: the destination station of this path is a mesh gate | 108 | * @is_gate: the destination station of this path is a mesh gate |
91 | * | 109 | * |
@@ -112,6 +130,7 @@ struct mesh_path { | |||
112 | enum mesh_path_flags flags; | 130 | enum mesh_path_flags flags; |
113 | spinlock_t state_lock; | 131 | spinlock_t state_lock; |
114 | u8 rann_snd_addr[ETH_ALEN]; | 132 | u8 rann_snd_addr[ETH_ALEN]; |
133 | u32 rann_metric; | ||
115 | bool is_root; | 134 | bool is_root; |
116 | bool is_gate; | 135 | bool is_gate; |
117 | }; | 136 | }; |
@@ -204,7 +223,7 @@ int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr, | |||
204 | int mesh_rmc_check(u8 *addr, struct ieee80211s_hdr *mesh_hdr, | 223 | int mesh_rmc_check(u8 *addr, struct ieee80211s_hdr *mesh_hdr, |
205 | struct ieee80211_sub_if_data *sdata); | 224 | struct ieee80211_sub_if_data *sdata); |
206 | bool mesh_matches_local(struct ieee802_11_elems *ie, | 225 | bool mesh_matches_local(struct ieee802_11_elems *ie, |
207 | struct ieee80211_sub_if_data *sdata); | 226 | struct ieee80211_sub_if_data *sdata, u32 basic_rates); |
208 | void mesh_ids_set_default(struct ieee80211_if_mesh *mesh); | 227 | void mesh_ids_set_default(struct ieee80211_if_mesh *mesh); |
209 | void mesh_mgmt_ies_add(struct sk_buff *skb, | 228 | void mesh_mgmt_ies_add(struct sk_buff *skb, |
210 | struct ieee80211_sub_if_data *sdata); | 229 | struct ieee80211_sub_if_data *sdata); |
@@ -220,7 +239,7 @@ int mesh_add_ds_params_ie(struct sk_buff *skb, | |||
220 | struct ieee80211_sub_if_data *sdata); | 239 | struct ieee80211_sub_if_data *sdata); |
221 | int mesh_add_ht_cap_ie(struct sk_buff *skb, | 240 | int mesh_add_ht_cap_ie(struct sk_buff *skb, |
222 | struct ieee80211_sub_if_data *sdata); | 241 | struct ieee80211_sub_if_data *sdata); |
223 | int mesh_add_ht_info_ie(struct sk_buff *skb, | 242 | int mesh_add_ht_oper_ie(struct sk_buff *skb, |
224 | struct ieee80211_sub_if_data *sdata); | 243 | struct ieee80211_sub_if_data *sdata); |
225 | void mesh_rmc_free(struct ieee80211_sub_if_data *sdata); | 244 | void mesh_rmc_free(struct ieee80211_sub_if_data *sdata); |
226 | int mesh_rmc_init(struct ieee80211_sub_if_data *sdata); | 245 | int mesh_rmc_init(struct ieee80211_sub_if_data *sdata); |
@@ -232,6 +251,7 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata); | |||
232 | void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata); | 251 | void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata); |
233 | void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata); | 252 | void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata); |
234 | void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh); | 253 | void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh); |
254 | struct ieee80211_mesh_sync_ops *ieee80211_mesh_sync_ops_get(u8 method); | ||
235 | 255 | ||
236 | /* Mesh paths */ | 256 | /* Mesh paths */ |
237 | int mesh_nexthop_lookup(struct sk_buff *skb, | 257 | int mesh_nexthop_lookup(struct sk_buff *skb, |
@@ -325,6 +345,7 @@ void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata); | |||
325 | void ieee80211_mesh_restart(struct ieee80211_sub_if_data *sdata); | 345 | void ieee80211_mesh_restart(struct ieee80211_sub_if_data *sdata); |
326 | void mesh_plink_quiesce(struct sta_info *sta); | 346 | void mesh_plink_quiesce(struct sta_info *sta); |
327 | void mesh_plink_restart(struct sta_info *sta); | 347 | void mesh_plink_restart(struct sta_info *sta); |
348 | void mesh_sync_adjust_tbtt(struct ieee80211_sub_if_data *sdata); | ||
328 | #else | 349 | #else |
329 | #define mesh_allocated 0 | 350 | #define mesh_allocated 0 |
330 | static inline void | 351 | static inline void |
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 1c6f3d02aebf..a80da3784a25 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c | |||
@@ -86,8 +86,8 @@ static inline u32 u16_field_get(u8 *preq_elem, int offset, bool ae) | |||
86 | #define PERR_IE_TARGET_RCODE(x) u16_field_get(x, 13, 0) | 86 | #define PERR_IE_TARGET_RCODE(x) u16_field_get(x, 13, 0) |
87 | 87 | ||
88 | #define MSEC_TO_TU(x) (x*1000/1024) | 88 | #define MSEC_TO_TU(x) (x*1000/1024) |
89 | #define SN_GT(x, y) ((long) (y) - (long) (x) < 0) | 89 | #define SN_GT(x, y) ((s32)(y - x) < 0) |
90 | #define SN_LT(x, y) ((long) (x) - (long) (y) < 0) | 90 | #define SN_LT(x, y) ((s32)(x - y) < 0) |
91 | 91 | ||
92 | #define net_traversal_jiffies(s) \ | 92 | #define net_traversal_jiffies(s) \ |
93 | msecs_to_jiffies(s->u.mesh.mshcfg.dot11MeshHWMPnetDiameterTraversalTime) | 93 | msecs_to_jiffies(s->u.mesh.mshcfg.dot11MeshHWMPnetDiameterTraversalTime) |
@@ -732,11 +732,12 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata, | |||
732 | struct ieee80211_rann_ie *rann) | 732 | struct ieee80211_rann_ie *rann) |
733 | { | 733 | { |
734 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 734 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
735 | struct ieee80211_local *local = sdata->local; | ||
736 | struct sta_info *sta; | ||
735 | struct mesh_path *mpath; | 737 | struct mesh_path *mpath; |
736 | u8 ttl, flags, hopcount; | 738 | u8 ttl, flags, hopcount; |
737 | u8 *orig_addr; | 739 | u8 *orig_addr; |
738 | u32 orig_sn, metric; | 740 | u32 orig_sn, metric, metric_txsta, interval; |
739 | u32 interval = ifmsh->mshcfg.dot11MeshHWMPRannInterval; | ||
740 | bool root_is_gate; | 741 | bool root_is_gate; |
741 | 742 | ||
742 | ttl = rann->rann_ttl; | 743 | ttl = rann->rann_ttl; |
@@ -748,10 +749,11 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata, | |||
748 | flags = rann->rann_flags; | 749 | flags = rann->rann_flags; |
749 | root_is_gate = !!(flags & RANN_FLAG_IS_GATE); | 750 | root_is_gate = !!(flags & RANN_FLAG_IS_GATE); |
750 | orig_addr = rann->rann_addr; | 751 | orig_addr = rann->rann_addr; |
751 | orig_sn = rann->rann_seq; | 752 | orig_sn = le32_to_cpu(rann->rann_seq); |
753 | interval = le32_to_cpu(rann->rann_interval); | ||
752 | hopcount = rann->rann_hopcount; | 754 | hopcount = rann->rann_hopcount; |
753 | hopcount++; | 755 | hopcount++; |
754 | metric = rann->rann_metric; | 756 | metric = le32_to_cpu(rann->rann_metric); |
755 | 757 | ||
756 | /* Ignore our own RANNs */ | 758 | /* Ignore our own RANNs */ |
757 | if (compare_ether_addr(orig_addr, sdata->vif.addr) == 0) | 759 | if (compare_ether_addr(orig_addr, sdata->vif.addr) == 0) |
@@ -761,6 +763,14 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata, | |||
761 | orig_addr, mgmt->sa, root_is_gate); | 763 | orig_addr, mgmt->sa, root_is_gate); |
762 | 764 | ||
763 | rcu_read_lock(); | 765 | rcu_read_lock(); |
766 | sta = sta_info_get(sdata, mgmt->sa); | ||
767 | if (!sta) { | ||
768 | rcu_read_unlock(); | ||
769 | return; | ||
770 | } | ||
771 | |||
772 | metric_txsta = airtime_link_metric_get(local, sta); | ||
773 | |||
764 | mpath = mesh_path_lookup(orig_addr, sdata); | 774 | mpath = mesh_path_lookup(orig_addr, sdata); |
765 | if (!mpath) { | 775 | if (!mpath) { |
766 | mesh_path_add(orig_addr, sdata); | 776 | mesh_path_add(orig_addr, sdata); |
@@ -780,14 +790,16 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata, | |||
780 | mesh_queue_preq(mpath, PREQ_Q_F_START | PREQ_Q_F_REFRESH); | 790 | mesh_queue_preq(mpath, PREQ_Q_F_START | PREQ_Q_F_REFRESH); |
781 | } | 791 | } |
782 | 792 | ||
783 | if (mpath->sn < orig_sn && ifmsh->mshcfg.dot11MeshForwarding) { | 793 | if ((SN_LT(mpath->sn, orig_sn) || (mpath->sn == orig_sn && |
794 | metric < mpath->rann_metric)) && ifmsh->mshcfg.dot11MeshForwarding) { | ||
784 | mesh_path_sel_frame_tx(MPATH_RANN, flags, orig_addr, | 795 | mesh_path_sel_frame_tx(MPATH_RANN, flags, orig_addr, |
785 | cpu_to_le32(orig_sn), | 796 | cpu_to_le32(orig_sn), |
786 | 0, NULL, 0, broadcast_addr, | 797 | 0, NULL, 0, broadcast_addr, |
787 | hopcount, ttl, cpu_to_le32(interval), | 798 | hopcount, ttl, cpu_to_le32(interval), |
788 | cpu_to_le32(metric + mpath->metric), | 799 | cpu_to_le32(metric + metric_txsta), |
789 | 0, sdata); | 800 | 0, sdata); |
790 | mpath->sn = orig_sn; | 801 | mpath->sn = orig_sn; |
802 | mpath->rann_metric = metric + metric_txsta; | ||
791 | } | 803 | } |
792 | 804 | ||
793 | /* Using individually addressed PREQ for root node */ | 805 | /* Using individually addressed PREQ for root node */ |
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 4e53c4cbca9e..9c836e774fbd 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c | |||
@@ -187,7 +187,7 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, | |||
187 | 2 + sdata->u.mesh.mesh_id_len + | 187 | 2 + sdata->u.mesh.mesh_id_len + |
188 | 2 + sizeof(struct ieee80211_meshconf_ie) + | 188 | 2 + sizeof(struct ieee80211_meshconf_ie) + |
189 | 2 + sizeof(struct ieee80211_ht_cap) + | 189 | 2 + sizeof(struct ieee80211_ht_cap) + |
190 | 2 + sizeof(struct ieee80211_ht_info) + | 190 | 2 + sizeof(struct ieee80211_ht_operation) + |
191 | 2 + 8 + /* peering IE */ | 191 | 2 + 8 + /* peering IE */ |
192 | sdata->u.mesh.ie_len); | 192 | sdata->u.mesh.ie_len); |
193 | if (!skb) | 193 | if (!skb) |
@@ -212,8 +212,8 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, | |||
212 | pos = skb_put(skb, 2); | 212 | pos = skb_put(skb, 2); |
213 | memcpy(pos + 2, &plid, 2); | 213 | memcpy(pos + 2, &plid, 2); |
214 | } | 214 | } |
215 | if (ieee80211_add_srates_ie(&sdata->vif, skb) || | 215 | if (ieee80211_add_srates_ie(&sdata->vif, skb, true) || |
216 | ieee80211_add_ext_srates_ie(&sdata->vif, skb) || | 216 | ieee80211_add_ext_srates_ie(&sdata->vif, skb, true) || |
217 | mesh_add_rsn_ie(skb, sdata) || | 217 | mesh_add_rsn_ie(skb, sdata) || |
218 | mesh_add_meshid_ie(skb, sdata) || | 218 | mesh_add_meshid_ie(skb, sdata) || |
219 | mesh_add_meshconf_ie(skb, sdata)) | 219 | mesh_add_meshconf_ie(skb, sdata)) |
@@ -263,7 +263,7 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, | |||
263 | 263 | ||
264 | if (action != WLAN_SP_MESH_PEERING_CLOSE) { | 264 | if (action != WLAN_SP_MESH_PEERING_CLOSE) { |
265 | if (mesh_add_ht_cap_ie(skb, sdata) || | 265 | if (mesh_add_ht_cap_ie(skb, sdata) || |
266 | mesh_add_ht_info_ie(skb, sdata)) | 266 | mesh_add_ht_oper_ie(skb, sdata)) |
267 | return -1; | 267 | return -1; |
268 | } | 268 | } |
269 | 269 | ||
@@ -465,6 +465,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
465 | bool deactivated, matches_local = true; | 465 | bool deactivated, matches_local = true; |
466 | u8 ie_len; | 466 | u8 ie_len; |
467 | u8 *baseaddr; | 467 | u8 *baseaddr; |
468 | u32 rates, basic_rates = 0; | ||
468 | __le16 plid, llid, reason; | 469 | __le16 plid, llid, reason; |
469 | #ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG | 470 | #ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG |
470 | static const char *mplstates[] = { | 471 | static const char *mplstates[] = { |
@@ -559,8 +560,11 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
559 | 560 | ||
560 | /* Now we will figure out the appropriate event... */ | 561 | /* Now we will figure out the appropriate event... */ |
561 | event = PLINK_UNDEFINED; | 562 | event = PLINK_UNDEFINED; |
563 | rates = ieee80211_sta_get_rates(local, &elems, | ||
564 | rx_status->band, &basic_rates); | ||
565 | |||
562 | if (ftype != WLAN_SP_MESH_PEERING_CLOSE && | 566 | if (ftype != WLAN_SP_MESH_PEERING_CLOSE && |
563 | (!mesh_matches_local(&elems, sdata))) { | 567 | (!mesh_matches_local(&elems, sdata, basic_rates))) { |
564 | matches_local = false; | 568 | matches_local = false; |
565 | switch (ftype) { | 569 | switch (ftype) { |
566 | case WLAN_SP_MESH_PEERING_OPEN: | 570 | case WLAN_SP_MESH_PEERING_OPEN: |
@@ -583,7 +587,6 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
583 | return; | 587 | return; |
584 | } else if (!sta) { | 588 | } else if (!sta) { |
585 | /* ftype == WLAN_SP_MESH_PEERING_OPEN */ | 589 | /* ftype == WLAN_SP_MESH_PEERING_OPEN */ |
586 | u32 rates; | ||
587 | 590 | ||
588 | rcu_read_unlock(); | 591 | rcu_read_unlock(); |
589 | 592 | ||
@@ -591,8 +594,6 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
591 | mpl_dbg("Mesh plink error: no more free plinks\n"); | 594 | mpl_dbg("Mesh plink error: no more free plinks\n"); |
592 | return; | 595 | return; |
593 | } | 596 | } |
594 | |||
595 | rates = ieee80211_sta_get_rates(local, &elems, rx_status->band); | ||
596 | sta = mesh_plink_alloc(sdata, mgmt->sa, rates, &elems); | 597 | sta = mesh_plink_alloc(sdata, mgmt->sa, rates, &elems); |
597 | if (!sta) { | 598 | if (!sta) { |
598 | mpl_dbg("Mesh plink error: plink table full\n"); | 599 | mpl_dbg("Mesh plink error: plink table full\n"); |
diff --git a/net/mac80211/mesh_sync.c b/net/mac80211/mesh_sync.c new file mode 100644 index 000000000000..f78b0139856f --- /dev/null +++ b/net/mac80211/mesh_sync.c | |||
@@ -0,0 +1,296 @@ | |||
1 | /* | ||
2 | * Copyright 2011-2012, Pavel Zubarev <pavel.zubarev@gmail.com> | ||
3 | * Copyright 2011-2012, Marco Porsch <marco.porsch@s2005.tu-chemnitz.de> | ||
4 | * Copyright 2011-2012, cozybit Inc. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #include "ieee80211_i.h" | ||
12 | #include "mesh.h" | ||
13 | #include "driver-ops.h" | ||
14 | |||
15 | #ifdef CONFIG_MAC80211_VERBOSE_MESH_SYNC_DEBUG | ||
16 | #define msync_dbg(fmt, args...) \ | ||
17 | printk(KERN_DEBUG "Mesh sync (%s): " fmt "\n", sdata->name, ##args) | ||
18 | #else | ||
19 | #define msync_dbg(fmt, args...) do { (void)(0); } while (0) | ||
20 | #endif | ||
21 | |||
22 | /* This is not in the standard. It represents a tolerable tbtt drift below | ||
23 | * which we do no TSF adjustment. | ||
24 | */ | ||
25 | #define TBTT_MINIMUM_ADJUSTMENT 10 | ||
26 | |||
27 | struct sync_method { | ||
28 | u8 method; | ||
29 | struct ieee80211_mesh_sync_ops ops; | ||
30 | }; | ||
31 | |||
32 | /** | ||
33 | * mesh_peer_tbtt_adjusting - check if an mp is currently adjusting its TBTT | ||
34 | * | ||
35 | * @ie: information elements of a management frame from the mesh peer | ||
36 | */ | ||
37 | static bool mesh_peer_tbtt_adjusting(struct ieee802_11_elems *ie) | ||
38 | { | ||
39 | return (ie->mesh_config->meshconf_cap & | ||
40 | MESHCONF_CAPAB_TBTT_ADJUSTING) != 0; | ||
41 | } | ||
42 | |||
43 | void mesh_sync_adjust_tbtt(struct ieee80211_sub_if_data *sdata) | ||
44 | { | ||
45 | struct ieee80211_local *local = sdata->local; | ||
46 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||
47 | /* sdata->vif.bss_conf.beacon_int in 1024us units, 0.04% */ | ||
48 | u64 beacon_int_fraction = sdata->vif.bss_conf.beacon_int * 1024 / 2500; | ||
49 | u64 tsf; | ||
50 | u64 tsfdelta; | ||
51 | |||
52 | spin_lock_bh(&ifmsh->sync_offset_lock); | ||
53 | |||
54 | if (ifmsh->sync_offset_clockdrift_max < beacon_int_fraction) { | ||
55 | msync_dbg("TBTT : max clockdrift=%lld; adjusting", | ||
56 | (long long) ifmsh->sync_offset_clockdrift_max); | ||
57 | tsfdelta = -ifmsh->sync_offset_clockdrift_max; | ||
58 | ifmsh->sync_offset_clockdrift_max = 0; | ||
59 | } else { | ||
60 | msync_dbg("TBTT : max clockdrift=%lld; adjusting by %llu", | ||
61 | (long long) ifmsh->sync_offset_clockdrift_max, | ||
62 | (unsigned long long) beacon_int_fraction); | ||
63 | tsfdelta = -beacon_int_fraction; | ||
64 | ifmsh->sync_offset_clockdrift_max -= beacon_int_fraction; | ||
65 | } | ||
66 | |||
67 | tsf = drv_get_tsf(local, sdata); | ||
68 | if (tsf != -1ULL) | ||
69 | drv_set_tsf(local, sdata, tsf + tsfdelta); | ||
70 | spin_unlock_bh(&ifmsh->sync_offset_lock); | ||
71 | } | ||
72 | |||
73 | static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, | ||
74 | u16 stype, | ||
75 | struct ieee80211_mgmt *mgmt, | ||
76 | struct ieee802_11_elems *elems, | ||
77 | struct ieee80211_rx_status *rx_status) | ||
78 | { | ||
79 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||
80 | struct ieee80211_local *local = sdata->local; | ||
81 | struct sta_info *sta; | ||
82 | u64 t_t, t_r; | ||
83 | |||
84 | WARN_ON(ifmsh->mesh_sp_id != IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET); | ||
85 | |||
86 | /* standard mentions only beacons */ | ||
87 | if (stype != IEEE80211_STYPE_BEACON) | ||
88 | return; | ||
89 | |||
90 | /* The current tsf is a first approximation for the timestamp | ||
91 | * for the received beacon. Further down we try to get a | ||
92 | * better value from the rx_status->mactime field if | ||
93 | * available. Also we have to call drv_get_tsf() before | ||
94 | * entering the rcu-read section.*/ | ||
95 | t_r = drv_get_tsf(local, sdata); | ||
96 | |||
97 | rcu_read_lock(); | ||
98 | sta = sta_info_get(sdata, mgmt->sa); | ||
99 | if (!sta) | ||
100 | goto no_sync; | ||
101 | |||
102 | /* check offset sync conditions (13.13.2.2.1) | ||
103 | * | ||
104 | * TODO also sync to | ||
105 | * dot11MeshNbrOffsetMaxNeighbor non-peer non-MBSS neighbors | ||
106 | */ | ||
107 | |||
108 | if (elems->mesh_config && mesh_peer_tbtt_adjusting(elems)) { | ||
109 | clear_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN); | ||
110 | msync_dbg("STA %pM : is adjusting TBTT", sta->sta.addr); | ||
111 | goto no_sync; | ||
112 | } | ||
113 | |||
114 | if (rx_status->flag & RX_FLAG_MACTIME_MPDU && rx_status->mactime) { | ||
115 | /* | ||
116 | * The mactime is defined as the time the first data symbol | ||
117 | * of the frame hits the PHY, and the timestamp of the beacon | ||
118 | * is defined as "the time that the data symbol containing the | ||
119 | * first bit of the timestamp is transmitted to the PHY plus | ||
120 | * the transmitting STA's delays through its local PHY from the | ||
121 | * MAC-PHY interface to its interface with the WM" (802.11 | ||
122 | * 11.1.2) | ||
123 | * | ||
124 | * T_r, in 13.13.2.2.2, is just defined as "the frame reception | ||
125 | * time" but we unless we interpret that time to be the same | ||
126 | * time of the beacon timestamp, the offset calculation will be | ||
127 | * off. Below we adjust t_r to be "the time at which the first | ||
128 | * symbol of the timestamp element in the beacon is received". | ||
129 | * This correction depends on the rate. | ||
130 | * | ||
131 | * Based on similar code in ibss.c | ||
132 | */ | ||
133 | int rate; | ||
134 | |||
135 | if (rx_status->flag & RX_FLAG_HT) { | ||
136 | /* TODO: | ||
137 | * In principle there could be HT-beacons (Dual Beacon | ||
138 | * HT Operation options), but for now ignore them and | ||
139 | * just use the primary (i.e. non-HT) beacons for | ||
140 | * synchronization. | ||
141 | * */ | ||
142 | goto no_sync; | ||
143 | } else | ||
144 | rate = local->hw.wiphy->bands[rx_status->band]-> | ||
145 | bitrates[rx_status->rate_idx].bitrate; | ||
146 | |||
147 | /* 24 bytes of header * 8 bits/byte * | ||
148 | * 10*(100 Kbps)/Mbps / rate (100 Kbps)*/ | ||
149 | t_r = rx_status->mactime + (24 * 8 * 10 / rate); | ||
150 | } | ||
151 | |||
152 | /* Timing offset calculation (see 13.13.2.2.2) */ | ||
153 | t_t = le64_to_cpu(mgmt->u.beacon.timestamp); | ||
154 | sta->t_offset = t_t - t_r; | ||
155 | |||
156 | if (test_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN)) { | ||
157 | s64 t_clockdrift = sta->t_offset_setpoint | ||
158 | - sta->t_offset; | ||
159 | |||
160 | msync_dbg("STA %pM : sta->t_offset=%lld," | ||
161 | " sta->t_offset_setpoint=%lld," | ||
162 | " t_clockdrift=%lld", | ||
163 | sta->sta.addr, | ||
164 | (long long) sta->t_offset, | ||
165 | (long long) | ||
166 | sta->t_offset_setpoint, | ||
167 | (long long) t_clockdrift); | ||
168 | rcu_read_unlock(); | ||
169 | |||
170 | spin_lock_bh(&ifmsh->sync_offset_lock); | ||
171 | if (t_clockdrift > | ||
172 | ifmsh->sync_offset_clockdrift_max) | ||
173 | ifmsh->sync_offset_clockdrift_max | ||
174 | = t_clockdrift; | ||
175 | spin_unlock_bh(&ifmsh->sync_offset_lock); | ||
176 | |||
177 | } else { | ||
178 | sta->t_offset_setpoint = sta->t_offset; | ||
179 | set_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN); | ||
180 | msync_dbg("STA %pM : offset was invalid, " | ||
181 | " sta->t_offset=%lld", | ||
182 | sta->sta.addr, | ||
183 | (long long) sta->t_offset); | ||
184 | rcu_read_unlock(); | ||
185 | } | ||
186 | return; | ||
187 | |||
188 | no_sync: | ||
189 | rcu_read_unlock(); | ||
190 | } | ||
191 | |||
192 | static void mesh_sync_offset_adjust_tbtt(struct ieee80211_sub_if_data *sdata) | ||
193 | { | ||
194 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||
195 | |||
196 | WARN_ON(ifmsh->mesh_sp_id | ||
197 | != IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET); | ||
198 | BUG_ON(!rcu_read_lock_held()); | ||
199 | |||
200 | spin_lock_bh(&ifmsh->sync_offset_lock); | ||
201 | |||
202 | if (ifmsh->sync_offset_clockdrift_max > | ||
203 | TBTT_MINIMUM_ADJUSTMENT) { | ||
204 | /* Since ajusting the tsf here would | ||
205 | * require a possibly blocking call | ||
206 | * to the driver tsf setter, we punt | ||
207 | * the tsf adjustment to the mesh tasklet | ||
208 | */ | ||
209 | msync_dbg("TBTT : kicking off TBTT " | ||
210 | "adjustment with " | ||
211 | "clockdrift_max=%lld", | ||
212 | ifmsh->sync_offset_clockdrift_max); | ||
213 | set_bit(MESH_WORK_DRIFT_ADJUST, | ||
214 | &ifmsh->wrkq_flags); | ||
215 | } else { | ||
216 | msync_dbg("TBTT : max clockdrift=%lld; " | ||
217 | "too small to adjust", | ||
218 | (long long) | ||
219 | ifmsh->sync_offset_clockdrift_max); | ||
220 | ifmsh->sync_offset_clockdrift_max = 0; | ||
221 | } | ||
222 | spin_unlock_bh(&ifmsh->sync_offset_lock); | ||
223 | } | ||
224 | |||
225 | static const u8 *mesh_get_vendor_oui(struct ieee80211_sub_if_data *sdata) | ||
226 | { | ||
227 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||
228 | u8 offset; | ||
229 | |||
230 | if (!ifmsh->ie || !ifmsh->ie_len) | ||
231 | return NULL; | ||
232 | |||
233 | offset = ieee80211_ie_split_vendor(ifmsh->ie, | ||
234 | ifmsh->ie_len, 0); | ||
235 | |||
236 | if (!offset) | ||
237 | return NULL; | ||
238 | |||
239 | return ifmsh->ie + offset + 2; | ||
240 | } | ||
241 | |||
242 | static void mesh_sync_vendor_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, | ||
243 | u16 stype, | ||
244 | struct ieee80211_mgmt *mgmt, | ||
245 | struct ieee802_11_elems *elems, | ||
246 | struct ieee80211_rx_status *rx_status) | ||
247 | { | ||
248 | const u8 *oui; | ||
249 | |||
250 | WARN_ON(sdata->u.mesh.mesh_sp_id != IEEE80211_SYNC_METHOD_VENDOR); | ||
251 | msync_dbg("called mesh_sync_vendor_rx_bcn_presp"); | ||
252 | oui = mesh_get_vendor_oui(sdata); | ||
253 | /* here you would implement the vendor offset tracking for this oui */ | ||
254 | } | ||
255 | |||
256 | static void mesh_sync_vendor_adjust_tbtt(struct ieee80211_sub_if_data *sdata) | ||
257 | { | ||
258 | const u8 *oui; | ||
259 | |||
260 | WARN_ON(sdata->u.mesh.mesh_sp_id != IEEE80211_SYNC_METHOD_VENDOR); | ||
261 | msync_dbg("called mesh_sync_vendor_adjust_tbtt"); | ||
262 | oui = mesh_get_vendor_oui(sdata); | ||
263 | /* here you would implement the vendor tsf adjustment for this oui */ | ||
264 | } | ||
265 | |||
266 | /* global variable */ | ||
267 | static struct sync_method sync_methods[] = { | ||
268 | { | ||
269 | .method = IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET, | ||
270 | .ops = { | ||
271 | .rx_bcn_presp = &mesh_sync_offset_rx_bcn_presp, | ||
272 | .adjust_tbtt = &mesh_sync_offset_adjust_tbtt, | ||
273 | } | ||
274 | }, | ||
275 | { | ||
276 | .method = IEEE80211_SYNC_METHOD_VENDOR, | ||
277 | .ops = { | ||
278 | .rx_bcn_presp = &mesh_sync_vendor_rx_bcn_presp, | ||
279 | .adjust_tbtt = &mesh_sync_vendor_adjust_tbtt, | ||
280 | } | ||
281 | }, | ||
282 | }; | ||
283 | |||
284 | struct ieee80211_mesh_sync_ops *ieee80211_mesh_sync_ops_get(u8 method) | ||
285 | { | ||
286 | struct ieee80211_mesh_sync_ops *ops = NULL; | ||
287 | u8 i; | ||
288 | |||
289 | for (i = 0 ; i < ARRAY_SIZE(sync_methods); ++i) { | ||
290 | if (sync_methods[i].method == method) { | ||
291 | ops = &sync_methods[i].ops; | ||
292 | break; | ||
293 | } | ||
294 | } | ||
295 | return ops; | ||
296 | } | ||
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index f76da5b3f5c5..bbf1100d90d6 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -171,122 +171,64 @@ static int ecw2cw(int ecw) | |||
171 | return (1 << ecw) - 1; | 171 | return (1 << ecw) - 1; |
172 | } | 172 | } |
173 | 173 | ||
174 | /* | 174 | static u32 ieee80211_config_ht_tx(struct ieee80211_sub_if_data *sdata, |
175 | * ieee80211_enable_ht should be called only after the operating band | 175 | struct ieee80211_ht_operation *ht_oper, |
176 | * has been determined as ht configuration depends on the hw's | 176 | const u8 *bssid, bool reconfig) |
177 | * HT abilities for a specific band. | ||
178 | */ | ||
179 | static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, | ||
180 | struct ieee80211_ht_info *hti, | ||
181 | const u8 *bssid, u16 ap_ht_cap_flags, | ||
182 | bool beacon_htcap_ie) | ||
183 | { | 177 | { |
184 | struct ieee80211_local *local = sdata->local; | 178 | struct ieee80211_local *local = sdata->local; |
185 | struct ieee80211_supported_band *sband; | 179 | struct ieee80211_supported_band *sband; |
186 | struct sta_info *sta; | 180 | struct sta_info *sta; |
187 | u32 changed = 0; | 181 | u32 changed = 0; |
188 | int hti_cfreq; | ||
189 | u16 ht_opmode; | 182 | u16 ht_opmode; |
190 | bool enable_ht = true; | 183 | bool disable_40 = false; |
191 | enum nl80211_channel_type prev_chantype; | ||
192 | enum nl80211_channel_type rx_channel_type = NL80211_CHAN_NO_HT; | ||
193 | enum nl80211_channel_type tx_channel_type; | ||
194 | 184 | ||
195 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 185 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; |
196 | prev_chantype = sdata->vif.bss_conf.channel_type; | ||
197 | |||
198 | 186 | ||
199 | hti_cfreq = ieee80211_channel_to_frequency(hti->control_chan, | 187 | switch (sdata->vif.bss_conf.channel_type) { |
200 | sband->band); | 188 | case NL80211_CHAN_HT40PLUS: |
201 | /* check that channel matches the right operating channel */ | 189 | if (local->hw.conf.channel->flags & IEEE80211_CHAN_NO_HT40PLUS) |
202 | if (local->hw.conf.channel->center_freq != hti_cfreq) { | 190 | disable_40 = true; |
203 | /* Some APs mess this up, evidently. | 191 | break; |
204 | * Netgear WNDR3700 sometimes reports 4 higher than | 192 | case NL80211_CHAN_HT40MINUS: |
205 | * the actual channel, for instance. | 193 | if (local->hw.conf.channel->flags & IEEE80211_CHAN_NO_HT40MINUS) |
206 | */ | 194 | disable_40 = true; |
207 | printk(KERN_DEBUG | 195 | break; |
208 | "%s: Wrong control channel in association" | 196 | default: |
209 | " response: configured center-freq: %d" | 197 | break; |
210 | " hti-cfreq: %d hti->control_chan: %d" | ||
211 | " band: %d. Disabling HT.\n", | ||
212 | sdata->name, | ||
213 | local->hw.conf.channel->center_freq, | ||
214 | hti_cfreq, hti->control_chan, | ||
215 | sband->band); | ||
216 | enable_ht = false; | ||
217 | } | ||
218 | |||
219 | if (enable_ht) { | ||
220 | rx_channel_type = NL80211_CHAN_HT20; | ||
221 | |||
222 | if (!(ap_ht_cap_flags & IEEE80211_HT_CAP_40MHZ_INTOLERANT) && | ||
223 | !ieee80111_cfg_override_disables_ht40(sdata) && | ||
224 | (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) && | ||
225 | (hti->ht_param & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) { | ||
226 | switch(hti->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { | ||
227 | case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: | ||
228 | rx_channel_type = NL80211_CHAN_HT40PLUS; | ||
229 | break; | ||
230 | case IEEE80211_HT_PARAM_CHA_SEC_BELOW: | ||
231 | rx_channel_type = NL80211_CHAN_HT40MINUS; | ||
232 | break; | ||
233 | } | ||
234 | } | ||
235 | } | 198 | } |
236 | 199 | ||
237 | tx_channel_type = ieee80211_get_tx_channel_type(local, rx_channel_type); | 200 | /* This can change during the lifetime of the BSS */ |
238 | 201 | if (!(ht_oper->ht_param & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) | |
239 | if (local->tmp_channel) | 202 | disable_40 = true; |
240 | local->tmp_channel_type = rx_channel_type; | ||
241 | 203 | ||
242 | if (!ieee80211_set_channel_type(local, sdata, rx_channel_type)) { | 204 | mutex_lock(&local->sta_mtx); |
243 | /* can only fail due to HT40+/- mismatch */ | 205 | sta = sta_info_get(sdata, bssid); |
244 | rx_channel_type = NL80211_CHAN_HT20; | ||
245 | WARN_ON(!ieee80211_set_channel_type(local, sdata, | ||
246 | rx_channel_type)); | ||
247 | } | ||
248 | |||
249 | if (beacon_htcap_ie && (prev_chantype != rx_channel_type)) { | ||
250 | /* | ||
251 | * Whenever the AP announces the HT mode change that can be | ||
252 | * 40MHz intolerant or etc., it would be safer to stop tx | ||
253 | * queues before doing hw config to avoid buffer overflow. | ||
254 | */ | ||
255 | ieee80211_stop_queues_by_reason(&sdata->local->hw, | ||
256 | IEEE80211_QUEUE_STOP_REASON_CHTYPE_CHANGE); | ||
257 | 206 | ||
258 | /* flush out all packets */ | 207 | WARN_ON_ONCE(!sta); |
259 | synchronize_net(); | ||
260 | 208 | ||
261 | drv_flush(local, false); | 209 | if (sta && !sta->supports_40mhz) |
262 | } | 210 | disable_40 = true; |
263 | 211 | ||
264 | /* channel_type change automatically detected */ | 212 | if (sta && (!reconfig || |
265 | ieee80211_hw_config(local, 0); | 213 | (disable_40 != !!(sta->sta.ht_cap.cap & |
214 | IEEE80211_HT_CAP_SUP_WIDTH_20_40)))) { | ||
266 | 215 | ||
267 | if (prev_chantype != tx_channel_type) { | 216 | if (disable_40) |
268 | rcu_read_lock(); | 217 | sta->sta.ht_cap.cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; |
269 | sta = sta_info_get(sdata, bssid); | 218 | else |
270 | if (sta) | 219 | sta->sta.ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; |
271 | rate_control_rate_update(local, sband, sta, | ||
272 | IEEE80211_RC_HT_CHANGED, | ||
273 | tx_channel_type); | ||
274 | rcu_read_unlock(); | ||
275 | 220 | ||
276 | if (beacon_htcap_ie) | 221 | rate_control_rate_update(local, sband, sta, |
277 | ieee80211_wake_queues_by_reason(&sdata->local->hw, | 222 | IEEE80211_RC_BW_CHANGED); |
278 | IEEE80211_QUEUE_STOP_REASON_CHTYPE_CHANGE); | ||
279 | } | 223 | } |
224 | mutex_unlock(&local->sta_mtx); | ||
280 | 225 | ||
281 | ht_opmode = le16_to_cpu(hti->operation_mode); | 226 | ht_opmode = le16_to_cpu(ht_oper->operation_mode); |
282 | 227 | ||
283 | /* if bss configuration changed store the new one */ | 228 | /* if bss configuration changed store the new one */ |
284 | if (sdata->ht_opmode_valid != enable_ht || | 229 | if (!reconfig || (sdata->vif.bss_conf.ht_operation_mode != ht_opmode)) { |
285 | sdata->vif.bss_conf.ht_operation_mode != ht_opmode || | ||
286 | prev_chantype != rx_channel_type) { | ||
287 | changed |= BSS_CHANGED_HT; | 230 | changed |= BSS_CHANGED_HT; |
288 | sdata->vif.bss_conf.ht_operation_mode = ht_opmode; | 231 | sdata->vif.bss_conf.ht_operation_mode = ht_opmode; |
289 | sdata->ht_opmode_valid = enable_ht; | ||
290 | } | 232 | } |
291 | 233 | ||
292 | return changed; | 234 | return changed; |
@@ -316,12 +258,12 @@ static int ieee80211_compatible_rates(const u8 *supp_rates, int supp_rates_len, | |||
316 | } | 258 | } |
317 | 259 | ||
318 | static void ieee80211_add_ht_ie(struct ieee80211_sub_if_data *sdata, | 260 | static void ieee80211_add_ht_ie(struct ieee80211_sub_if_data *sdata, |
319 | struct sk_buff *skb, const u8 *ht_info_ie, | 261 | struct sk_buff *skb, const u8 *ht_oper_ie, |
320 | struct ieee80211_supported_band *sband, | 262 | struct ieee80211_supported_band *sband, |
321 | struct ieee80211_channel *channel, | 263 | struct ieee80211_channel *channel, |
322 | enum ieee80211_smps_mode smps) | 264 | enum ieee80211_smps_mode smps) |
323 | { | 265 | { |
324 | struct ieee80211_ht_info *ht_info; | 266 | struct ieee80211_ht_operation *ht_oper; |
325 | u8 *pos; | 267 | u8 *pos; |
326 | u32 flags = channel->flags; | 268 | u32 flags = channel->flags; |
327 | u16 cap; | 269 | u16 cap; |
@@ -329,21 +271,21 @@ static void ieee80211_add_ht_ie(struct ieee80211_sub_if_data *sdata, | |||
329 | 271 | ||
330 | BUILD_BUG_ON(sizeof(ht_cap) != sizeof(sband->ht_cap)); | 272 | BUILD_BUG_ON(sizeof(ht_cap) != sizeof(sband->ht_cap)); |
331 | 273 | ||
332 | if (!ht_info_ie) | 274 | if (!ht_oper_ie) |
333 | return; | 275 | return; |
334 | 276 | ||
335 | if (ht_info_ie[1] < sizeof(struct ieee80211_ht_info)) | 277 | if (ht_oper_ie[1] < sizeof(struct ieee80211_ht_operation)) |
336 | return; | 278 | return; |
337 | 279 | ||
338 | memcpy(&ht_cap, &sband->ht_cap, sizeof(ht_cap)); | 280 | memcpy(&ht_cap, &sband->ht_cap, sizeof(ht_cap)); |
339 | ieee80211_apply_htcap_overrides(sdata, &ht_cap); | 281 | ieee80211_apply_htcap_overrides(sdata, &ht_cap); |
340 | 282 | ||
341 | ht_info = (struct ieee80211_ht_info *)(ht_info_ie + 2); | 283 | ht_oper = (struct ieee80211_ht_operation *)(ht_oper_ie + 2); |
342 | 284 | ||
343 | /* determine capability flags */ | 285 | /* determine capability flags */ |
344 | cap = ht_cap.cap; | 286 | cap = ht_cap.cap; |
345 | 287 | ||
346 | switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { | 288 | switch (ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { |
347 | case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: | 289 | case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: |
348 | if (flags & IEEE80211_CHAN_NO_HT40PLUS) { | 290 | if (flags & IEEE80211_CHAN_NO_HT40PLUS) { |
349 | cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; | 291 | cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; |
@@ -358,6 +300,16 @@ static void ieee80211_add_ht_ie(struct ieee80211_sub_if_data *sdata, | |||
358 | break; | 300 | break; |
359 | } | 301 | } |
360 | 302 | ||
303 | /* | ||
304 | * If 40 MHz was disabled associate as though we weren't | ||
305 | * capable of 40 MHz -- some broken APs will never fall | ||
306 | * back to trying to transmit in 20 MHz. | ||
307 | */ | ||
308 | if (sdata->u.mgd.flags & IEEE80211_STA_DISABLE_40MHZ) { | ||
309 | cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||
310 | cap &= ~IEEE80211_HT_CAP_SGI_40; | ||
311 | } | ||
312 | |||
361 | /* set SM PS mode properly */ | 313 | /* set SM PS mode properly */ |
362 | cap &= ~IEEE80211_HT_CAP_SM_PS; | 314 | cap &= ~IEEE80211_HT_CAP_SM_PS; |
363 | switch (smps) { | 315 | switch (smps) { |
@@ -557,7 +509,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | |||
557 | } | 509 | } |
558 | 510 | ||
559 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) | 511 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) |
560 | ieee80211_add_ht_ie(sdata, skb, assoc_data->ht_information_ie, | 512 | ieee80211_add_ht_ie(sdata, skb, assoc_data->ht_operation_ie, |
561 | sband, local->oper_channel, ifmgd->ap_smps); | 513 | sband, local->oper_channel, ifmgd->ap_smps); |
562 | 514 | ||
563 | /* if present, add any custom non-vendor IEs that go after HT */ | 515 | /* if present, add any custom non-vendor IEs that go after HT */ |
@@ -1182,7 +1134,7 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, | |||
1182 | if (!local->ops->conf_tx) | 1134 | if (!local->ops->conf_tx) |
1183 | return; | 1135 | return; |
1184 | 1136 | ||
1185 | if (local->hw.queues < 4) | 1137 | if (local->hw.queues < IEEE80211_NUM_ACS) |
1186 | return; | 1138 | return; |
1187 | 1139 | ||
1188 | if (!wmm_param) | 1140 | if (!wmm_param) |
@@ -1435,7 +1387,6 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1435 | sdata->vif.bss_conf.assoc = false; | 1387 | sdata->vif.bss_conf.assoc = false; |
1436 | 1388 | ||
1437 | /* on the next assoc, re-program HT parameters */ | 1389 | /* on the next assoc, re-program HT parameters */ |
1438 | sdata->ht_opmode_valid = false; | ||
1439 | memset(&ifmgd->ht_capa, 0, sizeof(ifmgd->ht_capa)); | 1390 | memset(&ifmgd->ht_capa, 0, sizeof(ifmgd->ht_capa)); |
1440 | memset(&ifmgd->ht_capa_mask, 0, sizeof(ifmgd->ht_capa_mask)); | 1391 | memset(&ifmgd->ht_capa_mask, 0, sizeof(ifmgd->ht_capa_mask)); |
1441 | 1392 | ||
@@ -1567,14 +1518,23 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) | |||
1567 | ifmgd->nullfunc_failed = false; | 1518 | ifmgd->nullfunc_failed = false; |
1568 | ieee80211_send_nullfunc(sdata->local, sdata, 0); | 1519 | ieee80211_send_nullfunc(sdata->local, sdata, 0); |
1569 | } else { | 1520 | } else { |
1521 | int ssid_len; | ||
1522 | |||
1570 | ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID); | 1523 | ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID); |
1571 | ieee80211_send_probe_req(sdata, dst, ssid + 2, ssid[1], NULL, 0, | 1524 | if (WARN_ON_ONCE(ssid == NULL)) |
1572 | (u32) -1, true, false); | 1525 | ssid_len = 0; |
1526 | else | ||
1527 | ssid_len = ssid[1]; | ||
1528 | |||
1529 | ieee80211_send_probe_req(sdata, dst, ssid + 2, ssid_len, NULL, | ||
1530 | 0, (u32) -1, true, false); | ||
1573 | } | 1531 | } |
1574 | 1532 | ||
1575 | ifmgd->probe_send_count++; | 1533 | ifmgd->probe_send_count++; |
1576 | ifmgd->probe_timeout = jiffies + msecs_to_jiffies(probe_wait_ms); | 1534 | ifmgd->probe_timeout = jiffies + msecs_to_jiffies(probe_wait_ms); |
1577 | run_again(ifmgd, ifmgd->probe_timeout); | 1535 | run_again(ifmgd, ifmgd->probe_timeout); |
1536 | if (sdata->local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) | ||
1537 | drv_flush(sdata->local, false); | ||
1578 | } | 1538 | } |
1579 | 1539 | ||
1580 | static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata, | 1540 | static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata, |
@@ -1643,6 +1603,7 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw, | |||
1643 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 1603 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
1644 | struct sk_buff *skb; | 1604 | struct sk_buff *skb; |
1645 | const u8 *ssid; | 1605 | const u8 *ssid; |
1606 | int ssid_len; | ||
1646 | 1607 | ||
1647 | if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION)) | 1608 | if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION)) |
1648 | return NULL; | 1609 | return NULL; |
@@ -1653,8 +1614,13 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw, | |||
1653 | return NULL; | 1614 | return NULL; |
1654 | 1615 | ||
1655 | ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID); | 1616 | ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID); |
1617 | if (WARN_ON_ONCE(ssid == NULL)) | ||
1618 | ssid_len = 0; | ||
1619 | else | ||
1620 | ssid_len = ssid[1]; | ||
1621 | |||
1656 | skb = ieee80211_build_probe_req(sdata, ifmgd->associated->bssid, | 1622 | skb = ieee80211_build_probe_req(sdata, ifmgd->associated->bssid, |
1657 | (u32) -1, ssid + 2, ssid[1], | 1623 | (u32) -1, ssid + 2, ssid_len, |
1658 | NULL, 0, true); | 1624 | NULL, 0, true); |
1659 | 1625 | ||
1660 | return skb; | 1626 | return skb; |
@@ -2000,7 +1966,6 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, | |||
2000 | struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; | 1966 | struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; |
2001 | u32 changed = 0; | 1967 | u32 changed = 0; |
2002 | int err; | 1968 | int err; |
2003 | u16 ap_ht_cap_flags; | ||
2004 | 1969 | ||
2005 | /* AssocResp and ReassocResp have identical structure */ | 1970 | /* AssocResp and ReassocResp have identical structure */ |
2006 | 1971 | ||
@@ -2051,7 +2016,8 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, | |||
2051 | ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, | 2016 | ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, |
2052 | elems.ht_cap_elem, &sta->sta.ht_cap); | 2017 | elems.ht_cap_elem, &sta->sta.ht_cap); |
2053 | 2018 | ||
2054 | ap_ht_cap_flags = sta->sta.ht_cap.cap; | 2019 | sta->supports_40mhz = |
2020 | sta->sta.ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||
2055 | 2021 | ||
2056 | rate_control_rate_init(sta); | 2022 | rate_control_rate_init(sta); |
2057 | 2023 | ||
@@ -2092,11 +2058,10 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, | |||
2092 | ieee80211_set_wmm_default(sdata, false); | 2058 | ieee80211_set_wmm_default(sdata, false); |
2093 | changed |= BSS_CHANGED_QOS; | 2059 | changed |= BSS_CHANGED_QOS; |
2094 | 2060 | ||
2095 | if (elems.ht_info_elem && elems.wmm_param && | 2061 | if (elems.ht_operation && elems.wmm_param && |
2096 | !(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) | 2062 | !(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) |
2097 | changed |= ieee80211_enable_ht(sdata, elems.ht_info_elem, | 2063 | changed |= ieee80211_config_ht_tx(sdata, elems.ht_operation, |
2098 | cbss->bssid, ap_ht_cap_flags, | 2064 | cbss->bssid, false); |
2099 | false); | ||
2100 | 2065 | ||
2101 | /* set AID and assoc capability, | 2066 | /* set AID and assoc capability, |
2102 | * ieee80211_set_associated() will tell the driver */ | 2067 | * ieee80211_set_associated() will tell the driver */ |
@@ -2319,7 +2284,7 @@ static const u64 care_about_ies = | |||
2319 | (1ULL << WLAN_EID_CHANNEL_SWITCH) | | 2284 | (1ULL << WLAN_EID_CHANNEL_SWITCH) | |
2320 | (1ULL << WLAN_EID_PWR_CONSTRAINT) | | 2285 | (1ULL << WLAN_EID_PWR_CONSTRAINT) | |
2321 | (1ULL << WLAN_EID_HT_CAPABILITY) | | 2286 | (1ULL << WLAN_EID_HT_CAPABILITY) | |
2322 | (1ULL << WLAN_EID_HT_INFORMATION); | 2287 | (1ULL << WLAN_EID_HT_OPERATION); |
2323 | 2288 | ||
2324 | static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | 2289 | static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, |
2325 | struct ieee80211_mgmt *mgmt, | 2290 | struct ieee80211_mgmt *mgmt, |
@@ -2468,11 +2433,13 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
2468 | if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) { | 2433 | if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) { |
2469 | if (directed_tim) { | 2434 | if (directed_tim) { |
2470 | if (local->hw.conf.dynamic_ps_timeout > 0) { | 2435 | if (local->hw.conf.dynamic_ps_timeout > 0) { |
2471 | local->hw.conf.flags &= ~IEEE80211_CONF_PS; | 2436 | if (local->hw.conf.flags & IEEE80211_CONF_PS) { |
2472 | ieee80211_hw_config(local, | 2437 | local->hw.conf.flags &= ~IEEE80211_CONF_PS; |
2473 | IEEE80211_CONF_CHANGE_PS); | 2438 | ieee80211_hw_config(local, |
2439 | IEEE80211_CONF_CHANGE_PS); | ||
2440 | } | ||
2474 | ieee80211_send_nullfunc(local, sdata, 0); | 2441 | ieee80211_send_nullfunc(local, sdata, 0); |
2475 | } else { | 2442 | } else if (!local->pspolling && sdata->u.mgd.powersave) { |
2476 | local->pspolling = true; | 2443 | local->pspolling = true; |
2477 | 2444 | ||
2478 | /* | 2445 | /* |
@@ -2504,31 +2471,14 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
2504 | erp_valid, erp_value); | 2471 | erp_valid, erp_value); |
2505 | 2472 | ||
2506 | 2473 | ||
2507 | if (elems.ht_cap_elem && elems.ht_info_elem && elems.wmm_param && | 2474 | if (elems.ht_cap_elem && elems.ht_operation && elems.wmm_param && |
2508 | !(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) { | 2475 | !(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) { |
2509 | struct sta_info *sta; | ||
2510 | struct ieee80211_supported_band *sband; | 2476 | struct ieee80211_supported_band *sband; |
2511 | u16 ap_ht_cap_flags; | ||
2512 | |||
2513 | rcu_read_lock(); | ||
2514 | |||
2515 | sta = sta_info_get(sdata, bssid); | ||
2516 | if (WARN_ON(!sta)) { | ||
2517 | rcu_read_unlock(); | ||
2518 | return; | ||
2519 | } | ||
2520 | 2477 | ||
2521 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 2478 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; |
2522 | 2479 | ||
2523 | ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, | 2480 | changed |= ieee80211_config_ht_tx(sdata, elems.ht_operation, |
2524 | elems.ht_cap_elem, &sta->sta.ht_cap); | 2481 | bssid, true); |
2525 | |||
2526 | ap_ht_cap_flags = sta->sta.ht_cap.cap; | ||
2527 | |||
2528 | rcu_read_unlock(); | ||
2529 | |||
2530 | changed |= ieee80211_enable_ht(sdata, elems.ht_info_elem, | ||
2531 | bssid, ap_ht_cap_flags, true); | ||
2532 | } | 2482 | } |
2533 | 2483 | ||
2534 | /* Note: country IE parsing is done for us by cfg80211 */ | 2484 | /* Note: country IE parsing is done for us by cfg80211 */ |
@@ -3060,6 +3010,11 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, | |||
3060 | struct sta_info *sta; | 3010 | struct sta_info *sta; |
3061 | bool have_sta = false; | 3011 | bool have_sta = false; |
3062 | int err; | 3012 | int err; |
3013 | int ht_cfreq; | ||
3014 | enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; | ||
3015 | const u8 *ht_oper_ie; | ||
3016 | const struct ieee80211_ht_operation *ht_oper = NULL; | ||
3017 | struct ieee80211_supported_band *sband; | ||
3063 | 3018 | ||
3064 | if (WARN_ON(!ifmgd->auth_data && !ifmgd->assoc_data)) | 3019 | if (WARN_ON(!ifmgd->auth_data && !ifmgd->assoc_data)) |
3065 | return -EINVAL; | 3020 | return -EINVAL; |
@@ -3081,17 +3036,76 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, | |||
3081 | mutex_unlock(&local->mtx); | 3036 | mutex_unlock(&local->mtx); |
3082 | 3037 | ||
3083 | /* switch to the right channel */ | 3038 | /* switch to the right channel */ |
3039 | sband = local->hw.wiphy->bands[cbss->channel->band]; | ||
3040 | |||
3041 | ifmgd->flags &= ~IEEE80211_STA_DISABLE_40MHZ; | ||
3042 | |||
3043 | if (sband->ht_cap.ht_supported) { | ||
3044 | ht_oper_ie = cfg80211_find_ie(WLAN_EID_HT_OPERATION, | ||
3045 | cbss->information_elements, | ||
3046 | cbss->len_information_elements); | ||
3047 | if (ht_oper_ie && ht_oper_ie[1] >= sizeof(*ht_oper)) | ||
3048 | ht_oper = (void *)(ht_oper_ie + 2); | ||
3049 | } | ||
3050 | |||
3051 | if (ht_oper) { | ||
3052 | ht_cfreq = ieee80211_channel_to_frequency(ht_oper->primary_chan, | ||
3053 | cbss->channel->band); | ||
3054 | /* check that channel matches the right operating channel */ | ||
3055 | if (cbss->channel->center_freq != ht_cfreq) { | ||
3056 | /* | ||
3057 | * It's possible that some APs are confused here; | ||
3058 | * Netgear WNDR3700 sometimes reports 4 higher than | ||
3059 | * the actual channel in association responses, but | ||
3060 | * since we look at probe response/beacon data here | ||
3061 | * it should be OK. | ||
3062 | */ | ||
3063 | printk(KERN_DEBUG | ||
3064 | "%s: Wrong control channel: center-freq: %d" | ||
3065 | " ht-cfreq: %d ht->primary_chan: %d" | ||
3066 | " band: %d. Disabling HT.\n", | ||
3067 | sdata->name, cbss->channel->center_freq, | ||
3068 | ht_cfreq, ht_oper->primary_chan, | ||
3069 | cbss->channel->band); | ||
3070 | ht_oper = NULL; | ||
3071 | } | ||
3072 | } | ||
3073 | |||
3074 | if (ht_oper) { | ||
3075 | channel_type = NL80211_CHAN_HT20; | ||
3076 | |||
3077 | if (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) { | ||
3078 | switch (ht_oper->ht_param & | ||
3079 | IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { | ||
3080 | case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: | ||
3081 | channel_type = NL80211_CHAN_HT40PLUS; | ||
3082 | break; | ||
3083 | case IEEE80211_HT_PARAM_CHA_SEC_BELOW: | ||
3084 | channel_type = NL80211_CHAN_HT40MINUS; | ||
3085 | break; | ||
3086 | } | ||
3087 | } | ||
3088 | } | ||
3089 | |||
3090 | if (!ieee80211_set_channel_type(local, sdata, channel_type)) { | ||
3091 | /* can only fail due to HT40+/- mismatch */ | ||
3092 | channel_type = NL80211_CHAN_HT20; | ||
3093 | printk(KERN_DEBUG | ||
3094 | "%s: disabling 40 MHz due to multi-vif mismatch\n", | ||
3095 | sdata->name); | ||
3096 | ifmgd->flags |= IEEE80211_STA_DISABLE_40MHZ; | ||
3097 | WARN_ON(!ieee80211_set_channel_type(local, sdata, | ||
3098 | channel_type)); | ||
3099 | } | ||
3100 | |||
3084 | local->oper_channel = cbss->channel; | 3101 | local->oper_channel = cbss->channel; |
3085 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); | 3102 | ieee80211_hw_config(local, 0); |
3086 | 3103 | ||
3087 | if (!have_sta) { | 3104 | if (!have_sta) { |
3088 | struct ieee80211_supported_band *sband; | ||
3089 | u32 rates = 0, basic_rates = 0; | 3105 | u32 rates = 0, basic_rates = 0; |
3090 | bool have_higher_than_11mbit; | 3106 | bool have_higher_than_11mbit; |
3091 | int min_rate = INT_MAX, min_rate_index = -1; | 3107 | int min_rate = INT_MAX, min_rate_index = -1; |
3092 | 3108 | ||
3093 | sband = sdata->local->hw.wiphy->bands[cbss->channel->band]; | ||
3094 | |||
3095 | ieee80211_get_rates(sband, bss->supp_rates, | 3109 | ieee80211_get_rates(sband, bss->supp_rates, |
3096 | bss->supp_rates_len, | 3110 | bss->supp_rates_len, |
3097 | &rates, &basic_rates, | 3111 | &rates, &basic_rates, |
@@ -3311,7 +3325,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
3311 | /* Also disable HT if we don't support it or the AP doesn't use WMM */ | 3325 | /* Also disable HT if we don't support it or the AP doesn't use WMM */ |
3312 | sband = local->hw.wiphy->bands[req->bss->channel->band]; | 3326 | sband = local->hw.wiphy->bands[req->bss->channel->band]; |
3313 | if (!sband->ht_cap.ht_supported || | 3327 | if (!sband->ht_cap.ht_supported || |
3314 | local->hw.queues < 4 || !bss->wmm_used) | 3328 | local->hw.queues < IEEE80211_NUM_ACS || !bss->wmm_used) |
3315 | ifmgd->flags |= IEEE80211_STA_DISABLE_11N; | 3329 | ifmgd->flags |= IEEE80211_STA_DISABLE_11N; |
3316 | 3330 | ||
3317 | memcpy(&ifmgd->ht_capa, &req->ht_capa, sizeof(ifmgd->ht_capa)); | 3331 | memcpy(&ifmgd->ht_capa, &req->ht_capa, sizeof(ifmgd->ht_capa)); |
@@ -3334,11 +3348,12 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
3334 | ifmgd->ap_smps = ifmgd->req_smps; | 3348 | ifmgd->ap_smps = ifmgd->req_smps; |
3335 | 3349 | ||
3336 | assoc_data->capability = req->bss->capability; | 3350 | assoc_data->capability = req->bss->capability; |
3337 | assoc_data->wmm = bss->wmm_used && (local->hw.queues >= 4); | 3351 | assoc_data->wmm = bss->wmm_used && |
3352 | (local->hw.queues >= IEEE80211_NUM_ACS); | ||
3338 | assoc_data->supp_rates = bss->supp_rates; | 3353 | assoc_data->supp_rates = bss->supp_rates; |
3339 | assoc_data->supp_rates_len = bss->supp_rates_len; | 3354 | assoc_data->supp_rates_len = bss->supp_rates_len; |
3340 | assoc_data->ht_information_ie = | 3355 | assoc_data->ht_operation_ie = |
3341 | ieee80211_bss_get_ie(req->bss, WLAN_EID_HT_INFORMATION); | 3356 | ieee80211_bss_get_ie(req->bss, WLAN_EID_HT_OPERATION); |
3342 | 3357 | ||
3343 | if (bss->wmm_used && bss->uapsd_supported && | 3358 | if (bss->wmm_used && bss->uapsd_supported && |
3344 | (sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD)) { | 3359 | (sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD)) { |
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index ef8eba1d736d..af1c4e26e965 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c | |||
@@ -127,6 +127,10 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) | |||
127 | drv_remove_interface(local, sdata); | 127 | drv_remove_interface(local, sdata); |
128 | } | 128 | } |
129 | 129 | ||
130 | sdata = rtnl_dereference(local->monitor_sdata); | ||
131 | if (sdata) | ||
132 | drv_remove_interface(local, sdata); | ||
133 | |||
130 | /* stop hardware - this must stop RX */ | 134 | /* stop hardware - this must stop RX */ |
131 | if (local->open_count) | 135 | if (local->open_count) |
132 | ieee80211_stop_device(local); | 136 | ieee80211_stop_device(local); |
diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h index fbb1efdc4d04..6e4fd32c6617 100644 --- a/net/mac80211/rate.h +++ b/net/mac80211/rate.h | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <net/mac80211.h> | 17 | #include <net/mac80211.h> |
18 | #include "ieee80211_i.h" | 18 | #include "ieee80211_i.h" |
19 | #include "sta_info.h" | 19 | #include "sta_info.h" |
20 | #include "driver-ops.h" | ||
20 | 21 | ||
21 | struct rate_control_ref { | 22 | struct rate_control_ref { |
22 | struct ieee80211_local *local; | 23 | struct ieee80211_local *local; |
@@ -63,8 +64,7 @@ static inline void rate_control_rate_init(struct sta_info *sta) | |||
63 | 64 | ||
64 | static inline void rate_control_rate_update(struct ieee80211_local *local, | 65 | static inline void rate_control_rate_update(struct ieee80211_local *local, |
65 | struct ieee80211_supported_band *sband, | 66 | struct ieee80211_supported_band *sband, |
66 | struct sta_info *sta, u32 changed, | 67 | struct sta_info *sta, u32 changed) |
67 | enum nl80211_channel_type oper_chan_type) | ||
68 | { | 68 | { |
69 | struct rate_control_ref *ref = local->rate_ctrl; | 69 | struct rate_control_ref *ref = local->rate_ctrl; |
70 | struct ieee80211_sta *ista = &sta->sta; | 70 | struct ieee80211_sta *ista = &sta->sta; |
@@ -72,7 +72,8 @@ static inline void rate_control_rate_update(struct ieee80211_local *local, | |||
72 | 72 | ||
73 | if (ref && ref->ops->rate_update) | 73 | if (ref && ref->ops->rate_update) |
74 | ref->ops->rate_update(ref->priv, sband, ista, | 74 | ref->ops->rate_update(ref->priv, sband, ista, |
75 | priv_sta, changed, oper_chan_type); | 75 | priv_sta, changed); |
76 | drv_sta_rc_update(local, sta->sdata, &sta->sta, changed); | ||
76 | } | 77 | } |
77 | 78 | ||
78 | static inline void *rate_control_alloc_sta(struct rate_control_ref *ref, | 79 | static inline void *rate_control_alloc_sta(struct rate_control_ref *ref, |
diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index 16e0b277b9a8..3b3dcae13bbc 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c | |||
@@ -686,8 +686,7 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, | |||
686 | 686 | ||
687 | static void | 687 | static void |
688 | minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, | 688 | minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, |
689 | struct ieee80211_sta *sta, void *priv_sta, | 689 | struct ieee80211_sta *sta, void *priv_sta) |
690 | enum nl80211_channel_type oper_chan_type) | ||
691 | { | 690 | { |
692 | struct minstrel_priv *mp = priv; | 691 | struct minstrel_priv *mp = priv; |
693 | struct minstrel_ht_sta_priv *msp = priv_sta; | 692 | struct minstrel_ht_sta_priv *msp = priv_sta; |
@@ -735,10 +734,6 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, | |||
735 | if (sta_cap & IEEE80211_HT_CAP_LDPC_CODING) | 734 | if (sta_cap & IEEE80211_HT_CAP_LDPC_CODING) |
736 | mi->tx_flags |= IEEE80211_TX_CTL_LDPC; | 735 | mi->tx_flags |= IEEE80211_TX_CTL_LDPC; |
737 | 736 | ||
738 | if (oper_chan_type != NL80211_CHAN_HT40MINUS && | ||
739 | oper_chan_type != NL80211_CHAN_HT40PLUS) | ||
740 | sta_cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||
741 | |||
742 | smps = (sta_cap & IEEE80211_HT_CAP_SM_PS) >> | 737 | smps = (sta_cap & IEEE80211_HT_CAP_SM_PS) >> |
743 | IEEE80211_HT_CAP_SM_PS_SHIFT; | 738 | IEEE80211_HT_CAP_SM_PS_SHIFT; |
744 | 739 | ||
@@ -788,17 +783,15 @@ static void | |||
788 | minstrel_ht_rate_init(void *priv, struct ieee80211_supported_band *sband, | 783 | minstrel_ht_rate_init(void *priv, struct ieee80211_supported_band *sband, |
789 | struct ieee80211_sta *sta, void *priv_sta) | 784 | struct ieee80211_sta *sta, void *priv_sta) |
790 | { | 785 | { |
791 | struct minstrel_priv *mp = priv; | 786 | minstrel_ht_update_caps(priv, sband, sta, priv_sta); |
792 | |||
793 | minstrel_ht_update_caps(priv, sband, sta, priv_sta, mp->hw->conf.channel_type); | ||
794 | } | 787 | } |
795 | 788 | ||
796 | static void | 789 | static void |
797 | minstrel_ht_rate_update(void *priv, struct ieee80211_supported_band *sband, | 790 | minstrel_ht_rate_update(void *priv, struct ieee80211_supported_band *sband, |
798 | struct ieee80211_sta *sta, void *priv_sta, | 791 | struct ieee80211_sta *sta, void *priv_sta, |
799 | u32 changed, enum nl80211_channel_type oper_chan_type) | 792 | u32 changed) |
800 | { | 793 | { |
801 | minstrel_ht_update_caps(priv, sband, sta, priv_sta, oper_chan_type); | 794 | minstrel_ht_update_caps(priv, sband, sta, priv_sta); |
802 | } | 795 | } |
803 | 796 | ||
804 | static void * | 797 | static void * |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index bcfe8c77c839..54a049123a60 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -793,8 +793,7 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx) | |||
793 | 793 | ||
794 | /* reset session timer */ | 794 | /* reset session timer */ |
795 | if (tid_agg_rx->timeout) | 795 | if (tid_agg_rx->timeout) |
796 | mod_timer(&tid_agg_rx->session_timer, | 796 | tid_agg_rx->last_rx = jiffies; |
797 | TU_TO_EXP_TIME(tid_agg_rx->timeout)); | ||
798 | 797 | ||
799 | /* if this mpdu is fragmented - terminate rx aggregation session */ | 798 | /* if this mpdu is fragmented - terminate rx aggregation session */ |
800 | sc = le16_to_cpu(hdr->seq_ctrl); | 799 | sc = le16_to_cpu(hdr->seq_ctrl); |
@@ -2269,11 +2268,8 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
2269 | 2268 | ||
2270 | sband = rx->local->hw.wiphy->bands[status->band]; | 2269 | sband = rx->local->hw.wiphy->bands[status->band]; |
2271 | 2270 | ||
2272 | rate_control_rate_update( | 2271 | rate_control_rate_update(local, sband, rx->sta, |
2273 | local, sband, rx->sta, | 2272 | IEEE80211_RC_SMPS_CHANGED); |
2274 | IEEE80211_RC_SMPS_CHANGED, | ||
2275 | ieee80211_get_tx_channel_type( | ||
2276 | local, local->_oper_channel_type)); | ||
2277 | goto handled; | 2273 | goto handled; |
2278 | } | 2274 | } |
2279 | default: | 2275 | default: |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 38137cb5f6f0..7fd7ac48f893 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -1195,13 +1195,15 @@ ieee80211_sta_ps_deliver_response(struct sta_info *sta, | |||
1195 | ieee80211_is_qos_nullfunc(hdr->frame_control)) | 1195 | ieee80211_is_qos_nullfunc(hdr->frame_control)) |
1196 | qoshdr = ieee80211_get_qos_ctl(hdr); | 1196 | qoshdr = ieee80211_get_qos_ctl(hdr); |
1197 | 1197 | ||
1198 | /* set EOSP for the frame */ | 1198 | /* end service period after last frame */ |
1199 | if (reason == IEEE80211_FRAME_RELEASE_UAPSD && | 1199 | if (skb_queue_empty(&frames)) { |
1200 | qoshdr && skb_queue_empty(&frames)) | 1200 | if (reason == IEEE80211_FRAME_RELEASE_UAPSD && |
1201 | *qoshdr |= IEEE80211_QOS_CTL_EOSP; | 1201 | qoshdr) |
1202 | 1202 | *qoshdr |= IEEE80211_QOS_CTL_EOSP; | |
1203 | info->flags |= IEEE80211_TX_STATUS_EOSP | | 1203 | |
1204 | IEEE80211_TX_CTL_REQ_TX_STATUS; | 1204 | info->flags |= IEEE80211_TX_STATUS_EOSP | |
1205 | IEEE80211_TX_CTL_REQ_TX_STATUS; | ||
1206 | } | ||
1205 | 1207 | ||
1206 | if (qoshdr) | 1208 | if (qoshdr) |
1207 | tids |= BIT(*qoshdr & IEEE80211_QOS_CTL_TID_MASK); | 1209 | tids |= BIT(*qoshdr & IEEE80211_QOS_CTL_TID_MASK); |
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index ab0576827baf..f75f5d9ac06d 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -55,6 +55,7 @@ | |||
55 | * @WLAN_STA_4ADDR_EVENT: 4-addr event was already sent for this frame. | 55 | * @WLAN_STA_4ADDR_EVENT: 4-addr event was already sent for this frame. |
56 | * @WLAN_STA_INSERTED: This station is inserted into the hash table. | 56 | * @WLAN_STA_INSERTED: This station is inserted into the hash table. |
57 | * @WLAN_STA_RATE_CONTROL: rate control was initialized for this station. | 57 | * @WLAN_STA_RATE_CONTROL: rate control was initialized for this station. |
58 | * @WLAN_STA_TOFFSET_KNOWN: toffset calculated for this station is valid. | ||
58 | */ | 59 | */ |
59 | enum ieee80211_sta_info_flags { | 60 | enum ieee80211_sta_info_flags { |
60 | WLAN_STA_AUTH, | 61 | WLAN_STA_AUTH, |
@@ -76,6 +77,7 @@ enum ieee80211_sta_info_flags { | |||
76 | WLAN_STA_4ADDR_EVENT, | 77 | WLAN_STA_4ADDR_EVENT, |
77 | WLAN_STA_INSERTED, | 78 | WLAN_STA_INSERTED, |
78 | WLAN_STA_RATE_CONTROL, | 79 | WLAN_STA_RATE_CONTROL, |
80 | WLAN_STA_TOFFSET_KNOWN, | ||
79 | }; | 81 | }; |
80 | 82 | ||
81 | #define STA_TID_NUM 16 | 83 | #define STA_TID_NUM 16 |
@@ -101,6 +103,7 @@ enum ieee80211_sta_info_flags { | |||
101 | * @dialog_token: dialog token for aggregation session | 103 | * @dialog_token: dialog token for aggregation session |
102 | * @timeout: session timeout value to be filled in ADDBA requests | 104 | * @timeout: session timeout value to be filled in ADDBA requests |
103 | * @state: session state (see above) | 105 | * @state: session state (see above) |
106 | * @last_tx: jiffies of last tx activity | ||
104 | * @stop_initiator: initiator of a session stop | 107 | * @stop_initiator: initiator of a session stop |
105 | * @tx_stop: TX DelBA frame when stopping | 108 | * @tx_stop: TX DelBA frame when stopping |
106 | * @buf_size: reorder buffer size at receiver | 109 | * @buf_size: reorder buffer size at receiver |
@@ -122,6 +125,7 @@ struct tid_ampdu_tx { | |||
122 | struct timer_list addba_resp_timer; | 125 | struct timer_list addba_resp_timer; |
123 | struct sk_buff_head pending; | 126 | struct sk_buff_head pending; |
124 | unsigned long state; | 127 | unsigned long state; |
128 | unsigned long last_tx; | ||
125 | u16 timeout; | 129 | u16 timeout; |
126 | u8 dialog_token; | 130 | u8 dialog_token; |
127 | u8 stop_initiator; | 131 | u8 stop_initiator; |
@@ -139,6 +143,7 @@ struct tid_ampdu_tx { | |||
139 | * @reorder_time: jiffies when skb was added | 143 | * @reorder_time: jiffies when skb was added |
140 | * @session_timer: check if peer keeps Tx-ing on the TID (by timeout value) | 144 | * @session_timer: check if peer keeps Tx-ing on the TID (by timeout value) |
141 | * @reorder_timer: releases expired frames from the reorder buffer. | 145 | * @reorder_timer: releases expired frames from the reorder buffer. |
146 | * @last_rx: jiffies of last rx activity | ||
142 | * @head_seq_num: head sequence number in reordering buffer. | 147 | * @head_seq_num: head sequence number in reordering buffer. |
143 | * @stored_mpdu_num: number of MPDUs in reordering buffer | 148 | * @stored_mpdu_num: number of MPDUs in reordering buffer |
144 | * @ssn: Starting Sequence Number expected to be aggregated. | 149 | * @ssn: Starting Sequence Number expected to be aggregated. |
@@ -163,6 +168,7 @@ struct tid_ampdu_rx { | |||
163 | unsigned long *reorder_time; | 168 | unsigned long *reorder_time; |
164 | struct timer_list session_timer; | 169 | struct timer_list session_timer; |
165 | struct timer_list reorder_timer; | 170 | struct timer_list reorder_timer; |
171 | unsigned long last_rx; | ||
166 | u16 head_seq_num; | 172 | u16 head_seq_num; |
167 | u16 stored_mpdu_num; | 173 | u16 stored_mpdu_num; |
168 | u16 ssn; | 174 | u16 ssn; |
@@ -264,6 +270,7 @@ struct sta_ampdu_mlme { | |||
264 | * @plink_timeout: timeout of peer link | 270 | * @plink_timeout: timeout of peer link |
265 | * @plink_timer: peer link watch timer | 271 | * @plink_timer: peer link watch timer |
266 | * @plink_timer_was_running: used by suspend/resume to restore timers | 272 | * @plink_timer_was_running: used by suspend/resume to restore timers |
273 | * @t_offset: timing offset relative to this host | ||
267 | * @debugfs: debug filesystem info | 274 | * @debugfs: debug filesystem info |
268 | * @dead: set to true when sta is unlinked | 275 | * @dead: set to true when sta is unlinked |
269 | * @uploaded: set to true when sta is uploaded to the driver | 276 | * @uploaded: set to true when sta is uploaded to the driver |
@@ -353,6 +360,8 @@ struct sta_info { | |||
353 | enum nl80211_plink_state plink_state; | 360 | enum nl80211_plink_state plink_state; |
354 | u32 plink_timeout; | 361 | u32 plink_timeout; |
355 | struct timer_list plink_timer; | 362 | struct timer_list plink_timer; |
363 | s64 t_offset; | ||
364 | s64 t_offset_setpoint; | ||
356 | #endif | 365 | #endif |
357 | 366 | ||
358 | #ifdef CONFIG_MAC80211_DEBUGFS | 367 | #ifdef CONFIG_MAC80211_DEBUGFS |
@@ -365,6 +374,8 @@ struct sta_info { | |||
365 | unsigned int lost_packets; | 374 | unsigned int lost_packets; |
366 | unsigned int beacon_loss_count; | 375 | unsigned int beacon_loss_count; |
367 | 376 | ||
377 | bool supports_40mhz; | ||
378 | |||
368 | /* keep last! */ | 379 | /* keep last! */ |
369 | struct ieee80211_sta sta; | 380 | struct ieee80211_sta sta; |
370 | }; | 381 | }; |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 782a60198df4..4f6aac16ac3a 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -230,9 +230,9 @@ ieee80211_tx_h_dynamic_ps(struct ieee80211_tx_data *tx) | |||
230 | * changed via debugfs, user needs to reassociate manually to have | 230 | * changed via debugfs, user needs to reassociate manually to have |
231 | * everything in sync. | 231 | * everything in sync. |
232 | */ | 232 | */ |
233 | if ((ifmgd->flags & IEEE80211_STA_UAPSD_ENABLED) | 233 | if ((ifmgd->flags & IEEE80211_STA_UAPSD_ENABLED) && |
234 | && (ifmgd->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO) | 234 | (ifmgd->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO) && |
235 | && skb_get_queue_mapping(tx->skb) == 0) | 235 | skb_get_queue_mapping(tx->skb) == IEEE80211_AC_VO) |
236 | return TX_CONTINUE; | 236 | return TX_CONTINUE; |
237 | 237 | ||
238 | if (local->hw.conf.flags & IEEE80211_CONF_PS) { | 238 | if (local->hw.conf.flags & IEEE80211_CONF_PS) { |
@@ -400,6 +400,8 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx) | |||
400 | return TX_CONTINUE; | 400 | return TX_CONTINUE; |
401 | 401 | ||
402 | info->flags |= IEEE80211_TX_CTL_SEND_AFTER_DTIM; | 402 | info->flags |= IEEE80211_TX_CTL_SEND_AFTER_DTIM; |
403 | if (tx->local->hw.flags & IEEE80211_HW_QUEUE_CONTROL) | ||
404 | info->hw_queue = tx->sdata->vif.cab_queue; | ||
403 | 405 | ||
404 | /* device releases frame after DTIM beacon */ | 406 | /* device releases frame after DTIM beacon */ |
405 | if (!(tx->local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING)) | 407 | if (!(tx->local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING)) |
@@ -1118,8 +1120,7 @@ static bool ieee80211_tx_prep_agg(struct ieee80211_tx_data *tx, | |||
1118 | 1120 | ||
1119 | /* reset session timer */ | 1121 | /* reset session timer */ |
1120 | if (reset_agg_timer && tid_tx->timeout) | 1122 | if (reset_agg_timer && tid_tx->timeout) |
1121 | mod_timer(&tid_tx->session_timer, | 1123 | tid_tx->last_tx = jiffies; |
1122 | TU_TO_EXP_TIME(tid_tx->timeout)); | ||
1123 | 1124 | ||
1124 | return queued; | 1125 | return queued; |
1125 | } | 1126 | } |
@@ -1215,11 +1216,19 @@ static bool ieee80211_tx_frags(struct ieee80211_local *local, | |||
1215 | bool txpending) | 1216 | bool txpending) |
1216 | { | 1217 | { |
1217 | struct sk_buff *skb, *tmp; | 1218 | struct sk_buff *skb, *tmp; |
1218 | struct ieee80211_tx_info *info; | ||
1219 | unsigned long flags; | 1219 | unsigned long flags; |
1220 | 1220 | ||
1221 | skb_queue_walk_safe(skbs, skb, tmp) { | 1221 | skb_queue_walk_safe(skbs, skb, tmp) { |
1222 | int q = skb_get_queue_mapping(skb); | 1222 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
1223 | int q = info->hw_queue; | ||
1224 | |||
1225 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | ||
1226 | if (WARN_ON_ONCE(q >= local->hw.queues)) { | ||
1227 | __skb_unlink(skb, skbs); | ||
1228 | dev_kfree_skb(skb); | ||
1229 | continue; | ||
1230 | } | ||
1231 | #endif | ||
1223 | 1232 | ||
1224 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); | 1233 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); |
1225 | if (local->queue_stop_reasons[q] || | 1234 | if (local->queue_stop_reasons[q] || |
@@ -1241,7 +1250,6 @@ static bool ieee80211_tx_frags(struct ieee80211_local *local, | |||
1241 | } | 1250 | } |
1242 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | 1251 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); |
1243 | 1252 | ||
1244 | info = IEEE80211_SKB_CB(skb); | ||
1245 | info->control.vif = vif; | 1253 | info->control.vif = vif; |
1246 | info->control.sta = sta; | 1254 | info->control.sta = sta; |
1247 | 1255 | ||
@@ -1284,8 +1292,16 @@ static bool __ieee80211_tx(struct ieee80211_local *local, | |||
1284 | 1292 | ||
1285 | switch (sdata->vif.type) { | 1293 | switch (sdata->vif.type) { |
1286 | case NL80211_IFTYPE_MONITOR: | 1294 | case NL80211_IFTYPE_MONITOR: |
1287 | sdata = NULL; | 1295 | sdata = rcu_dereference(local->monitor_sdata); |
1288 | vif = NULL; | 1296 | if (sdata) { |
1297 | vif = &sdata->vif; | ||
1298 | info->hw_queue = | ||
1299 | vif->hw_queue[skb_get_queue_mapping(skb)]; | ||
1300 | } else if (local->hw.flags & IEEE80211_HW_QUEUE_CONTROL) { | ||
1301 | dev_kfree_skb(skb); | ||
1302 | return true; | ||
1303 | } else | ||
1304 | vif = NULL; | ||
1289 | break; | 1305 | break; |
1290 | case NL80211_IFTYPE_AP_VLAN: | 1306 | case NL80211_IFTYPE_AP_VLAN: |
1291 | sdata = container_of(sdata->bss, | 1307 | sdata = container_of(sdata->bss, |
@@ -1400,6 +1416,12 @@ static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata, | |||
1400 | tx.channel = local->hw.conf.channel; | 1416 | tx.channel = local->hw.conf.channel; |
1401 | info->band = tx.channel->band; | 1417 | info->band = tx.channel->band; |
1402 | 1418 | ||
1419 | /* set up hw_queue value early */ | ||
1420 | if (!(info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) || | ||
1421 | !(local->hw.flags & IEEE80211_HW_QUEUE_CONTROL)) | ||
1422 | info->hw_queue = | ||
1423 | sdata->vif.hw_queue[skb_get_queue_mapping(skb)]; | ||
1424 | |||
1403 | if (!invoke_tx_handlers(&tx)) | 1425 | if (!invoke_tx_handlers(&tx)) |
1404 | result = __ieee80211_tx(local, &tx.skbs, led_len, | 1426 | result = __ieee80211_tx(local, &tx.skbs, led_len, |
1405 | tx.sta, txpending); | 1427 | tx.sta, txpending); |
@@ -1468,12 +1490,12 @@ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) | |||
1468 | 1490 | ||
1469 | if (ieee80211_vif_is_mesh(&sdata->vif) && | 1491 | if (ieee80211_vif_is_mesh(&sdata->vif) && |
1470 | ieee80211_is_data(hdr->frame_control) && | 1492 | ieee80211_is_data(hdr->frame_control) && |
1471 | !is_multicast_ether_addr(hdr->addr1)) | 1493 | !is_multicast_ether_addr(hdr->addr1) && |
1472 | if (mesh_nexthop_resolve(skb, sdata)) { | 1494 | mesh_nexthop_resolve(skb, sdata)) { |
1473 | /* skb queued: don't free */ | 1495 | /* skb queued: don't free */ |
1474 | rcu_read_unlock(); | 1496 | rcu_read_unlock(); |
1475 | return; | 1497 | return; |
1476 | } | 1498 | } |
1477 | 1499 | ||
1478 | ieee80211_set_qos_hdr(sdata, skb); | 1500 | ieee80211_set_qos_hdr(sdata, skb); |
1479 | ieee80211_tx(sdata, skb, false); | 1501 | ieee80211_tx(sdata, skb, false); |
@@ -1929,7 +1951,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1929 | wme_sta = true; | 1951 | wme_sta = true; |
1930 | 1952 | ||
1931 | /* receiver and we are QoS enabled, use a QoS type frame */ | 1953 | /* receiver and we are QoS enabled, use a QoS type frame */ |
1932 | if (wme_sta && local->hw.queues >= 4) { | 1954 | if (wme_sta && local->hw.queues >= IEEE80211_NUM_ACS) { |
1933 | fc |= cpu_to_le16(IEEE80211_STYPE_QOS_DATA); | 1955 | fc |= cpu_to_le16(IEEE80211_STYPE_QOS_DATA); |
1934 | hdrlen += 2; | 1956 | hdrlen += 2; |
1935 | } | 1957 | } |
@@ -2170,7 +2192,6 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local, | |||
2170 | void ieee80211_tx_pending(unsigned long data) | 2192 | void ieee80211_tx_pending(unsigned long data) |
2171 | { | 2193 | { |
2172 | struct ieee80211_local *local = (struct ieee80211_local *)data; | 2194 | struct ieee80211_local *local = (struct ieee80211_local *)data; |
2173 | struct ieee80211_sub_if_data *sdata; | ||
2174 | unsigned long flags; | 2195 | unsigned long flags; |
2175 | int i; | 2196 | int i; |
2176 | bool txok; | 2197 | bool txok; |
@@ -2207,8 +2228,7 @@ void ieee80211_tx_pending(unsigned long data) | |||
2207 | } | 2228 | } |
2208 | 2229 | ||
2209 | if (skb_queue_empty(&local->pending[i])) | 2230 | if (skb_queue_empty(&local->pending[i])) |
2210 | list_for_each_entry_rcu(sdata, &local->interfaces, list) | 2231 | ieee80211_propagate_queue_wake(local, i); |
2211 | netif_wake_subqueue(sdata->dev, i); | ||
2212 | } | 2232 | } |
2213 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | 2233 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); |
2214 | 2234 | ||
@@ -2374,6 +2394,7 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, | |||
2374 | IEEE80211_STYPE_BEACON); | 2394 | IEEE80211_STYPE_BEACON); |
2375 | } else if (ieee80211_vif_is_mesh(&sdata->vif)) { | 2395 | } else if (ieee80211_vif_is_mesh(&sdata->vif)) { |
2376 | struct ieee80211_mgmt *mgmt; | 2396 | struct ieee80211_mgmt *mgmt; |
2397 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||
2377 | u8 *pos; | 2398 | u8 *pos; |
2378 | int hdr_len = offsetof(struct ieee80211_mgmt, u.beacon) + | 2399 | int hdr_len = offsetof(struct ieee80211_mgmt, u.beacon) + |
2379 | sizeof(mgmt->u.beacon); | 2400 | sizeof(mgmt->u.beacon); |
@@ -2383,6 +2404,10 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, | |||
2383 | goto out; | 2404 | goto out; |
2384 | #endif | 2405 | #endif |
2385 | 2406 | ||
2407 | if (ifmsh->sync_ops) | ||
2408 | ifmsh->sync_ops->adjust_tbtt( | ||
2409 | sdata); | ||
2410 | |||
2386 | skb = dev_alloc_skb(local->tx_headroom + | 2411 | skb = dev_alloc_skb(local->tx_headroom + |
2387 | hdr_len + | 2412 | hdr_len + |
2388 | 2 + /* NULL SSID */ | 2413 | 2 + /* NULL SSID */ |
@@ -2390,7 +2415,7 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, | |||
2390 | 2 + 3 + /* DS params */ | 2415 | 2 + 3 + /* DS params */ |
2391 | 2 + (IEEE80211_MAX_SUPP_RATES - 8) + | 2416 | 2 + (IEEE80211_MAX_SUPP_RATES - 8) + |
2392 | 2 + sizeof(struct ieee80211_ht_cap) + | 2417 | 2 + sizeof(struct ieee80211_ht_cap) + |
2393 | 2 + sizeof(struct ieee80211_ht_info) + | 2418 | 2 + sizeof(struct ieee80211_ht_operation) + |
2394 | 2 + sdata->u.mesh.mesh_id_len + | 2419 | 2 + sdata->u.mesh.mesh_id_len + |
2395 | 2 + sizeof(struct ieee80211_meshconf_ie) + | 2420 | 2 + sizeof(struct ieee80211_meshconf_ie) + |
2396 | sdata->u.mesh.ie_len); | 2421 | sdata->u.mesh.ie_len); |
@@ -2414,12 +2439,12 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, | |||
2414 | *pos++ = WLAN_EID_SSID; | 2439 | *pos++ = WLAN_EID_SSID; |
2415 | *pos++ = 0x0; | 2440 | *pos++ = 0x0; |
2416 | 2441 | ||
2417 | if (ieee80211_add_srates_ie(&sdata->vif, skb) || | 2442 | if (ieee80211_add_srates_ie(&sdata->vif, skb, true) || |
2418 | mesh_add_ds_params_ie(skb, sdata) || | 2443 | mesh_add_ds_params_ie(skb, sdata) || |
2419 | ieee80211_add_ext_srates_ie(&sdata->vif, skb) || | 2444 | ieee80211_add_ext_srates_ie(&sdata->vif, skb, true) || |
2420 | mesh_add_rsn_ie(skb, sdata) || | 2445 | mesh_add_rsn_ie(skb, sdata) || |
2421 | mesh_add_ht_cap_ie(skb, sdata) || | 2446 | mesh_add_ht_cap_ie(skb, sdata) || |
2422 | mesh_add_ht_info_ie(skb, sdata) || | 2447 | mesh_add_ht_oper_ie(skb, sdata) || |
2423 | mesh_add_meshid_ie(skb, sdata) || | 2448 | mesh_add_meshid_ie(skb, sdata) || |
2424 | mesh_add_meshconf_ie(skb, sdata) || | 2449 | mesh_add_meshconf_ie(skb, sdata) || |
2425 | mesh_add_vendor_ies(skb, sdata)) { | 2450 | mesh_add_vendor_ies(skb, sdata)) { |
@@ -2603,7 +2628,7 @@ struct sk_buff *ieee80211_probereq_get(struct ieee80211_hw *hw, | |||
2603 | pos = skb_put(skb, ie_ssid_len); | 2628 | pos = skb_put(skb, ie_ssid_len); |
2604 | *pos++ = WLAN_EID_SSID; | 2629 | *pos++ = WLAN_EID_SSID; |
2605 | *pos++ = ssid_len; | 2630 | *pos++ = ssid_len; |
2606 | if (ssid) | 2631 | if (ssid_len) |
2607 | memcpy(pos, ssid, ssid_len); | 2632 | memcpy(pos, ssid, ssid_len); |
2608 | pos += ssid_len; | 2633 | pos += ssid_len; |
2609 | 2634 | ||
@@ -2710,11 +2735,13 @@ EXPORT_SYMBOL(ieee80211_get_buffered_bc); | |||
2710 | void ieee80211_tx_skb_tid(struct ieee80211_sub_if_data *sdata, | 2735 | void ieee80211_tx_skb_tid(struct ieee80211_sub_if_data *sdata, |
2711 | struct sk_buff *skb, int tid) | 2736 | struct sk_buff *skb, int tid) |
2712 | { | 2737 | { |
2738 | int ac = ieee802_1d_to_ac[tid]; | ||
2739 | |||
2713 | skb_set_mac_header(skb, 0); | 2740 | skb_set_mac_header(skb, 0); |
2714 | skb_set_network_header(skb, 0); | 2741 | skb_set_network_header(skb, 0); |
2715 | skb_set_transport_header(skb, 0); | 2742 | skb_set_transport_header(skb, 0); |
2716 | 2743 | ||
2717 | skb_set_queue_mapping(skb, ieee802_1d_to_ac[tid]); | 2744 | skb_set_queue_mapping(skb, ac); |
2718 | skb->priority = tid; | 2745 | skb->priority = tid; |
2719 | 2746 | ||
2720 | /* | 2747 | /* |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 32f7a3b3d43c..e67fe5c1def9 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -265,17 +265,45 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, | |||
265 | } | 265 | } |
266 | EXPORT_SYMBOL(ieee80211_ctstoself_duration); | 266 | EXPORT_SYMBOL(ieee80211_ctstoself_duration); |
267 | 267 | ||
268 | void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue) | ||
269 | { | ||
270 | struct ieee80211_sub_if_data *sdata; | ||
271 | |||
272 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { | ||
273 | int ac; | ||
274 | |||
275 | if (test_bit(SDATA_STATE_OFFCHANNEL, &sdata->state)) | ||
276 | continue; | ||
277 | |||
278 | if (sdata->vif.cab_queue != IEEE80211_INVAL_HW_QUEUE && | ||
279 | local->queue_stop_reasons[sdata->vif.cab_queue] != 0) | ||
280 | continue; | ||
281 | |||
282 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { | ||
283 | int ac_queue = sdata->vif.hw_queue[ac]; | ||
284 | |||
285 | if (ac_queue == queue || | ||
286 | (sdata->vif.cab_queue == queue && | ||
287 | local->queue_stop_reasons[ac_queue] == 0 && | ||
288 | skb_queue_empty(&local->pending[ac_queue]))) | ||
289 | netif_wake_subqueue(sdata->dev, ac); | ||
290 | } | ||
291 | } | ||
292 | } | ||
293 | |||
268 | static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue, | 294 | static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue, |
269 | enum queue_stop_reason reason) | 295 | enum queue_stop_reason reason) |
270 | { | 296 | { |
271 | struct ieee80211_local *local = hw_to_local(hw); | 297 | struct ieee80211_local *local = hw_to_local(hw); |
272 | struct ieee80211_sub_if_data *sdata; | ||
273 | 298 | ||
274 | trace_wake_queue(local, queue, reason); | 299 | trace_wake_queue(local, queue, reason); |
275 | 300 | ||
276 | if (WARN_ON(queue >= hw->queues)) | 301 | if (WARN_ON(queue >= hw->queues)) |
277 | return; | 302 | return; |
278 | 303 | ||
304 | if (!test_bit(reason, &local->queue_stop_reasons[queue])) | ||
305 | return; | ||
306 | |||
279 | __clear_bit(reason, &local->queue_stop_reasons[queue]); | 307 | __clear_bit(reason, &local->queue_stop_reasons[queue]); |
280 | 308 | ||
281 | if (local->queue_stop_reasons[queue] != 0) | 309 | if (local->queue_stop_reasons[queue] != 0) |
@@ -284,11 +312,7 @@ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue, | |||
284 | 312 | ||
285 | if (skb_queue_empty(&local->pending[queue])) { | 313 | if (skb_queue_empty(&local->pending[queue])) { |
286 | rcu_read_lock(); | 314 | rcu_read_lock(); |
287 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { | 315 | ieee80211_propagate_queue_wake(local, queue); |
288 | if (test_bit(SDATA_STATE_OFFCHANNEL, &sdata->state)) | ||
289 | continue; | ||
290 | netif_wake_subqueue(sdata->dev, queue); | ||
291 | } | ||
292 | rcu_read_unlock(); | 316 | rcu_read_unlock(); |
293 | } else | 317 | } else |
294 | tasklet_schedule(&local->tx_pending_tasklet); | 318 | tasklet_schedule(&local->tx_pending_tasklet); |
@@ -323,11 +347,21 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue, | |||
323 | if (WARN_ON(queue >= hw->queues)) | 347 | if (WARN_ON(queue >= hw->queues)) |
324 | return; | 348 | return; |
325 | 349 | ||
350 | if (test_bit(reason, &local->queue_stop_reasons[queue])) | ||
351 | return; | ||
352 | |||
326 | __set_bit(reason, &local->queue_stop_reasons[queue]); | 353 | __set_bit(reason, &local->queue_stop_reasons[queue]); |
327 | 354 | ||
328 | rcu_read_lock(); | 355 | rcu_read_lock(); |
329 | list_for_each_entry_rcu(sdata, &local->interfaces, list) | 356 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { |
330 | netif_stop_subqueue(sdata->dev, queue); | 357 | int ac; |
358 | |||
359 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { | ||
360 | if (sdata->vif.hw_queue[ac] == queue || | ||
361 | sdata->vif.cab_queue == queue) | ||
362 | netif_stop_subqueue(sdata->dev, ac); | ||
363 | } | ||
364 | } | ||
331 | rcu_read_unlock(); | 365 | rcu_read_unlock(); |
332 | } | 366 | } |
333 | 367 | ||
@@ -354,8 +388,8 @@ void ieee80211_add_pending_skb(struct ieee80211_local *local, | |||
354 | { | 388 | { |
355 | struct ieee80211_hw *hw = &local->hw; | 389 | struct ieee80211_hw *hw = &local->hw; |
356 | unsigned long flags; | 390 | unsigned long flags; |
357 | int queue = skb_get_queue_mapping(skb); | ||
358 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 391 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
392 | int queue = info->hw_queue; | ||
359 | 393 | ||
360 | if (WARN_ON(!info->control.vif)) { | 394 | if (WARN_ON(!info->control.vif)) { |
361 | kfree_skb(skb); | 395 | kfree_skb(skb); |
@@ -379,10 +413,6 @@ void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local, | |||
379 | int queue, i; | 413 | int queue, i; |
380 | 414 | ||
381 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); | 415 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); |
382 | for (i = 0; i < hw->queues; i++) | ||
383 | __ieee80211_stop_queue(hw, i, | ||
384 | IEEE80211_QUEUE_STOP_REASON_SKB_ADD); | ||
385 | |||
386 | while ((skb = skb_dequeue(skbs))) { | 416 | while ((skb = skb_dequeue(skbs))) { |
387 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 417 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
388 | 418 | ||
@@ -391,7 +421,11 @@ void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local, | |||
391 | continue; | 421 | continue; |
392 | } | 422 | } |
393 | 423 | ||
394 | queue = skb_get_queue_mapping(skb); | 424 | queue = info->hw_queue; |
425 | |||
426 | __ieee80211_stop_queue(hw, queue, | ||
427 | IEEE80211_QUEUE_STOP_REASON_SKB_ADD); | ||
428 | |||
395 | __skb_queue_tail(&local->pending[queue], skb); | 429 | __skb_queue_tail(&local->pending[queue], skb); |
396 | } | 430 | } |
397 | 431 | ||
@@ -404,12 +438,6 @@ void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local, | |||
404 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | 438 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); |
405 | } | 439 | } |
406 | 440 | ||
407 | void ieee80211_add_pending_skbs(struct ieee80211_local *local, | ||
408 | struct sk_buff_head *skbs) | ||
409 | { | ||
410 | ieee80211_add_pending_skbs_fn(local, skbs, NULL, NULL); | ||
411 | } | ||
412 | |||
413 | void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw, | 441 | void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw, |
414 | enum queue_stop_reason reason) | 442 | enum queue_stop_reason reason) |
415 | { | 443 | { |
@@ -684,9 +712,9 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, | |||
684 | else | 712 | else |
685 | elem_parse_failed = true; | 713 | elem_parse_failed = true; |
686 | break; | 714 | break; |
687 | case WLAN_EID_HT_INFORMATION: | 715 | case WLAN_EID_HT_OPERATION: |
688 | if (elen >= sizeof(struct ieee80211_ht_info)) | 716 | if (elen >= sizeof(struct ieee80211_ht_operation)) |
689 | elems->ht_info_elem = (void *)pos; | 717 | elems->ht_operation = (void *)pos; |
690 | else | 718 | else |
691 | elem_parse_failed = true; | 719 | elem_parse_failed = true; |
692 | break; | 720 | break; |
@@ -775,19 +803,22 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata, | |||
775 | { | 803 | { |
776 | struct ieee80211_local *local = sdata->local; | 804 | struct ieee80211_local *local = sdata->local; |
777 | struct ieee80211_tx_queue_params qparam; | 805 | struct ieee80211_tx_queue_params qparam; |
778 | int queue; | 806 | int ac; |
779 | bool use_11b; | 807 | bool use_11b; |
780 | int aCWmin, aCWmax; | 808 | int aCWmin, aCWmax; |
781 | 809 | ||
782 | if (!local->ops->conf_tx) | 810 | if (!local->ops->conf_tx) |
783 | return; | 811 | return; |
784 | 812 | ||
813 | if (local->hw.queues < IEEE80211_NUM_ACS) | ||
814 | return; | ||
815 | |||
785 | memset(&qparam, 0, sizeof(qparam)); | 816 | memset(&qparam, 0, sizeof(qparam)); |
786 | 817 | ||
787 | use_11b = (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ) && | 818 | use_11b = (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ) && |
788 | !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE); | 819 | !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE); |
789 | 820 | ||
790 | for (queue = 0; queue < local->hw.queues; queue++) { | 821 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { |
791 | /* Set defaults according to 802.11-2007 Table 7-37 */ | 822 | /* Set defaults according to 802.11-2007 Table 7-37 */ |
792 | aCWmax = 1023; | 823 | aCWmax = 1023; |
793 | if (use_11b) | 824 | if (use_11b) |
@@ -795,21 +826,21 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata, | |||
795 | else | 826 | else |
796 | aCWmin = 15; | 827 | aCWmin = 15; |
797 | 828 | ||
798 | switch (queue) { | 829 | switch (ac) { |
799 | case 3: /* AC_BK */ | 830 | case IEEE80211_AC_BK: |
800 | qparam.cw_max = aCWmax; | 831 | qparam.cw_max = aCWmax; |
801 | qparam.cw_min = aCWmin; | 832 | qparam.cw_min = aCWmin; |
802 | qparam.txop = 0; | 833 | qparam.txop = 0; |
803 | qparam.aifs = 7; | 834 | qparam.aifs = 7; |
804 | break; | 835 | break; |
805 | default: /* never happens but let's not leave undefined */ | 836 | default: /* never happens but let's not leave undefined */ |
806 | case 2: /* AC_BE */ | 837 | case IEEE80211_AC_BE: |
807 | qparam.cw_max = aCWmax; | 838 | qparam.cw_max = aCWmax; |
808 | qparam.cw_min = aCWmin; | 839 | qparam.cw_min = aCWmin; |
809 | qparam.txop = 0; | 840 | qparam.txop = 0; |
810 | qparam.aifs = 3; | 841 | qparam.aifs = 3; |
811 | break; | 842 | break; |
812 | case 1: /* AC_VI */ | 843 | case IEEE80211_AC_VI: |
813 | qparam.cw_max = aCWmin; | 844 | qparam.cw_max = aCWmin; |
814 | qparam.cw_min = (aCWmin + 1) / 2 - 1; | 845 | qparam.cw_min = (aCWmin + 1) / 2 - 1; |
815 | if (use_11b) | 846 | if (use_11b) |
@@ -818,7 +849,7 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata, | |||
818 | qparam.txop = 3008/32; | 849 | qparam.txop = 3008/32; |
819 | qparam.aifs = 2; | 850 | qparam.aifs = 2; |
820 | break; | 851 | break; |
821 | case 0: /* AC_VO */ | 852 | case IEEE80211_AC_VO: |
822 | qparam.cw_max = (aCWmin + 1) / 2 - 1; | 853 | qparam.cw_max = (aCWmin + 1) / 2 - 1; |
823 | qparam.cw_min = (aCWmin + 1) / 4 - 1; | 854 | qparam.cw_min = (aCWmin + 1) / 4 - 1; |
824 | if (use_11b) | 855 | if (use_11b) |
@@ -831,8 +862,8 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata, | |||
831 | 862 | ||
832 | qparam.uapsd = false; | 863 | qparam.uapsd = false; |
833 | 864 | ||
834 | sdata->tx_conf[queue] = qparam; | 865 | sdata->tx_conf[ac] = qparam; |
835 | drv_conf_tx(local, sdata, queue, &qparam); | 866 | drv_conf_tx(local, sdata, ac, &qparam); |
836 | } | 867 | } |
837 | 868 | ||
838 | /* after reinitialize QoS TX queues setting to default, | 869 | /* after reinitialize QoS TX queues setting to default, |
@@ -1106,7 +1137,7 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | |||
1106 | 1137 | ||
1107 | u32 ieee80211_sta_get_rates(struct ieee80211_local *local, | 1138 | u32 ieee80211_sta_get_rates(struct ieee80211_local *local, |
1108 | struct ieee802_11_elems *elems, | 1139 | struct ieee802_11_elems *elems, |
1109 | enum ieee80211_band band) | 1140 | enum ieee80211_band band, u32 *basic_rates) |
1110 | { | 1141 | { |
1111 | struct ieee80211_supported_band *sband; | 1142 | struct ieee80211_supported_band *sband; |
1112 | struct ieee80211_rate *bitrates; | 1143 | struct ieee80211_rate *bitrates; |
@@ -1127,15 +1158,25 @@ u32 ieee80211_sta_get_rates(struct ieee80211_local *local, | |||
1127 | elems->ext_supp_rates_len; i++) { | 1158 | elems->ext_supp_rates_len; i++) { |
1128 | u8 rate = 0; | 1159 | u8 rate = 0; |
1129 | int own_rate; | 1160 | int own_rate; |
1161 | bool is_basic; | ||
1130 | if (i < elems->supp_rates_len) | 1162 | if (i < elems->supp_rates_len) |
1131 | rate = elems->supp_rates[i]; | 1163 | rate = elems->supp_rates[i]; |
1132 | else if (elems->ext_supp_rates) | 1164 | else if (elems->ext_supp_rates) |
1133 | rate = elems->ext_supp_rates | 1165 | rate = elems->ext_supp_rates |
1134 | [i - elems->supp_rates_len]; | 1166 | [i - elems->supp_rates_len]; |
1135 | own_rate = 5 * (rate & 0x7f); | 1167 | own_rate = 5 * (rate & 0x7f); |
1136 | for (j = 0; j < num_rates; j++) | 1168 | is_basic = !!(rate & 0x80); |
1137 | if (bitrates[j].bitrate == own_rate) | 1169 | |
1170 | if (is_basic && (rate & 0x7f) == BSS_MEMBERSHIP_SELECTOR_HT_PHY) | ||
1171 | continue; | ||
1172 | |||
1173 | for (j = 0; j < num_rates; j++) { | ||
1174 | if (bitrates[j].bitrate == own_rate) { | ||
1138 | supp_rates |= BIT(j); | 1175 | supp_rates |= BIT(j); |
1176 | if (basic_rates && is_basic) | ||
1177 | *basic_rates |= BIT(j); | ||
1178 | } | ||
1179 | } | ||
1139 | } | 1180 | } |
1140 | return supp_rates; | 1181 | return supp_rates; |
1141 | } | 1182 | } |
@@ -1210,6 +1251,16 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1210 | IEEE80211_TPT_LEDTRIG_FL_RADIO, 0); | 1251 | IEEE80211_TPT_LEDTRIG_FL_RADIO, 0); |
1211 | 1252 | ||
1212 | /* add interfaces */ | 1253 | /* add interfaces */ |
1254 | sdata = rtnl_dereference(local->monitor_sdata); | ||
1255 | if (sdata) { | ||
1256 | res = drv_add_interface(local, sdata); | ||
1257 | if (WARN_ON(res)) { | ||
1258 | rcu_assign_pointer(local->monitor_sdata, NULL); | ||
1259 | synchronize_net(); | ||
1260 | kfree(sdata); | ||
1261 | } | ||
1262 | } | ||
1263 | |||
1213 | list_for_each_entry(sdata, &local->interfaces, list) { | 1264 | list_for_each_entry(sdata, &local->interfaces, list) { |
1214 | if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN && | 1265 | if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN && |
1215 | sdata->vif.type != NL80211_IFTYPE_MONITOR && | 1266 | sdata->vif.type != NL80211_IFTYPE_MONITOR && |
@@ -1232,14 +1283,17 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1232 | mutex_unlock(&local->sta_mtx); | 1283 | mutex_unlock(&local->sta_mtx); |
1233 | 1284 | ||
1234 | /* reconfigure tx conf */ | 1285 | /* reconfigure tx conf */ |
1235 | list_for_each_entry(sdata, &local->interfaces, list) { | 1286 | if (hw->queues >= IEEE80211_NUM_ACS) { |
1236 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN || | 1287 | list_for_each_entry(sdata, &local->interfaces, list) { |
1237 | sdata->vif.type == NL80211_IFTYPE_MONITOR || | 1288 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN || |
1238 | !ieee80211_sdata_running(sdata)) | 1289 | sdata->vif.type == NL80211_IFTYPE_MONITOR || |
1239 | continue; | 1290 | !ieee80211_sdata_running(sdata)) |
1291 | continue; | ||
1240 | 1292 | ||
1241 | for (i = 0; i < hw->queues; i++) | 1293 | for (i = 0; i < IEEE80211_NUM_ACS; i++) |
1242 | drv_conf_tx(local, sdata, i, &sdata->tx_conf[i]); | 1294 | drv_conf_tx(local, sdata, i, |
1295 | &sdata->tx_conf[i]); | ||
1296 | } | ||
1243 | } | 1297 | } |
1244 | 1298 | ||
1245 | /* reconfigure hardware */ | 1299 | /* reconfigure hardware */ |
@@ -1611,57 +1665,56 @@ u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, | |||
1611 | return pos; | 1665 | return pos; |
1612 | } | 1666 | } |
1613 | 1667 | ||
1614 | u8 *ieee80211_ie_build_ht_info(u8 *pos, | 1668 | u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, |
1615 | struct ieee80211_sta_ht_cap *ht_cap, | ||
1616 | struct ieee80211_channel *channel, | 1669 | struct ieee80211_channel *channel, |
1617 | enum nl80211_channel_type channel_type) | 1670 | enum nl80211_channel_type channel_type) |
1618 | { | 1671 | { |
1619 | struct ieee80211_ht_info *ht_info; | 1672 | struct ieee80211_ht_operation *ht_oper; |
1620 | /* Build HT Information */ | 1673 | /* Build HT Information */ |
1621 | *pos++ = WLAN_EID_HT_INFORMATION; | 1674 | *pos++ = WLAN_EID_HT_OPERATION; |
1622 | *pos++ = sizeof(struct ieee80211_ht_info); | 1675 | *pos++ = sizeof(struct ieee80211_ht_operation); |
1623 | ht_info = (struct ieee80211_ht_info *)pos; | 1676 | ht_oper = (struct ieee80211_ht_operation *)pos; |
1624 | ht_info->control_chan = | 1677 | ht_oper->primary_chan = |
1625 | ieee80211_frequency_to_channel(channel->center_freq); | 1678 | ieee80211_frequency_to_channel(channel->center_freq); |
1626 | switch (channel_type) { | 1679 | switch (channel_type) { |
1627 | case NL80211_CHAN_HT40MINUS: | 1680 | case NL80211_CHAN_HT40MINUS: |
1628 | ht_info->ht_param = IEEE80211_HT_PARAM_CHA_SEC_BELOW; | 1681 | ht_oper->ht_param = IEEE80211_HT_PARAM_CHA_SEC_BELOW; |
1629 | break; | 1682 | break; |
1630 | case NL80211_CHAN_HT40PLUS: | 1683 | case NL80211_CHAN_HT40PLUS: |
1631 | ht_info->ht_param = IEEE80211_HT_PARAM_CHA_SEC_ABOVE; | 1684 | ht_oper->ht_param = IEEE80211_HT_PARAM_CHA_SEC_ABOVE; |
1632 | break; | 1685 | break; |
1633 | case NL80211_CHAN_HT20: | 1686 | case NL80211_CHAN_HT20: |
1634 | default: | 1687 | default: |
1635 | ht_info->ht_param = IEEE80211_HT_PARAM_CHA_SEC_NONE; | 1688 | ht_oper->ht_param = IEEE80211_HT_PARAM_CHA_SEC_NONE; |
1636 | break; | 1689 | break; |
1637 | } | 1690 | } |
1638 | if (ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) | 1691 | if (ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) |
1639 | ht_info->ht_param |= IEEE80211_HT_PARAM_CHAN_WIDTH_ANY; | 1692 | ht_oper->ht_param |= IEEE80211_HT_PARAM_CHAN_WIDTH_ANY; |
1640 | 1693 | ||
1641 | /* | 1694 | /* |
1642 | * Note: According to 802.11n-2009 9.13.3.1, HT Protection field and | 1695 | * Note: According to 802.11n-2009 9.13.3.1, HT Protection field and |
1643 | * RIFS Mode are reserved in IBSS mode, therefore keep them at 0 | 1696 | * RIFS Mode are reserved in IBSS mode, therefore keep them at 0 |
1644 | */ | 1697 | */ |
1645 | ht_info->operation_mode = 0x0000; | 1698 | ht_oper->operation_mode = 0x0000; |
1646 | ht_info->stbc_param = 0x0000; | 1699 | ht_oper->stbc_param = 0x0000; |
1647 | 1700 | ||
1648 | /* It seems that Basic MCS set and Supported MCS set | 1701 | /* It seems that Basic MCS set and Supported MCS set |
1649 | are identical for the first 10 bytes */ | 1702 | are identical for the first 10 bytes */ |
1650 | memset(&ht_info->basic_set, 0, 16); | 1703 | memset(&ht_oper->basic_set, 0, 16); |
1651 | memcpy(&ht_info->basic_set, &ht_cap->mcs, 10); | 1704 | memcpy(&ht_oper->basic_set, &ht_cap->mcs, 10); |
1652 | 1705 | ||
1653 | return pos + sizeof(struct ieee80211_ht_info); | 1706 | return pos + sizeof(struct ieee80211_ht_operation); |
1654 | } | 1707 | } |
1655 | 1708 | ||
1656 | enum nl80211_channel_type | 1709 | enum nl80211_channel_type |
1657 | ieee80211_ht_info_to_channel_type(struct ieee80211_ht_info *ht_info) | 1710 | ieee80211_ht_oper_to_channel_type(struct ieee80211_ht_operation *ht_oper) |
1658 | { | 1711 | { |
1659 | enum nl80211_channel_type channel_type; | 1712 | enum nl80211_channel_type channel_type; |
1660 | 1713 | ||
1661 | if (!ht_info) | 1714 | if (!ht_oper) |
1662 | return NL80211_CHAN_NO_HT; | 1715 | return NL80211_CHAN_NO_HT; |
1663 | 1716 | ||
1664 | switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { | 1717 | switch (ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { |
1665 | case IEEE80211_HT_PARAM_CHA_SEC_NONE: | 1718 | case IEEE80211_HT_PARAM_CHA_SEC_NONE: |
1666 | channel_type = NL80211_CHAN_HT20; | 1719 | channel_type = NL80211_CHAN_HT20; |
1667 | break; | 1720 | break; |
@@ -1678,13 +1731,15 @@ ieee80211_ht_info_to_channel_type(struct ieee80211_ht_info *ht_info) | |||
1678 | return channel_type; | 1731 | return channel_type; |
1679 | } | 1732 | } |
1680 | 1733 | ||
1681 | int ieee80211_add_srates_ie(struct ieee80211_vif *vif, struct sk_buff *skb) | 1734 | int ieee80211_add_srates_ie(struct ieee80211_vif *vif, |
1735 | struct sk_buff *skb, bool need_basic) | ||
1682 | { | 1736 | { |
1683 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | 1737 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); |
1684 | struct ieee80211_local *local = sdata->local; | 1738 | struct ieee80211_local *local = sdata->local; |
1685 | struct ieee80211_supported_band *sband; | 1739 | struct ieee80211_supported_band *sband; |
1686 | int rate; | 1740 | int rate; |
1687 | u8 i, rates, *pos; | 1741 | u8 i, rates, *pos; |
1742 | u32 basic_rates = vif->bss_conf.basic_rates; | ||
1688 | 1743 | ||
1689 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 1744 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; |
1690 | rates = sband->n_bitrates; | 1745 | rates = sband->n_bitrates; |
@@ -1698,20 +1753,25 @@ int ieee80211_add_srates_ie(struct ieee80211_vif *vif, struct sk_buff *skb) | |||
1698 | *pos++ = WLAN_EID_SUPP_RATES; | 1753 | *pos++ = WLAN_EID_SUPP_RATES; |
1699 | *pos++ = rates; | 1754 | *pos++ = rates; |
1700 | for (i = 0; i < rates; i++) { | 1755 | for (i = 0; i < rates; i++) { |
1756 | u8 basic = 0; | ||
1757 | if (need_basic && basic_rates & BIT(i)) | ||
1758 | basic = 0x80; | ||
1701 | rate = sband->bitrates[i].bitrate; | 1759 | rate = sband->bitrates[i].bitrate; |
1702 | *pos++ = (u8) (rate / 5); | 1760 | *pos++ = basic | (u8) (rate / 5); |
1703 | } | 1761 | } |
1704 | 1762 | ||
1705 | return 0; | 1763 | return 0; |
1706 | } | 1764 | } |
1707 | 1765 | ||
1708 | int ieee80211_add_ext_srates_ie(struct ieee80211_vif *vif, struct sk_buff *skb) | 1766 | int ieee80211_add_ext_srates_ie(struct ieee80211_vif *vif, |
1767 | struct sk_buff *skb, bool need_basic) | ||
1709 | { | 1768 | { |
1710 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | 1769 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); |
1711 | struct ieee80211_local *local = sdata->local; | 1770 | struct ieee80211_local *local = sdata->local; |
1712 | struct ieee80211_supported_band *sband; | 1771 | struct ieee80211_supported_band *sband; |
1713 | int rate; | 1772 | int rate; |
1714 | u8 i, exrates, *pos; | 1773 | u8 i, exrates, *pos; |
1774 | u32 basic_rates = vif->bss_conf.basic_rates; | ||
1715 | 1775 | ||
1716 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 1776 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; |
1717 | exrates = sband->n_bitrates; | 1777 | exrates = sband->n_bitrates; |
@@ -1728,8 +1788,11 @@ int ieee80211_add_ext_srates_ie(struct ieee80211_vif *vif, struct sk_buff *skb) | |||
1728 | *pos++ = WLAN_EID_EXT_SUPP_RATES; | 1788 | *pos++ = WLAN_EID_EXT_SUPP_RATES; |
1729 | *pos++ = exrates; | 1789 | *pos++ = exrates; |
1730 | for (i = 8; i < sband->n_bitrates; i++) { | 1790 | for (i = 8; i < sband->n_bitrates; i++) { |
1791 | u8 basic = 0; | ||
1792 | if (need_basic && basic_rates & BIT(i)) | ||
1793 | basic = 0x80; | ||
1731 | rate = sband->bitrates[i].bitrate; | 1794 | rate = sband->bitrates[i].bitrate; |
1732 | *pos++ = (u8) (rate / 5); | 1795 | *pos++ = basic | (u8) (rate / 5); |
1733 | } | 1796 | } |
1734 | } | 1797 | } |
1735 | return 0; | 1798 | return 0; |
diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index 89511be3111e..c3d643a6536c 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c | |||
@@ -52,6 +52,26 @@ static int wme_downgrade_ac(struct sk_buff *skb) | |||
52 | } | 52 | } |
53 | } | 53 | } |
54 | 54 | ||
55 | static u16 ieee80211_downgrade_queue(struct ieee80211_local *local, | ||
56 | struct sk_buff *skb) | ||
57 | { | ||
58 | /* in case we are a client verify acm is not set for this ac */ | ||
59 | while (unlikely(local->wmm_acm & BIT(skb->priority))) { | ||
60 | if (wme_downgrade_ac(skb)) { | ||
61 | /* | ||
62 | * This should not really happen. The AP has marked all | ||
63 | * lower ACs to require admission control which is not | ||
64 | * a reasonable configuration. Allow the frame to be | ||
65 | * transmitted using AC_BK as a workaround. | ||
66 | */ | ||
67 | break; | ||
68 | } | ||
69 | } | ||
70 | |||
71 | /* look up which queue to use for frames with this 1d tag */ | ||
72 | return ieee802_1d_to_ac[skb->priority]; | ||
73 | } | ||
74 | |||
55 | /* Indicate which queue to use for this fully formed 802.11 frame */ | 75 | /* Indicate which queue to use for this fully formed 802.11 frame */ |
56 | u16 ieee80211_select_queue_80211(struct ieee80211_local *local, | 76 | u16 ieee80211_select_queue_80211(struct ieee80211_local *local, |
57 | struct sk_buff *skb, | 77 | struct sk_buff *skb, |
@@ -59,7 +79,7 @@ u16 ieee80211_select_queue_80211(struct ieee80211_local *local, | |||
59 | { | 79 | { |
60 | u8 *p; | 80 | u8 *p; |
61 | 81 | ||
62 | if (local->hw.queues < 4) | 82 | if (local->hw.queues < IEEE80211_NUM_ACS) |
63 | return 0; | 83 | return 0; |
64 | 84 | ||
65 | if (!ieee80211_is_data(hdr->frame_control)) { | 85 | if (!ieee80211_is_data(hdr->frame_control)) { |
@@ -86,9 +106,9 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata, | |||
86 | const u8 *ra = NULL; | 106 | const u8 *ra = NULL; |
87 | bool qos = false; | 107 | bool qos = false; |
88 | 108 | ||
89 | if (local->hw.queues < 4 || skb->len < 6) { | 109 | if (local->hw.queues < IEEE80211_NUM_ACS || skb->len < 6) { |
90 | skb->priority = 0; /* required for correct WPA/11i MIC */ | 110 | skb->priority = 0; /* required for correct WPA/11i MIC */ |
91 | return min_t(u16, local->hw.queues - 1, IEEE80211_AC_BE); | 111 | return 0; |
92 | } | 112 | } |
93 | 113 | ||
94 | rcu_read_lock(); | 114 | rcu_read_lock(); |
@@ -139,26 +159,6 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata, | |||
139 | return ieee80211_downgrade_queue(local, skb); | 159 | return ieee80211_downgrade_queue(local, skb); |
140 | } | 160 | } |
141 | 161 | ||
142 | u16 ieee80211_downgrade_queue(struct ieee80211_local *local, | ||
143 | struct sk_buff *skb) | ||
144 | { | ||
145 | /* in case we are a client verify acm is not set for this ac */ | ||
146 | while (unlikely(local->wmm_acm & BIT(skb->priority))) { | ||
147 | if (wme_downgrade_ac(skb)) { | ||
148 | /* | ||
149 | * This should not really happen. The AP has marked all | ||
150 | * lower ACs to require admission control which is not | ||
151 | * a reasonable configuration. Allow the frame to be | ||
152 | * transmitted using AC_BK as a workaround. | ||
153 | */ | ||
154 | break; | ||
155 | } | ||
156 | } | ||
157 | |||
158 | /* look up which queue to use for frames with this 1d tag */ | ||
159 | return ieee802_1d_to_ac[skb->priority]; | ||
160 | } | ||
161 | |||
162 | void ieee80211_set_qos_hdr(struct ieee80211_sub_if_data *sdata, | 162 | void ieee80211_set_qos_hdr(struct ieee80211_sub_if_data *sdata, |
163 | struct sk_buff *skb) | 163 | struct sk_buff *skb) |
164 | { | 164 | { |
diff --git a/net/mac80211/wme.h b/net/mac80211/wme.h index 94edceb617ff..ca80818b7b66 100644 --- a/net/mac80211/wme.h +++ b/net/mac80211/wme.h | |||
@@ -22,8 +22,5 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata, | |||
22 | struct sk_buff *skb); | 22 | struct sk_buff *skb); |
23 | void ieee80211_set_qos_hdr(struct ieee80211_sub_if_data *sdata, | 23 | void ieee80211_set_qos_hdr(struct ieee80211_sub_if_data *sdata, |
24 | struct sk_buff *skb); | 24 | struct sk_buff *skb); |
25 | u16 ieee80211_downgrade_queue(struct ieee80211_local *local, | ||
26 | struct sk_buff *skb); | ||
27 | |||
28 | 25 | ||
29 | #endif /* _WME_H */ | 26 | #endif /* _WME_H */ |