aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2009-08-07 10:17:38 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-08-14 09:13:43 -0400
commitf5ea9120be2e5d5c846243416cfdce01d02f5836 (patch)
treecade27e47a90dde79a523598b96a2ebb50770d2f
parentf401a6f7ede753e56b84025e7d2db0d5ef560ce6 (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>
-rw-r--r--include/linux/nl80211.h17
-rw-r--r--include/net/cfg80211.h12
-rw-r--r--net/mac80211/cfg.c4
-rw-r--r--net/mac80211/ieee80211_i.h1
-rw-r--r--net/mac80211/mesh.h2
-rw-r--r--net/mac80211/mesh_pathtbl.c5
-rw-r--r--net/mac80211/sta_info.c2
-rw-r--r--net/wireless/core.c5
-rw-r--r--net/wireless/core.h2
-rw-r--r--net/wireless/nl80211.c31
-rw-r--r--net/wireless/scan.c1
11 files changed, 67 insertions, 15 deletions
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index cb3dc6027fd9..a8d71ed43a0e 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -480,10 +480,6 @@ enum nl80211_commands {
480 * @NL80211_ATTR_SCAN_FREQUENCIES: nested attribute with frequencies (in MHz) 480 * @NL80211_ATTR_SCAN_FREQUENCIES: nested attribute with frequencies (in MHz)
481 * @NL80211_ATTR_SCAN_SSIDS: nested attribute with SSIDs, leave out for passive 481 * @NL80211_ATTR_SCAN_SSIDS: nested attribute with SSIDs, leave out for passive
482 * scanning and include a zero-length SSID (wildcard) for wildcard scan 482 * scanning and include a zero-length SSID (wildcard) for wildcard scan
483 * @NL80211_ATTR_SCAN_GENERATION: the scan generation increases whenever the
484 * scan result list changes (BSS expired or added) so that applications
485 * can verify that they got a single, consistent snapshot (when all dump
486 * messages carried the same generation number)
487 * @NL80211_ATTR_BSS: scan result BSS 483 * @NL80211_ATTR_BSS: scan result BSS
488 * 484 *
489 * @NL80211_ATTR_REG_INITIATOR: indicates who requested the regulatory domain 485 * @NL80211_ATTR_REG_INITIATOR: indicates who requested the regulatory domain
@@ -580,6 +576,14 @@ enum nl80211_commands {
580 * 576 *
581 * @NL80211_ATTR_PID: Process ID of a network namespace. 577 * @NL80211_ATTR_PID: Process ID of a network namespace.
582 * 578 *
579 * @NL80211_ATTR_GENERATION: Used to indicate consistent snapshots for
580 * dumps. This number increases whenever the object list being
581 * dumped changes, and as such userspace can verify that it has
582 * obtained a complete and consistent snapshot by verifying that
583 * all dump messages contain the same generation number. If it
584 * changed then the list changed and the dump should be repeated
585 * completely from scratch.
586 *
583 * @NL80211_ATTR_MAX: highest attribute number currently defined 587 * @NL80211_ATTR_MAX: highest attribute number currently defined
584 * @__NL80211_ATTR_AFTER_LAST: internal use 588 * @__NL80211_ATTR_AFTER_LAST: internal use
585 */ 589 */
@@ -651,7 +655,7 @@ enum nl80211_attrs {
651 655
652 NL80211_ATTR_SCAN_FREQUENCIES, 656 NL80211_ATTR_SCAN_FREQUENCIES,
653 NL80211_ATTR_SCAN_SSIDS, 657 NL80211_ATTR_SCAN_SSIDS,
654 NL80211_ATTR_SCAN_GENERATION, 658 NL80211_ATTR_GENERATION, /* replaces old SCAN_GENERATION */
655 NL80211_ATTR_BSS, 659 NL80211_ATTR_BSS,
656 660
657 NL80211_ATTR_REG_INITIATOR, 661 NL80211_ATTR_REG_INITIATOR,
@@ -716,6 +720,9 @@ enum nl80211_attrs {
716 NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1 720 NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1
717}; 721};
718 722
723/* source-level API compatibility */
724#define NL80211_ATTR_SCAN_GENERATION NL80211_ATTR_GENERATION
725
719/* 726/*
720 * Allow user space programs to use #ifdef on new attributes by defining them 727 * Allow user space programs to use #ifdef on new attributes by defining them
721 * here 728 * here
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 1ee30fcd6fdc..de7d116acc3d 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -372,6 +372,10 @@ struct rate_info {
372 * @txrate: current unicast bitrate to this station 372 * @txrate: current unicast bitrate to this station
373 * @rx_packets: packets received from this station 373 * @rx_packets: packets received from this station
374 * @tx_packets: packets transmitted to this station 374 * @tx_packets: packets transmitted to this station
375 * @generation: generation number for nl80211 dumps.
376 * This number should increase every time the list of stations
377 * changes, i.e. when a station is added or removed, so that
378 * userspace can tell whether it got a consistent snapshot.
375 */ 379 */
376struct station_info { 380struct station_info {
377 u32 filled; 381 u32 filled;
@@ -385,6 +389,8 @@ struct station_info {
385 struct rate_info txrate; 389 struct rate_info txrate;
386 u32 rx_packets; 390 u32 rx_packets;
387 u32 tx_packets; 391 u32 tx_packets;
392
393 int generation;
388}; 394};
389 395
390/** 396/**
@@ -444,6 +450,10 @@ enum mpath_info_flags {
444 * @flags: mesh path flags 450 * @flags: mesh path flags
445 * @discovery_timeout: total mesh path discovery timeout, in msecs 451 * @discovery_timeout: total mesh path discovery timeout, in msecs
446 * @discovery_retries: mesh path discovery retries 452 * @discovery_retries: mesh path discovery retries
453 * @generation: generation number for nl80211 dumps.
454 * This number should increase every time the list of mesh paths
455 * changes, i.e. when a station is added or removed, so that
456 * userspace can tell whether it got a consistent snapshot.
447 */ 457 */
448struct mpath_info { 458struct mpath_info {
449 u32 filled; 459 u32 filled;
@@ -454,6 +464,8 @@ struct mpath_info {
454 u32 discovery_timeout; 464 u32 discovery_timeout;
455 u8 discovery_retries; 465 u8 discovery_retries;
456 u8 flags; 466 u8 flags;
467
468 int generation;
457}; 469};
458 470
459/** 471/**
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,
265void mesh_path_quiesce(struct ieee80211_sub_if_data *sdata); 265void mesh_path_quiesce(struct ieee80211_sub_if_data *sdata);
266void mesh_path_restart(struct ieee80211_sub_if_data *sdata); 266void mesh_path_restart(struct ieee80211_sub_if_data *sdata);
267 267
268extern int mesh_paths_generation;
269
268#ifdef CONFIG_MAC80211_MESH 270#ifdef CONFIG_MAC80211_MESH
269extern int mesh_allocated; 271extern 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 {
38static struct mesh_table *mesh_paths; 38static struct mesh_table *mesh_paths;
39static struct mesh_table *mpp_paths; /* Store paths for MPP&MAP */ 39static struct mesh_table *mpp_paths; /* Store paths for MPP&MAP */
40 40
41int 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;
486enddel: 490enddel:
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 */
34LIST_HEAD(cfg80211_rdev_list); 34LIST_HEAD(cfg80211_rdev_list);
35int 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
102extern struct mutex cfg80211_mutex; 103extern struct mutex cfg80211_mutex;
103extern struct list_head cfg80211_rdev_list; 104extern struct list_head cfg80211_rdev_list;
105extern 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);