Search Linux Wireless

[PATCH] wireless: nl80211: Broadcast CMD_NEW_INTERFACE and CMD_DEL_INTERFACE

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Let the other listeners being notified when a new or del interface
command has been issued, thus reducing later necessary request to be in
sync with current context.

Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@xxxxxxxxxxxxxxx>
---

Hi, 

In order not to change current API behavior for the command issuer, I kept
the reply for NEW_INTERFACE unicasted, as well as the returned status for
DEL_INTERFACE. This patch only add the notification for all other listeners.

It bloats a bit nl80211_send_iface() function (I wanted to reuse its logic
for both commands). Tell me if you would prefer a better way to do this.

Tomasz

 net/wireless/nl80211.c | 82 +++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 67 insertions(+), 15 deletions(-)

diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index cb9f5a4..b555c26 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -2336,12 +2336,18 @@ static int nl80211_send_chandef(struct sk_buff *msg,
 
 static int nl80211_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flags,
 			      struct cfg80211_registered_device *rdev,
-			      struct wireless_dev *wdev)
+			      struct wireless_dev *wdev,
+			      enum nl80211_iftype iftype, u64 wdev_id,
+			      u8 *wdev_address, struct net_device *dev,
+			      u8 ssid_len, u8 *ssid, bool new)
 {
-	struct net_device *dev = wdev->netdev;
+	u8 cmd = NL80211_CMD_NEW_INTERFACE;
 	void *hdr;
 
-	hdr = nl80211hdr_put(msg, portid, seq, flags, NL80211_CMD_NEW_INTERFACE);
+	if (!new)
+		cmd = NL80211_CMD_DEL_INTERFACE;
+
+	hdr = nl80211hdr_put(msg, portid, seq, flags, cmd);
 	if (!hdr)
 		return -1;
 
@@ -2351,15 +2357,15 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flag
 		goto nla_put_failure;
 
 	if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
-	    nla_put_u32(msg, NL80211_ATTR_IFTYPE, wdev->iftype) ||
-	    nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev)) ||
-	    nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, wdev_address(wdev)) ||
+	    nla_put_u32(msg, NL80211_ATTR_IFTYPE, iftype) ||
+	    nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id) ||
+	    nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, wdev_address) ||
 	    nla_put_u32(msg, NL80211_ATTR_GENERATION,
 			rdev->devlist_generation ^
 			(cfg80211_rdev_list_generation << 2)))
 		goto nla_put_failure;
 
-	if (rdev->ops->get_channel) {
+	if (wdev && rdev->ops->get_channel) {
 		int ret;
 		struct cfg80211_chan_def chandef;
 
@@ -2370,10 +2376,8 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flag
 		}
 	}
 
-	if (wdev->ssid_len) {
-		if (nla_put(msg, NL80211_ATTR_SSID, wdev->ssid_len, wdev->ssid))
+	if (ssid_len && nla_put(msg, NL80211_ATTR_SSID, ssid_len, ssid))
 			goto nla_put_failure;
-	}
 
 	return genlmsg_end(msg, hdr);
 
@@ -2382,6 +2386,28 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flag
 	return -EMSGSIZE;
 }
 
+static void nl80211_notify_iface(struct cfg80211_registered_device *rdev,
+				 struct wireless_dev *wdev,
+				 enum nl80211_iftype iftype, u64 wdev_id,
+				 u8 *wdev_address, struct net_device *dev,
+				 u8 ssid_len, u8 *ssid, bool new, u32 portid)
+{
+	struct sk_buff *msg;
+
+	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+	if (!msg)
+		return;
+
+	if (nl80211_send_iface(msg, 0, 0, 0, rdev, wdev, iftype, wdev_id,
+			       wdev_address, dev, ssid_len, ssid, new) < 0) {
+		nlmsg_free(msg);
+		return;
+	}
+
+	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy),
+				msg, portid, NL80211_MCGRP_CONFIG, GFP_KERNEL);
+}
+
 static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback *cb)
 {
 	int wp_idx = 0;
@@ -2408,7 +2434,11 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback *
 			}
 			if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).portid,
 					       cb->nlh->nlmsg_seq, NLM_F_MULTI,
-					       rdev, wdev) < 0) {
+					       rdev, wdev, wdev->iftype,
+					       wdev_id(wdev),
+					       wdev_address(wdev),
+					       wdev->netdev, wdev->ssid_len,
+					       wdev->ssid, true) < 0) {
 				goto out;
 			}
 			if_idx++;
@@ -2436,7 +2466,9 @@ static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info)
 		return -ENOMEM;
 
 	if (nl80211_send_iface(msg, info->snd_portid, info->snd_seq, 0,
-			       rdev, wdev) < 0) {
+			       rdev, wdev, wdev->iftype, wdev_id(wdev),
+			       wdev_address(wdev), wdev->netdev,
+			       wdev->ssid_len, wdev->ssid, true) < 0) {
 		nlmsg_free(msg);
 		return -ENOBUFS;
 	}
@@ -2675,11 +2707,17 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
 	}
 
 	if (nl80211_send_iface(msg, info->snd_portid, info->snd_seq, 0,
-			       rdev, wdev) < 0) {
+			       rdev, wdev, wdev->iftype, wdev_id(wdev),
+			       wdev_address(wdev), wdev->netdev,
+			       wdev->ssid_len, wdev->ssid, true) < 0) {
 		nlmsg_free(msg);
 		return -ENOBUFS;
 	}
 
+	nl80211_notify_iface(rdev, wdev, wdev->iftype, wdev_id(wdev),
+			     wdev_address(wdev), wdev->netdev, wdev->ssid_len,
+			     wdev->ssid, true, info->snd_portid);
+
 	return genlmsg_reply(msg, info);
 }
 
@@ -2687,10 +2725,17 @@ static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info)
 {
 	struct cfg80211_registered_device *rdev = info->user_ptr[0];
 	struct wireless_dev *wdev = info->user_ptr[1];
+	enum nl80211_iftype iftype = wdev->iftype;
+	struct net_device *dev = wdev->netdev;
+	u8 address[ETH_ALEN];
+	u64 id = wdev_id(wdev);
+	int status;
 
 	if (!rdev->ops->del_virtual_intf)
 		return -EOPNOTSUPP;
 
+	memcpy(address, wdev_address(wdev), ETH_ALEN);
+
 	/*
 	 * If we remove a wireless device without a netdev then clear
 	 * user_ptr[1] so that nl80211_post_doit won't dereference it
@@ -2698,10 +2743,17 @@ static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info)
 	 * since the wdev has been freed, unlike with a netdev where
 	 * we need the dev_put() for the netdev to really be freed.
 	 */
-	if (!wdev->netdev)
+	if (!dev)
 		info->user_ptr[1] = NULL;
 
-	return rdev_del_virtual_intf(rdev, wdev);
+	status = rdev_del_virtual_intf(rdev, wdev);
+	if (status < 0)
+		return status;
+
+	nl80211_notify_iface(rdev, NULL, iftype, id, address, dev,
+			     0, NULL, false, info->snd_portid);
+
+	return status;
 }
 
 static int nl80211_set_noack_map(struct sk_buff *skb, struct genl_info *info)
-- 
2.0.4

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Host AP]     [ATH6KL]     [Linux Wireless Personal Area Network]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite Hiking]     [MIPS Linux]     [ARM Linux]     [Linux RAID]

  Powered by Linux