Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Janusz.Dziedzic@tieto.com and committed by
Johannes Berg
76bed0f4 97ffe757

+97 -12
+79 -2
net/mac80211/ibss.c
··· 1270 1270 1271 1271 scan_width = cfg80211_chandef_to_scan_width(&ifibss->chandef); 1272 1272 ieee80211_request_ibss_scan(sdata, ifibss->ssid, ifibss->ssid_len, 1273 - NULL, scan_width); 1273 + NULL, 0, scan_width); 1274 1274 } 1275 1275 1276 1276 static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) ··· 1305 1305 __ieee80211_sta_join_ibss(sdata, bssid, sdata->vif.bss_conf.beacon_int, 1306 1306 &ifibss->chandef, ifibss->basic_rates, 1307 1307 capability, 0, true); 1308 + } 1309 + 1310 + static 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 + 1341 + static unsigned int 1342 + ieee80211_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; 1308 1378 } 1309 1379 1310 1380 /* ··· 1442 1372 /* Selected IBSS not found in current scan results - try to scan */ 1443 1373 if (time_after(jiffies, ifibss->last_scan_completed + 1444 1374 IEEE80211_SCAN_INTERVAL)) { 1375 + struct ieee80211_channel *channels[8]; 1376 + unsigned int num; 1377 + 1445 1378 sdata_info(sdata, "Trigger new scan to find an IBSS to join\n"); 1446 1379 1380 + num = ieee80211_ibss_setup_scan_channels(local->hw.wiphy, 1381 + &ifibss->chandef, 1382 + channels, 1383 + ARRAY_SIZE(channels)); 1447 1384 scan_width = cfg80211_chandef_to_scan_width(&ifibss->chandef); 1448 1385 ieee80211_request_ibss_scan(sdata, ifibss->ssid, 1449 - ifibss->ssid_len, chan, 1386 + ifibss->ssid_len, channels, num, 1450 1387 scan_width); 1451 1388 } else { 1452 1389 int interval = IEEE80211_SCAN_INTERVAL;
+2 -1
net/mac80211/ieee80211_i.h
··· 1529 1529 void ieee80211_scan_work(struct work_struct *work); 1530 1530 int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata, 1531 1531 const u8 *ssid, u8 ssid_len, 1532 - struct ieee80211_channel *chan, 1532 + struct ieee80211_channel **channels, 1533 + unsigned int n_channels, 1533 1534 enum nl80211_bss_scan_width scan_width); 1534 1535 int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, 1535 1536 struct cfg80211_scan_request *req);
+16 -9
net/mac80211/scan.c
··· 928 928 929 929 int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata, 930 930 const u8 *ssid, u8 ssid_len, 931 - struct ieee80211_channel *chan, 931 + struct ieee80211_channel **channels, 932 + unsigned int n_channels, 932 933 enum nl80211_bss_scan_width scan_width) 933 934 { 934 935 struct ieee80211_local *local = sdata->local; 935 - int ret = -EBUSY; 936 + int ret = -EBUSY, i, n_ch = 0; 936 937 enum ieee80211_band band; 937 938 938 939 mutex_lock(&local->mtx); ··· 943 942 goto unlock; 944 943 945 944 /* fill internal scan request */ 946 - if (!chan) { 947 - int i, max_n; 948 - int n_ch = 0; 945 + if (!channels) { 946 + int max_n; 949 947 950 948 for (band = 0; band < IEEE80211_NUM_BANDS; band++) { 951 949 if (!local->hw.wiphy->bands[band]) ··· 969 969 970 970 local->int_scan_req->n_channels = n_ch; 971 971 } else { 972 - if (WARN_ON_ONCE(chan->flags & (IEEE80211_CHAN_NO_IR | 973 - IEEE80211_CHAN_DISABLED))) 972 + for (i = 0; i < n_channels; i++) { 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 982 goto unlock; 975 983 976 - local->int_scan_req->channels[0] = chan; 977 - local->int_scan_req->n_channels = 1; 984 + local->int_scan_req->n_channels = n_ch; 978 985 } 979 986 980 987 local->int_scan_req->ssids = &local->scan_ssid;