aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/mlme.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2012-09-30 02:30:16 -0400
committerDavid S. Miller <davem@davemloft.net>2012-09-30 02:30:16 -0400
commita248afdc1b5916c2bfd007233112333d85aa28f6 (patch)
tree49d4a0b8fdcf7624ea6b0bdf0af2567d7392210e /net/mac80211/mlme.c
parentd379142bc4d9b78cdd9fc5aa696ca1ea083fb7d4 (diff)
parentc487606f835a93a725bac1aefd536be98f22474d (diff)
Merge branch 'for-davem' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next
John W. Linville says: ==================== Here is another batch of updates intended for 3.7... Highlights include an hci_connect re-write in Bluetooth, HCI/LLC layer separation in NFC, removal of the raw pn544 NFC driver, NFC LLCP raw sockets support, improved IBSS auth frame handling in mac80211, full-MAC AP mode notification support in mac80211, a lot of attention paid to brcmfmac, and the usual level of updates to iwlwifi, ath9k, mwifiex, and rt2x00, and various other updates. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r--net/mac80211/mlme.c207
1 files changed, 116 insertions, 91 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 5d77650d4363..e714ed8bb198 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -88,8 +88,6 @@ MODULE_PARM_DESC(probe_wait_ms,
88#define TMR_RUNNING_TIMER 0 88#define TMR_RUNNING_TIMER 0
89#define TMR_RUNNING_CHANSW 1 89#define TMR_RUNNING_CHANSW 1
90 90
91#define DEAUTH_DISASSOC_LEN (24 /* hdr */ + 2 /* reason */)
92
93/* 91/*
94 * All cfg80211 functions have to be called outside a locked 92 * All cfg80211 functions have to be called outside a locked
95 * section so that they can acquire a lock themselves... This 93 * section so that they can acquire a lock themselves... This
@@ -574,46 +572,6 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
574 ieee80211_tx_skb(sdata, skb); 572 ieee80211_tx_skb(sdata, skb);
575} 573}
576 574
577static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
578 const u8 *bssid, u16 stype,
579 u16 reason, bool send_frame,
580 u8 *frame_buf)
581{
582 struct ieee80211_local *local = sdata->local;
583 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
584 struct sk_buff *skb;
585 struct ieee80211_mgmt *mgmt = (void *)frame_buf;
586
587 /* build frame */
588 mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | stype);
589 mgmt->duration = 0; /* initialize only */
590 mgmt->seq_ctrl = 0; /* initialize only */
591 memcpy(mgmt->da, bssid, ETH_ALEN);
592 memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
593 memcpy(mgmt->bssid, bssid, ETH_ALEN);
594 /* u.deauth.reason_code == u.disassoc.reason_code */
595 mgmt->u.deauth.reason_code = cpu_to_le16(reason);
596
597 if (send_frame) {
598 skb = dev_alloc_skb(local->hw.extra_tx_headroom +
599 DEAUTH_DISASSOC_LEN);
600 if (!skb)
601 return;
602
603 skb_reserve(skb, local->hw.extra_tx_headroom);
604
605 /* copy in frame */
606 memcpy(skb_put(skb, DEAUTH_DISASSOC_LEN),
607 mgmt, DEAUTH_DISASSOC_LEN);
608
609 if (!(ifmgd->flags & IEEE80211_STA_MFP_ENABLED))
610 IEEE80211_SKB_CB(skb)->flags |=
611 IEEE80211_TX_INTFL_DONT_ENCRYPT;
612
613 ieee80211_tx_skb(sdata, skb);
614 }
615}
616
617void ieee80211_send_pspoll(struct ieee80211_local *local, 575void ieee80211_send_pspoll(struct ieee80211_local *local,
618 struct ieee80211_sub_if_data *sdata) 576 struct ieee80211_sub_if_data *sdata)
619{ 577{
@@ -730,16 +688,13 @@ void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success)
730 688
731 trace_api_chswitch_done(sdata, success); 689 trace_api_chswitch_done(sdata, success);
732 if (!success) { 690 if (!success) {
733 /* 691 sdata_info(sdata,
734 * If the channel switch was not successful, stay 692 "driver channel switch failed, disconnecting\n");
735 * around on the old channel. We currently lack 693 ieee80211_queue_work(&sdata->local->hw,
736 * good handling of this situation, possibly we 694 &ifmgd->csa_connection_drop_work);
737 * should just drop the association. 695 } else {
738 */ 696 ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work);
739 sdata->local->csa_channel = sdata->local->oper_channel;
740 } 697 }
741
742 ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work);
743} 698}
744EXPORT_SYMBOL(ieee80211_chswitch_done); 699EXPORT_SYMBOL(ieee80211_chswitch_done);
745 700
@@ -784,8 +739,14 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
784 return; 739 return;
785 740
786 new_ch = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq); 741 new_ch = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq);
787 if (!new_ch || new_ch->flags & IEEE80211_CHAN_DISABLED) 742 if (!new_ch || new_ch->flags & IEEE80211_CHAN_DISABLED) {
743 sdata_info(sdata,
744 "AP %pM switches to unsupported channel (%d MHz), disconnecting\n",
745 ifmgd->associated->bssid, new_freq);
746 ieee80211_queue_work(&sdata->local->hw,
747 &ifmgd->csa_connection_drop_work);
788 return; 748 return;
749 }
789 750
790 sdata->local->csa_channel = new_ch; 751 sdata->local->csa_channel = new_ch;
791 752
@@ -818,23 +779,71 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
818} 779}
819 780
820static void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata, 781static void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
821 u16 capab_info, u8 *pwr_constr_elem, 782 struct ieee80211_channel *channel,
822 u8 pwr_constr_elem_len) 783 const u8 *country_ie, u8 country_ie_len,
784 const u8 *pwr_constr_elem)
823{ 785{
824 struct ieee80211_conf *conf = &sdata->local->hw.conf; 786 struct ieee80211_country_ie_triplet *triplet;
787 int chan = ieee80211_frequency_to_channel(channel->center_freq);
788 int i, chan_pwr, chan_increment, new_ap_level;
789 bool have_chan_pwr = false;
825 790
826 if (!(capab_info & WLAN_CAPABILITY_SPECTRUM_MGMT)) 791 /* Invalid IE */
792 if (country_ie_len % 2 || country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN)
827 return; 793 return;
828 794
829 /* Power constraint IE length should be 1 octet */ 795 triplet = (void *)(country_ie + 3);
830 if (pwr_constr_elem_len != 1) 796 country_ie_len -= 3;
831 return;
832 797
833 if ((*pwr_constr_elem <= conf->channel->max_reg_power) && 798 switch (channel->band) {
834 (*pwr_constr_elem != sdata->local->power_constr_level)) { 799 default:
835 sdata->local->power_constr_level = *pwr_constr_elem; 800 WARN_ON_ONCE(1);
836 ieee80211_hw_config(sdata->local, 0); 801 /* fall through */
802 case IEEE80211_BAND_2GHZ:
803 case IEEE80211_BAND_60GHZ:
804 chan_increment = 1;
805 break;
806 case IEEE80211_BAND_5GHZ:
807 chan_increment = 4;
808 break;
837 } 809 }
810
811 /* find channel */
812 while (country_ie_len >= 3) {
813 u8 first_channel = triplet->chans.first_channel;
814
815 if (first_channel >= IEEE80211_COUNTRY_EXTENSION_ID)
816 goto next;
817
818 for (i = 0; i < triplet->chans.num_channels; i++) {
819 if (first_channel + i * chan_increment == chan) {
820 have_chan_pwr = true;
821 chan_pwr = triplet->chans.max_power;
822 break;
823 }
824 }
825 if (have_chan_pwr)
826 break;
827
828 next:
829 triplet++;
830 country_ie_len -= 3;
831 }
832
833 if (!have_chan_pwr)
834 return;
835
836 new_ap_level = max_t(int, 0, chan_pwr - *pwr_constr_elem);
837
838 if (sdata->local->ap_power_level == new_ap_level)
839 return;
840
841 sdata_info(sdata,
842 "Limiting TX power to %d (%d - %d) dBm as advertised by %pM\n",
843 new_ap_level, chan_pwr, *pwr_constr_elem,
844 sdata->u.mgd.bssid);
845 sdata->local->ap_power_level = new_ap_level;
846 ieee80211_hw_config(sdata->local, 0);
838} 847}
839 848
840void ieee80211_enable_dyn_ps(struct ieee80211_vif *vif) 849void ieee80211_enable_dyn_ps(struct ieee80211_vif *vif)
@@ -1339,9 +1348,9 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
1339 1348
1340 mutex_lock(&local->iflist_mtx); 1349 mutex_lock(&local->iflist_mtx);
1341 ieee80211_recalc_ps(local, -1); 1350 ieee80211_recalc_ps(local, -1);
1342 ieee80211_recalc_smps(local);
1343 mutex_unlock(&local->iflist_mtx); 1351 mutex_unlock(&local->iflist_mtx);
1344 1352
1353 ieee80211_recalc_smps(local);
1345 ieee80211_recalc_ps_vif(sdata); 1354 ieee80211_recalc_ps_vif(sdata);
1346 1355
1347 netif_tx_start_all_queues(sdata->dev); 1356 netif_tx_start_all_queues(sdata->dev);
@@ -1390,7 +1399,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
1390 sta = sta_info_get(sdata, ifmgd->bssid); 1399 sta = sta_info_get(sdata, ifmgd->bssid);
1391 if (sta) { 1400 if (sta) {
1392 set_sta_flag(sta, WLAN_STA_BLOCK_BA); 1401 set_sta_flag(sta, WLAN_STA_BLOCK_BA);
1393 ieee80211_sta_tear_down_BA_sessions(sta, tx); 1402 ieee80211_sta_tear_down_BA_sessions(sta, false);
1394 } 1403 }
1395 mutex_unlock(&local->sta_mtx); 1404 mutex_unlock(&local->sta_mtx);
1396 1405
@@ -1438,7 +1447,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
1438 memset(&ifmgd->ht_capa, 0, sizeof(ifmgd->ht_capa)); 1447 memset(&ifmgd->ht_capa, 0, sizeof(ifmgd->ht_capa));
1439 memset(&ifmgd->ht_capa_mask, 0, sizeof(ifmgd->ht_capa_mask)); 1448 memset(&ifmgd->ht_capa_mask, 0, sizeof(ifmgd->ht_capa_mask));
1440 1449
1441 local->power_constr_level = 0; 1450 local->ap_power_level = 0;
1442 1451
1443 del_timer_sync(&local->dynamic_ps_timer); 1452 del_timer_sync(&local->dynamic_ps_timer);
1444 cancel_work_sync(&local->dynamic_ps_enable_work); 1453 cancel_work_sync(&local->dynamic_ps_enable_work);
@@ -1692,11 +1701,12 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw,
1692} 1701}
1693EXPORT_SYMBOL(ieee80211_ap_probereq_get); 1702EXPORT_SYMBOL(ieee80211_ap_probereq_get);
1694 1703
1695static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata) 1704static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata,
1705 bool transmit_frame)
1696{ 1706{
1697 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; 1707 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
1698 struct ieee80211_local *local = sdata->local; 1708 struct ieee80211_local *local = sdata->local;
1699 u8 frame_buf[DEAUTH_DISASSOC_LEN]; 1709 u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN];
1700 1710
1701 mutex_lock(&ifmgd->mtx); 1711 mutex_lock(&ifmgd->mtx);
1702 if (!ifmgd->associated) { 1712 if (!ifmgd->associated) {
@@ -1704,19 +1714,17 @@ static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata)
1704 return; 1714 return;
1705 } 1715 }
1706 1716
1707 sdata_info(sdata, "Connection to AP %pM lost\n",
1708 ifmgd->associated->bssid);
1709
1710 ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, 1717 ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
1711 WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, 1718 WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY,
1712 false, frame_buf); 1719 transmit_frame, frame_buf);
1720 ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED;
1713 mutex_unlock(&ifmgd->mtx); 1721 mutex_unlock(&ifmgd->mtx);
1714 1722
1715 /* 1723 /*
1716 * must be outside lock due to cfg80211, 1724 * must be outside lock due to cfg80211,
1717 * but that's not a problem. 1725 * but that's not a problem.
1718 */ 1726 */
1719 cfg80211_send_deauth(sdata->dev, frame_buf, DEAUTH_DISASSOC_LEN); 1727 cfg80211_send_deauth(sdata->dev, frame_buf, IEEE80211_DEAUTH_FRAME_LEN);
1720 1728
1721 mutex_lock(&local->mtx); 1729 mutex_lock(&local->mtx);
1722 ieee80211_recalc_idle(local); 1730 ieee80211_recalc_idle(local);
@@ -1739,10 +1747,24 @@ static void ieee80211_beacon_connection_loss_work(struct work_struct *work)
1739 rcu_read_unlock(); 1747 rcu_read_unlock();
1740 } 1748 }
1741 1749
1742 if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR) 1750 if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR) {
1743 __ieee80211_connection_loss(sdata); 1751 sdata_info(sdata, "Connection to AP %pM lost\n",
1744 else 1752 ifmgd->bssid);
1753 __ieee80211_disconnect(sdata, false);
1754 } else {
1745 ieee80211_mgd_probe_ap(sdata, true); 1755 ieee80211_mgd_probe_ap(sdata, true);
1756 }
1757}
1758
1759static void ieee80211_csa_connection_drop_work(struct work_struct *work)
1760{
1761 struct ieee80211_sub_if_data *sdata =
1762 container_of(work, struct ieee80211_sub_if_data,
1763 u.mgd.csa_connection_drop_work);
1764
1765 ieee80211_wake_queues_by_reason(&sdata->local->hw,
1766 IEEE80211_QUEUE_STOP_REASON_CSA);
1767 __ieee80211_disconnect(sdata, true);
1746} 1768}
1747 1769
1748void ieee80211_beacon_loss(struct ieee80211_vif *vif) 1770void ieee80211_beacon_loss(struct ieee80211_vif *vif)
@@ -2530,15 +2552,13 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
2530 bssid, true); 2552 bssid, true);
2531 } 2553 }
2532 2554
2533 /* Note: country IE parsing is done for us by cfg80211 */ 2555 if (elems.country_elem && elems.pwr_constr_elem &&
2534 if (elems.country_elem) { 2556 mgmt->u.probe_resp.capab_info &
2535 /* TODO: IBSS also needs this */ 2557 cpu_to_le16(WLAN_CAPABILITY_SPECTRUM_MGMT))
2536 if (elems.pwr_constr_elem) 2558 ieee80211_handle_pwr_constr(sdata, local->oper_channel,
2537 ieee80211_handle_pwr_constr(sdata, 2559 elems.country_elem,
2538 le16_to_cpu(mgmt->u.probe_resp.capab_info), 2560 elems.country_elem_len,
2539 elems.pwr_constr_elem, 2561 elems.pwr_constr_elem);
2540 elems.pwr_constr_elem_len);
2541 }
2542 2562
2543 ieee80211_bss_info_change_notify(sdata, changed); 2563 ieee80211_bss_info_change_notify(sdata, changed);
2544} 2564}
@@ -2635,7 +2655,7 @@ static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata,
2635{ 2655{
2636 struct ieee80211_local *local = sdata->local; 2656 struct ieee80211_local *local = sdata->local;
2637 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; 2657 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
2638 u8 frame_buf[DEAUTH_DISASSOC_LEN]; 2658 u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN];
2639 2659
2640 ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, reason, 2660 ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, reason,
2641 false, frame_buf); 2661 false, frame_buf);
@@ -2645,7 +2665,7 @@ static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata,
2645 * must be outside lock due to cfg80211, 2665 * must be outside lock due to cfg80211,
2646 * but that's not a problem. 2666 * but that's not a problem.
2647 */ 2667 */
2648 cfg80211_send_deauth(sdata->dev, frame_buf, DEAUTH_DISASSOC_LEN); 2668 cfg80211_send_deauth(sdata->dev, frame_buf, IEEE80211_DEAUTH_FRAME_LEN);
2649 2669
2650 mutex_lock(&local->mtx); 2670 mutex_lock(&local->mtx);
2651 ieee80211_recalc_idle(local); 2671 ieee80211_recalc_idle(local);
@@ -2929,6 +2949,7 @@ void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata)
2929 2949
2930 cancel_work_sync(&ifmgd->monitor_work); 2950 cancel_work_sync(&ifmgd->monitor_work);
2931 cancel_work_sync(&ifmgd->beacon_connection_loss_work); 2951 cancel_work_sync(&ifmgd->beacon_connection_loss_work);
2952 cancel_work_sync(&ifmgd->csa_connection_drop_work);
2932 if (del_timer_sync(&ifmgd->timer)) 2953 if (del_timer_sync(&ifmgd->timer))
2933 set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running); 2954 set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running);
2934 2955
@@ -2985,6 +3006,8 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
2985 INIT_WORK(&ifmgd->chswitch_work, ieee80211_chswitch_work); 3006 INIT_WORK(&ifmgd->chswitch_work, ieee80211_chswitch_work);
2986 INIT_WORK(&ifmgd->beacon_connection_loss_work, 3007 INIT_WORK(&ifmgd->beacon_connection_loss_work,
2987 ieee80211_beacon_connection_loss_work); 3008 ieee80211_beacon_connection_loss_work);
3009 INIT_WORK(&ifmgd->csa_connection_drop_work,
3010 ieee80211_csa_connection_drop_work);
2988 INIT_WORK(&ifmgd->request_smps_work, ieee80211_request_smps_work); 3011 INIT_WORK(&ifmgd->request_smps_work, ieee80211_request_smps_work);
2989 setup_timer(&ifmgd->timer, ieee80211_sta_timer, 3012 setup_timer(&ifmgd->timer, ieee80211_sta_timer,
2990 (unsigned long) sdata); 3013 (unsigned long) sdata);
@@ -3525,7 +3548,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
3525 struct cfg80211_deauth_request *req) 3548 struct cfg80211_deauth_request *req)
3526{ 3549{
3527 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; 3550 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
3528 u8 frame_buf[DEAUTH_DISASSOC_LEN]; 3551 u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN];
3529 3552
3530 mutex_lock(&ifmgd->mtx); 3553 mutex_lock(&ifmgd->mtx);
3531 3554
@@ -3553,7 +3576,8 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
3553 3576
3554 mutex_unlock(&ifmgd->mtx); 3577 mutex_unlock(&ifmgd->mtx);
3555 3578
3556 __cfg80211_send_deauth(sdata->dev, frame_buf, DEAUTH_DISASSOC_LEN); 3579 __cfg80211_send_deauth(sdata->dev, frame_buf,
3580 IEEE80211_DEAUTH_FRAME_LEN);
3557 3581
3558 mutex_lock(&sdata->local->mtx); 3582 mutex_lock(&sdata->local->mtx);
3559 ieee80211_recalc_idle(sdata->local); 3583 ieee80211_recalc_idle(sdata->local);
@@ -3567,7 +3591,7 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
3567{ 3591{
3568 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; 3592 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
3569 u8 bssid[ETH_ALEN]; 3593 u8 bssid[ETH_ALEN];
3570 u8 frame_buf[DEAUTH_DISASSOC_LEN]; 3594 u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN];
3571 3595
3572 mutex_lock(&ifmgd->mtx); 3596 mutex_lock(&ifmgd->mtx);
3573 3597
@@ -3592,7 +3616,8 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
3592 frame_buf); 3616 frame_buf);
3593 mutex_unlock(&ifmgd->mtx); 3617 mutex_unlock(&ifmgd->mtx);
3594 3618
3595 __cfg80211_send_disassoc(sdata->dev, frame_buf, DEAUTH_DISASSOC_LEN); 3619 __cfg80211_send_disassoc(sdata->dev, frame_buf,
3620 IEEE80211_DEAUTH_FRAME_LEN);
3596 3621
3597 mutex_lock(&sdata->local->mtx); 3622 mutex_lock(&sdata->local->mtx);
3598 ieee80211_recalc_idle(sdata->local); 3623 ieee80211_recalc_idle(sdata->local);