Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 34d4bc4d authored by Johannes Berg's avatar Johannes Berg Committed by John W. Linville
Browse files

mac80211: support runtime interface type changes



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.

Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 87490f6d
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -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);
+0 −3
Original line number Diff line number Diff line
@@ -52,9 +52,6 @@ static int ieee80211_change_iface(struct wiphy *wiphy,
	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;
+14 −0
Original line number Diff line number Diff line
@@ -54,6 +54,20 @@ static inline int drv_add_interface(struct ieee80211_local *local,
	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)
{
+25 −0
Original line number Diff line number Diff line
@@ -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),

+13 −1
Original line number Diff line number Diff line
@@ -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];
@@ -1087,7 +1099,7 @@ void ieee80211_recalc_idle(struct ieee80211_local *local);

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 */
Loading