aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJanusz.Dziedzic@tieto.com <Janusz.Dziedzic@tieto.com>2015-03-20 01:37:00 -0400
committerJohannes Berg <johannes.berg@intel.com>2015-03-30 04:47:56 -0400
commit76bed0f43b27d37cbe5fe9f3c27362db59451dea (patch)
treea68643e01844ee200490b47b496350f4e43304c0
parent97ffe75791b3e9c0797d5891070e41321c3beccb (diff)
mac80211: IBSS fix scan request
In case of wide bandwidth (wider than 20MHz) used by IBSS, scan all channels in chandef to be able to find neighboring IBSS netwqworks that use the same overall channels but a different control channel. Signed-off-by: Janusz Dziedzic <janusz.dziedzic@tieto.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r--net/mac80211/ibss.c81
-rw-r--r--net/mac80211/ieee80211_i.h3
-rw-r--r--net/mac80211/scan.c25
3 files changed, 97 insertions, 12 deletions
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index 6da4e72f8178..8f8391e008ed 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -1270,7 +1270,7 @@ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata)
1270 1270
1271 scan_width = cfg80211_chandef_to_scan_width(&ifibss->chandef); 1271 scan_width = cfg80211_chandef_to_scan_width(&ifibss->chandef);
1272 ieee80211_request_ibss_scan(sdata, ifibss->ssid, ifibss->ssid_len, 1272 ieee80211_request_ibss_scan(sdata, ifibss->ssid, ifibss->ssid_len,
1273 NULL, scan_width); 1273 NULL, 0, scan_width);
1274} 1274}
1275 1275
1276static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) 1276static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata)
@@ -1307,6 +1307,76 @@ static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata)
1307 capability, 0, true); 1307 capability, 0, true);
1308} 1308}
1309 1309
1310static unsigned ibss_setup_channels(struct wiphy *wiphy,
1311 struct ieee80211_channel **channels,
1312 unsigned int channels_max,
1313 u32 center_freq, u32 width)
1314{
1315 struct ieee80211_channel *chan = NULL;
1316 unsigned int n_chan = 0;
1317 u32 start_freq, end_freq, freq;
1318
1319 if (width <= 20) {
1320 start_freq = center_freq;
1321 end_freq = center_freq;
1322 } else {
1323 start_freq = center_freq - width / 2 + 10;
1324 end_freq = center_freq + width / 2 - 10;
1325 }
1326
1327 for (freq = start_freq; freq <= end_freq; freq += 20) {
1328 chan = ieee80211_get_channel(wiphy, freq);
1329 if (!chan)
1330 continue;
1331 if (n_chan >= channels_max)
1332 return n_chan;
1333
1334 channels[n_chan] = chan;
1335 n_chan++;
1336 }
1337
1338 return n_chan;
1339}
1340
1341static unsigned int
1342ieee80211_ibss_setup_scan_channels(struct wiphy *wiphy,
1343 const struct cfg80211_chan_def *chandef,
1344 struct ieee80211_channel **channels,
1345 unsigned int channels_max)
1346{
1347 unsigned int n_chan = 0;
1348 u32 width, cf1, cf2 = 0;
1349
1350 switch (chandef->width) {
1351 case NL80211_CHAN_WIDTH_40:
1352 width = 40;
1353 break;
1354 case NL80211_CHAN_WIDTH_80P80:
1355 cf2 = chandef->center_freq2;
1356 /* fall through */
1357 case NL80211_CHAN_WIDTH_80:
1358 width = 80;
1359 break;
1360 case NL80211_CHAN_WIDTH_160:
1361 width = 160;
1362 break;
1363 default:
1364 width = 20;
1365 break;
1366 }
1367
1368 cf1 = chandef->center_freq1;
1369
1370 n_chan = ibss_setup_channels(wiphy, channels, channels_max, cf1, width);
1371
1372 if (cf2)
1373 n_chan += ibss_setup_channels(wiphy, &channels[n_chan],
1374 channels_max - n_chan, cf2,
1375 width);
1376
1377 return n_chan;
1378}
1379
1310/* 1380/*
1311 * This function is called with state == IEEE80211_IBSS_MLME_SEARCH 1381 * This function is called with state == IEEE80211_IBSS_MLME_SEARCH
1312 */ 1382 */
@@ -1372,11 +1442,18 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
1372 /* Selected IBSS not found in current scan results - try to scan */ 1442 /* Selected IBSS not found in current scan results - try to scan */
1373 if (time_after(jiffies, ifibss->last_scan_completed + 1443 if (time_after(jiffies, ifibss->last_scan_completed +
1374 IEEE80211_SCAN_INTERVAL)) { 1444 IEEE80211_SCAN_INTERVAL)) {
1445 struct ieee80211_channel *channels[8];
1446 unsigned int num;
1447
1375 sdata_info(sdata, "Trigger new scan to find an IBSS to join\n"); 1448 sdata_info(sdata, "Trigger new scan to find an IBSS to join\n");
1376 1449
1450 num = ieee80211_ibss_setup_scan_channels(local->hw.wiphy,
1451 &ifibss->chandef,
1452 channels,
1453 ARRAY_SIZE(channels));
1377 scan_width = cfg80211_chandef_to_scan_width(&ifibss->chandef); 1454 scan_width = cfg80211_chandef_to_scan_width(&ifibss->chandef);
1378 ieee80211_request_ibss_scan(sdata, ifibss->ssid, 1455 ieee80211_request_ibss_scan(sdata, ifibss->ssid,
1379 ifibss->ssid_len, chan, 1456 ifibss->ssid_len, channels, num,
1380 scan_width); 1457 scan_width);
1381 } else { 1458 } else {
1382 int interval = IEEE80211_SCAN_INTERVAL; 1459 int interval = IEEE80211_SCAN_INTERVAL;
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 3e3cfe8da4ef..3331c62b4433 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1529,7 +1529,8 @@ int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata);
1529void ieee80211_scan_work(struct work_struct *work); 1529void ieee80211_scan_work(struct work_struct *work);
1530int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata, 1530int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata,
1531 const u8 *ssid, u8 ssid_len, 1531 const u8 *ssid, u8 ssid_len,
1532 struct ieee80211_channel *chan, 1532 struct ieee80211_channel **channels,
1533 unsigned int n_channels,
1533 enum nl80211_bss_scan_width scan_width); 1534 enum nl80211_bss_scan_width scan_width);
1534int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, 1535int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata,
1535 struct cfg80211_scan_request *req); 1536 struct cfg80211_scan_request *req);
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index 05f0d711b6d8..7bb6a9383f58 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -928,11 +928,12 @@ int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata,
928 928
929int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata, 929int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata,
930 const u8 *ssid, u8 ssid_len, 930 const u8 *ssid, u8 ssid_len,
931 struct ieee80211_channel *chan, 931 struct ieee80211_channel **channels,
932 unsigned int n_channels,
932 enum nl80211_bss_scan_width scan_width) 933 enum nl80211_bss_scan_width scan_width)
933{ 934{
934 struct ieee80211_local *local = sdata->local; 935 struct ieee80211_local *local = sdata->local;
935 int ret = -EBUSY; 936 int ret = -EBUSY, i, n_ch = 0;
936 enum ieee80211_band band; 937 enum ieee80211_band band;
937 938
938 mutex_lock(&local->mtx); 939 mutex_lock(&local->mtx);
@@ -942,9 +943,8 @@ int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata,
942 goto unlock; 943 goto unlock;
943 944
944 /* fill internal scan request */ 945 /* fill internal scan request */
945 if (!chan) { 946 if (!channels) {
946 int i, max_n; 947 int max_n;
947 int n_ch = 0;
948 948
949 for (band = 0; band < IEEE80211_NUM_BANDS; band++) { 949 for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
950 if (!local->hw.wiphy->bands[band]) 950 if (!local->hw.wiphy->bands[band])
@@ -969,12 +969,19 @@ int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata,
969 969
970 local->int_scan_req->n_channels = n_ch; 970 local->int_scan_req->n_channels = n_ch;
971 } else { 971 } else {
972 if (WARN_ON_ONCE(chan->flags & (IEEE80211_CHAN_NO_IR | 972 for (i = 0; i < n_channels; i++) {
973 IEEE80211_CHAN_DISABLED))) 973 if (channels[i]->flags & (IEEE80211_CHAN_NO_IR |
974 IEEE80211_CHAN_DISABLED))
975 continue;
976
977 local->int_scan_req->channels[n_ch] = channels[i];
978 n_ch++;
979 }
980
981 if (WARN_ON_ONCE(n_ch == 0))
974 goto unlock; 982 goto unlock;
975 983
976 local->int_scan_req->channels[0] = chan; 984 local->int_scan_req->n_channels = n_ch;
977 local->int_scan_req->n_channels = 1;
978 } 985 }
979 986
980 local->int_scan_req->ssids = &local->scan_ssid; 987 local->int_scan_req->ssids = &local->scan_ssid;