diff options
author | Johannes Berg <johannes.berg@intel.com> | 2013-06-19 04:57:22 -0400 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2013-06-19 12:55:38 -0400 |
commit | 86e8cf98de3e74bbfb0003501e0004bf1e5e2618 (patch) | |
tree | 89713ea44449ff036a5bbc5236357a382e5b0ed2 /net | |
parent | f93beba705842af466e7c916b39630cacb40e9c6 (diff) |
nl80211: use small state buffer for wiphy_dump
Avoid parsing the original dump message again and again by
allocating a small state struct that is used by the functions
involved in the dump, storing this struct in cb->args[0].
This reduces the memory allocation size as well.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net')
-rw-r--r-- | net/wireless/nl80211.c | 210 |
1 files changed, 116 insertions, 94 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index f8ffb9a59c83..7dc3343427c1 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) || |
@@ -1192,8 +1193,8 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, | |||
1192 | nla_put_flag(msg, WIPHY_FLAG_SUPPORTS_5_10_MHZ)) | 1193 | nla_put_flag(msg, WIPHY_FLAG_SUPPORTS_5_10_MHZ)) |
1193 | goto nla_put_failure; | 1194 | goto nla_put_failure; |
1194 | 1195 | ||
1195 | (*split_start)++; | 1196 | state->split_start++; |
1196 | if (split) | 1197 | if (state->split) |
1197 | break; | 1198 | break; |
1198 | case 1: | 1199 | case 1: |
1199 | if (nla_put(msg, NL80211_ATTR_CIPHER_SUITES, | 1200 | if (nla_put(msg, NL80211_ATTR_CIPHER_SUITES, |
@@ -1237,22 +1238,23 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, | |||
1237 | } | 1238 | } |
1238 | } | 1239 | } |
1239 | 1240 | ||
1240 | (*split_start)++; | 1241 | state->split_start++; |
1241 | if (split) | 1242 | if (state->split) |
1242 | break; | 1243 | break; |
1243 | case 2: | 1244 | case 2: |
1244 | if (nl80211_put_iftypes(msg, NL80211_ATTR_SUPPORTED_IFTYPES, | 1245 | if (nl80211_put_iftypes(msg, NL80211_ATTR_SUPPORTED_IFTYPES, |
1245 | dev->wiphy.interface_modes)) | 1246 | dev->wiphy.interface_modes)) |
1246 | goto nla_put_failure; | 1247 | goto nla_put_failure; |
1247 | (*split_start)++; | 1248 | state->split_start++; |
1248 | if (split) | 1249 | if (state->split) |
1249 | break; | 1250 | break; |
1250 | case 3: | 1251 | case 3: |
1251 | nl_bands = nla_nest_start(msg, NL80211_ATTR_WIPHY_BANDS); | 1252 | nl_bands = nla_nest_start(msg, NL80211_ATTR_WIPHY_BANDS); |
1252 | if (!nl_bands) | 1253 | if (!nl_bands) |
1253 | goto nla_put_failure; | 1254 | goto nla_put_failure; |
1254 | 1255 | ||
1255 | for (band = *band_start; band < IEEE80211_NUM_BANDS; band++) { | 1256 | for (band = state->band_start; |
1257 | band < IEEE80211_NUM_BANDS; band++) { | ||
1256 | struct ieee80211_supported_band *sband; | 1258 | struct ieee80211_supported_band *sband; |
1257 | 1259 | ||
1258 | sband = dev->wiphy.bands[band]; | 1260 | sband = dev->wiphy.bands[band]; |
@@ -1264,12 +1266,12 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, | |||
1264 | if (!nl_band) | 1266 | if (!nl_band) |
1265 | goto nla_put_failure; | 1267 | goto nla_put_failure; |
1266 | 1268 | ||
1267 | switch (*chan_start) { | 1269 | switch (state->chan_start) { |
1268 | case 0: | 1270 | case 0: |
1269 | if (nl80211_send_band_rateinfo(msg, sband)) | 1271 | if (nl80211_send_band_rateinfo(msg, sband)) |
1270 | goto nla_put_failure; | 1272 | goto nla_put_failure; |
1271 | (*chan_start)++; | 1273 | state->chan_start++; |
1272 | if (split) | 1274 | if (state->split) |
1273 | break; | 1275 | break; |
1274 | default: | 1276 | default: |
1275 | /* add frequencies */ | 1277 | /* add frequencies */ |
@@ -1278,7 +1280,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, | |||
1278 | if (!nl_freqs) | 1280 | if (!nl_freqs) |
1279 | goto nla_put_failure; | 1281 | goto nla_put_failure; |
1280 | 1282 | ||
1281 | for (i = *chan_start - 1; | 1283 | for (i = state->chan_start - 1; |
1282 | i < sband->n_channels; | 1284 | i < sband->n_channels; |
1283 | i++) { | 1285 | i++) { |
1284 | nl_freq = nla_nest_start(msg, i); | 1286 | nl_freq = nla_nest_start(msg, i); |
@@ -1287,26 +1289,27 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, | |||
1287 | 1289 | ||
1288 | chan = &sband->channels[i]; | 1290 | chan = &sband->channels[i]; |
1289 | 1291 | ||
1290 | if (nl80211_msg_put_channel(msg, chan, | 1292 | if (nl80211_msg_put_channel( |
1291 | split)) | 1293 | msg, chan, |
1294 | state->split)) | ||
1292 | goto nla_put_failure; | 1295 | goto nla_put_failure; |
1293 | 1296 | ||
1294 | nla_nest_end(msg, nl_freq); | 1297 | nla_nest_end(msg, nl_freq); |
1295 | if (split) | 1298 | if (state->split) |
1296 | break; | 1299 | break; |
1297 | } | 1300 | } |
1298 | if (i < sband->n_channels) | 1301 | if (i < sband->n_channels) |
1299 | *chan_start = i + 2; | 1302 | state->chan_start = i + 2; |
1300 | else | 1303 | else |
1301 | *chan_start = 0; | 1304 | state->chan_start = 0; |
1302 | nla_nest_end(msg, nl_freqs); | 1305 | nla_nest_end(msg, nl_freqs); |
1303 | } | 1306 | } |
1304 | 1307 | ||
1305 | nla_nest_end(msg, nl_band); | 1308 | nla_nest_end(msg, nl_band); |
1306 | 1309 | ||
1307 | if (split) { | 1310 | if (state->split) { |
1308 | /* start again here */ | 1311 | /* start again here */ |
1309 | if (*chan_start) | 1312 | if (state->chan_start) |
1310 | band--; | 1313 | band--; |
1311 | break; | 1314 | break; |
1312 | } | 1315 | } |
@@ -1314,14 +1317,14 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, | |||
1314 | nla_nest_end(msg, nl_bands); | 1317 | nla_nest_end(msg, nl_bands); |
1315 | 1318 | ||
1316 | if (band < IEEE80211_NUM_BANDS) | 1319 | if (band < IEEE80211_NUM_BANDS) |
1317 | *band_start = band + 1; | 1320 | state->band_start = band + 1; |
1318 | else | 1321 | else |
1319 | *band_start = 0; | 1322 | state->band_start = 0; |
1320 | 1323 | ||
1321 | /* if bands & channels are done, continue outside */ | 1324 | /* if bands & channels are done, continue outside */ |
1322 | if (*band_start == 0 && *chan_start == 0) | 1325 | if (state->band_start == 0 && state->chan_start == 0) |
1323 | (*split_start)++; | 1326 | state->split_start++; |
1324 | if (split) | 1327 | if (state->split) |
1325 | break; | 1328 | break; |
1326 | case 4: | 1329 | case 4: |
1327 | nl_cmds = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_COMMANDS); | 1330 | nl_cmds = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_COMMANDS); |
@@ -1387,7 +1390,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, | |||
1387 | } | 1390 | } |
1388 | CMD(start_p2p_device, START_P2P_DEVICE); | 1391 | CMD(start_p2p_device, START_P2P_DEVICE); |
1389 | CMD(set_mcast_rate, SET_MCAST_RATE); | 1392 | CMD(set_mcast_rate, SET_MCAST_RATE); |
1390 | if (split) { | 1393 | if (state->split) { |
1391 | CMD(crit_proto_start, CRIT_PROTOCOL_START); | 1394 | CMD(crit_proto_start, CRIT_PROTOCOL_START); |
1392 | CMD(crit_proto_stop, CRIT_PROTOCOL_STOP); | 1395 | CMD(crit_proto_stop, CRIT_PROTOCOL_STOP); |
1393 | } | 1396 | } |
@@ -1411,8 +1414,8 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, | |||
1411 | } | 1414 | } |
1412 | 1415 | ||
1413 | nla_nest_end(msg, nl_cmds); | 1416 | nla_nest_end(msg, nl_cmds); |
1414 | (*split_start)++; | 1417 | state->split_start++; |
1415 | if (split) | 1418 | if (state->split) |
1416 | break; | 1419 | break; |
1417 | case 5: | 1420 | case 5: |
1418 | if (dev->ops->remain_on_channel && | 1421 | if (dev->ops->remain_on_channel && |
@@ -1428,29 +1431,30 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, | |||
1428 | 1431 | ||
1429 | if (nl80211_send_mgmt_stypes(msg, mgmt_stypes)) | 1432 | if (nl80211_send_mgmt_stypes(msg, mgmt_stypes)) |
1430 | goto nla_put_failure; | 1433 | goto nla_put_failure; |
1431 | (*split_start)++; | 1434 | state->split_start++; |
1432 | if (split) | 1435 | if (state->split) |
1433 | break; | 1436 | break; |
1434 | case 6: | 1437 | case 6: |
1435 | #ifdef CONFIG_PM | 1438 | #ifdef CONFIG_PM |
1436 | if (nl80211_send_wowlan(msg, dev, split)) | 1439 | if (nl80211_send_wowlan(msg, dev, state->split)) |
1437 | goto nla_put_failure; | 1440 | goto nla_put_failure; |
1438 | (*split_start)++; | 1441 | state->split_start++; |
1439 | if (split) | 1442 | if (state->split) |
1440 | break; | 1443 | break; |
1441 | #else | 1444 | #else |
1442 | (*split_start)++; | 1445 | state->split_start++; |
1443 | #endif | 1446 | #endif |
1444 | case 7: | 1447 | case 7: |
1445 | if (nl80211_put_iftypes(msg, NL80211_ATTR_SOFTWARE_IFTYPES, | 1448 | if (nl80211_put_iftypes(msg, NL80211_ATTR_SOFTWARE_IFTYPES, |
1446 | dev->wiphy.software_iftypes)) | 1449 | dev->wiphy.software_iftypes)) |
1447 | goto nla_put_failure; | 1450 | goto nla_put_failure; |
1448 | 1451 | ||
1449 | if (nl80211_put_iface_combinations(&dev->wiphy, msg, split)) | 1452 | if (nl80211_put_iface_combinations(&dev->wiphy, msg, |
1453 | state->split)) | ||
1450 | goto nla_put_failure; | 1454 | goto nla_put_failure; |
1451 | 1455 | ||
1452 | (*split_start)++; | 1456 | state->split_start++; |
1453 | if (split) | 1457 | if (state->split) |
1454 | break; | 1458 | break; |
1455 | case 8: | 1459 | case 8: |
1456 | if ((dev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME) && | 1460 | if ((dev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME) && |
@@ -1464,7 +1468,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, | |||
1464 | * dump is split, otherwise it makes it too big. Therefore | 1468 | * dump is split, otherwise it makes it too big. Therefore |
1465 | * only advertise it in that case. | 1469 | * only advertise it in that case. |
1466 | */ | 1470 | */ |
1467 | if (split) | 1471 | if (state->split) |
1468 | features |= NL80211_FEATURE_ADVERTISE_CHAN_LIMITS; | 1472 | features |= NL80211_FEATURE_ADVERTISE_CHAN_LIMITS; |
1469 | if (nla_put_u32(msg, NL80211_ATTR_FEATURE_FLAGS, features)) | 1473 | if (nla_put_u32(msg, NL80211_ATTR_FEATURE_FLAGS, features)) |
1470 | goto nla_put_failure; | 1474 | goto nla_put_failure; |
@@ -1491,7 +1495,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, | |||
1491 | * case we'll continue with more data in the next round, | 1495 | * case we'll continue with more data in the next round, |
1492 | * but break unconditionally so unsplit data stops here. | 1496 | * but break unconditionally so unsplit data stops here. |
1493 | */ | 1497 | */ |
1494 | (*split_start)++; | 1498 | state->split_start++; |
1495 | break; | 1499 | break; |
1496 | case 9: | 1500 | case 9: |
1497 | if (dev->wiphy.extended_capabilities && | 1501 | if (dev->wiphy.extended_capabilities && |
@@ -1510,7 +1514,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, | |||
1510 | goto nla_put_failure; | 1514 | goto nla_put_failure; |
1511 | 1515 | ||
1512 | /* done */ | 1516 | /* done */ |
1513 | *split_start = 0; | 1517 | state->split_start = 0; |
1514 | break; | 1518 | break; |
1515 | } | 1519 | } |
1516 | return genlmsg_end(msg, hdr); | 1520 | return genlmsg_end(msg, hdr); |
@@ -1520,66 +1524,76 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, | |||
1520 | return -EMSGSIZE; | 1524 | return -EMSGSIZE; |
1521 | } | 1525 | } |
1522 | 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 | |||
1523 | 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) |
1524 | { | 1563 | { |
1525 | int idx = 0, ret; | 1564 | int idx = 0, ret; |
1526 | int start = cb->args[0]; | 1565 | struct nl80211_dump_wiphy_state *state = (void *)cb->args[0]; |
1527 | struct cfg80211_registered_device *dev; | 1566 | struct cfg80211_registered_device *dev; |
1528 | s64 filter_wiphy = -1; | ||
1529 | bool split = false; | ||
1530 | struct nlattr **tb; | ||
1531 | int res; | ||
1532 | |||
1533 | /* will be zeroed in nlmsg_parse() */ | ||
1534 | tb = kmalloc(sizeof(*tb) * (NL80211_ATTR_MAX + 1), GFP_KERNEL); | ||
1535 | if (!tb) | ||
1536 | return -ENOMEM; | ||
1537 | 1567 | ||
1538 | rtnl_lock(); | 1568 | rtnl_lock(); |
1539 | res = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize, | 1569 | if (!state) { |
1540 | tb, NL80211_ATTR_MAX, nl80211_policy); | 1570 | state = kzalloc(sizeof(*state), GFP_KERNEL); |
1541 | if (res == 0) { | 1571 | if (!state) |
1542 | split = tb[NL80211_ATTR_SPLIT_WIPHY_DUMP]; | 1572 | return -ENOMEM; |
1543 | if (tb[NL80211_ATTR_WIPHY]) | 1573 | state->filter_wiphy = -1; |
1544 | filter_wiphy = nla_get_u32(tb[NL80211_ATTR_WIPHY]); | 1574 | ret = nl80211_dump_wiphy_parse(skb, cb, state); |
1545 | if (tb[NL80211_ATTR_WDEV]) | 1575 | if (ret) { |
1546 | filter_wiphy = nla_get_u64(tb[NL80211_ATTR_WDEV]) >> 32; | 1576 | kfree(state); |
1547 | if (tb[NL80211_ATTR_IFINDEX]) { | 1577 | rtnl_unlock(); |
1548 | struct net_device *netdev; | 1578 | return ret; |
1549 | int ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]); | ||
1550 | |||
1551 | netdev = dev_get_by_index(sock_net(skb->sk), ifidx); | ||
1552 | if (!netdev) { | ||
1553 | rtnl_unlock(); | ||
1554 | kfree(tb); | ||
1555 | return -ENODEV; | ||
1556 | } | ||
1557 | if (netdev->ieee80211_ptr) { | ||
1558 | dev = wiphy_to_dev( | ||
1559 | netdev->ieee80211_ptr->wiphy); | ||
1560 | filter_wiphy = dev->wiphy_idx; | ||
1561 | } | ||
1562 | dev_put(netdev); | ||
1563 | } | 1579 | } |
1580 | cb->args[0] = (long)state; | ||
1564 | } | 1581 | } |
1565 | kfree(tb); | ||
1566 | 1582 | ||
1567 | list_for_each_entry(dev, &cfg80211_rdev_list, list) { | 1583 | list_for_each_entry(dev, &cfg80211_rdev_list, list) { |
1568 | if (!net_eq(wiphy_net(&dev->wiphy), sock_net(skb->sk))) | 1584 | if (!net_eq(wiphy_net(&dev->wiphy), sock_net(skb->sk))) |
1569 | continue; | 1585 | continue; |
1570 | if (++idx <= start) | 1586 | if (++idx <= state->start) |
1571 | continue; | 1587 | continue; |
1572 | if (filter_wiphy != -1 && dev->wiphy_idx != filter_wiphy) | 1588 | if (state->filter_wiphy != -1 && |
1589 | state->filter_wiphy != dev->wiphy_idx) | ||
1573 | continue; | 1590 | continue; |
1574 | /* attempt to fit multiple wiphy data chunks into the skb */ | 1591 | /* attempt to fit multiple wiphy data chunks into the skb */ |
1575 | do { | 1592 | do { |
1576 | ret = nl80211_send_wiphy(dev, skb, | 1593 | ret = nl80211_send_wiphy(dev, skb, |
1577 | NETLINK_CB(cb->skb).portid, | 1594 | NETLINK_CB(cb->skb).portid, |
1578 | cb->nlh->nlmsg_seq, | 1595 | cb->nlh->nlmsg_seq, |
1579 | NLM_F_MULTI, | 1596 | NLM_F_MULTI, state); |
1580 | split, &cb->args[1], | ||
1581 | &cb->args[2], | ||
1582 | &cb->args[3]); | ||
1583 | if (ret < 0) { | 1597 | if (ret < 0) { |
1584 | /* | 1598 | /* |
1585 | * If sending the wiphy data didn't fit (ENOBUFS | 1599 | * If sending the wiphy data didn't fit (ENOBUFS |
@@ -1604,27 +1618,34 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb) | |||
1604 | idx--; | 1618 | idx--; |
1605 | break; | 1619 | break; |
1606 | } | 1620 | } |
1607 | } while (cb->args[1] > 0); | 1621 | } while (state->split_start > 0); |
1608 | break; | 1622 | break; |
1609 | } | 1623 | } |
1610 | rtnl_unlock(); | 1624 | rtnl_unlock(); |
1611 | 1625 | ||
1612 | cb->args[0] = idx; | 1626 | state->start = idx; |
1613 | 1627 | ||
1614 | return skb->len; | 1628 | return skb->len; |
1615 | } | 1629 | } |
1616 | 1630 | ||
1631 | static int nl80211_dump_wiphy_done(struct netlink_callback *cb) | ||
1632 | { | ||
1633 | kfree((void *)cb->args[0]); | ||
1634 | return 0; | ||
1635 | } | ||
1636 | |||
1617 | static int nl80211_get_wiphy(struct sk_buff *skb, struct genl_info *info) | 1637 | static int nl80211_get_wiphy(struct sk_buff *skb, struct genl_info *info) |
1618 | { | 1638 | { |
1619 | struct sk_buff *msg; | 1639 | struct sk_buff *msg; |
1620 | struct cfg80211_registered_device *dev = info->user_ptr[0]; | 1640 | struct cfg80211_registered_device *dev = info->user_ptr[0]; |
1641 | struct nl80211_dump_wiphy_state state = {}; | ||
1621 | 1642 | ||
1622 | msg = nlmsg_new(4096, GFP_KERNEL); | 1643 | msg = nlmsg_new(4096, GFP_KERNEL); |
1623 | if (!msg) | 1644 | if (!msg) |
1624 | return -ENOMEM; | 1645 | return -ENOMEM; |
1625 | 1646 | ||
1626 | if (nl80211_send_wiphy(dev, msg, info->snd_portid, info->snd_seq, 0, | 1647 | if (nl80211_send_wiphy(dev, msg, info->snd_portid, info->snd_seq, 0, |
1627 | false, NULL, NULL, NULL) < 0) { | 1648 | &state) < 0) { |
1628 | nlmsg_free(msg); | 1649 | nlmsg_free(msg); |
1629 | return -ENOBUFS; | 1650 | return -ENOBUFS; |
1630 | } | 1651 | } |
@@ -8418,6 +8439,7 @@ static struct genl_ops nl80211_ops[] = { | |||
8418 | .cmd = NL80211_CMD_GET_WIPHY, | 8439 | .cmd = NL80211_CMD_GET_WIPHY, |
8419 | .doit = nl80211_get_wiphy, | 8440 | .doit = nl80211_get_wiphy, |
8420 | .dumpit = nl80211_dump_wiphy, | 8441 | .dumpit = nl80211_dump_wiphy, |
8442 | .done = nl80211_dump_wiphy_done, | ||
8421 | .policy = nl80211_policy, | 8443 | .policy = nl80211_policy, |
8422 | /* can be retrieved by unprivileged users */ | 8444 | /* can be retrieved by unprivileged users */ |
8423 | .internal_flags = NL80211_FLAG_NEED_WIPHY | | 8445 | .internal_flags = NL80211_FLAG_NEED_WIPHY | |
@@ -9038,13 +9060,13 @@ static struct genl_multicast_group nl80211_regulatory_mcgrp = { | |||
9038 | void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev) | 9060 | void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev) |
9039 | { | 9061 | { |
9040 | struct sk_buff *msg; | 9062 | struct sk_buff *msg; |
9063 | struct nl80211_dump_wiphy_state state = {}; | ||
9041 | 9064 | ||
9042 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 9065 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
9043 | if (!msg) | 9066 | if (!msg) |
9044 | return; | 9067 | return; |
9045 | 9068 | ||
9046 | if (nl80211_send_wiphy(rdev, msg, 0, 0, 0, | 9069 | if (nl80211_send_wiphy(rdev, msg, 0, 0, 0, &state) < 0) { |
9047 | false, NULL, NULL, NULL) < 0) { | ||
9048 | nlmsg_free(msg); | 9070 | nlmsg_free(msg); |
9049 | return; | 9071 | return; |
9050 | } | 9072 | } |