Skip to contentSkip to conversation

interface type switching while up

PATCH In review Johannes Berg 2 participants 9 messages Aug 27, 2010

Subsystems (2)
lore
Share & tools
lore

Johannes Berg

author maintainer
#0 lore raw

cover interface type switching while up

I've now tested this series, fixed a few bugs
in error cases and reworked a few minor details,
so that I'm happy with it now.

johannes

author maintainer
#1 lore raw

PATCH 1/6 mac80211: clean up ifdown/cleanup paths

From: Johannes Berg <[email protected]>

There's a lot of redundant code in mac80211's interface cleanup/down, for example freeing AP beacons is done both when the interface is set DOWN as well as when it is torn down, of which only the former has any effect.

Also, a bunch of things should be closer to where they matter, like the MLME timers that we should cancel when disassociating, rather than only when the interface is set DOWN.

Clean up all this code.

---
 net/mac80211/iface.c |   89 +++++++++++++--------------------------------------
 net/mac80211/mlme.c  |    5 ++
 2 files changed, 28 insertions(+), 66 deletions(-)
net/mac80211/iface.c +23 -66
@@ -370,12 +370,9 @@ static int ieee80211_stop(struct net_dev
 	 * (because if we remove a STA after ops->remove_interface()
 	 * the driver will have removed the vif info already!)
 	 *
-	 * We could relax this and only unlink the stations from the
-	 * hash table and list but keep them on a per-sdata list that
-	 * will be inserted back again when the interface is brought
-	 * up again, but I don't currently see a use case for that,
-	 * except with WDS which gets a STA entry created when it is
-	 * brought up.
+	 * This is relevant only in AP, WDS and mesh modes, since in
+	 * all other modes we've already removed all stations when
+	 * disconnecting etc.
 	 */
 	sta_info_flush(local, sdata);
 
@@ -410,11 +407,21 @@ static int ieee80211_stop(struct net_dev
 		struct ieee80211_sub_if_data *vlan, *tmpsdata;
 		struct beacon_data *old_beacon = sdata->u.ap.beacon;
 
+		/* sdata_running will return false, so this will disable */
+		ieee80211_bss_info_change_notify(sdata,
+						 BSS_CHANGED_BEACON_ENABLED);
+
 		/* remove beacon */
 		rcu_assign_pointer(sdata->u.ap.beacon, NULL);
 		synchronize_rcu();
 		kfree(old_beacon);
 
+		/* free all potentially still buffered bcast frames */
+		while ((skb = skb_dequeue(&sdata->u.ap.ps_bc_buf))) {
+			local->total_ps_buffered--;
+			dev_kfree_skb(skb);
+		}
+
 		/* down all dependent devices, that is VLANs */
 		list_for_each_entry_safe(vlan, tmpsdata, &sdata->u.ap.vlans,
 					 u.vlan.list)
@@ -454,27 +461,6 @@ static int ieee80211_stop(struct net_dev
 
 		ieee80211_configure_filter(local);
 		break;
-	case NL80211_IFTYPE_STATION:
-		del_timer_sync(&sdata->u.mgd.chswitch_timer);
-		del_timer_sync(&sdata->u.mgd.timer);
-		del_timer_sync(&sdata->u.mgd.conn_mon_timer);
-		del_timer_sync(&sdata->u.mgd.bcn_mon_timer);
-		/*
-		 * If any of the timers fired while we waited for it, it will
-		 * have queued its work. Now the work will be running again
-		 * but will not rearm the timer again because it checks
-		 * whether the interface is running, which, at this point,
-		 * it no longer is.
-		 */
-		cancel_work_sync(&sdata->u.mgd.chswitch_work);
-		cancel_work_sync(&sdata->u.mgd.monitor_work);
-		cancel_work_sync(&sdata->u.mgd.beacon_connection_loss_work);
-
-		/* fall through */
-	case NL80211_IFTYPE_ADHOC:
-		if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
-			del_timer_sync(&sdata->u.ibss.timer);
-		/* fall through */
 	case NL80211_IFTYPE_MESH_POINT:
 		if (ieee80211_vif_is_mesh(&sdata->vif)) {
 			/* other_bss and allmulti are always set on mesh
@@ -502,17 +488,19 @@ static int ieee80211_stop(struct net_dev
 			ieee80211_scan_cancel(local);
 
 		/*
-		 * Disable beaconing for AP and mesh, IBSS can't
-		 * still be joined to a network at this point.
+		 * Disable beaconing here for mesh only, AP and IBSS
+		 * are already taken care of.
 		 */
-		if (sdata->vif.type == NL80211_IFTYPE_AP ||
-		    sdata->vif.type == NL80211_IFTYPE_MESH_POINT) {
+		if (sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
 			ieee80211_bss_info_change_notify(sdata,
 				BSS_CHANGED_BEACON_ENABLED);
-		}
 
-		/* free all remaining keys, there shouldn't be any */
+		/*
+		 * Free all remaining keys, there shouldn't be any,
+		 * except maybe group keys in AP more or WDS?
+		 */
 		ieee80211_free_keys(sdata);
+
 		drv_remove_interface(local, &sdata->vif);
 	}
 
@@ -593,8 +581,6 @@ static void ieee80211_teardown_sdata(str
 {
 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	struct ieee80211_local *local = sdata->local;
-	struct beacon_data *beacon;
-	struct sk_buff *skb;
 	int flushed;
 	int i;
 
@@ -607,37 +593,8 @@ static void ieee80211_teardown_sdata(str
 		__skb_queue_purge(&sdata->fragments[i].skb_list);
 	sdata->fragment_next = 0;
 
-	switch (sdata->vif.type) {
-	case NL80211_IFTYPE_AP:
-		beacon = sdata->u.ap.beacon;
-		rcu_assign_pointer(sdata->u.ap.beacon, NULL);
-		synchronize_rcu();
-		kfree(beacon);
-
-		while ((skb = skb_dequeue(&sdata->u.ap.ps_bc_buf))) {
-			local->total_ps_buffered--;
-			dev_kfree_skb(skb);
-		}
-
-		break;
-	case NL80211_IFTYPE_MESH_POINT:
-		if (ieee80211_vif_is_mesh(&sdata->vif))
-			mesh_rmc_free(sdata);
-		break;
-	case NL80211_IFTYPE_ADHOC:
-		if (WARN_ON(sdata->u.ibss.presp))
-			kfree_skb(sdata->u.ibss.presp);
-		break;
-	case NL80211_IFTYPE_STATION:
-	case NL80211_IFTYPE_WDS:
-	case NL80211_IFTYPE_AP_VLAN:
-	case NL80211_IFTYPE_MONITOR:
-		break;
-	case NL80211_IFTYPE_UNSPECIFIED:
-	case NUM_NL80211_IFTYPES:
-		BUG();
-		break;
-	}
+	if (ieee80211_vif_is_mesh(&sdata->vif))
+		mesh_rmc_free(sdata);
 
 	flushed = sta_info_flush(local, sdata);
 	WARN_ON(flushed);
net/mac80211/mlme.c +5 -0
@@ -991,6 +991,11 @@ static void ieee80211_set_disassoc(struc
 
 	if (remove_sta)
 		sta_info_destroy_addr(sdata, bssid);
+
+	del_timer_sync(&sdata->u.mgd.conn_mon_timer);
+	del_timer_sync(&sdata->u.mgd.bcn_mon_timer);
+	del_timer_sync(&sdata->u.mgd.timer);
+	del_timer_sync(&sdata->u.mgd.chswitch_timer);
 }
 
 void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata,
author maintainer
#2 lore raw

PATCH 2/6 mac80211: switch to ieee80211_sdata_running

In reply to Johannes Berg

From: Johannes Berg <[email protected]>

Since the introduction of ieee80211_sdata_running(), some new code was introduced that uses netif_running() instead. Switch all these instances over.

---
 net/mac80211/cfg.c  |    6 ++----
 net/mac80211/main.c |    6 +++---
 net/mac80211/util.c |    2 +-
 3 files changed, 6 insertions(+), 8 deletions(-)
net/mac80211/cfg.c +2 -4
@@ -81,16 +81,14 @@ static int ieee80211_add_key(struct wiph
 			     u8 key_idx, const u8 *mac_addr,
 			     struct key_params *params)
 {
-	struct ieee80211_sub_if_data *sdata;
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	struct sta_info *sta = NULL;
 	struct ieee80211_key *key;
 	int err;
 
-	if (!netif_running(dev))
+	if (!ieee80211_sdata_running(sdata))
 		return -ENETDOWN;
 
-	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
 	/* reject WEP and TKIP keys if WEP failed to initialize */
 	switch (params->cipher) {
 	case WLAN_CIPHER_SUITE_WEP40:
net/mac80211/main.c +3 -3
@@ -339,9 +339,6 @@ static int ieee80211_ifa_changed(struct
 	struct ieee80211_if_managed *ifmgd;
 	int c = 0;
 
-	if (!netif_running(ndev))
-		return NOTIFY_DONE;
-
 	/* Make sure it's our interface that got changed */
 	if (!wdev)
 		return NOTIFY_DONE;
@@ -352,6 +349,9 @@ static int ieee80211_ifa_changed(struct
 	sdata = IEEE80211_DEV_TO_SUB_IF(ndev);
 	bss_conf = &sdata->vif.bss_conf;
 
+	if (!ieee80211_sdata_running(sdata))
+		return NOTIFY_DONE;
+
 	/* ARP filtering is only supported in managed mode */
 	if (sdata->vif.type != NL80211_IFTYPE_STATION)
 		return NOTIFY_DONE;
net/mac80211/util.c +1 -1
@@ -1308,7 +1308,7 @@ void ieee80211_recalc_smps(struct ieee80
 	 */
 
 	list_for_each_entry(sdata, &local->interfaces, list) {
-		if (!netif_running(sdata->dev))
+		if (!ieee80211_sdata_running(sdata))
 			continue;
 		if (sdata->vif.type != NL80211_IFTYPE_STATION)
 			goto set;
author maintainer
#3 lore raw

PATCH 3/6 mac80211: simplify zero address checks

In reply to Johannes Berg

From: Johannes Berg <[email protected]>

The libertas_tf special code for zero addresses is a bit too complex, it compares against a stack value instead of using is_zero_ether_addr() and tries to update all interfaces even if just the one that's being brought up needs to be changed. Additionally, the repeated check for a valid MAC address need only be done if we actually changed it on the fly.

---
 net/mac80211/iface.c |   38 +++++++++++++-------------------------
 1 file changed, 13 insertions(+), 25 deletions(-)
net/mac80211/iface.c +13 -25
@@ -103,10 +103,9 @@ static int ieee80211_open(struct net_dev
 	u32 changed = 0;
 	int res;
 	u32 hw_reconf_flags = 0;
-	u8 null_addr[ETH_ALEN] = {0};
 
 	/* fail early if user set an invalid address */
-	if (compare_ether_addr(dev->dev_addr, null_addr) &&
+	if (!is_zero_ether_addr(dev->dev_addr) &&
 	    !is_valid_ether_addr(dev->dev_addr))
 		return -EADDRNOTAVAIL;
 
@@ -195,33 +194,22 @@ static int ieee80211_open(struct net_dev
 	}
 
 	/*
-	 * Check all interfaces and copy the hopefully now-present
-	 * MAC address to those that have the special null one.
+	 * Copy the hopefully now-present MAC address to
+	 * this interface, if it has the special null one.
 	 */
-	list_for_each_entry(nsdata, &local->interfaces, list) {
-		struct net_device *ndev = nsdata->dev;
-
-		/*
-		 * No need to check running since we do not allow
-		 * it to start up with this invalid address.
-		 */
-		if (compare_ether_addr(null_addr, ndev->dev_addr) == 0) {
-			memcpy(ndev->dev_addr,
-			       local->hw.wiphy->perm_addr,
-			       ETH_ALEN);
-			memcpy(ndev->perm_addr, ndev->dev_addr, ETH_ALEN);
+	if (is_zero_ether_addr(dev->dev_addr)) {
+		memcpy(dev->dev_addr,
+		       local->hw.wiphy->perm_addr,
+		       ETH_ALEN);
+		memcpy(dev->perm_addr, dev->dev_addr, ETH_ALEN);
+
+		if (!is_valid_ether_addr(dev->dev_addr)) {
+			if (!local->open_count)
+				drv_stop(local);
+			return -EADDRNOTAVAIL;
 		}
 	}
 
-	/*
-	 * Validate the MAC address for this device.
-	 */
-	if (!is_valid_ether_addr(dev->dev_addr)) {
-		if (!local->open_count)
-			drv_stop(local);
-		return -EADDRNOTAVAIL;
-	}
-
 	switch (sdata->vif.type) {
 	case NL80211_IFTYPE_AP_VLAN:
 		/* no need to tell driver */
#4 lore raw

Re: [PATCH 3/6] mac80211: simplify zero address checks

Quoted 3 lines · Johannes Berg

From: Johannes Berg <[email protected]>

The libertas_tf special code for zero addresses

libertas_tf? This looks like a mac80211 patch to me...

Quoted 80 lines

is a bit too complex, it compares against a stack
value instead of using is_zero_ether_addr() and
tries to update all interfaces even if just the
one that's being brought up needs to be changed.
Additionally, the repeated check for a valid MAC
address need only be done if we actually changed
it on the fly.

---
 net/mac80211/iface.c |   38 +++++++++++++-------------------------

 1 file changed, 13 insertions(+), 25 deletions(-)
net/mac80211/iface.c       2010-08-26 16:00:31.000000000 +0200 renamed from net/mac80211/iface.c  2010-08-26 16:00:30.000000000 +0200 +13 -25
@@ -103,10 +103,9 @@ static int ieee80211_open(struct net_dev
        u32 changed = 0;
        int res;
        u32 hw_reconf_flags = 0;
-       u8 null_addr[ETH_ALEN] = {0};
 
        /* fail early if user set an invalid address */
-       if (compare_ether_addr(dev->dev_addr, null_addr) &&
+       if (!is_zero_ether_addr(dev->dev_addr) &&
            !is_valid_ether_addr(dev->dev_addr))
                return -EADDRNOTAVAIL;
 
@@ -195,33 +194,22 @@ static int ieee80211_open(struct net_dev
        }
 
        /*
-        * Check all interfaces and copy the hopefully now-present
-        * MAC address to those that have the special null one.
+        * Copy the hopefully now-present MAC address to
+        * this interface, if it has the special null one.
         */
-       list_for_each_entry(nsdata, &local->interfaces, list) {
-               struct net_device *ndev = nsdata->dev;
-
-               /*
-                * No need to check running since we do not allow
-                * it to start up with this invalid address.
-                */
-               if (compare_ether_addr(null_addr, ndev->dev_addr) == 0) {
-                       memcpy(ndev->dev_addr,
-                              local->hw.wiphy->perm_addr,
-                              ETH_ALEN);
-                       memcpy(ndev->perm_addr, ndev->dev_addr, ETH_ALEN);
+       if (is_zero_ether_addr(dev->dev_addr)) {
+               memcpy(dev->dev_addr,
+                      local->hw.wiphy->perm_addr,
+                      ETH_ALEN);
+               memcpy(dev->perm_addr, dev->dev_addr, ETH_ALEN);
+
+               if (!is_valid_ether_addr(dev->dev_addr)) {
+                       if (!local->open_count)
+                               drv_stop(local);
+                       return -EADDRNOTAVAIL;
                }
        }
 
-       /*
-        * Validate the MAC address for this device.
-        */
-       if (!is_valid_ether_addr(dev->dev_addr)) {
-               if (!local->open_count)
-                       drv_stop(local);
-               return -EADDRNOTAVAIL;
-       }
-
        switch (sdata->vif.type) {

       case NL80211_IFTYPE_AP_VLAN:
               /* no need to tell driver */

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

Signature · 1 line
Vista: [V]iruses, [I]ntruders, [S]pyware, [T]rojans and [A]dware. :-)
author maintainer
#5 lore raw

Re: [PATCH 3/6] mac80211: simplify zero address checks

Quoted 3 lines
Quoted 1 line

The libertas_tf special code for zero addresses

libertas_tf? This looks like a mac80211 patch to me...

Yeah, but this mac80211 code exists only for libertas_tf.

Johannes

author maintainer
#6 lore raw

PATCH 4/6 mac80211: split out concurrent vif checks

In reply to Johannes Berg

From: Johannes Berg <[email protected]>

Split the concurrent virtual interface checks
into a new function that can be used to check
for any given new interface type.

---
 net/mac80211/iface.c |   43 +++++++++++++++++++++++++++++--------------
 1 file changed, 29 insertions(+), 14 deletions(-)
net/mac80211/iface.c +29 -14
@@ -94,20 +94,14 @@ static inline int identical_mac_addr_all
 			 type2 == NL80211_IFTYPE_AP_VLAN));
 }
 
-static int ieee80211_open(struct net_device *dev)
+static int ieee80211_check_concurrent_iface(struct ieee80211_sub_if_data *sdata,
+					    enum nl80211_iftype iftype)
 {
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	struct ieee80211_sub_if_data *nsdata;
 	struct ieee80211_local *local = sdata->local;
-	struct sta_info *sta;
-	u32 changed = 0;
-	int res;
-	u32 hw_reconf_flags = 0;
+	struct ieee80211_sub_if_data *nsdata;
+	struct net_device *dev = sdata->dev;
 
-	/* fail early if user set an invalid address */
-	if (!is_zero_ether_addr(dev->dev_addr) &&
-	    !is_valid_ether_addr(dev->dev_addr))
-		return -EADDRNOTAVAIL;
+	ASSERT_RTNL();
 
 	/* we hold the RTNL here so can safely walk the list */
 	list_for_each_entry(nsdata, &local->interfaces, list) {
@@ -124,7 +118,7 @@ static int ieee80211_open(struct net_dev
 			 * belonging to the same hardware. Then, however, we're
 			 * faced with having to adopt two different TSF timers...
 			 */
-			if (sdata->vif.type == NL80211_IFTYPE_ADHOC &&
+			if (iftype == NL80211_IFTYPE_ADHOC &&
 			    nsdata->vif.type == NL80211_IFTYPE_ADHOC)
 				return -EBUSY;
 
@@ -138,19 +132,40 @@ static int ieee80211_open(struct net_dev
 			/*
 			 * check whether it may have the same address
 			 */
-			if (!identical_mac_addr_allowed(sdata->vif.type,
+			if (!identical_mac_addr_allowed(iftype,
 							nsdata->vif.type))
 				return -ENOTUNIQ;
 
 			/*
 			 * can only add VLANs to enabled APs
 			 */
-			if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
+			if (iftype == NL80211_IFTYPE_AP_VLAN &&
 			    nsdata->vif.type == NL80211_IFTYPE_AP)
 				sdata->bss = &nsdata->u.ap;
 		}
 	}
 
+	return 0;
+}
+
+static int ieee80211_open(struct net_device *dev)
+{
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct ieee80211_local *local = sdata->local;
+	struct sta_info *sta;
+	u32 changed = 0;
+	int res;
+	u32 hw_reconf_flags = 0;
+
+	/* fail early if user set an invalid address */
+	if (!is_zero_ether_addr(dev->dev_addr) &&
+	    !is_valid_ether_addr(dev->dev_addr))
+		return -EADDRNOTAVAIL;
+
+	res = ieee80211_check_concurrent_iface(sdata, sdata->vif.type);
+	if (res)
+		return res;
+
 	switch (sdata->vif.type) {
 	case NL80211_IFTYPE_WDS:
 		if (!is_valid_ether_addr(sdata->u.wds.remote_addr))
author maintainer
#7 lore raw

PATCH 5/6 mac80211: support runtime interface type changes

In reply to Johannes Berg

From: Johannes Berg <[email protected]>

Add support to mac80211 for changing the interface type even when the interface is UP, if the driver supports it.

To achieve this
* add a new driver callback for switching,
* split some of the interface up/down code out
into new functions (do_open/do_stop), and
* maintain an own __SDATA_RUNNING bit that will
not be set during interface type, so that any
other code doesn't use the interface.

---
v2: - bug fix in error case
- tracing

 include/net/mac80211.h      |    9 ++
 net/mac80211/cfg.c          |    3 
 net/mac80211/driver-ops.h   |   14 +++
 net/mac80211/driver-trace.h |   25 +++++++
 net/mac80211/ieee80211_i.h  |   14 +++
 net/mac80211/iface.c        |  157 ++++++++++++++++++++++++++++++++++----------
 6 files changed, 185 insertions(+), 37 deletions(-)
include/net/mac80211.h +9 -0
@@ -1537,6 +1537,12 @@ enum ieee80211_ampdu_mlme_action {
  *	negative error code (which will be seen in userspace.)
  *	Must be implemented and can sleep.
  *
+ * @change_interface: Called when a netdevice changes type. This callback
+ *	is optional, but only if it is supported can interface types be
+ *	switched while the interface is UP. The callback may sleep.
+ *	Note that while an interface is being switched, it will not be
+ *	found by the interface iteration callbacks.
+ *
  * @remove_interface: Notifies a driver that an interface is going down.
  *	The @stop callback is called after this if it is the last interface
  *	and no monitor interfaces are present.
@@ -1693,6 +1699,9 @@ struct ieee80211_ops {
 	void (*stop)(struct ieee80211_hw *hw);
 	int (*add_interface)(struct ieee80211_hw *hw,
 			     struct ieee80211_vif *vif);
+	int (*change_interface)(struct ieee80211_hw *hw,
+				struct ieee80211_vif *vif,
+				enum nl80211_iftype new_type);
 	void (*remove_interface)(struct ieee80211_hw *hw,
 				 struct ieee80211_vif *vif);
 	int (*config)(struct ieee80211_hw *hw, u32 changed);
net/mac80211/iface.c +124 -33

245 lines not on this page · raw message

net/mac80211/ieee80211_i.h +13 -1
@@ -472,6 +472,16 @@ enum ieee80211_sub_if_data_flags {
 	IEEE80211_SDATA_DONT_BRIDGE_PACKETS	= BIT(3),
 };
 
+/**
+ * enum ieee80211_sdata_state_bits - virtual interface state bits
+ * @SDATA_STATE_RUNNING: virtual interface is up & running; this
+ *	mirrors netif_running() but is separate for interface type
+ *	change handling while the interface is up
+ */
+enum ieee80211_sdata_state_bits {
+	SDATA_STATE_RUNNING,
+};
+
 struct ieee80211_sub_if_data {
 	struct list_head list;
 
@@ -485,6 +495,8 @@ struct ieee80211_sub_if_data {
 
 	unsigned int flags;
 
+	unsigned long state;
+
 	int drop_unencrypted;
 
 	char name[IFNAMSIZ];
@@ -1083,7 +1095,7 @@ void ieee80211_recalc_idle(struct ieee80
 
 static inline bool ieee80211_sdata_running(struct ieee80211_sub_if_data *sdata)
 {
-	return netif_running(sdata->dev);
+	return test_bit(SDATA_STATE_RUNNING, &sdata->state);
 }
 
 /* tx handling */
net/mac80211/cfg.c +0 -3
@@ -52,9 +52,6 @@ static int ieee80211_change_iface(struct
 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	int ret;
 
-	if (ieee80211_sdata_running(sdata))
-		return -EBUSY;
-
 	ret = ieee80211_if_change_type(sdata, type);
 	if (ret)
 		return ret;
net/mac80211/driver-ops.h +14 -0
@@ -54,6 +54,20 @@ static inline int drv_add_interface(stru
 	return ret;
 }
 
+static inline int drv_change_interface(struct ieee80211_local *local,
+				       struct ieee80211_sub_if_data *sdata,
+				       enum nl80211_iftype type)
+{
+	int ret;
+
+	might_sleep();
+
+	trace_drv_change_interface(local, sdata, type);
+	ret = local->ops->change_interface(&local->hw, &sdata->vif, type);
+	trace_drv_return_int(local, ret);
+	return ret;
+}
+
 static inline void drv_remove_interface(struct ieee80211_local *local,
 					struct ieee80211_vif *vif)
 {
net/mac80211/driver-trace.h +25 -0
@@ -136,6 +136,31 @@ TRACE_EVENT(drv_add_interface,
 	)
 );
 
+TRACE_EVENT(drv_change_interface,
+	TP_PROTO(struct ieee80211_local *local,
+		 struct ieee80211_sub_if_data *sdata,
+		 enum nl80211_iftype type),
+
+	TP_ARGS(local, sdata, type),
+
+	TP_STRUCT__entry(
+		LOCAL_ENTRY
+		VIF_ENTRY
+		__field(u32, new_type)
+	),
+
+	TP_fast_assign(
+		LOCAL_ASSIGN;
+		VIF_ASSIGN;
+		__entry->new_type = type;
+	),
+
+	TP_printk(
+		LOCAL_PR_FMT  VIF_PR_FMT " new type:%d",
+		LOCAL_PR_ARG, VIF_PR_ARG, __entry->new_type
+	)
+);
+
 TRACE_EVENT(drv_remove_interface,
 	TP_PROTO(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata),
 
author maintainer
#8 lore raw

PATCH 6/6 mac80211_hwsim: support runtime iftype changes

In reply to Johannes Berg

From: Johannes Berg <[email protected]>

Add the trivial support for runtime interface
type changes to mac80211_hwsim for testing.

---
 drivers/net/wireless/mac80211_hwsim.c |   13 +++++++++++++
 1 file changed, 13 insertions(+)
drivers/net/wireless/mac80211_hwsim.c +13 -0
@@ -601,6 +601,18 @@ static int mac80211_hwsim_add_interface(
 }
 
 
+static int mac80211_hwsim_change_interface(struct ieee80211_hw *hw,
+					   struct ieee80211_vif *vif,
+					   enum nl80211_iftype newtype)
+{
+	wiphy_debug(hw->wiphy,
+		    "%s (old type=%d, new type=%d, mac_addr=%pM)\n",
+		    __func__, vif->type, newtype, vif->addr);
+	hwsim_check_magic(vif);
+
+	return 0;
+}
+
 static void mac80211_hwsim_remove_interface(
 	struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 {
@@ -1027,6 +1039,7 @@ static struct ieee80211_ops mac80211_hws
 	.start = mac80211_hwsim_start,
 	.stop = mac80211_hwsim_stop,
 	.add_interface = mac80211_hwsim_add_interface,
+	.change_interface = mac80211_hwsim_change_interface,
 	.remove_interface = mac80211_hwsim_remove_interface,
 	.config = mac80211_hwsim_config,
 	.configure_filter = mac80211_hwsim_configure_filter,