aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/nl80211.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r--net/wireless/nl80211.c275
1 files changed, 153 insertions, 122 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index b7fefffd2d0d..59eb2cf42e5f 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -29,16 +29,16 @@ static struct genl_family nl80211_fam = {
29}; 29};
30 30
31/* internal helper: get drv and dev */ 31/* internal helper: get drv and dev */
32static int get_drv_dev_by_info_ifindex(struct genl_info *info, 32static int get_drv_dev_by_info_ifindex(struct nlattr **attrs,
33 struct cfg80211_registered_device **drv, 33 struct cfg80211_registered_device **drv,
34 struct net_device **dev) 34 struct net_device **dev)
35{ 35{
36 int ifindex; 36 int ifindex;
37 37
38 if (!info->attrs[NL80211_ATTR_IFINDEX]) 38 if (!attrs[NL80211_ATTR_IFINDEX])
39 return -EINVAL; 39 return -EINVAL;
40 40
41 ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]); 41 ifindex = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]);
42 *dev = dev_get_by_index(&init_net, ifindex); 42 *dev = dev_get_by_index(&init_net, ifindex);
43 if (!*dev) 43 if (!*dev)
44 return -ENODEV; 44 return -ENODEV;
@@ -291,21 +291,31 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback *
291 291
292 mutex_lock(&cfg80211_drv_mutex); 292 mutex_lock(&cfg80211_drv_mutex);
293 list_for_each_entry(dev, &cfg80211_drv_list, list) { 293 list_for_each_entry(dev, &cfg80211_drv_list, list) {
294 if (++wp_idx < wp_start) 294 if (wp_idx < wp_start) {
295 wp_idx++;
295 continue; 296 continue;
297 }
296 if_idx = 0; 298 if_idx = 0;
297 299
298 mutex_lock(&dev->devlist_mtx); 300 mutex_lock(&dev->devlist_mtx);
299 list_for_each_entry(wdev, &dev->netdev_list, list) { 301 list_for_each_entry(wdev, &dev->netdev_list, list) {
300 if (++if_idx < if_start) 302 if (if_idx < if_start) {
303 if_idx++;
301 continue; 304 continue;
305 }
302 if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).pid, 306 if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).pid,
303 cb->nlh->nlmsg_seq, NLM_F_MULTI, 307 cb->nlh->nlmsg_seq, NLM_F_MULTI,
304 wdev->netdev) < 0) 308 wdev->netdev) < 0) {
305 break; 309 mutex_unlock(&dev->devlist_mtx);
310 goto out;
311 }
312 if_idx++;
306 } 313 }
307 mutex_unlock(&dev->devlist_mtx); 314 mutex_unlock(&dev->devlist_mtx);
315
316 wp_idx++;
308 } 317 }
318 out:
309 mutex_unlock(&cfg80211_drv_mutex); 319 mutex_unlock(&cfg80211_drv_mutex);
310 320
311 cb->args[0] = wp_idx; 321 cb->args[0] = wp_idx;
@@ -321,7 +331,7 @@ static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info)
321 struct net_device *netdev; 331 struct net_device *netdev;
322 int err; 332 int err;
323 333
324 err = get_drv_dev_by_info_ifindex(info, &dev, &netdev); 334 err = get_drv_dev_by_info_ifindex(info->attrs, &dev, &netdev);
325 if (err) 335 if (err)
326 return err; 336 return err;
327 337
@@ -392,7 +402,7 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
392 } else 402 } else
393 return -EINVAL; 403 return -EINVAL;
394 404
395 err = get_drv_dev_by_info_ifindex(info, &drv, &dev); 405 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
396 if (err) 406 if (err)
397 return err; 407 return err;
398 ifindex = dev->ifindex; 408 ifindex = dev->ifindex;
@@ -477,7 +487,7 @@ static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info)
477 int ifindex, err; 487 int ifindex, err;
478 struct net_device *dev; 488 struct net_device *dev;
479 489
480 err = get_drv_dev_by_info_ifindex(info, &drv, &dev); 490 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
481 if (err) 491 if (err)
482 return err; 492 return err;
483 ifindex = dev->ifindex; 493 ifindex = dev->ifindex;
@@ -545,7 +555,7 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
545 if (info->attrs[NL80211_ATTR_MAC]) 555 if (info->attrs[NL80211_ATTR_MAC])
546 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); 556 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
547 557
548 err = get_drv_dev_by_info_ifindex(info, &drv, &dev); 558 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
549 if (err) 559 if (err)
550 return err; 560 return err;
551 561
@@ -618,7 +628,7 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
618 if (!info->attrs[NL80211_ATTR_KEY_DEFAULT]) 628 if (!info->attrs[NL80211_ATTR_KEY_DEFAULT])
619 return -EINVAL; 629 return -EINVAL;
620 630
621 err = get_drv_dev_by_info_ifindex(info, &drv, &dev); 631 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
622 if (err) 632 if (err)
623 return err; 633 return err;
624 634
@@ -699,7 +709,7 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
699 return -EINVAL; 709 return -EINVAL;
700 } 710 }
701 711
702 err = get_drv_dev_by_info_ifindex(info, &drv, &dev); 712 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
703 if (err) 713 if (err)
704 return err; 714 return err;
705 715
@@ -735,7 +745,7 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
735 if (info->attrs[NL80211_ATTR_MAC]) 745 if (info->attrs[NL80211_ATTR_MAC])
736 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); 746 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
737 747
738 err = get_drv_dev_by_info_ifindex(info, &drv, &dev); 748 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
739 if (err) 749 if (err)
740 return err; 750 return err;
741 751
@@ -764,7 +774,7 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
764 struct beacon_parameters params; 774 struct beacon_parameters params;
765 int haveinfo = 0; 775 int haveinfo = 0;
766 776
767 err = get_drv_dev_by_info_ifindex(info, &drv, &dev); 777 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
768 if (err) 778 if (err)
769 return err; 779 return err;
770 780
@@ -843,7 +853,7 @@ static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info)
843 int err; 853 int err;
844 struct net_device *dev; 854 struct net_device *dev;
845 855
846 err = get_drv_dev_by_info_ifindex(info, &drv, &dev); 856 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
847 if (err) 857 if (err)
848 return err; 858 return err;
849 859
@@ -937,67 +947,78 @@ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq,
937} 947}
938 948
939static int nl80211_dump_station(struct sk_buff *skb, 949static int nl80211_dump_station(struct sk_buff *skb,
940 struct netlink_callback *cb) 950 struct netlink_callback *cb)
941{ 951{
942 int wp_idx = 0;
943 int if_idx = 0;
944 int sta_idx = cb->args[2];
945 int wp_start = cb->args[0];
946 int if_start = cb->args[1];
947 struct station_info sinfo; 952 struct station_info sinfo;
948 struct cfg80211_registered_device *dev; 953 struct cfg80211_registered_device *dev;
949 struct wireless_dev *wdev; 954 struct net_device *netdev;
950 u8 mac_addr[ETH_ALEN]; 955 u8 mac_addr[ETH_ALEN];
956 int ifidx = cb->args[0];
957 int sta_idx = cb->args[1];
951 int err; 958 int err;
952 int exit = 0;
953 959
954 /* TODO: filter by device */ 960 if (!ifidx) {
955 mutex_lock(&cfg80211_drv_mutex); 961 err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize,
956 list_for_each_entry(dev, &cfg80211_drv_list, list) { 962 nl80211_fam.attrbuf, nl80211_fam.maxattr,
957 if (exit) 963 nl80211_policy);
964 if (err)
965 return err;
966
967 if (!nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX])
968 return -EINVAL;
969
970 ifidx = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]);
971 if (!ifidx)
972 return -EINVAL;
973 }
974
975 netdev = dev_get_by_index(&init_net, ifidx);
976 if (!netdev)
977 return -ENODEV;
978
979 dev = cfg80211_get_dev_from_ifindex(ifidx);
980 if (IS_ERR(dev)) {
981 err = PTR_ERR(dev);
982 goto out_put_netdev;
983 }
984
985 if (!dev->ops->dump_station) {
986 err = -ENOSYS;
987 goto out_err;
988 }
989
990 rtnl_lock();
991
992 while (1) {
993 err = dev->ops->dump_station(&dev->wiphy, netdev, sta_idx,
994 mac_addr, &sinfo);
995 if (err == -ENOENT)
958 break; 996 break;
959 if (++wp_idx < wp_start) 997 if (err)
960 continue; 998 goto out_err_rtnl;
961 if_idx = 0;
962 999
963 mutex_lock(&dev->devlist_mtx); 1000 if (nl80211_send_station(skb,
964 list_for_each_entry(wdev, &dev->netdev_list, list) { 1001 NETLINK_CB(cb->skb).pid,
965 if (exit) 1002 cb->nlh->nlmsg_seq, NLM_F_MULTI,
966 break; 1003 netdev, mac_addr,
967 if (++if_idx < if_start) 1004 &sinfo) < 0)
968 continue; 1005 goto out;
969 if (!dev->ops->dump_station)
970 continue;
971 1006
972 for (;; ++sta_idx) { 1007 sta_idx++;
973 rtnl_lock();
974 err = dev->ops->dump_station(&dev->wiphy,
975 wdev->netdev, sta_idx, mac_addr,
976 &sinfo);
977 rtnl_unlock();
978 if (err) {
979 sta_idx = 0;
980 break;
981 }
982 if (nl80211_send_station(skb,
983 NETLINK_CB(cb->skb).pid,
984 cb->nlh->nlmsg_seq, NLM_F_MULTI,
985 wdev->netdev, mac_addr,
986 &sinfo) < 0) {
987 exit = 1;
988 break;
989 }
990 }
991 }
992 mutex_unlock(&dev->devlist_mtx);
993 } 1008 }
994 mutex_unlock(&cfg80211_drv_mutex);
995 1009
996 cb->args[0] = wp_idx;
997 cb->args[1] = if_idx;
998 cb->args[2] = sta_idx;
999 1010
1000 return skb->len; 1011 out:
1012 cb->args[1] = sta_idx;
1013 err = skb->len;
1014 out_err_rtnl:
1015 rtnl_unlock();
1016 out_err:
1017 cfg80211_put_dev(dev);
1018 out_put_netdev:
1019 dev_put(netdev);
1020
1021 return err;
1001} 1022}
1002 1023
1003static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) 1024static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
@@ -1016,7 +1037,7 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
1016 1037
1017 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); 1038 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
1018 1039
1019 err = get_drv_dev_by_info_ifindex(info, &drv, &dev); 1040 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
1020 if (err) 1041 if (err)
1021 return err; 1042 return err;
1022 1043
@@ -1112,7 +1133,7 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
1112 params.plink_action = 1133 params.plink_action =
1113 nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]); 1134 nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]);
1114 1135
1115 err = get_drv_dev_by_info_ifindex(info, &drv, &dev); 1136 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
1116 if (err) 1137 if (err)
1117 return err; 1138 return err;
1118 1139
@@ -1172,7 +1193,7 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
1172 &params.station_flags)) 1193 &params.station_flags))
1173 return -EINVAL; 1194 return -EINVAL;
1174 1195
1175 err = get_drv_dev_by_info_ifindex(info, &drv, &dev); 1196 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
1176 if (err) 1197 if (err)
1177 return err; 1198 return err;
1178 1199
@@ -1207,7 +1228,7 @@ static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info)
1207 if (info->attrs[NL80211_ATTR_MAC]) 1228 if (info->attrs[NL80211_ATTR_MAC])
1208 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); 1229 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
1209 1230
1210 err = get_drv_dev_by_info_ifindex(info, &drv, &dev); 1231 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
1211 if (err) 1232 if (err)
1212 return err; 1233 return err;
1213 1234
@@ -1277,68 +1298,78 @@ static int nl80211_send_mpath(struct sk_buff *msg, u32 pid, u32 seq,
1277} 1298}
1278 1299
1279static int nl80211_dump_mpath(struct sk_buff *skb, 1300static int nl80211_dump_mpath(struct sk_buff *skb,
1280 struct netlink_callback *cb) 1301 struct netlink_callback *cb)
1281{ 1302{
1282 int wp_idx = 0;
1283 int if_idx = 0;
1284 int sta_idx = cb->args[2];
1285 int wp_start = cb->args[0];
1286 int if_start = cb->args[1];
1287 struct mpath_info pinfo; 1303 struct mpath_info pinfo;
1288 struct cfg80211_registered_device *dev; 1304 struct cfg80211_registered_device *dev;
1289 struct wireless_dev *wdev; 1305 struct net_device *netdev;
1290 u8 dst[ETH_ALEN]; 1306 u8 dst[ETH_ALEN];
1291 u8 next_hop[ETH_ALEN]; 1307 u8 next_hop[ETH_ALEN];
1308 int ifidx = cb->args[0];
1309 int path_idx = cb->args[1];
1292 int err; 1310 int err;
1293 int exit = 0;
1294 1311
1295 /* TODO: filter by device */ 1312 if (!ifidx) {
1296 mutex_lock(&cfg80211_drv_mutex); 1313 err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize,
1297 list_for_each_entry(dev, &cfg80211_drv_list, list) { 1314 nl80211_fam.attrbuf, nl80211_fam.maxattr,
1298 if (exit) 1315 nl80211_policy);
1316 if (err)
1317 return err;
1318
1319 if (!nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX])
1320 return -EINVAL;
1321
1322 ifidx = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]);
1323 if (!ifidx)
1324 return -EINVAL;
1325 }
1326
1327 netdev = dev_get_by_index(&init_net, ifidx);
1328 if (!netdev)
1329 return -ENODEV;
1330
1331 dev = cfg80211_get_dev_from_ifindex(ifidx);
1332 if (IS_ERR(dev)) {
1333 err = PTR_ERR(dev);
1334 goto out_put_netdev;
1335 }
1336
1337 if (!dev->ops->dump_mpath) {
1338 err = -ENOSYS;
1339 goto out_err;
1340 }
1341
1342 rtnl_lock();
1343
1344 while (1) {
1345 err = dev->ops->dump_mpath(&dev->wiphy, netdev, path_idx,
1346 dst, next_hop, &pinfo);
1347 if (err == -ENOENT)
1299 break; 1348 break;
1300 if (++wp_idx < wp_start) 1349 if (err)
1301 continue; 1350 goto out_err_rtnl;
1302 if_idx = 0;
1303 1351
1304 mutex_lock(&dev->devlist_mtx); 1352 if (nl80211_send_mpath(skb, NETLINK_CB(cb->skb).pid,
1305 list_for_each_entry(wdev, &dev->netdev_list, list) { 1353 cb->nlh->nlmsg_seq, NLM_F_MULTI,
1306 if (exit) 1354 netdev, dst, next_hop,
1307 break; 1355 &pinfo) < 0)
1308 if (++if_idx < if_start) 1356 goto out;
1309 continue;
1310 if (!dev->ops->dump_mpath)
1311 continue;
1312 1357
1313 for (;; ++sta_idx) { 1358 path_idx++;
1314 rtnl_lock();
1315 err = dev->ops->dump_mpath(&dev->wiphy,
1316 wdev->netdev, sta_idx, dst,
1317 next_hop, &pinfo);
1318 rtnl_unlock();
1319 if (err) {
1320 sta_idx = 0;
1321 break;
1322 }
1323 if (nl80211_send_mpath(skb,
1324 NETLINK_CB(cb->skb).pid,
1325 cb->nlh->nlmsg_seq, NLM_F_MULTI,
1326 wdev->netdev, dst, next_hop,
1327 &pinfo) < 0) {
1328 exit = 1;
1329 break;
1330 }
1331 }
1332 }
1333 mutex_unlock(&dev->devlist_mtx);
1334 } 1359 }
1335 mutex_unlock(&cfg80211_drv_mutex);
1336 1360
1337 cb->args[0] = wp_idx;
1338 cb->args[1] = if_idx;
1339 cb->args[2] = sta_idx;
1340 1361
1341 return skb->len; 1362 out:
1363 cb->args[1] = path_idx;
1364 err = skb->len;
1365 out_err_rtnl:
1366 rtnl_unlock();
1367 out_err:
1368 cfg80211_put_dev(dev);
1369 out_put_netdev:
1370 dev_put(netdev);
1371
1372 return err;
1342} 1373}
1343 1374
1344static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info) 1375static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info)
@@ -1358,7 +1389,7 @@ static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info)
1358 1389
1359 dst = nla_data(info->attrs[NL80211_ATTR_MAC]); 1390 dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
1360 1391
1361 err = get_drv_dev_by_info_ifindex(info, &drv, &dev); 1392 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
1362 if (err) 1393 if (err)
1363 return err; 1394 return err;
1364 1395
@@ -1411,7 +1442,7 @@ static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info)
1411 dst = nla_data(info->attrs[NL80211_ATTR_MAC]); 1442 dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
1412 next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]); 1443 next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]);
1413 1444
1414 err = get_drv_dev_by_info_ifindex(info, &drv, &dev); 1445 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
1415 if (err) 1446 if (err)
1416 return err; 1447 return err;
1417 1448
@@ -1446,7 +1477,7 @@ static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info)
1446 dst = nla_data(info->attrs[NL80211_ATTR_MAC]); 1477 dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
1447 next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]); 1478 next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]);
1448 1479
1449 err = get_drv_dev_by_info_ifindex(info, &drv, &dev); 1480 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
1450 if (err) 1481 if (err)
1451 return err; 1482 return err;
1452 1483
@@ -1475,7 +1506,7 @@ static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info)
1475 if (info->attrs[NL80211_ATTR_MAC]) 1506 if (info->attrs[NL80211_ATTR_MAC])
1476 dst = nla_data(info->attrs[NL80211_ATTR_MAC]); 1507 dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
1477 1508
1478 err = get_drv_dev_by_info_ifindex(info, &drv, &dev); 1509 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
1479 if (err) 1510 if (err)
1480 return err; 1511 return err;
1481 1512