diff options
-rw-r--r-- | net/wireless/scan.c | 212 |
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 | } |
1240 | EXPORT_WEXT_HANDLER(cfg80211_wext_siwscan); | 1240 | EXPORT_WEXT_HANDLER(cfg80211_wext_siwscan); |
1241 | 1241 | ||
1242 | static void ieee80211_scan_add_ies(struct iw_request_info *info, | 1242 | static 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 | ||
1284 | static char * | 1289 | static 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, ¤t_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 | ||