aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/wireless/scan.c212
1 files changed, 136 insertions, 76 deletions
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index 25e1e1fad905..ceb8f0040dae 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -1239,15 +1239,15 @@ int cfg80211_wext_siwscan(struct net_device *dev,
1239} 1239}
1240EXPORT_WEXT_HANDLER(cfg80211_wext_siwscan); 1240EXPORT_WEXT_HANDLER(cfg80211_wext_siwscan);
1241 1241
1242static void ieee80211_scan_add_ies(struct iw_request_info *info, 1242static char *ieee80211_scan_add_ies(struct iw_request_info *info,
1243 const struct cfg80211_bss_ies *ies, 1243 const struct cfg80211_bss_ies *ies,
1244 char **current_ev, char *end_buf) 1244 char *current_ev, char *end_buf)
1245{ 1245{
1246 const u8 *pos, *end, *next; 1246 const u8 *pos, *end, *next;
1247 struct iw_event iwe; 1247 struct iw_event iwe;
1248 1248
1249 if (!ies) 1249 if (!ies)
1250 return; 1250 return current_ev;
1251 1251
1252 /* 1252 /*
1253 * If needed, fragment the IEs buffer (at IE boundaries) into short 1253 * If needed, fragment the IEs buffer (at IE boundaries) into short
@@ -1264,10 +1264,11 @@ static void ieee80211_scan_add_ies(struct iw_request_info *info,
1264 memset(&iwe, 0, sizeof(iwe)); 1264 memset(&iwe, 0, sizeof(iwe));
1265 iwe.cmd = IWEVGENIE; 1265 iwe.cmd = IWEVGENIE;
1266 iwe.u.data.length = next - pos; 1266 iwe.u.data.length = next - pos;
1267 *current_ev = iwe_stream_add_point(info, *current_ev, 1267 current_ev = iwe_stream_add_point_check(info, current_ev,
1268 end_buf, &iwe, 1268 end_buf, &iwe,
1269 (void *)pos); 1269 (void *)pos);
1270 1270 if (IS_ERR(current_ev))
1271 return current_ev;
1271 pos = next; 1272 pos = next;
1272 } 1273 }
1273 1274
@@ -1275,10 +1276,14 @@ static void ieee80211_scan_add_ies(struct iw_request_info *info,
1275 memset(&iwe, 0, sizeof(iwe)); 1276 memset(&iwe, 0, sizeof(iwe));
1276 iwe.cmd = IWEVGENIE; 1277 iwe.cmd = IWEVGENIE;
1277 iwe.u.data.length = end - pos; 1278 iwe.u.data.length = end - pos;
1278 *current_ev = iwe_stream_add_point(info, *current_ev, 1279 current_ev = iwe_stream_add_point_check(info, current_ev,
1279 end_buf, &iwe, 1280 end_buf, &iwe,
1280 (void *)pos); 1281 (void *)pos);
1282 if (IS_ERR(current_ev))
1283 return current_ev;
1281 } 1284 }
1285
1286 return current_ev;
1282} 1287}
1283 1288
1284static char * 1289static char *
@@ -1289,7 +1294,8 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
1289 const struct cfg80211_bss_ies *ies; 1294 const struct cfg80211_bss_ies *ies;
1290 struct iw_event iwe; 1295 struct iw_event iwe;
1291 const u8 *ie; 1296 const u8 *ie;
1292 u8 *buf, *cfg, *p; 1297 u8 buf[50];
1298 u8 *cfg, *p, *tmp;
1293 int rem, i, sig; 1299 int rem, i, sig;
1294 bool ismesh = false; 1300 bool ismesh = false;
1295 1301
@@ -1297,22 +1303,28 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
1297 iwe.cmd = SIOCGIWAP; 1303 iwe.cmd = SIOCGIWAP;
1298 iwe.u.ap_addr.sa_family = ARPHRD_ETHER; 1304 iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
1299 memcpy(iwe.u.ap_addr.sa_data, bss->pub.bssid, ETH_ALEN); 1305 memcpy(iwe.u.ap_addr.sa_data, bss->pub.bssid, ETH_ALEN);
1300 current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, 1306 current_ev = iwe_stream_add_event_check(info, current_ev, end_buf, &iwe,
1301 IW_EV_ADDR_LEN); 1307 IW_EV_ADDR_LEN);
1308 if (IS_ERR(current_ev))
1309 return current_ev;
1302 1310
1303 memset(&iwe, 0, sizeof(iwe)); 1311 memset(&iwe, 0, sizeof(iwe));
1304 iwe.cmd = SIOCGIWFREQ; 1312 iwe.cmd = SIOCGIWFREQ;
1305 iwe.u.freq.m = ieee80211_frequency_to_channel(bss->pub.channel->center_freq); 1313 iwe.u.freq.m = ieee80211_frequency_to_channel(bss->pub.channel->center_freq);
1306 iwe.u.freq.e = 0; 1314 iwe.u.freq.e = 0;
1307 current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, 1315 current_ev = iwe_stream_add_event_check(info, current_ev, end_buf, &iwe,
1308 IW_EV_FREQ_LEN); 1316 IW_EV_FREQ_LEN);
1317 if (IS_ERR(current_ev))
1318 return current_ev;
1309 1319
1310 memset(&iwe, 0, sizeof(iwe)); 1320 memset(&iwe, 0, sizeof(iwe));
1311 iwe.cmd = SIOCGIWFREQ; 1321 iwe.cmd = SIOCGIWFREQ;
1312 iwe.u.freq.m = bss->pub.channel->center_freq; 1322 iwe.u.freq.m = bss->pub.channel->center_freq;
1313 iwe.u.freq.e = 6; 1323 iwe.u.freq.e = 6;
1314 current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, 1324 current_ev = iwe_stream_add_event_check(info, current_ev, end_buf, &iwe,
1315 IW_EV_FREQ_LEN); 1325 IW_EV_FREQ_LEN);
1326 if (IS_ERR(current_ev))
1327 return current_ev;
1316 1328
1317 if (wiphy->signal_type != CFG80211_SIGNAL_TYPE_NONE) { 1329 if (wiphy->signal_type != CFG80211_SIGNAL_TYPE_NONE) {
1318 memset(&iwe, 0, sizeof(iwe)); 1330 memset(&iwe, 0, sizeof(iwe));
@@ -1341,8 +1353,11 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
1341 /* not reached */ 1353 /* not reached */
1342 break; 1354 break;
1343 } 1355 }
1344 current_ev = iwe_stream_add_event(info, current_ev, end_buf, 1356 current_ev = iwe_stream_add_event_check(info, current_ev,
1345 &iwe, IW_EV_QUAL_LEN); 1357 end_buf, &iwe,
1358 IW_EV_QUAL_LEN);
1359 if (IS_ERR(current_ev))
1360 return current_ev;
1346 } 1361 }
1347 1362
1348 memset(&iwe, 0, sizeof(iwe)); 1363 memset(&iwe, 0, sizeof(iwe));
@@ -1352,8 +1367,10 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
1352 else 1367 else
1353 iwe.u.data.flags = IW_ENCODE_DISABLED; 1368 iwe.u.data.flags = IW_ENCODE_DISABLED;
1354 iwe.u.data.length = 0; 1369 iwe.u.data.length = 0;
1355 current_ev = iwe_stream_add_point(info, current_ev, end_buf, 1370 current_ev = iwe_stream_add_point_check(info, current_ev, end_buf,
1356 &iwe, ""); 1371 &iwe, "");
1372 if (IS_ERR(current_ev))
1373 return current_ev;
1357 1374
1358 rcu_read_lock(); 1375 rcu_read_lock();
1359 ies = rcu_dereference(bss->pub.ies); 1376 ies = rcu_dereference(bss->pub.ies);
@@ -1371,66 +1388,91 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
1371 iwe.cmd = SIOCGIWESSID; 1388 iwe.cmd = SIOCGIWESSID;
1372 iwe.u.data.length = ie[1]; 1389 iwe.u.data.length = ie[1];
1373 iwe.u.data.flags = 1; 1390 iwe.u.data.flags = 1;
1374 current_ev = iwe_stream_add_point(info, current_ev, end_buf, 1391 current_ev = iwe_stream_add_point_check(info,
1375 &iwe, (u8 *)ie + 2); 1392 current_ev,
1393 end_buf, &iwe,
1394 (u8 *)ie + 2);
1395 if (IS_ERR(current_ev))
1396 goto unlock;
1376 break; 1397 break;
1377 case WLAN_EID_MESH_ID: 1398 case WLAN_EID_MESH_ID:
1378 memset(&iwe, 0, sizeof(iwe)); 1399 memset(&iwe, 0, sizeof(iwe));
1379 iwe.cmd = SIOCGIWESSID; 1400 iwe.cmd = SIOCGIWESSID;
1380 iwe.u.data.length = ie[1]; 1401 iwe.u.data.length = ie[1];
1381 iwe.u.data.flags = 1; 1402 iwe.u.data.flags = 1;
1382 current_ev = iwe_stream_add_point(info, current_ev, end_buf, 1403 current_ev = iwe_stream_add_point_check(info,
1383 &iwe, (u8 *)ie + 2); 1404 current_ev,
1405 end_buf, &iwe,
1406 (u8 *)ie + 2);
1407 if (IS_ERR(current_ev))
1408 goto unlock;
1384 break; 1409 break;
1385 case WLAN_EID_MESH_CONFIG: 1410 case WLAN_EID_MESH_CONFIG:
1386 ismesh = true; 1411 ismesh = true;
1387 if (ie[1] != sizeof(struct ieee80211_meshconf_ie)) 1412 if (ie[1] != sizeof(struct ieee80211_meshconf_ie))
1388 break; 1413 break;
1389 buf = kmalloc(50, GFP_ATOMIC);
1390 if (!buf)
1391 break;
1392 cfg = (u8 *)ie + 2; 1414 cfg = (u8 *)ie + 2;
1393 memset(&iwe, 0, sizeof(iwe)); 1415 memset(&iwe, 0, sizeof(iwe));
1394 iwe.cmd = IWEVCUSTOM; 1416 iwe.cmd = IWEVCUSTOM;
1395 sprintf(buf, "Mesh Network Path Selection Protocol ID: " 1417 sprintf(buf, "Mesh Network Path Selection Protocol ID: "
1396 "0x%02X", cfg[0]); 1418 "0x%02X", cfg[0]);
1397 iwe.u.data.length = strlen(buf); 1419 iwe.u.data.length = strlen(buf);
1398 current_ev = iwe_stream_add_point(info, current_ev, 1420 current_ev = iwe_stream_add_point_check(info,
1399 end_buf, 1421 current_ev,
1400 &iwe, buf); 1422 end_buf,
1423 &iwe, buf);
1424 if (IS_ERR(current_ev))
1425 goto unlock;
1401 sprintf(buf, "Path Selection Metric ID: 0x%02X", 1426 sprintf(buf, "Path Selection Metric ID: 0x%02X",
1402 cfg[1]); 1427 cfg[1]);
1403 iwe.u.data.length = strlen(buf); 1428 iwe.u.data.length = strlen(buf);
1404 current_ev = iwe_stream_add_point(info, current_ev, 1429 current_ev = iwe_stream_add_point_check(info,
1405 end_buf, 1430 current_ev,
1406 &iwe, buf); 1431 end_buf,
1432 &iwe, buf);
1433 if (IS_ERR(current_ev))
1434 goto unlock;
1407 sprintf(buf, "Congestion Control Mode ID: 0x%02X", 1435 sprintf(buf, "Congestion Control Mode ID: 0x%02X",
1408 cfg[2]); 1436 cfg[2]);
1409 iwe.u.data.length = strlen(buf); 1437 iwe.u.data.length = strlen(buf);
1410 current_ev = iwe_stream_add_point(info, current_ev, 1438 current_ev = iwe_stream_add_point_check(info,
1411 end_buf, 1439 current_ev,
1412 &iwe, buf); 1440 end_buf,
1441 &iwe, buf);
1442 if (IS_ERR(current_ev))
1443 goto unlock;
1413 sprintf(buf, "Synchronization ID: 0x%02X", cfg[3]); 1444 sprintf(buf, "Synchronization ID: 0x%02X", cfg[3]);
1414 iwe.u.data.length = strlen(buf); 1445 iwe.u.data.length = strlen(buf);
1415 current_ev = iwe_stream_add_point(info, current_ev, 1446 current_ev = iwe_stream_add_point_check(info,
1416 end_buf, 1447 current_ev,
1417 &iwe, buf); 1448 end_buf,
1449 &iwe, buf);
1450 if (IS_ERR(current_ev))
1451 goto unlock;
1418 sprintf(buf, "Authentication ID: 0x%02X", cfg[4]); 1452 sprintf(buf, "Authentication ID: 0x%02X", cfg[4]);
1419 iwe.u.data.length = strlen(buf); 1453 iwe.u.data.length = strlen(buf);
1420 current_ev = iwe_stream_add_point(info, current_ev, 1454 current_ev = iwe_stream_add_point_check(info,
1421 end_buf, 1455 current_ev,
1422 &iwe, buf); 1456 end_buf,
1457 &iwe, buf);
1458 if (IS_ERR(current_ev))
1459 goto unlock;
1423 sprintf(buf, "Formation Info: 0x%02X", cfg[5]); 1460 sprintf(buf, "Formation Info: 0x%02X", cfg[5]);
1424 iwe.u.data.length = strlen(buf); 1461 iwe.u.data.length = strlen(buf);
1425 current_ev = iwe_stream_add_point(info, current_ev, 1462 current_ev = iwe_stream_add_point_check(info,
1426 end_buf, 1463 current_ev,
1427 &iwe, buf); 1464 end_buf,
1465 &iwe, buf);
1466 if (IS_ERR(current_ev))
1467 goto unlock;
1428 sprintf(buf, "Capabilities: 0x%02X", cfg[6]); 1468 sprintf(buf, "Capabilities: 0x%02X", cfg[6]);
1429 iwe.u.data.length = strlen(buf); 1469 iwe.u.data.length = strlen(buf);
1430 current_ev = iwe_stream_add_point(info, current_ev, 1470 current_ev = iwe_stream_add_point_check(info,
1431 end_buf, 1471 current_ev,
1432 &iwe, buf); 1472 end_buf,
1433 kfree(buf); 1473 &iwe, buf);
1474 if (IS_ERR(current_ev))
1475 goto unlock;
1434 break; 1476 break;
1435 case WLAN_EID_SUPP_RATES: 1477 case WLAN_EID_SUPP_RATES:
1436 case WLAN_EID_EXT_SUPP_RATES: 1478 case WLAN_EID_EXT_SUPP_RATES:
@@ -1445,8 +1487,14 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
1445 for (i = 0; i < ie[1]; i++) { 1487 for (i = 0; i < ie[1]; i++) {
1446 iwe.u.bitrate.value = 1488 iwe.u.bitrate.value =
1447 ((ie[i + 2] & 0x7f) * 500000); 1489 ((ie[i + 2] & 0x7f) * 500000);
1490 tmp = p;
1448 p = iwe_stream_add_value(info, current_ev, p, 1491 p = iwe_stream_add_value(info, current_ev, p,
1449 end_buf, &iwe, IW_EV_PARAM_LEN); 1492 end_buf, &iwe,
1493 IW_EV_PARAM_LEN);
1494 if (p == tmp) {
1495 current_ev = ERR_PTR(-E2BIG);
1496 goto unlock;
1497 }
1450 } 1498 }
1451 current_ev = p; 1499 current_ev = p;
1452 break; 1500 break;
@@ -1465,31 +1513,35 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
1465 iwe.u.mode = IW_MODE_MASTER; 1513 iwe.u.mode = IW_MODE_MASTER;
1466 else 1514 else
1467 iwe.u.mode = IW_MODE_ADHOC; 1515 iwe.u.mode = IW_MODE_ADHOC;
1468 current_ev = iwe_stream_add_event(info, current_ev, end_buf, 1516 current_ev = iwe_stream_add_event_check(info, current_ev,
1469 &iwe, IW_EV_UINT_LEN); 1517 end_buf, &iwe,
1470 } 1518 IW_EV_UINT_LEN);
1471 1519 if (IS_ERR(current_ev))
1472 buf = kmalloc(31, GFP_ATOMIC); 1520 goto unlock;
1473 if (buf) {
1474 memset(&iwe, 0, sizeof(iwe));
1475 iwe.cmd = IWEVCUSTOM;
1476 sprintf(buf, "tsf=%016llx", (unsigned long long)(ies->tsf));
1477 iwe.u.data.length = strlen(buf);
1478 current_ev = iwe_stream_add_point(info, current_ev, end_buf,
1479 &iwe, buf);
1480 memset(&iwe, 0, sizeof(iwe));
1481 iwe.cmd = IWEVCUSTOM;
1482 sprintf(buf, " Last beacon: %ums ago",
1483 elapsed_jiffies_msecs(bss->ts));
1484 iwe.u.data.length = strlen(buf);
1485 current_ev = iwe_stream_add_point(info, current_ev,
1486 end_buf, &iwe, buf);
1487 kfree(buf);
1488 } 1521 }
1489 1522
1490 ieee80211_scan_add_ies(info, ies, &current_ev, end_buf); 1523 memset(&iwe, 0, sizeof(iwe));
1524 iwe.cmd = IWEVCUSTOM;
1525 sprintf(buf, "tsf=%016llx", (unsigned long long)(ies->tsf));
1526 iwe.u.data.length = strlen(buf);
1527 current_ev = iwe_stream_add_point_check(info, current_ev, end_buf,
1528 &iwe, buf);
1529 if (IS_ERR(current_ev))
1530 goto unlock;
1531 memset(&iwe, 0, sizeof(iwe));
1532 iwe.cmd = IWEVCUSTOM;
1533 sprintf(buf, " Last beacon: %ums ago",
1534 elapsed_jiffies_msecs(bss->ts));
1535 iwe.u.data.length = strlen(buf);
1536 current_ev = iwe_stream_add_point_check(info, current_ev,
1537 end_buf, &iwe, buf);
1538 if (IS_ERR(current_ev))
1539 goto unlock;
1540
1541 current_ev = ieee80211_scan_add_ies(info, ies, current_ev, end_buf);
1542
1543 unlock:
1491 rcu_read_unlock(); 1544 rcu_read_unlock();
1492
1493 return current_ev; 1545 return current_ev;
1494} 1546}
1495 1547
@@ -1501,19 +1553,27 @@ static int ieee80211_scan_results(struct cfg80211_registered_device *rdev,
1501 char *current_ev = buf; 1553 char *current_ev = buf;
1502 char *end_buf = buf + len; 1554 char *end_buf = buf + len;
1503 struct cfg80211_internal_bss *bss; 1555 struct cfg80211_internal_bss *bss;
1556 int err = 0;
1504 1557
1505 spin_lock_bh(&rdev->bss_lock); 1558 spin_lock_bh(&rdev->bss_lock);
1506 cfg80211_bss_expire(rdev); 1559 cfg80211_bss_expire(rdev);
1507 1560
1508 list_for_each_entry(bss, &rdev->bss_list, list) { 1561 list_for_each_entry(bss, &rdev->bss_list, list) {
1509 if (buf + len - current_ev <= IW_EV_ADDR_LEN) { 1562 if (buf + len - current_ev <= IW_EV_ADDR_LEN) {
1510 spin_unlock_bh(&rdev->bss_lock); 1563 err = -E2BIG;
1511 return -E2BIG; 1564 break;
1512 } 1565 }
1513 current_ev = ieee80211_bss(&rdev->wiphy, info, bss, 1566 current_ev = ieee80211_bss(&rdev->wiphy, info, bss,
1514 current_ev, end_buf); 1567 current_ev, end_buf);
1568 if (IS_ERR(current_ev)) {
1569 err = PTR_ERR(current_ev);
1570 break;
1571 }
1515 } 1572 }
1516 spin_unlock_bh(&rdev->bss_lock); 1573 spin_unlock_bh(&rdev->bss_lock);
1574
1575 if (err)
1576 return err;
1517 return current_ev - buf; 1577 return current_ev - buf;
1518} 1578}
1519 1579