summaryrefslogtreecommitdiffstats
path: root/net/mac80211/mlme.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2013-03-26 09:02:26 -0400
committerJohannes Berg <johannes.berg@intel.com>2013-04-16 09:29:42 -0400
commit37799e52a29af2268d1fbe18908a0d6b9f68af88 (patch)
tree709de66fb30ca2a5d15afa0c8c5daf9e18cfb37b /net/mac80211/mlme.c
parent6553bf04ff6686db658e09626edad003809f6baf (diff)
mac80211: unify CSA action frame/beacon processing
CSA action frame content should be processed as variable IEs rather than fixed to make it extensible. Unify the code and process them just like CSA in beacons to make it easier to extend for HT/VHT. Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r--net/mac80211/mlme.c71
1 files changed, 43 insertions, 28 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 2a2c45354498..ade3cd6c337d 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -1020,33 +1020,37 @@ static void ieee80211_chswitch_timer(unsigned long data)
1020 ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.chswitch_work); 1020 ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.chswitch_work);
1021} 1021}
1022 1022
1023void 1023static void
1024ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, 1024ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
1025 const struct ieee80211_channel_sw_ie *sw_elem, 1025 u64 timestamp, struct ieee802_11_elems *elems)
1026 struct ieee80211_bss *bss, u64 timestamp)
1027{ 1026{
1028 struct cfg80211_bss *cbss =
1029 container_of((void *)bss, struct cfg80211_bss, priv);
1030 struct ieee80211_channel *new_ch;
1031 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; 1027 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
1032 int new_freq = ieee80211_channel_to_frequency(sw_elem->new_ch_num, 1028 struct cfg80211_bss *cbss = ifmgd->associated;
1033 cbss->channel->band); 1029 struct ieee80211_bss *bss;
1030 struct ieee80211_channel *new_ch;
1031 int new_freq;
1034 struct ieee80211_chanctx *chanctx; 1032 struct ieee80211_chanctx *chanctx;
1035 1033
1036 ASSERT_MGD_MTX(ifmgd); 1034 ASSERT_MGD_MTX(ifmgd);
1037 1035
1038 if (!ifmgd->associated) 1036 if (!cbss)
1039 return; 1037 return;
1040 1038
1041 if (sdata->local->scanning) 1039 if (sdata->local->scanning)
1042 return; 1040 return;
1043 1041
1044 /* Disregard subsequent beacons if we are already running a timer 1042 /* disregard subsequent announcements if we are already processing */
1045 processing a CSA */
1046
1047 if (ifmgd->flags & IEEE80211_STA_CSA_RECEIVED) 1043 if (ifmgd->flags & IEEE80211_STA_CSA_RECEIVED)
1048 return; 1044 return;
1049 1045
1046 if (!elems->ch_switch_ie)
1047 return;
1048
1049 bss = (void *)cbss->priv;
1050
1051 new_freq = ieee80211_channel_to_frequency(
1052 elems->ch_switch_ie->new_ch_num,
1053 cbss->channel->band);
1050 new_ch = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq); 1054 new_ch = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq);
1051 if (!new_ch || new_ch->flags & IEEE80211_CHAN_DISABLED) { 1055 if (!new_ch || new_ch->flags & IEEE80211_CHAN_DISABLED) {
1052 sdata_info(sdata, 1056 sdata_info(sdata,
@@ -1086,7 +1090,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
1086 1090
1087 sdata->local->csa_channel = new_ch; 1091 sdata->local->csa_channel = new_ch;
1088 1092
1089 if (sw_elem->mode) 1093 if (elems->ch_switch_ie->mode)
1090 ieee80211_stop_queues_by_reason(&sdata->local->hw, 1094 ieee80211_stop_queues_by_reason(&sdata->local->hw,
1091 IEEE80211_MAX_QUEUE_MAP, 1095 IEEE80211_MAX_QUEUE_MAP,
1092 IEEE80211_QUEUE_STOP_REASON_CSA); 1096 IEEE80211_QUEUE_STOP_REASON_CSA);
@@ -1095,9 +1099,9 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
1095 /* use driver's channel switch callback */ 1099 /* use driver's channel switch callback */
1096 struct ieee80211_channel_switch ch_switch = { 1100 struct ieee80211_channel_switch ch_switch = {
1097 .timestamp = timestamp, 1101 .timestamp = timestamp,
1098 .block_tx = sw_elem->mode, 1102 .block_tx = elems->ch_switch_ie->mode,
1099 .channel = new_ch, 1103 .channel = new_ch,
1100 .count = sw_elem->count, 1104 .count = elems->ch_switch_ie->count,
1101 }; 1105 };
1102 1106
1103 drv_channel_switch(sdata->local, &ch_switch); 1107 drv_channel_switch(sdata->local, &ch_switch);
@@ -1105,11 +1109,11 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
1105 } 1109 }
1106 1110
1107 /* channel switch handled in software */ 1111 /* channel switch handled in software */
1108 if (sw_elem->count <= 1) 1112 if (elems->ch_switch_ie->count <= 1)
1109 ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work); 1113 ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work);
1110 else 1114 else
1111 mod_timer(&ifmgd->chswitch_timer, 1115 mod_timer(&ifmgd->chswitch_timer,
1112 TU_TO_EXP_TIME(sw_elem->count * 1116 TU_TO_EXP_TIME(elems->ch_switch_ie->count *
1113 cbss->beacon_interval)); 1117 cbss->beacon_interval));
1114} 1118}
1115 1119
@@ -2655,7 +2659,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
2655 if (bss) 2659 if (bss)
2656 ieee80211_rx_bss_put(local, bss); 2660 ieee80211_rx_bss_put(local, bss);
2657 2661
2658 if (!sdata->u.mgd.associated) 2662 if (!sdata->u.mgd.associated ||
2663 !ether_addr_equal(mgmt->bssid, sdata->u.mgd.associated->bssid))
2659 return; 2664 return;
2660 2665
2661 if (need_ps) { 2666 if (need_ps) {
@@ -2664,10 +2669,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
2664 mutex_unlock(&local->iflist_mtx); 2669 mutex_unlock(&local->iflist_mtx);
2665 } 2670 }
2666 2671
2667 if (elems->ch_switch_ie && 2672 ieee80211_sta_process_chanswitch(sdata, rx_status->mactime, elems);
2668 memcmp(mgmt->bssid, sdata->u.mgd.associated->bssid, ETH_ALEN) == 0)
2669 ieee80211_sta_process_chanswitch(sdata, elems->ch_switch_ie,
2670 bss, rx_status->mactime);
2671} 2673}
2672 2674
2673 2675
@@ -3061,14 +3063,27 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
3061 rma = ieee80211_rx_mgmt_assoc_resp(sdata, mgmt, skb->len, &bss); 3063 rma = ieee80211_rx_mgmt_assoc_resp(sdata, mgmt, skb->len, &bss);
3062 break; 3064 break;
3063 case IEEE80211_STYPE_ACTION: 3065 case IEEE80211_STYPE_ACTION:
3064 switch (mgmt->u.action.category) { 3066 if (mgmt->u.action.category == WLAN_CATEGORY_SPECTRUM_MGMT) {
3065 case WLAN_CATEGORY_SPECTRUM_MGMT: 3067 struct ieee802_11_elems elems;
3068 int ies_len = skb->len -
3069 offsetof(struct ieee80211_mgmt,
3070 u.action.u.chan_switch.variable);
3071
3072 if (ies_len < 0)
3073 break;
3074
3075 ieee802_11_parse_elems(
3076 mgmt->u.action.u.chan_switch.variable,
3077 ies_len, &elems);
3078
3079 if (elems.parse_error)
3080 break;
3081
3066 ieee80211_sta_process_chanswitch(sdata, 3082 ieee80211_sta_process_chanswitch(sdata,
3067 &mgmt->u.action.u.chan_switch.sw_elem, 3083 rx_status->mactime,
3068 (void *)ifmgd->associated->priv, 3084 &elems);
3069 rx_status->mactime);
3070 break;
3071 } 3085 }
3086 break;
3072 } 3087 }
3073 mutex_unlock(&ifmgd->mtx); 3088 mutex_unlock(&ifmgd->mtx);
3074 3089