diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2009-08-07 10:17:38 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-08-14 09:13:43 -0400 |
commit | f5ea9120be2e5d5c846243416cfdce01d02f5836 (patch) | |
tree | cade27e47a90dde79a523598b96a2ebb50770d2f /net | |
parent | f401a6f7ede753e56b84025e7d2db0d5ef560ce6 (diff) |
nl80211: add generation number to all dumps
In order for userspace to be able to figure out whether
it obtained a consistent snapshot of data or not when
using netlink dumps, we need to have a generation number
in each dump message that indicates whether the list has
changed or not -- its value is arbitrary.
This patch adds such a number to all dumps, this needs
some mac80211 involvement to keep track of a generation
number to start with when adding/removing mesh paths or
stations.
The wiphy and netdev lists can be fully handled within
cfg80211, of course, but generation numbers need to be
stored there as well.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net')
-rw-r--r-- | net/mac80211/cfg.c | 4 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 1 | ||||
-rw-r--r-- | net/mac80211/mesh.h | 2 | ||||
-rw-r--r-- | net/mac80211/mesh_pathtbl.c | 5 | ||||
-rw-r--r-- | net/mac80211/sta_info.c | 2 | ||||
-rw-r--r-- | net/wireless/core.c | 5 | ||||
-rw-r--r-- | net/wireless/core.h | 2 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 31 | ||||
-rw-r--r-- | net/wireless/scan.c | 1 |
9 files changed, 43 insertions, 10 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 4bbf5007799b..5608f6c68413 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -323,6 +323,8 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) | |||
323 | { | 323 | { |
324 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 324 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
325 | 325 | ||
326 | sinfo->generation = sdata->local->sta_generation; | ||
327 | |||
326 | sinfo->filled = STATION_INFO_INACTIVE_TIME | | 328 | sinfo->filled = STATION_INFO_INACTIVE_TIME | |
327 | STATION_INFO_RX_BYTES | | 329 | STATION_INFO_RX_BYTES | |
328 | STATION_INFO_TX_BYTES | | 330 | STATION_INFO_TX_BYTES | |
@@ -909,6 +911,8 @@ static void mpath_set_pinfo(struct mesh_path *mpath, u8 *next_hop, | |||
909 | else | 911 | else |
910 | memset(next_hop, 0, ETH_ALEN); | 912 | memset(next_hop, 0, ETH_ALEN); |
911 | 913 | ||
914 | pinfo->generation = mesh_paths_generation; | ||
915 | |||
912 | pinfo->filled = MPATH_INFO_FRAME_QLEN | | 916 | pinfo->filled = MPATH_INFO_FRAME_QLEN | |
913 | MPATH_INFO_DSN | | 917 | MPATH_INFO_DSN | |
914 | MPATH_INFO_METRIC | | 918 | MPATH_INFO_METRIC | |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 989591787aee..99433222bc5c 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -678,6 +678,7 @@ struct ieee80211_local { | |||
678 | struct list_head sta_list; | 678 | struct list_head sta_list; |
679 | struct sta_info *sta_hash[STA_HASH_SIZE]; | 679 | struct sta_info *sta_hash[STA_HASH_SIZE]; |
680 | struct timer_list sta_cleanup; | 680 | struct timer_list sta_cleanup; |
681 | int sta_generation; | ||
681 | 682 | ||
682 | struct sk_buff_head pending[IEEE80211_MAX_QUEUES]; | 683 | struct sk_buff_head pending[IEEE80211_MAX_QUEUES]; |
683 | struct tasklet_struct tx_pending_tasklet; | 684 | struct tasklet_struct tx_pending_tasklet; |
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index 2a2ed182cb7e..ce538814b9bd 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h | |||
@@ -265,6 +265,8 @@ void mesh_path_discard_frame(struct sk_buff *skb, | |||
265 | void mesh_path_quiesce(struct ieee80211_sub_if_data *sdata); | 265 | void mesh_path_quiesce(struct ieee80211_sub_if_data *sdata); |
266 | void mesh_path_restart(struct ieee80211_sub_if_data *sdata); | 266 | void mesh_path_restart(struct ieee80211_sub_if_data *sdata); |
267 | 267 | ||
268 | extern int mesh_paths_generation; | ||
269 | |||
268 | #ifdef CONFIG_MAC80211_MESH | 270 | #ifdef CONFIG_MAC80211_MESH |
269 | extern int mesh_allocated; | 271 | extern int mesh_allocated; |
270 | 272 | ||
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index 04b9e4d61b8e..431865a58622 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c | |||
@@ -38,6 +38,8 @@ struct mpath_node { | |||
38 | static struct mesh_table *mesh_paths; | 38 | static struct mesh_table *mesh_paths; |
39 | static struct mesh_table *mpp_paths; /* Store paths for MPP&MAP */ | 39 | static struct mesh_table *mpp_paths; /* Store paths for MPP&MAP */ |
40 | 40 | ||
41 | int mesh_paths_generation; | ||
42 | |||
41 | /* This lock will have the grow table function as writer and add / delete nodes | 43 | /* This lock will have the grow table function as writer and add / delete nodes |
42 | * as readers. When reading the table (i.e. doing lookups) we are well protected | 44 | * as readers. When reading the table (i.e. doing lookups) we are well protected |
43 | * by RCU | 45 | * by RCU |
@@ -243,6 +245,8 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata) | |||
243 | mesh_paths->mean_chain_len * (mesh_paths->hash_mask + 1)) | 245 | mesh_paths->mean_chain_len * (mesh_paths->hash_mask + 1)) |
244 | grow = 1; | 246 | grow = 1; |
245 | 247 | ||
248 | mesh_paths_generation++; | ||
249 | |||
246 | spin_unlock(&mesh_paths->hashwlock[hash_idx]); | 250 | spin_unlock(&mesh_paths->hashwlock[hash_idx]); |
247 | read_unlock(&pathtbl_resize_lock); | 251 | read_unlock(&pathtbl_resize_lock); |
248 | if (grow) { | 252 | if (grow) { |
@@ -484,6 +488,7 @@ int mesh_path_del(u8 *addr, struct ieee80211_sub_if_data *sdata) | |||
484 | 488 | ||
485 | err = -ENXIO; | 489 | err = -ENXIO; |
486 | enddel: | 490 | enddel: |
491 | mesh_paths_generation++; | ||
487 | spin_unlock(&mesh_paths->hashwlock[hash_idx]); | 492 | spin_unlock(&mesh_paths->hashwlock[hash_idx]); |
488 | read_unlock(&pathtbl_resize_lock); | 493 | read_unlock(&pathtbl_resize_lock); |
489 | return err; | 494 | return err; |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index a360bceeba59..eec001491e66 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -349,6 +349,7 @@ int sta_info_insert(struct sta_info *sta) | |||
349 | goto out_free; | 349 | goto out_free; |
350 | } | 350 | } |
351 | list_add(&sta->list, &local->sta_list); | 351 | list_add(&sta->list, &local->sta_list); |
352 | local->sta_generation++; | ||
352 | local->num_sta++; | 353 | local->num_sta++; |
353 | sta_info_hash_add(local, sta); | 354 | sta_info_hash_add(local, sta); |
354 | 355 | ||
@@ -485,6 +486,7 @@ static void __sta_info_unlink(struct sta_info **sta) | |||
485 | } | 486 | } |
486 | 487 | ||
487 | local->num_sta--; | 488 | local->num_sta--; |
489 | local->sta_generation++; | ||
488 | 490 | ||
489 | if (local->ops->sta_notify) { | 491 | if (local->ops->sta_notify) { |
490 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 492 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
diff --git a/net/wireless/core.c b/net/wireless/core.c index 1e189306560d..62e1ac00879b 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -32,6 +32,7 @@ MODULE_DESCRIPTION("wireless configuration support"); | |||
32 | * only read the list, and that can happen quite | 32 | * only read the list, and that can happen quite |
33 | * often because we need to do it for each command */ | 33 | * often because we need to do it for each command */ |
34 | LIST_HEAD(cfg80211_rdev_list); | 34 | LIST_HEAD(cfg80211_rdev_list); |
35 | int cfg80211_rdev_list_generation; | ||
35 | 36 | ||
36 | /* | 37 | /* |
37 | * This is used to protect the cfg80211_rdev_list | 38 | * This is used to protect the cfg80211_rdev_list |
@@ -511,6 +512,7 @@ int wiphy_register(struct wiphy *wiphy) | |||
511 | wiphy_update_regulatory(wiphy, NL80211_REGDOM_SET_BY_CORE); | 512 | wiphy_update_regulatory(wiphy, NL80211_REGDOM_SET_BY_CORE); |
512 | 513 | ||
513 | list_add(&rdev->list, &cfg80211_rdev_list); | 514 | list_add(&rdev->list, &cfg80211_rdev_list); |
515 | cfg80211_rdev_list_generation++; | ||
514 | 516 | ||
515 | mutex_unlock(&cfg80211_mutex); | 517 | mutex_unlock(&cfg80211_mutex); |
516 | 518 | ||
@@ -593,6 +595,7 @@ void wiphy_unregister(struct wiphy *wiphy) | |||
593 | reg_device_remove(wiphy); | 595 | reg_device_remove(wiphy); |
594 | 596 | ||
595 | list_del(&rdev->list); | 597 | list_del(&rdev->list); |
598 | cfg80211_rdev_list_generation++; | ||
596 | device_del(&rdev->wiphy.dev); | 599 | device_del(&rdev->wiphy.dev); |
597 | debugfs_remove(rdev->wiphy.debugfsdir); | 600 | debugfs_remove(rdev->wiphy.debugfsdir); |
598 | 601 | ||
@@ -653,6 +656,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
653 | spin_lock_init(&wdev->event_lock); | 656 | spin_lock_init(&wdev->event_lock); |
654 | mutex_lock(&rdev->devlist_mtx); | 657 | mutex_lock(&rdev->devlist_mtx); |
655 | list_add(&wdev->list, &rdev->netdev_list); | 658 | list_add(&wdev->list, &rdev->netdev_list); |
659 | rdev->devlist_generation++; | ||
656 | /* can only change netns with wiphy */ | 660 | /* can only change netns with wiphy */ |
657 | dev->features |= NETIF_F_NETNS_LOCAL; | 661 | dev->features |= NETIF_F_NETNS_LOCAL; |
658 | 662 | ||
@@ -733,6 +737,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
733 | if (!list_empty(&wdev->list)) { | 737 | if (!list_empty(&wdev->list)) { |
734 | sysfs_remove_link(&dev->dev.kobj, "phy80211"); | 738 | sysfs_remove_link(&dev->dev.kobj, "phy80211"); |
735 | list_del_init(&wdev->list); | 739 | list_del_init(&wdev->list); |
740 | rdev->devlist_generation++; | ||
736 | mutex_destroy(&wdev->mtx); | 741 | mutex_destroy(&wdev->mtx); |
737 | #ifdef CONFIG_WIRELESS_EXT | 742 | #ifdef CONFIG_WIRELESS_EXT |
738 | kfree(wdev->wext.keys); | 743 | kfree(wdev->wext.keys); |
diff --git a/net/wireless/core.h b/net/wireless/core.h index 92e0492b0e4d..639db52eeff7 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -49,6 +49,7 @@ struct cfg80211_registered_device { | |||
49 | /* associate netdev list */ | 49 | /* associate netdev list */ |
50 | struct mutex devlist_mtx; | 50 | struct mutex devlist_mtx; |
51 | struct list_head netdev_list; | 51 | struct list_head netdev_list; |
52 | int devlist_generation; | ||
52 | 53 | ||
53 | /* BSSes/scanning */ | 54 | /* BSSes/scanning */ |
54 | spinlock_t bss_lock; | 55 | spinlock_t bss_lock; |
@@ -101,6 +102,7 @@ bool wiphy_idx_valid(int wiphy_idx) | |||
101 | 102 | ||
102 | extern struct mutex cfg80211_mutex; | 103 | extern struct mutex cfg80211_mutex; |
103 | extern struct list_head cfg80211_rdev_list; | 104 | extern struct list_head cfg80211_rdev_list; |
105 | extern int cfg80211_rdev_list_generation; | ||
104 | 106 | ||
105 | #define assert_cfg80211_lock() WARN_ON(!mutex_is_locked(&cfg80211_mutex)) | 107 | #define assert_cfg80211_lock() WARN_ON(!mutex_is_locked(&cfg80211_mutex)) |
106 | 108 | ||
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 2ff7376f35a3..b3d5c1df08dd 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -408,6 +408,9 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
408 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->wiphy_idx); | 408 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->wiphy_idx); |
409 | NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy)); | 409 | NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy)); |
410 | 410 | ||
411 | NLA_PUT_U32(msg, NL80211_ATTR_GENERATION, | ||
412 | cfg80211_rdev_list_generation); | ||
413 | |||
411 | NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_RETRY_SHORT, | 414 | NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_RETRY_SHORT, |
412 | dev->wiphy.retry_short); | 415 | dev->wiphy.retry_short); |
413 | NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_RETRY_LONG, | 416 | NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_RETRY_LONG, |
@@ -825,6 +828,11 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
825 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); | 828 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); |
826 | NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, dev->name); | 829 | NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, dev->name); |
827 | NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, dev->ieee80211_ptr->iftype); | 830 | NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, dev->ieee80211_ptr->iftype); |
831 | |||
832 | NLA_PUT_U32(msg, NL80211_ATTR_GENERATION, | ||
833 | rdev->devlist_generation ^ | ||
834 | (cfg80211_rdev_list_generation << 2)); | ||
835 | |||
828 | return genlmsg_end(msg, hdr); | 836 | return genlmsg_end(msg, hdr); |
829 | 837 | ||
830 | nla_put_failure: | 838 | nla_put_failure: |
@@ -838,12 +846,12 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback * | |||
838 | int if_idx = 0; | 846 | int if_idx = 0; |
839 | int wp_start = cb->args[0]; | 847 | int wp_start = cb->args[0]; |
840 | int if_start = cb->args[1]; | 848 | int if_start = cb->args[1]; |
841 | struct cfg80211_registered_device *dev; | 849 | struct cfg80211_registered_device *rdev; |
842 | struct wireless_dev *wdev; | 850 | struct wireless_dev *wdev; |
843 | 851 | ||
844 | mutex_lock(&cfg80211_mutex); | 852 | mutex_lock(&cfg80211_mutex); |
845 | list_for_each_entry(dev, &cfg80211_rdev_list, list) { | 853 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) { |
846 | if (!net_eq(wiphy_net(&dev->wiphy), sock_net(skb->sk))) | 854 | if (!net_eq(wiphy_net(&rdev->wiphy), sock_net(skb->sk))) |
847 | continue; | 855 | continue; |
848 | if (wp_idx < wp_start) { | 856 | if (wp_idx < wp_start) { |
849 | wp_idx++; | 857 | wp_idx++; |
@@ -851,21 +859,21 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback * | |||
851 | } | 859 | } |
852 | if_idx = 0; | 860 | if_idx = 0; |
853 | 861 | ||
854 | mutex_lock(&dev->devlist_mtx); | 862 | mutex_lock(&rdev->devlist_mtx); |
855 | list_for_each_entry(wdev, &dev->netdev_list, list) { | 863 | list_for_each_entry(wdev, &rdev->netdev_list, list) { |
856 | if (if_idx < if_start) { | 864 | if (if_idx < if_start) { |
857 | if_idx++; | 865 | if_idx++; |
858 | continue; | 866 | continue; |
859 | } | 867 | } |
860 | if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).pid, | 868 | if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).pid, |
861 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | 869 | cb->nlh->nlmsg_seq, NLM_F_MULTI, |
862 | dev, wdev->netdev) < 0) { | 870 | rdev, wdev->netdev) < 0) { |
863 | mutex_unlock(&dev->devlist_mtx); | 871 | mutex_unlock(&rdev->devlist_mtx); |
864 | goto out; | 872 | goto out; |
865 | } | 873 | } |
866 | if_idx++; | 874 | if_idx++; |
867 | } | 875 | } |
868 | mutex_unlock(&dev->devlist_mtx); | 876 | mutex_unlock(&rdev->devlist_mtx); |
869 | 877 | ||
870 | wp_idx++; | 878 | wp_idx++; |
871 | } | 879 | } |
@@ -1616,6 +1624,8 @@ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, | |||
1616 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); | 1624 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); |
1617 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); | 1625 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); |
1618 | 1626 | ||
1627 | NLA_PUT_U32(msg, NL80211_ATTR_GENERATION, sinfo->generation); | ||
1628 | |||
1619 | sinfoattr = nla_nest_start(msg, NL80211_ATTR_STA_INFO); | 1629 | sinfoattr = nla_nest_start(msg, NL80211_ATTR_STA_INFO); |
1620 | if (!sinfoattr) | 1630 | if (!sinfoattr) |
1621 | goto nla_put_failure; | 1631 | goto nla_put_failure; |
@@ -2101,6 +2111,8 @@ static int nl80211_send_mpath(struct sk_buff *msg, u32 pid, u32 seq, | |||
2101 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, dst); | 2111 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, dst); |
2102 | NLA_PUT(msg, NL80211_ATTR_MPATH_NEXT_HOP, ETH_ALEN, next_hop); | 2112 | NLA_PUT(msg, NL80211_ATTR_MPATH_NEXT_HOP, ETH_ALEN, next_hop); |
2103 | 2113 | ||
2114 | NLA_PUT_U32(msg, NL80211_ATTR_GENERATION, pinfo->generation); | ||
2115 | |||
2104 | pinfoattr = nla_nest_start(msg, NL80211_ATTR_MPATH_INFO); | 2116 | pinfoattr = nla_nest_start(msg, NL80211_ATTR_MPATH_INFO); |
2105 | if (!pinfoattr) | 2117 | if (!pinfoattr) |
2106 | goto nla_put_failure; | 2118 | goto nla_put_failure; |
@@ -3090,8 +3102,7 @@ static int nl80211_send_bss(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
3090 | if (!hdr) | 3102 | if (!hdr) |
3091 | return -1; | 3103 | return -1; |
3092 | 3104 | ||
3093 | NLA_PUT_U32(msg, NL80211_ATTR_SCAN_GENERATION, | 3105 | NLA_PUT_U32(msg, NL80211_ATTR_GENERATION, rdev->bss_generation); |
3094 | rdev->bss_generation); | ||
3095 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, wdev->netdev->ifindex); | 3106 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, wdev->netdev->ifindex); |
3096 | 3107 | ||
3097 | bss = nla_nest_start(msg, NL80211_ATTR_BSS); | 3108 | bss = nla_nest_start(msg, NL80211_ATTR_BSS); |
diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 0ccf3a07dc02..1bcb1312bd94 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c | |||
@@ -562,6 +562,7 @@ void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *pub) | |||
562 | spin_lock_bh(&dev->bss_lock); | 562 | spin_lock_bh(&dev->bss_lock); |
563 | 563 | ||
564 | list_del(&bss->list); | 564 | list_del(&bss->list); |
565 | dev->bss_generation++; | ||
565 | rb_erase(&bss->rbn, &dev->bss_tree); | 566 | rb_erase(&bss->rbn, &dev->bss_tree); |
566 | 567 | ||
567 | spin_unlock_bh(&dev->bss_lock); | 568 | spin_unlock_bh(&dev->bss_lock); |