diff options
author | John W. Linville <linville@tuxdriver.com> | 2013-06-28 13:18:21 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2013-06-28 13:18:21 -0400 |
commit | 57ed5cd695d7373b8ae0ae9f10fe945e774d58f0 (patch) | |
tree | 7ee6244ea7c0be81a541d4e57783f83c4dfd7d66 /net/wireless/nl80211.c | |
parent | 5e6700b3bf98fe98d630bf9c939ad4c85ce95592 (diff) | |
parent | 0f817ed52d07873cd39c9d3f6d87fae962dc742f (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next into for-davem
Conflicts:
net/wireless/nl80211.c
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r-- | net/wireless/nl80211.c | 287 |
1 files changed, 160 insertions, 127 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index e545023e2871..1cc47aca7f05 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -1111,10 +1111,16 @@ nl80211_send_mgmt_stypes(struct sk_buff *msg, | |||
1111 | return 0; | 1111 | return 0; |
1112 | } | 1112 | } |
1113 | 1113 | ||
1114 | struct nl80211_dump_wiphy_state { | ||
1115 | s64 filter_wiphy; | ||
1116 | long start; | ||
1117 | long split_start, band_start, chan_start; | ||
1118 | bool split; | ||
1119 | }; | ||
1120 | |||
1114 | static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, | 1121 | static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, |
1115 | struct sk_buff *msg, u32 portid, u32 seq, | 1122 | struct sk_buff *msg, u32 portid, u32 seq, |
1116 | int flags, bool split, long *split_start, | 1123 | int flags, struct nl80211_dump_wiphy_state *state) |
1117 | long *band_start, long *chan_start) | ||
1118 | { | 1124 | { |
1119 | void *hdr; | 1125 | void *hdr; |
1120 | struct nlattr *nl_bands, *nl_band; | 1126 | struct nlattr *nl_bands, *nl_band; |
@@ -1125,19 +1131,14 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, | |||
1125 | int i; | 1131 | int i; |
1126 | const struct ieee80211_txrx_stypes *mgmt_stypes = | 1132 | const struct ieee80211_txrx_stypes *mgmt_stypes = |
1127 | dev->wiphy.mgmt_stypes; | 1133 | dev->wiphy.mgmt_stypes; |
1128 | long start = 0, start_chan = 0, start_band = 0; | ||
1129 | u32 features; | 1134 | u32 features; |
1130 | 1135 | ||
1131 | hdr = nl80211hdr_put(msg, portid, seq, flags, NL80211_CMD_NEW_WIPHY); | 1136 | hdr = nl80211hdr_put(msg, portid, seq, flags, NL80211_CMD_NEW_WIPHY); |
1132 | if (!hdr) | 1137 | if (!hdr) |
1133 | return -ENOBUFS; | 1138 | return -ENOBUFS; |
1134 | 1139 | ||
1135 | /* allow always using the variables */ | 1140 | if (WARN_ON(!state)) |
1136 | if (!split) { | 1141 | return -EINVAL; |
1137 | split_start = &start; | ||
1138 | band_start = &start_band; | ||
1139 | chan_start = &start_chan; | ||
1140 | } | ||
1141 | 1142 | ||
1142 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, dev->wiphy_idx) || | 1143 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, dev->wiphy_idx) || |
1143 | nla_put_string(msg, NL80211_ATTR_WIPHY_NAME, | 1144 | nla_put_string(msg, NL80211_ATTR_WIPHY_NAME, |
@@ -1146,7 +1147,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, | |||
1146 | cfg80211_rdev_list_generation)) | 1147 | cfg80211_rdev_list_generation)) |
1147 | goto nla_put_failure; | 1148 | goto nla_put_failure; |
1148 | 1149 | ||
1149 | switch (*split_start) { | 1150 | switch (state->split_start) { |
1150 | case 0: | 1151 | case 0: |
1151 | if (nla_put_u8(msg, NL80211_ATTR_WIPHY_RETRY_SHORT, | 1152 | if (nla_put_u8(msg, NL80211_ATTR_WIPHY_RETRY_SHORT, |
1152 | dev->wiphy.retry_short) || | 1153 | dev->wiphy.retry_short) || |
@@ -1188,9 +1189,12 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, | |||
1188 | if ((dev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP) && | 1189 | if ((dev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP) && |
1189 | nla_put_flag(msg, NL80211_ATTR_TDLS_EXTERNAL_SETUP)) | 1190 | nla_put_flag(msg, NL80211_ATTR_TDLS_EXTERNAL_SETUP)) |
1190 | goto nla_put_failure; | 1191 | goto nla_put_failure; |
1192 | if ((dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_5_10_MHZ) && | ||
1193 | nla_put_flag(msg, WIPHY_FLAG_SUPPORTS_5_10_MHZ)) | ||
1194 | goto nla_put_failure; | ||
1191 | 1195 | ||
1192 | (*split_start)++; | 1196 | state->split_start++; |
1193 | if (split) | 1197 | if (state->split) |
1194 | break; | 1198 | break; |
1195 | case 1: | 1199 | case 1: |
1196 | if (nla_put(msg, NL80211_ATTR_CIPHER_SUITES, | 1200 | if (nla_put(msg, NL80211_ATTR_CIPHER_SUITES, |
@@ -1234,22 +1238,23 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, | |||
1234 | } | 1238 | } |
1235 | } | 1239 | } |
1236 | 1240 | ||
1237 | (*split_start)++; | 1241 | state->split_start++; |
1238 | if (split) | 1242 | if (state->split) |
1239 | break; | 1243 | break; |
1240 | case 2: | 1244 | case 2: |
1241 | if (nl80211_put_iftypes(msg, NL80211_ATTR_SUPPORTED_IFTYPES, | 1245 | if (nl80211_put_iftypes(msg, NL80211_ATTR_SUPPORTED_IFTYPES, |
1242 | dev->wiphy.interface_modes)) | 1246 | dev->wiphy.interface_modes)) |
1243 | goto nla_put_failure; | 1247 | goto nla_put_failure; |
1244 | (*split_start)++; | 1248 | state->split_start++; |
1245 | if (split) | 1249 | if (state->split) |
1246 | break; | 1250 | break; |
1247 | case 3: | 1251 | case 3: |
1248 | nl_bands = nla_nest_start(msg, NL80211_ATTR_WIPHY_BANDS); | 1252 | nl_bands = nla_nest_start(msg, NL80211_ATTR_WIPHY_BANDS); |
1249 | if (!nl_bands) | 1253 | if (!nl_bands) |
1250 | goto nla_put_failure; | 1254 | goto nla_put_failure; |
1251 | 1255 | ||
1252 | for (band = *band_start; band < IEEE80211_NUM_BANDS; band++) { | 1256 | for (band = state->band_start; |
1257 | band < IEEE80211_NUM_BANDS; band++) { | ||
1253 | struct ieee80211_supported_band *sband; | 1258 | struct ieee80211_supported_band *sband; |
1254 | 1259 | ||
1255 | sband = dev->wiphy.bands[band]; | 1260 | sband = dev->wiphy.bands[band]; |
@@ -1261,12 +1266,12 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, | |||
1261 | if (!nl_band) | 1266 | if (!nl_band) |
1262 | goto nla_put_failure; | 1267 | goto nla_put_failure; |
1263 | 1268 | ||
1264 | switch (*chan_start) { | 1269 | switch (state->chan_start) { |
1265 | case 0: | 1270 | case 0: |
1266 | if (nl80211_send_band_rateinfo(msg, sband)) | 1271 | if (nl80211_send_band_rateinfo(msg, sband)) |
1267 | goto nla_put_failure; | 1272 | goto nla_put_failure; |
1268 | (*chan_start)++; | 1273 | state->chan_start++; |
1269 | if (split) | 1274 | if (state->split) |
1270 | break; | 1275 | break; |
1271 | default: | 1276 | default: |
1272 | /* add frequencies */ | 1277 | /* add frequencies */ |
@@ -1275,7 +1280,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, | |||
1275 | if (!nl_freqs) | 1280 | if (!nl_freqs) |
1276 | goto nla_put_failure; | 1281 | goto nla_put_failure; |
1277 | 1282 | ||
1278 | for (i = *chan_start - 1; | 1283 | for (i = state->chan_start - 1; |
1279 | i < sband->n_channels; | 1284 | i < sband->n_channels; |
1280 | i++) { | 1285 | i++) { |
1281 | nl_freq = nla_nest_start(msg, i); | 1286 | nl_freq = nla_nest_start(msg, i); |
@@ -1284,26 +1289,27 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, | |||
1284 | 1289 | ||
1285 | chan = &sband->channels[i]; | 1290 | chan = &sband->channels[i]; |
1286 | 1291 | ||
1287 | if (nl80211_msg_put_channel(msg, chan, | 1292 | if (nl80211_msg_put_channel( |
1288 | split)) | 1293 | msg, chan, |
1294 | state->split)) | ||
1289 | goto nla_put_failure; | 1295 | goto nla_put_failure; |
1290 | 1296 | ||
1291 | nla_nest_end(msg, nl_freq); | 1297 | nla_nest_end(msg, nl_freq); |
1292 | if (split) | 1298 | if (state->split) |
1293 | break; | 1299 | break; |
1294 | } | 1300 | } |
1295 | if (i < sband->n_channels) | 1301 | if (i < sband->n_channels) |
1296 | *chan_start = i + 2; | 1302 | state->chan_start = i + 2; |
1297 | else | 1303 | else |
1298 | *chan_start = 0; | 1304 | state->chan_start = 0; |
1299 | nla_nest_end(msg, nl_freqs); | 1305 | nla_nest_end(msg, nl_freqs); |
1300 | } | 1306 | } |
1301 | 1307 | ||
1302 | nla_nest_end(msg, nl_band); | 1308 | nla_nest_end(msg, nl_band); |
1303 | 1309 | ||
1304 | if (split) { | 1310 | if (state->split) { |
1305 | /* start again here */ | 1311 | /* start again here */ |
1306 | if (*chan_start) | 1312 | if (state->chan_start) |
1307 | band--; | 1313 | band--; |
1308 | break; | 1314 | break; |
1309 | } | 1315 | } |
@@ -1311,14 +1317,14 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, | |||
1311 | nla_nest_end(msg, nl_bands); | 1317 | nla_nest_end(msg, nl_bands); |
1312 | 1318 | ||
1313 | if (band < IEEE80211_NUM_BANDS) | 1319 | if (band < IEEE80211_NUM_BANDS) |
1314 | *band_start = band + 1; | 1320 | state->band_start = band + 1; |
1315 | else | 1321 | else |
1316 | *band_start = 0; | 1322 | state->band_start = 0; |
1317 | 1323 | ||
1318 | /* if bands & channels are done, continue outside */ | 1324 | /* if bands & channels are done, continue outside */ |
1319 | if (*band_start == 0 && *chan_start == 0) | 1325 | if (state->band_start == 0 && state->chan_start == 0) |
1320 | (*split_start)++; | 1326 | state->split_start++; |
1321 | if (split) | 1327 | if (state->split) |
1322 | break; | 1328 | break; |
1323 | case 4: | 1329 | case 4: |
1324 | nl_cmds = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_COMMANDS); | 1330 | nl_cmds = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_COMMANDS); |
@@ -1384,7 +1390,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, | |||
1384 | } | 1390 | } |
1385 | CMD(start_p2p_device, START_P2P_DEVICE); | 1391 | CMD(start_p2p_device, START_P2P_DEVICE); |
1386 | CMD(set_mcast_rate, SET_MCAST_RATE); | 1392 | CMD(set_mcast_rate, SET_MCAST_RATE); |
1387 | if (split) { | 1393 | if (state->split) { |
1388 | CMD(crit_proto_start, CRIT_PROTOCOL_START); | 1394 | CMD(crit_proto_start, CRIT_PROTOCOL_START); |
1389 | CMD(crit_proto_stop, CRIT_PROTOCOL_STOP); | 1395 | CMD(crit_proto_stop, CRIT_PROTOCOL_STOP); |
1390 | } | 1396 | } |
@@ -1408,8 +1414,8 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, | |||
1408 | } | 1414 | } |
1409 | 1415 | ||
1410 | nla_nest_end(msg, nl_cmds); | 1416 | nla_nest_end(msg, nl_cmds); |
1411 | (*split_start)++; | 1417 | state->split_start++; |
1412 | if (split) | 1418 | if (state->split) |
1413 | break; | 1419 | break; |
1414 | case 5: | 1420 | case 5: |
1415 | if (dev->ops->remain_on_channel && | 1421 | if (dev->ops->remain_on_channel && |
@@ -1425,29 +1431,30 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, | |||
1425 | 1431 | ||
1426 | if (nl80211_send_mgmt_stypes(msg, mgmt_stypes)) | 1432 | if (nl80211_send_mgmt_stypes(msg, mgmt_stypes)) |
1427 | goto nla_put_failure; | 1433 | goto nla_put_failure; |
1428 | (*split_start)++; | 1434 | state->split_start++; |
1429 | if (split) | 1435 | if (state->split) |
1430 | break; | 1436 | break; |
1431 | case 6: | 1437 | case 6: |
1432 | #ifdef CONFIG_PM | 1438 | #ifdef CONFIG_PM |
1433 | if (nl80211_send_wowlan(msg, dev, split)) | 1439 | if (nl80211_send_wowlan(msg, dev, state->split)) |
1434 | goto nla_put_failure; | 1440 | goto nla_put_failure; |
1435 | (*split_start)++; | 1441 | state->split_start++; |
1436 | if (split) | 1442 | if (state->split) |
1437 | break; | 1443 | break; |
1438 | #else | 1444 | #else |
1439 | (*split_start)++; | 1445 | state->split_start++; |
1440 | #endif | 1446 | #endif |
1441 | case 7: | 1447 | case 7: |
1442 | if (nl80211_put_iftypes(msg, NL80211_ATTR_SOFTWARE_IFTYPES, | 1448 | if (nl80211_put_iftypes(msg, NL80211_ATTR_SOFTWARE_IFTYPES, |
1443 | dev->wiphy.software_iftypes)) | 1449 | dev->wiphy.software_iftypes)) |
1444 | goto nla_put_failure; | 1450 | goto nla_put_failure; |
1445 | 1451 | ||
1446 | if (nl80211_put_iface_combinations(&dev->wiphy, msg, split)) | 1452 | if (nl80211_put_iface_combinations(&dev->wiphy, msg, |
1453 | state->split)) | ||
1447 | goto nla_put_failure; | 1454 | goto nla_put_failure; |
1448 | 1455 | ||
1449 | (*split_start)++; | 1456 | state->split_start++; |
1450 | if (split) | 1457 | if (state->split) |
1451 | break; | 1458 | break; |
1452 | case 8: | 1459 | case 8: |
1453 | if ((dev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME) && | 1460 | if ((dev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME) && |
@@ -1461,7 +1468,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, | |||
1461 | * dump is split, otherwise it makes it too big. Therefore | 1468 | * dump is split, otherwise it makes it too big. Therefore |
1462 | * only advertise it in that case. | 1469 | * only advertise it in that case. |
1463 | */ | 1470 | */ |
1464 | if (split) | 1471 | if (state->split) |
1465 | features |= NL80211_FEATURE_ADVERTISE_CHAN_LIMITS; | 1472 | features |= NL80211_FEATURE_ADVERTISE_CHAN_LIMITS; |
1466 | if (nla_put_u32(msg, NL80211_ATTR_FEATURE_FLAGS, features)) | 1473 | if (nla_put_u32(msg, NL80211_ATTR_FEATURE_FLAGS, features)) |
1467 | goto nla_put_failure; | 1474 | goto nla_put_failure; |
@@ -1488,7 +1495,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, | |||
1488 | * case we'll continue with more data in the next round, | 1495 | * case we'll continue with more data in the next round, |
1489 | * but break unconditionally so unsplit data stops here. | 1496 | * but break unconditionally so unsplit data stops here. |
1490 | */ | 1497 | */ |
1491 | (*split_start)++; | 1498 | state->split_start++; |
1492 | break; | 1499 | break; |
1493 | case 9: | 1500 | case 9: |
1494 | if (dev->wiphy.extended_capabilities && | 1501 | if (dev->wiphy.extended_capabilities && |
@@ -1507,7 +1514,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, | |||
1507 | goto nla_put_failure; | 1514 | goto nla_put_failure; |
1508 | 1515 | ||
1509 | /* done */ | 1516 | /* done */ |
1510 | *split_start = 0; | 1517 | state->split_start = 0; |
1511 | break; | 1518 | break; |
1512 | } | 1519 | } |
1513 | return genlmsg_end(msg, hdr); | 1520 | return genlmsg_end(msg, hdr); |
@@ -1517,67 +1524,78 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, | |||
1517 | return -EMSGSIZE; | 1524 | return -EMSGSIZE; |
1518 | } | 1525 | } |
1519 | 1526 | ||
1527 | static int nl80211_dump_wiphy_parse(struct sk_buff *skb, | ||
1528 | struct netlink_callback *cb, | ||
1529 | struct nl80211_dump_wiphy_state *state) | ||
1530 | { | ||
1531 | struct nlattr **tb = nl80211_fam.attrbuf; | ||
1532 | int ret = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize, | ||
1533 | tb, nl80211_fam.maxattr, nl80211_policy); | ||
1534 | /* ignore parse errors for backward compatibility */ | ||
1535 | if (ret) | ||
1536 | return 0; | ||
1537 | |||
1538 | state->split = tb[NL80211_ATTR_SPLIT_WIPHY_DUMP]; | ||
1539 | if (tb[NL80211_ATTR_WIPHY]) | ||
1540 | state->filter_wiphy = nla_get_u32(tb[NL80211_ATTR_WIPHY]); | ||
1541 | if (tb[NL80211_ATTR_WDEV]) | ||
1542 | state->filter_wiphy = nla_get_u64(tb[NL80211_ATTR_WDEV]) >> 32; | ||
1543 | if (tb[NL80211_ATTR_IFINDEX]) { | ||
1544 | struct net_device *netdev; | ||
1545 | struct cfg80211_registered_device *rdev; | ||
1546 | int ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]); | ||
1547 | |||
1548 | netdev = dev_get_by_index(sock_net(skb->sk), ifidx); | ||
1549 | if (!netdev) | ||
1550 | return -ENODEV; | ||
1551 | if (netdev->ieee80211_ptr) { | ||
1552 | rdev = wiphy_to_dev( | ||
1553 | netdev->ieee80211_ptr->wiphy); | ||
1554 | state->filter_wiphy = rdev->wiphy_idx; | ||
1555 | } | ||
1556 | dev_put(netdev); | ||
1557 | } | ||
1558 | |||
1559 | return 0; | ||
1560 | } | ||
1561 | |||
1520 | static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb) | 1562 | static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb) |
1521 | { | 1563 | { |
1522 | int idx = 0, ret; | 1564 | int idx = 0, ret; |
1523 | int start = cb->args[0]; | 1565 | struct nl80211_dump_wiphy_state *state = (void *)cb->args[0]; |
1524 | struct cfg80211_registered_device *dev; | 1566 | struct cfg80211_registered_device *dev; |
1525 | s64 filter_wiphy = -1; | ||
1526 | bool split = false; | ||
1527 | struct nlattr **tb; | ||
1528 | int res; | ||
1529 | |||
1530 | /* will be zeroed in nlmsg_parse() */ | ||
1531 | tb = kmalloc(sizeof(*tb) * (NL80211_ATTR_MAX + 1), GFP_KERNEL); | ||
1532 | if (!tb) | ||
1533 | return -ENOMEM; | ||
1534 | 1567 | ||
1535 | rtnl_lock(); | 1568 | rtnl_lock(); |
1536 | 1569 | if (!state) { | |
1537 | res = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize, | 1570 | state = kzalloc(sizeof(*state), GFP_KERNEL); |
1538 | tb, NL80211_ATTR_MAX, nl80211_policy); | 1571 | if (!state) { |
1539 | if (res == 0) { | 1572 | rtnl_unlock(); |
1540 | split = tb[NL80211_ATTR_SPLIT_WIPHY_DUMP]; | 1573 | return -ENOMEM; |
1541 | if (tb[NL80211_ATTR_WIPHY]) | ||
1542 | filter_wiphy = nla_get_u32(tb[NL80211_ATTR_WIPHY]); | ||
1543 | if (tb[NL80211_ATTR_WDEV]) | ||
1544 | filter_wiphy = nla_get_u64(tb[NL80211_ATTR_WDEV]) >> 32; | ||
1545 | if (tb[NL80211_ATTR_IFINDEX]) { | ||
1546 | struct net_device *netdev; | ||
1547 | int ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]); | ||
1548 | |||
1549 | netdev = dev_get_by_index(sock_net(skb->sk), ifidx); | ||
1550 | if (!netdev) { | ||
1551 | rtnl_unlock(); | ||
1552 | kfree(tb); | ||
1553 | return -ENODEV; | ||
1554 | } | ||
1555 | if (netdev->ieee80211_ptr) { | ||
1556 | dev = wiphy_to_dev( | ||
1557 | netdev->ieee80211_ptr->wiphy); | ||
1558 | filter_wiphy = dev->wiphy_idx; | ||
1559 | } | ||
1560 | dev_put(netdev); | ||
1561 | } | 1574 | } |
1575 | state->filter_wiphy = -1; | ||
1576 | ret = nl80211_dump_wiphy_parse(skb, cb, state); | ||
1577 | if (ret) { | ||
1578 | kfree(state); | ||
1579 | rtnl_unlock(); | ||
1580 | return ret; | ||
1581 | } | ||
1582 | cb->args[0] = (long)state; | ||
1562 | } | 1583 | } |
1563 | kfree(tb); | ||
1564 | 1584 | ||
1565 | list_for_each_entry(dev, &cfg80211_rdev_list, list) { | 1585 | list_for_each_entry(dev, &cfg80211_rdev_list, list) { |
1566 | if (!net_eq(wiphy_net(&dev->wiphy), sock_net(skb->sk))) | 1586 | if (!net_eq(wiphy_net(&dev->wiphy), sock_net(skb->sk))) |
1567 | continue; | 1587 | continue; |
1568 | if (++idx <= start) | 1588 | if (++idx <= state->start) |
1569 | continue; | 1589 | continue; |
1570 | if (filter_wiphy != -1 && dev->wiphy_idx != filter_wiphy) | 1590 | if (state->filter_wiphy != -1 && |
1591 | state->filter_wiphy != dev->wiphy_idx) | ||
1571 | continue; | 1592 | continue; |
1572 | /* attempt to fit multiple wiphy data chunks into the skb */ | 1593 | /* attempt to fit multiple wiphy data chunks into the skb */ |
1573 | do { | 1594 | do { |
1574 | ret = nl80211_send_wiphy(dev, skb, | 1595 | ret = nl80211_send_wiphy(dev, skb, |
1575 | NETLINK_CB(cb->skb).portid, | 1596 | NETLINK_CB(cb->skb).portid, |
1576 | cb->nlh->nlmsg_seq, | 1597 | cb->nlh->nlmsg_seq, |
1577 | NLM_F_MULTI, | 1598 | NLM_F_MULTI, state); |
1578 | split, &cb->args[1], | ||
1579 | &cb->args[2], | ||
1580 | &cb->args[3]); | ||
1581 | if (ret < 0) { | 1599 | if (ret < 0) { |
1582 | /* | 1600 | /* |
1583 | * If sending the wiphy data didn't fit (ENOBUFS | 1601 | * If sending the wiphy data didn't fit (ENOBUFS |
@@ -1602,27 +1620,34 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb) | |||
1602 | idx--; | 1620 | idx--; |
1603 | break; | 1621 | break; |
1604 | } | 1622 | } |
1605 | } while (cb->args[1] > 0); | 1623 | } while (state->split_start > 0); |
1606 | break; | 1624 | break; |
1607 | } | 1625 | } |
1608 | rtnl_unlock(); | 1626 | rtnl_unlock(); |
1609 | 1627 | ||
1610 | cb->args[0] = idx; | 1628 | state->start = idx; |
1611 | 1629 | ||
1612 | return skb->len; | 1630 | return skb->len; |
1613 | } | 1631 | } |
1614 | 1632 | ||
1633 | static int nl80211_dump_wiphy_done(struct netlink_callback *cb) | ||
1634 | { | ||
1635 | kfree((void *)cb->args[0]); | ||
1636 | return 0; | ||
1637 | } | ||
1638 | |||
1615 | static int nl80211_get_wiphy(struct sk_buff *skb, struct genl_info *info) | 1639 | static int nl80211_get_wiphy(struct sk_buff *skb, struct genl_info *info) |
1616 | { | 1640 | { |
1617 | struct sk_buff *msg; | 1641 | struct sk_buff *msg; |
1618 | struct cfg80211_registered_device *dev = info->user_ptr[0]; | 1642 | struct cfg80211_registered_device *dev = info->user_ptr[0]; |
1643 | struct nl80211_dump_wiphy_state state = {}; | ||
1619 | 1644 | ||
1620 | msg = nlmsg_new(4096, GFP_KERNEL); | 1645 | msg = nlmsg_new(4096, GFP_KERNEL); |
1621 | if (!msg) | 1646 | if (!msg) |
1622 | return -ENOMEM; | 1647 | return -ENOMEM; |
1623 | 1648 | ||
1624 | if (nl80211_send_wiphy(dev, msg, info->snd_portid, info->snd_seq, 0, | 1649 | if (nl80211_send_wiphy(dev, msg, info->snd_portid, info->snd_seq, 0, |
1625 | false, NULL, NULL, NULL) < 0) { | 1650 | &state) < 0) { |
1626 | nlmsg_free(msg); | 1651 | nlmsg_free(msg); |
1627 | return -ENOBUFS; | 1652 | return -ENOBUFS; |
1628 | } | 1653 | } |
@@ -1739,6 +1764,11 @@ static int nl80211_parse_chandef(struct cfg80211_registered_device *rdev, | |||
1739 | IEEE80211_CHAN_DISABLED)) | 1764 | IEEE80211_CHAN_DISABLED)) |
1740 | return -EINVAL; | 1765 | return -EINVAL; |
1741 | 1766 | ||
1767 | if ((chandef->width == NL80211_CHAN_WIDTH_5 || | ||
1768 | chandef->width == NL80211_CHAN_WIDTH_10) && | ||
1769 | !(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_5_10_MHZ)) | ||
1770 | return -EINVAL; | ||
1771 | |||
1742 | return 0; | 1772 | return 0; |
1743 | } | 1773 | } |
1744 | 1774 | ||
@@ -2890,61 +2920,58 @@ static int nl80211_set_mac_acl(struct sk_buff *skb, struct genl_info *info) | |||
2890 | return err; | 2920 | return err; |
2891 | } | 2921 | } |
2892 | 2922 | ||
2893 | static int nl80211_parse_beacon(struct genl_info *info, | 2923 | static int nl80211_parse_beacon(struct nlattr *attrs[], |
2894 | struct cfg80211_beacon_data *bcn) | 2924 | struct cfg80211_beacon_data *bcn) |
2895 | { | 2925 | { |
2896 | bool haveinfo = false; | 2926 | bool haveinfo = false; |
2897 | 2927 | ||
2898 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_BEACON_TAIL]) || | 2928 | if (!is_valid_ie_attr(attrs[NL80211_ATTR_BEACON_TAIL]) || |
2899 | !is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]) || | 2929 | !is_valid_ie_attr(attrs[NL80211_ATTR_IE]) || |
2900 | !is_valid_ie_attr(info->attrs[NL80211_ATTR_IE_PROBE_RESP]) || | 2930 | !is_valid_ie_attr(attrs[NL80211_ATTR_IE_PROBE_RESP]) || |
2901 | !is_valid_ie_attr(info->attrs[NL80211_ATTR_IE_ASSOC_RESP])) | 2931 | !is_valid_ie_attr(attrs[NL80211_ATTR_IE_ASSOC_RESP])) |
2902 | return -EINVAL; | 2932 | return -EINVAL; |
2903 | 2933 | ||
2904 | memset(bcn, 0, sizeof(*bcn)); | 2934 | memset(bcn, 0, sizeof(*bcn)); |
2905 | 2935 | ||
2906 | if (info->attrs[NL80211_ATTR_BEACON_HEAD]) { | 2936 | if (attrs[NL80211_ATTR_BEACON_HEAD]) { |
2907 | bcn->head = nla_data(info->attrs[NL80211_ATTR_BEACON_HEAD]); | 2937 | bcn->head = nla_data(attrs[NL80211_ATTR_BEACON_HEAD]); |
2908 | bcn->head_len = nla_len(info->attrs[NL80211_ATTR_BEACON_HEAD]); | 2938 | bcn->head_len = nla_len(attrs[NL80211_ATTR_BEACON_HEAD]); |
2909 | if (!bcn->head_len) | 2939 | if (!bcn->head_len) |
2910 | return -EINVAL; | 2940 | return -EINVAL; |
2911 | haveinfo = true; | 2941 | haveinfo = true; |
2912 | } | 2942 | } |
2913 | 2943 | ||
2914 | if (info->attrs[NL80211_ATTR_BEACON_TAIL]) { | 2944 | if (attrs[NL80211_ATTR_BEACON_TAIL]) { |
2915 | bcn->tail = nla_data(info->attrs[NL80211_ATTR_BEACON_TAIL]); | 2945 | bcn->tail = nla_data(attrs[NL80211_ATTR_BEACON_TAIL]); |
2916 | bcn->tail_len = | 2946 | bcn->tail_len = nla_len(attrs[NL80211_ATTR_BEACON_TAIL]); |
2917 | nla_len(info->attrs[NL80211_ATTR_BEACON_TAIL]); | ||
2918 | haveinfo = true; | 2947 | haveinfo = true; |
2919 | } | 2948 | } |
2920 | 2949 | ||
2921 | if (!haveinfo) | 2950 | if (!haveinfo) |
2922 | return -EINVAL; | 2951 | return -EINVAL; |
2923 | 2952 | ||
2924 | if (info->attrs[NL80211_ATTR_IE]) { | 2953 | if (attrs[NL80211_ATTR_IE]) { |
2925 | bcn->beacon_ies = nla_data(info->attrs[NL80211_ATTR_IE]); | 2954 | bcn->beacon_ies = nla_data(attrs[NL80211_ATTR_IE]); |
2926 | bcn->beacon_ies_len = nla_len(info->attrs[NL80211_ATTR_IE]); | 2955 | bcn->beacon_ies_len = nla_len(attrs[NL80211_ATTR_IE]); |
2927 | } | 2956 | } |
2928 | 2957 | ||
2929 | if (info->attrs[NL80211_ATTR_IE_PROBE_RESP]) { | 2958 | if (attrs[NL80211_ATTR_IE_PROBE_RESP]) { |
2930 | bcn->proberesp_ies = | 2959 | bcn->proberesp_ies = |
2931 | nla_data(info->attrs[NL80211_ATTR_IE_PROBE_RESP]); | 2960 | nla_data(attrs[NL80211_ATTR_IE_PROBE_RESP]); |
2932 | bcn->proberesp_ies_len = | 2961 | bcn->proberesp_ies_len = |
2933 | nla_len(info->attrs[NL80211_ATTR_IE_PROBE_RESP]); | 2962 | nla_len(attrs[NL80211_ATTR_IE_PROBE_RESP]); |
2934 | } | 2963 | } |
2935 | 2964 | ||
2936 | if (info->attrs[NL80211_ATTR_IE_ASSOC_RESP]) { | 2965 | if (attrs[NL80211_ATTR_IE_ASSOC_RESP]) { |
2937 | bcn->assocresp_ies = | 2966 | bcn->assocresp_ies = |
2938 | nla_data(info->attrs[NL80211_ATTR_IE_ASSOC_RESP]); | 2967 | nla_data(attrs[NL80211_ATTR_IE_ASSOC_RESP]); |
2939 | bcn->assocresp_ies_len = | 2968 | bcn->assocresp_ies_len = |
2940 | nla_len(info->attrs[NL80211_ATTR_IE_ASSOC_RESP]); | 2969 | nla_len(attrs[NL80211_ATTR_IE_ASSOC_RESP]); |
2941 | } | 2970 | } |
2942 | 2971 | ||
2943 | if (info->attrs[NL80211_ATTR_PROBE_RESP]) { | 2972 | if (attrs[NL80211_ATTR_PROBE_RESP]) { |
2944 | bcn->probe_resp = | 2973 | bcn->probe_resp = nla_data(attrs[NL80211_ATTR_PROBE_RESP]); |
2945 | nla_data(info->attrs[NL80211_ATTR_PROBE_RESP]); | 2974 | bcn->probe_resp_len = nla_len(attrs[NL80211_ATTR_PROBE_RESP]); |
2946 | bcn->probe_resp_len = | ||
2947 | nla_len(info->attrs[NL80211_ATTR_PROBE_RESP]); | ||
2948 | } | 2975 | } |
2949 | 2976 | ||
2950 | return 0; | 2977 | return 0; |
@@ -3023,7 +3050,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) | |||
3023 | !info->attrs[NL80211_ATTR_BEACON_HEAD]) | 3050 | !info->attrs[NL80211_ATTR_BEACON_HEAD]) |
3024 | return -EINVAL; | 3051 | return -EINVAL; |
3025 | 3052 | ||
3026 | err = nl80211_parse_beacon(info, ¶ms.beacon); | 3053 | err = nl80211_parse_beacon(info->attrs, ¶ms.beacon); |
3027 | if (err) | 3054 | if (err) |
3028 | return err; | 3055 | return err; |
3029 | 3056 | ||
@@ -3175,7 +3202,7 @@ static int nl80211_set_beacon(struct sk_buff *skb, struct genl_info *info) | |||
3175 | if (!wdev->beacon_interval) | 3202 | if (!wdev->beacon_interval) |
3176 | return -EINVAL; | 3203 | return -EINVAL; |
3177 | 3204 | ||
3178 | err = nl80211_parse_beacon(info, ¶ms); | 3205 | err = nl80211_parse_beacon(info->attrs, ¶ms); |
3179 | if (err) | 3206 | if (err) |
3180 | return err; | 3207 | return err; |
3181 | 3208 | ||
@@ -6291,11 +6318,16 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) | |||
6291 | if (!cfg80211_reg_can_beacon(&rdev->wiphy, &ibss.chandef)) | 6318 | if (!cfg80211_reg_can_beacon(&rdev->wiphy, &ibss.chandef)) |
6292 | return -EINVAL; | 6319 | return -EINVAL; |
6293 | 6320 | ||
6294 | if (ibss.chandef.width > NL80211_CHAN_WIDTH_40) | 6321 | switch (ibss.chandef.width) { |
6295 | return -EINVAL; | 6322 | case NL80211_CHAN_WIDTH_20_NOHT: |
6296 | if (ibss.chandef.width != NL80211_CHAN_WIDTH_20_NOHT && | 6323 | break; |
6297 | !(rdev->wiphy.features & NL80211_FEATURE_HT_IBSS)) | 6324 | case NL80211_CHAN_WIDTH_20: |
6325 | case NL80211_CHAN_WIDTH_40: | ||
6326 | if (rdev->wiphy.features & NL80211_FEATURE_HT_IBSS) | ||
6327 | break; | ||
6328 | default: | ||
6298 | return -EINVAL; | 6329 | return -EINVAL; |
6330 | } | ||
6299 | 6331 | ||
6300 | ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED]; | 6332 | ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED]; |
6301 | ibss.privacy = !!info->attrs[NL80211_ATTR_PRIVACY]; | 6333 | ibss.privacy = !!info->attrs[NL80211_ATTR_PRIVACY]; |
@@ -8409,6 +8441,7 @@ static struct genl_ops nl80211_ops[] = { | |||
8409 | .cmd = NL80211_CMD_GET_WIPHY, | 8441 | .cmd = NL80211_CMD_GET_WIPHY, |
8410 | .doit = nl80211_get_wiphy, | 8442 | .doit = nl80211_get_wiphy, |
8411 | .dumpit = nl80211_dump_wiphy, | 8443 | .dumpit = nl80211_dump_wiphy, |
8444 | .done = nl80211_dump_wiphy_done, | ||
8412 | .policy = nl80211_policy, | 8445 | .policy = nl80211_policy, |
8413 | /* can be retrieved by unprivileged users */ | 8446 | /* can be retrieved by unprivileged users */ |
8414 | .internal_flags = NL80211_FLAG_NEED_WIPHY | | 8447 | .internal_flags = NL80211_FLAG_NEED_WIPHY | |
@@ -9029,13 +9062,13 @@ static struct genl_multicast_group nl80211_regulatory_mcgrp = { | |||
9029 | void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev) | 9062 | void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev) |
9030 | { | 9063 | { |
9031 | struct sk_buff *msg; | 9064 | struct sk_buff *msg; |
9065 | struct nl80211_dump_wiphy_state state = {}; | ||
9032 | 9066 | ||
9033 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 9067 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
9034 | if (!msg) | 9068 | if (!msg) |
9035 | return; | 9069 | return; |
9036 | 9070 | ||
9037 | if (nl80211_send_wiphy(rdev, msg, 0, 0, 0, | 9071 | if (nl80211_send_wiphy(rdev, msg, 0, 0, 0, &state) < 0) { |
9038 | false, NULL, NULL, NULL) < 0) { | ||
9039 | nlmsg_free(msg); | 9072 | nlmsg_free(msg); |
9040 | return; | 9073 | return; |
9041 | } | 9074 | } |