aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Wunderlich <simon.wunderlich@s2003.tu-chemnitz.de>2013-10-07 12:41:06 -0400
committerJohannes Berg <johannes.berg@intel.com>2013-10-28 10:05:21 -0400
commit8e8d347da7613d0315295e730f2eecf9fe6f36ba (patch)
tree3eb39dbb5c38542cd3946869a8a80812be57a220
parent5336fa88e8ac6b666a3db9902a4797d94d86a702 (diff)
mac80211: enable DFS for IBSS mode
Allow changing to DFS channels if the channel is available for beaconing and userspace controls DFS operation. Channel switch announcement from other stations on DFS channels will be interpreted as radar event. These channels will then be marked as unvailable. Signed-off-by: Simon Wunderlich <siwu@hrz.tu-chemnitz.de> Signed-off-by: Mathias Kretschmer <mathias.kretschmer@fokus.fraunhofer.de> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r--net/mac80211/ibss.c49
-rw-r--r--net/mac80211/ieee80211_i.h1
2 files changed, 45 insertions, 5 deletions
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index 21a0b8835cb3..275bbb2c1a5a 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -229,6 +229,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
229 struct beacon_data *presp; 229 struct beacon_data *presp;
230 enum nl80211_bss_scan_width scan_width; 230 enum nl80211_bss_scan_width scan_width;
231 bool have_higher_than_11mbit; 231 bool have_higher_than_11mbit;
232 bool radar_required = false;
232 int err; 233 int err;
233 234
234 sdata_assert_lock(sdata); 235 sdata_assert_lock(sdata);
@@ -273,6 +274,23 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
273 } 274 }
274 chandef.width = NL80211_CHAN_WIDTH_20; 275 chandef.width = NL80211_CHAN_WIDTH_20;
275 chandef.center_freq1 = chan->center_freq; 276 chandef.center_freq1 = chan->center_freq;
277 /* check again for downgraded chandef */
278 if (!cfg80211_reg_can_beacon(local->hw.wiphy, &chandef)) {
279 sdata_info(sdata,
280 "Failed to join IBSS, beacons forbidden\n");
281 return;
282 }
283 }
284
285 err = cfg80211_chandef_dfs_required(sdata->local->hw.wiphy,
286 &chandef);
287 if (err > 0) {
288 if (!ifibss->userspace_handles_dfs) {
289 sdata_info(sdata,
290 "Failed to join IBSS, DFS channel without control program\n");
291 return;
292 }
293 radar_required = true;
276 } 294 }
277 295
278 ieee80211_vif_release_channel(sdata); 296 ieee80211_vif_release_channel(sdata);
@@ -297,6 +315,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
297 rcu_assign_pointer(ifibss->presp, presp); 315 rcu_assign_pointer(ifibss->presp, presp);
298 mgmt = (void *)presp->head; 316 mgmt = (void *)presp->head;
299 317
318 sdata->radar_required = radar_required;
300 sdata->vif.bss_conf.enable_beacon = true; 319 sdata->vif.bss_conf.enable_beacon = true;
301 sdata->vif.bss_conf.beacon_int = beacon_int; 320 sdata->vif.bss_conf.beacon_int = beacon_int;
302 sdata->vif.bss_conf.basic_rates = basic_rates; 321 sdata->vif.bss_conf.basic_rates = basic_rates;
@@ -796,6 +815,21 @@ static void ieee80211_csa_connection_drop_work(struct work_struct *work)
796 ieee80211_queue_work(&sdata->local->hw, &sdata->work); 815 ieee80211_queue_work(&sdata->local->hw, &sdata->work);
797} 816}
798 817
818static void ieee80211_ibss_csa_mark_radar(struct ieee80211_sub_if_data *sdata)
819{
820 struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
821 int err;
822
823 /* if the current channel is a DFS channel, mark the channel as
824 * unavailable.
825 */
826 err = cfg80211_chandef_dfs_required(sdata->local->hw.wiphy,
827 &ifibss->chandef);
828 if (err > 0)
829 cfg80211_radar_event(sdata->local->hw.wiphy, &ifibss->chandef,
830 GFP_ATOMIC);
831}
832
799static bool 833static bool
800ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata, 834ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata,
801 struct ieee802_11_elems *elems, 835 struct ieee802_11_elems *elems,
@@ -880,8 +914,7 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata,
880 goto disconnect; 914 goto disconnect;
881 } 915 }
882 916
883 if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, &params.chandef, 917 if (!cfg80211_reg_can_beacon(sdata->local->hw.wiphy, &params.chandef)) {
884 IEEE80211_CHAN_DISABLED)) {
885 sdata_info(sdata, 918 sdata_info(sdata,
886 "IBSS %pM switches to unsupported channel (%d MHz, width:%d, CF1/2: %d/%d MHz), disconnecting\n", 919 "IBSS %pM switches to unsupported channel (%d MHz, width:%d, CF1/2: %d/%d MHz), disconnecting\n",
887 ifibss->bssid, 920 ifibss->bssid,
@@ -897,10 +930,11 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata,
897 if (err < 0) 930 if (err < 0)
898 goto disconnect; 931 goto disconnect;
899 if (err) { 932 if (err) {
900 params.radar_required = true; 933 /* IBSS-DFS only allowed with a control program */
934 if (!ifibss->userspace_handles_dfs)
935 goto disconnect;
901 936
902 /* TODO: IBSS-DFS not (yet) supported, disconnect. */ 937 params.radar_required = true;
903 goto disconnect;
904 } 938 }
905 939
906 rcu_read_lock(); 940 rcu_read_lock();
@@ -947,12 +981,16 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata,
947 ieee80211_bss_info_change_notify(sdata, err); 981 ieee80211_bss_info_change_notify(sdata, err);
948 drv_channel_switch_beacon(sdata, &params.chandef); 982 drv_channel_switch_beacon(sdata, &params.chandef);
949 983
984 ieee80211_ibss_csa_mark_radar(sdata);
985
950 return true; 986 return true;
951disconnect: 987disconnect:
952 ibss_dbg(sdata, "Can't handle channel switch, disconnect\n"); 988 ibss_dbg(sdata, "Can't handle channel switch, disconnect\n");
953 ieee80211_queue_work(&sdata->local->hw, 989 ieee80211_queue_work(&sdata->local->hw,
954 &ifibss->csa_connection_drop_work); 990 &ifibss->csa_connection_drop_work);
955 991
992 ieee80211_ibss_csa_mark_radar(sdata);
993
956 return true; 994 return true;
957} 995}
958 996
@@ -1688,6 +1726,7 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
1688 1726
1689 sdata->u.ibss.privacy = params->privacy; 1727 sdata->u.ibss.privacy = params->privacy;
1690 sdata->u.ibss.control_port = params->control_port; 1728 sdata->u.ibss.control_port = params->control_port;
1729 sdata->u.ibss.userspace_handles_dfs = params->userspace_handles_dfs;
1691 sdata->u.ibss.basic_rates = params->basic_rates; 1730 sdata->u.ibss.basic_rates = params->basic_rates;
1692 1731
1693 /* fix basic_rates if channel does not support these rates */ 1732 /* fix basic_rates if channel does not support these rates */
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 8340d4939f1b..ff3c310142b5 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -501,6 +501,7 @@ struct ieee80211_if_ibss {
501 bool privacy; 501 bool privacy;
502 502
503 bool control_port; 503 bool control_port;
504 bool userspace_handles_dfs;
504 505
505 u8 bssid[ETH_ALEN] __aligned(2); 506 u8 bssid[ETH_ALEN] __aligned(2);
506 u8 ssid[IEEE80211_MAX_SSID_LEN]; 507 u8 ssid[IEEE80211_MAX_SSID_LEN];