mac80211_hwsim: add generation count for netlink dump operation
authorBenjamin Beichler <benjamin.beichler@uni-rostock.de>
Mon, 22 Jan 2018 17:04:37 +0000 (18:04 +0100)
committerJohannes Berg <johannes.berg@intel.com>
Wed, 31 Jan 2018 11:48:06 +0000 (12:48 +0100)
Make the dump operation aware of changes on radio list and corresponding
inconsistent dumps. Changed variable name for better understanding.

Signed-off-by: Benjamin Beichler <benjamin.beichler@uni-rostock.de>
[compress ternary operator]
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
drivers/net/wireless/mac80211_hwsim.c

index 6996dad24e7110f15c9dc952bca4983ecea074ff..f0379223ec6d88cde6e32298d3793a896c8efe50 100644 (file)
@@ -493,6 +493,7 @@ static LIST_HEAD(hwsim_radios);
 static struct workqueue_struct *hwsim_wq;
 static struct rhashtable hwsim_radios_rht;
 static int hwsim_radio_idx;
+static int hwsim_radios_generation = 1;
 
 static struct platform_driver mac80211_hwsim_driver = {
        .driver = {
@@ -2807,6 +2808,7 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
        }
 
        list_add_tail(&data->list, &hwsim_radios);
+       hwsim_radios_generation++;
        spin_unlock_bh(&hwsim_radio_lock);
 
        if (idx > 0)
@@ -3277,6 +3279,7 @@ static int hwsim_del_radio_nl(struct sk_buff *msg, struct genl_info *info)
                list_del(&data->list);
                rhashtable_remove_fast(&hwsim_radios_rht, &data->rht,
                                       hwsim_rht_params);
+               hwsim_radios_generation++;
                spin_unlock_bh(&hwsim_radio_lock);
                mac80211_hwsim_del_radio(data, wiphy_name(data->hw->wiphy),
                                         info);
@@ -3333,17 +3336,19 @@ out_err:
 static int hwsim_dump_radio_nl(struct sk_buff *skb,
                               struct netlink_callback *cb)
 {
-       int idx = cb->args[0];
+       int last_idx = cb->args[0];
        struct mac80211_hwsim_data *data = NULL;
-       int res;
+       int res = 0;
+       void *hdr;
 
        spin_lock_bh(&hwsim_radio_lock);
+       cb->seq = hwsim_radios_generation;
 
-       if (idx == hwsim_radio_idx)
+       if (last_idx >= hwsim_radio_idx-1)
                goto done;
 
        list_for_each_entry(data, &hwsim_radios, list) {
-               if (data->idx < idx)
+               if (data->idx <= last_idx)
                        continue;
 
                if (!net_eq(wiphy_net(data->hw->wiphy), sock_net(skb->sk)))
@@ -3356,14 +3361,25 @@ static int hwsim_dump_radio_nl(struct sk_buff *skb,
                if (res < 0)
                        break;
 
-               idx = data->idx + 1;
+               last_idx = data->idx;
        }
 
-       cb->args[0] = idx;
+       cb->args[0] = last_idx;
+
+       /* list changed, but no new element sent, set interrupted flag */
+       if (skb->len == 0 && cb->prev_seq && cb->seq != cb->prev_seq) {
+               hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid,
+                                 cb->nlh->nlmsg_seq, &hwsim_genl_family,
+                                 NLM_F_MULTI, HWSIM_CMD_GET_RADIO);
+               if (!hdr)
+                       res = -EMSGSIZE;
+               genl_dump_check_consistent(cb, hdr);
+               genlmsg_end(skb, hdr);
+       }
 
 done:
        spin_unlock_bh(&hwsim_radio_lock);
-       return skb->len;
+       return res ?: skb->len;
 }
 
 /* Generic Netlink operations array */
@@ -3421,6 +3437,7 @@ static void destroy_radio(struct work_struct *work)
        struct mac80211_hwsim_data *data =
                container_of(work, struct mac80211_hwsim_data, destroy_work);
 
+       hwsim_radios_generation++;
        mac80211_hwsim_del_radio(data, wiphy_name(data->hw->wiphy), NULL);
 }