aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/mlme.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2012-07-26 11:24:39 -0400
committerJohannes Berg <johannes.berg@intel.com>2012-10-17 05:02:09 -0400
commit55de908ab292c03f1eb280f51170ddb9c6b57e31 (patch)
treebc75bb5cea581cadf6fe8b4f121cce02d07c276a /net/mac80211/mlme.c
parentfe57d9f5c0a2c1ef97ba8cdc42cfda5743f287b8 (diff)
mac80211: use channel contexts
Instead of operating on a single channel only, use the new channel context infrastructure in all mac80211 code. This enables drivers that want to use the new channel context infrastructure to use multiple channels, while nothing should change for all the other drivers that don't support it. Right now this disables both TX power settings and spatial multiplexing powersave. Both need to be re-enabled on a channel context basis. Additionally, when channel contexts are used drop the connection when channel switch is received rather than trying to handle it. This will have to be improved later. [With fixes from Eliad and Emmanuel incorporated] Signed-off-by: Eliad Peller <eliad@wizery.com> Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r--net/mac80211/mlme.c129
1 files changed, 86 insertions, 43 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index e714ed8bb198..4add50063161 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -178,20 +178,30 @@ static u32 ieee80211_config_ht_tx(struct ieee80211_sub_if_data *sdata,
178{ 178{
179 struct ieee80211_local *local = sdata->local; 179 struct ieee80211_local *local = sdata->local;
180 struct ieee80211_supported_band *sband; 180 struct ieee80211_supported_band *sband;
181 struct ieee80211_chanctx_conf *chanctx_conf;
182 struct ieee80211_channel *chan;
181 struct sta_info *sta; 183 struct sta_info *sta;
182 u32 changed = 0; 184 u32 changed = 0;
183 u16 ht_opmode; 185 u16 ht_opmode;
184 bool disable_40 = false; 186 bool disable_40 = false;
185 187
186 sband = local->hw.wiphy->bands[local->oper_channel->band]; 188 rcu_read_lock();
189 chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
190 if (WARN_ON(!chanctx_conf)) {
191 rcu_read_unlock();
192 return 0;
193 }
194 chan = chanctx_conf->channel;
195 rcu_read_unlock();
196 sband = local->hw.wiphy->bands[chan->band];
187 197
188 switch (sdata->vif.bss_conf.channel_type) { 198 switch (sdata->vif.bss_conf.channel_type) {
189 case NL80211_CHAN_HT40PLUS: 199 case NL80211_CHAN_HT40PLUS:
190 if (local->oper_channel->flags & IEEE80211_CHAN_NO_HT40PLUS) 200 if (chan->flags & IEEE80211_CHAN_NO_HT40PLUS)
191 disable_40 = true; 201 disable_40 = true;
192 break; 202 break;
193 case NL80211_CHAN_HT40MINUS: 203 case NL80211_CHAN_HT40MINUS:
194 if (local->oper_channel->flags & IEEE80211_CHAN_NO_HT40MINUS) 204 if (chan->flags & IEEE80211_CHAN_NO_HT40MINUS)
195 disable_40 = true; 205 disable_40 = true;
196 break; 206 break;
197 default: 207 default:
@@ -359,11 +369,21 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
359 int i, count, rates_len, supp_rates_len; 369 int i, count, rates_len, supp_rates_len;
360 u16 capab; 370 u16 capab;
361 struct ieee80211_supported_band *sband; 371 struct ieee80211_supported_band *sband;
372 struct ieee80211_chanctx_conf *chanctx_conf;
373 struct ieee80211_channel *chan;
362 u32 rates = 0; 374 u32 rates = 0;
363 375
364 lockdep_assert_held(&ifmgd->mtx); 376 lockdep_assert_held(&ifmgd->mtx);
365 377
366 sband = local->hw.wiphy->bands[local->oper_channel->band]; 378 rcu_read_lock();
379 chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
380 if (WARN_ON(!chanctx_conf)) {
381 rcu_read_unlock();
382 return;
383 }
384 chan = chanctx_conf->channel;
385 rcu_read_unlock();
386 sband = local->hw.wiphy->bands[chan->band];
367 387
368 if (assoc_data->supp_rates_len) { 388 if (assoc_data->supp_rates_len) {
369 /* 389 /*
@@ -485,7 +505,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
485 *pos++ = WLAN_EID_PWR_CAPABILITY; 505 *pos++ = WLAN_EID_PWR_CAPABILITY;
486 *pos++ = 2; 506 *pos++ = 2;
487 *pos++ = 0; /* min tx power */ 507 *pos++ = 0; /* min tx power */
488 *pos++ = local->oper_channel->max_power; /* max tx power */ 508 *pos++ = chan->max_power; /* max tx power */
489 509
490 /* 2. supported channels */ 510 /* 2. supported channels */
491 /* TODO: get this in reg domain format */ 511 /* TODO: get this in reg domain format */
@@ -523,7 +543,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
523 543
524 if (!(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) 544 if (!(ifmgd->flags & IEEE80211_STA_DISABLE_11N))
525 ieee80211_add_ht_ie(sdata, skb, assoc_data->ap_ht_param, 545 ieee80211_add_ht_ie(sdata, skb, assoc_data->ap_ht_param,
526 sband, local->oper_channel, ifmgd->ap_smps); 546 sband, chan, ifmgd->ap_smps);
527 547
528 if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) 548 if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT))
529 ieee80211_add_vht_ie(sdata, skb, sband); 549 ieee80211_add_vht_ie(sdata, skb, sband);
@@ -657,18 +677,18 @@ static void ieee80211_chswitch_work(struct work_struct *work)
657 if (!ifmgd->associated) 677 if (!ifmgd->associated)
658 goto out; 678 goto out;
659 679
660 sdata->local->oper_channel = sdata->local->csa_channel; 680 sdata->local->_oper_channel = sdata->local->csa_channel;
661 if (!sdata->local->ops->channel_switch) { 681 if (!sdata->local->ops->channel_switch) {
662 /* call "hw_config" only if doing sw channel switch */ 682 /* call "hw_config" only if doing sw channel switch */
663 ieee80211_hw_config(sdata->local, 683 ieee80211_hw_config(sdata->local,
664 IEEE80211_CONF_CHANGE_CHANNEL); 684 IEEE80211_CONF_CHANGE_CHANNEL);
665 } else { 685 } else {
666 /* update the device channel directly */ 686 /* update the device channel directly */
667 sdata->local->hw.conf.channel = sdata->local->oper_channel; 687 sdata->local->hw.conf.channel = sdata->local->_oper_channel;
668 } 688 }
669 689
670 /* XXX: shouldn't really modify cfg80211-owned data! */ 690 /* XXX: shouldn't really modify cfg80211-owned data! */
671 ifmgd->associated->channel = sdata->local->oper_channel; 691 ifmgd->associated->channel = sdata->local->_oper_channel;
672 692
673 /* XXX: wait for a beacon first? */ 693 /* XXX: wait for a beacon first? */
674 ieee80211_wake_queues_by_reason(&sdata->local->hw, 694 ieee80211_wake_queues_by_reason(&sdata->local->hw,
@@ -680,11 +700,8 @@ static void ieee80211_chswitch_work(struct work_struct *work)
680 700
681void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success) 701void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success)
682{ 702{
683 struct ieee80211_sub_if_data *sdata; 703 struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
684 struct ieee80211_if_managed *ifmgd; 704 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
685
686 sdata = vif_to_sdata(vif);
687 ifmgd = &sdata->u.mgd;
688 705
689 trace_api_chswitch_done(sdata, success); 706 trace_api_chswitch_done(sdata, success);
690 if (!success) { 707 if (!success) {
@@ -723,6 +740,7 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
723 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; 740 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
724 int new_freq = ieee80211_channel_to_frequency(sw_elem->new_ch_num, 741 int new_freq = ieee80211_channel_to_frequency(sw_elem->new_ch_num,
725 cbss->channel->band); 742 cbss->channel->band);
743 struct ieee80211_chanctx *chanctx;
726 744
727 ASSERT_MGD_MTX(ifmgd); 745 ASSERT_MGD_MTX(ifmgd);
728 746
@@ -748,10 +766,34 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
748 return; 766 return;
749 } 767 }
750 768
751 sdata->local->csa_channel = new_ch;
752
753 ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED; 769 ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED;
754 770
771 if (sdata->local->use_chanctx) {
772 sdata_info(sdata,
773 "not handling channel switch with channel contexts\n");
774 ieee80211_queue_work(&sdata->local->hw,
775 &ifmgd->csa_connection_drop_work);
776 }
777
778 mutex_lock(&sdata->local->chanctx_mtx);
779 if (WARN_ON(!rcu_access_pointer(sdata->vif.chanctx_conf))) {
780 mutex_unlock(&sdata->local->chanctx_mtx);
781 return;
782 }
783 chanctx = container_of(rcu_access_pointer(sdata->vif.chanctx_conf),
784 struct ieee80211_chanctx, conf);
785 if (chanctx->refcount > 1) {
786 sdata_info(sdata,
787 "channel switch with multiple interfaces on the same channel, disconnecting\n");
788 ieee80211_queue_work(&sdata->local->hw,
789 &ifmgd->csa_connection_drop_work);
790 mutex_unlock(&sdata->local->chanctx_mtx);
791 return;
792 }
793 mutex_unlock(&sdata->local->chanctx_mtx);
794
795 sdata->local->csa_channel = new_ch;
796
755 if (sw_elem->mode) 797 if (sw_elem->mode)
756 ieee80211_stop_queues_by_reason(&sdata->local->hw, 798 ieee80211_stop_queues_by_reason(&sdata->local->hw,
757 IEEE80211_QUEUE_STOP_REASON_CSA); 799 IEEE80211_QUEUE_STOP_REASON_CSA);
@@ -1280,7 +1322,7 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata,
1280 } 1322 }
1281 1323
1282 use_short_slot = !!(capab & WLAN_CAPABILITY_SHORT_SLOT_TIME); 1324 use_short_slot = !!(capab & WLAN_CAPABILITY_SHORT_SLOT_TIME);
1283 if (sdata->local->oper_channel->band == IEEE80211_BAND_5GHZ) 1325 if (ieee80211_get_sdata_band(sdata) == IEEE80211_BAND_5GHZ)
1284 use_short_slot = true; 1326 use_short_slot = true;
1285 1327
1286 if (use_protection != bss_conf->use_cts_prot) { 1328 if (use_protection != bss_conf->use_cts_prot) {
@@ -1465,9 +1507,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
1465 changed |= BSS_CHANGED_BSSID | BSS_CHANGED_HT; 1507 changed |= BSS_CHANGED_BSSID | BSS_CHANGED_HT;
1466 ieee80211_bss_info_change_notify(sdata, changed); 1508 ieee80211_bss_info_change_notify(sdata, changed);
1467 1509
1468 /* channel(_type) changes are handled by ieee80211_hw_config */ 1510 ieee80211_vif_release_channel(sdata);
1469 WARN_ON(!ieee80211_set_channel_type(local, sdata, NL80211_CHAN_NO_HT));
1470 ieee80211_hw_config(local, 0);
1471 1511
1472 /* disassociated - set to defaults now */ 1512 /* disassociated - set to defaults now */
1473 ieee80211_set_wmm_default(sdata, false); 1513 ieee80211_set_wmm_default(sdata, false);
@@ -1589,7 +1629,7 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata)
1589 1629
1590 ieee80211_send_probe_req(sdata, dst, ssid + 2, ssid_len, NULL, 1630 ieee80211_send_probe_req(sdata, dst, ssid + 2, ssid_len, NULL,
1591 0, (u32) -1, true, false, 1631 0, (u32) -1, true, false,
1592 ifmgd->associated->channel); 1632 ifmgd->associated->channel, false);
1593 } 1633 }
1594 1634
1595 ifmgd->probe_timeout = jiffies + msecs_to_jiffies(probe_wait_ms); 1635 ifmgd->probe_timeout = jiffies + msecs_to_jiffies(probe_wait_ms);
@@ -1692,8 +1732,7 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw,
1692 ssid_len = ssid[1]; 1732 ssid_len = ssid[1];
1693 1733
1694 skb = ieee80211_build_probe_req(sdata, cbss->bssid, 1734 skb = ieee80211_build_probe_req(sdata, cbss->bssid,
1695 (u32) -1, 1735 (u32) -1, cbss->channel,
1696 sdata->local->oper_channel,
1697 ssid + 2, ssid_len, 1736 ssid + 2, ssid_len,
1698 NULL, 0, true); 1737 NULL, 0, true);
1699 1738
@@ -1804,6 +1843,7 @@ static void ieee80211_destroy_auth_data(struct ieee80211_sub_if_data *sdata,
1804 1843
1805 memset(sdata->u.mgd.bssid, 0, ETH_ALEN); 1844 memset(sdata->u.mgd.bssid, 0, ETH_ALEN);
1806 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID); 1845 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID);
1846 ieee80211_vif_release_channel(sdata);
1807 } 1847 }
1808 1848
1809 cfg80211_put_bss(auth_data->bss); 1849 cfg80211_put_bss(auth_data->bss);
@@ -2030,6 +2070,7 @@ static void ieee80211_destroy_assoc_data(struct ieee80211_sub_if_data *sdata,
2030 2070
2031 memset(sdata->u.mgd.bssid, 0, ETH_ALEN); 2071 memset(sdata->u.mgd.bssid, 0, ETH_ALEN);
2032 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID); 2072 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID);
2073 ieee80211_vif_release_channel(sdata);
2033 } 2074 }
2034 2075
2035 kfree(assoc_data); 2076 kfree(assoc_data);
@@ -2091,7 +2132,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
2091 return false; 2132 return false;
2092 } 2133 }
2093 2134
2094 sband = local->hw.wiphy->bands[local->oper_channel->band]; 2135 sband = local->hw.wiphy->bands[ieee80211_get_sdata_band(sdata)];
2095 2136
2096 if (elems.ht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) 2137 if (elems.ht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_11N))
2097 ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, 2138 ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
@@ -2369,6 +2410,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
2369 size_t baselen; 2410 size_t baselen;
2370 struct ieee802_11_elems elems; 2411 struct ieee802_11_elems elems;
2371 struct ieee80211_local *local = sdata->local; 2412 struct ieee80211_local *local = sdata->local;
2413 struct ieee80211_chanctx_conf *chanctx_conf;
2414 struct ieee80211_channel *chan;
2372 u32 changed = 0; 2415 u32 changed = 0;
2373 bool erp_valid, directed_tim = false; 2416 bool erp_valid, directed_tim = false;
2374 u8 erp_value = 0; 2417 u8 erp_value = 0;
@@ -2382,8 +2425,19 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
2382 if (baselen > len) 2425 if (baselen > len)
2383 return; 2426 return;
2384 2427
2385 if (rx_status->freq != local->oper_channel->center_freq) 2428 rcu_read_lock();
2429 chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
2430 if (!chanctx_conf) {
2431 rcu_read_unlock();
2386 return; 2432 return;
2433 }
2434
2435 if (rx_status->freq != chanctx_conf->channel->center_freq) {
2436 rcu_read_unlock();
2437 return;
2438 }
2439 chan = chanctx_conf->channel;
2440 rcu_read_unlock();
2387 2441
2388 if (ifmgd->assoc_data && !ifmgd->assoc_data->have_beacon && 2442 if (ifmgd->assoc_data && !ifmgd->assoc_data->have_beacon &&
2389 ether_addr_equal(mgmt->bssid, ifmgd->assoc_data->bss->bssid)) { 2443 ether_addr_equal(mgmt->bssid, ifmgd->assoc_data->bss->bssid)) {
@@ -2546,7 +2600,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
2546 !(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) { 2600 !(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) {
2547 struct ieee80211_supported_band *sband; 2601 struct ieee80211_supported_band *sband;
2548 2602
2549 sband = local->hw.wiphy->bands[local->oper_channel->band]; 2603 sband = local->hw.wiphy->bands[chan->band];
2550 2604
2551 changed |= ieee80211_config_ht_tx(sdata, elems.ht_operation, 2605 changed |= ieee80211_config_ht_tx(sdata, elems.ht_operation,
2552 bssid, true); 2606 bssid, true);
@@ -2555,7 +2609,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
2555 if (elems.country_elem && elems.pwr_constr_elem && 2609 if (elems.country_elem && elems.pwr_constr_elem &&
2556 mgmt->u.probe_resp.capab_info & 2610 mgmt->u.probe_resp.capab_info &
2557 cpu_to_le16(WLAN_CAPABILITY_SPECTRUM_MGMT)) 2611 cpu_to_le16(WLAN_CAPABILITY_SPECTRUM_MGMT))
2558 ieee80211_handle_pwr_constr(sdata, local->oper_channel, 2612 ieee80211_handle_pwr_constr(sdata, chan,
2559 elems.country_elem, 2613 elems.country_elem,
2560 elems.country_elem_len, 2614 elems.country_elem_len,
2561 elems.pwr_constr_elem); 2615 elems.pwr_constr_elem);
@@ -2728,7 +2782,7 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata)
2728 */ 2782 */
2729 ieee80211_send_probe_req(sdata, NULL, ssidie + 2, ssidie[1], 2783 ieee80211_send_probe_req(sdata, NULL, ssidie + 2, ssidie[1],
2730 NULL, 0, (u32) -1, true, false, 2784 NULL, 0, (u32) -1, true, false,
2731 auth_data->bss->channel); 2785 auth_data->bss->channel, false);
2732 } 2786 }
2733 2787
2734 auth_data->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; 2788 auth_data->timeout = jiffies + IEEE80211_AUTH_TIMEOUT;
@@ -3118,20 +3172,9 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
3118 } 3172 }
3119 } 3173 }
3120 3174
3121 if (!ieee80211_set_channel_type(local, sdata, channel_type)) { 3175 ieee80211_vif_release_channel(sdata);
3122 /* can only fail due to HT40+/- mismatch */ 3176 return ieee80211_vif_use_channel(sdata, cbss->channel, channel_type,
3123 channel_type = NL80211_CHAN_HT20; 3177 IEEE80211_CHANCTX_SHARED);
3124 sdata_info(sdata,
3125 "disabling 40 MHz due to multi-vif mismatch\n");
3126 ifmgd->flags |= IEEE80211_STA_DISABLE_40MHZ;
3127 WARN_ON(!ieee80211_set_channel_type(local, sdata,
3128 channel_type));
3129 }
3130
3131 local->oper_channel = cbss->channel;
3132 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
3133
3134 return 0;
3135} 3178}
3136 3179
3137static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, 3180static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
@@ -3201,7 +3244,7 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
3201 sdata->vif.bss_conf.basic_rates = basic_rates; 3244 sdata->vif.bss_conf.basic_rates = basic_rates;
3202 3245
3203 /* cf. IEEE 802.11 9.2.12 */ 3246 /* cf. IEEE 802.11 9.2.12 */
3204 if (local->oper_channel->band == IEEE80211_BAND_2GHZ && 3247 if (cbss->channel->band == IEEE80211_BAND_2GHZ &&
3205 have_higher_than_11mbit) 3248 have_higher_than_11mbit)
3206 sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE; 3249 sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE;
3207 else 3250 else