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

Commit 31eba5bc authored by Felix Fietkau's avatar Felix Fietkau Committed by Johannes Berg
Browse files

mac80211: support active monitor interfaces



Support them only if the driver advertises support for them via
IEEE80211_HW_SUPPORTS_ACTIVE_MONITOR. Unlike normal monitor interfaces,
they are added to the driver, along with their MAC address.

Signed-off-by: default avatarFelix Fietkau <nbd@openwrt.org>
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent e057d3c3
Loading
Loading
Loading
Loading
+7 −4
Original line number Original line Diff line number Diff line
@@ -73,16 +73,19 @@ static int ieee80211_change_iface(struct wiphy *wiphy,
		struct ieee80211_local *local = sdata->local;
		struct ieee80211_local *local = sdata->local;


		if (ieee80211_sdata_running(sdata)) {
		if (ieee80211_sdata_running(sdata)) {
			u32 mask = MONITOR_FLAG_COOK_FRAMES |
				   MONITOR_FLAG_ACTIVE;

			/*
			/*
			 * Prohibit MONITOR_FLAG_COOK_FRAMES to be
			 * Prohibit MONITOR_FLAG_COOK_FRAMES and
			 * changed while the interface is up.
			 * MONITOR_FLAG_ACTIVE to be changed while the
			 * interface is up.
			 * Else we would need to add a lot of cruft
			 * Else we would need to add a lot of cruft
			 * to update everything:
			 * to update everything:
			 *	cooked_mntrs, monitor and all fif_* counters
			 *	cooked_mntrs, monitor and all fif_* counters
			 *	reconfigure hardware
			 *	reconfigure hardware
			 */
			 */
			if ((*flags & MONITOR_FLAG_COOK_FRAMES) !=
			if ((*flags & mask) != (sdata->u.mntr_flags & mask))
			    (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES))
				return -EBUSY;
				return -EBUSY;


			ieee80211_adjust_monitor_flags(sdata, -1);
			ieee80211_adjust_monitor_flags(sdata, -1);
+2 −1
Original line number Original line Diff line number Diff line
@@ -146,7 +146,8 @@ static inline int drv_add_interface(struct ieee80211_local *local,


	if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
	if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
		    (sdata->vif.type == NL80211_IFTYPE_MONITOR &&
		    (sdata->vif.type == NL80211_IFTYPE_MONITOR &&
		     !(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF))))
		     !(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF) &&
		     !(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE))))
		return -EINVAL;
		return -EINVAL;


	trace_drv_add_interface(local, sdata);
	trace_drv_add_interface(local, sdata);
+23 −6
Original line number Original line Diff line number Diff line
@@ -159,7 +159,8 @@ static int ieee80211_change_mtu(struct net_device *dev, int new_mtu)
	return 0;
	return 0;
}
}


static int ieee80211_verify_mac(struct ieee80211_local *local, u8 *addr)
static int ieee80211_verify_mac(struct ieee80211_local *local, u8 *addr,
				bool check_dup)
{
{
	struct ieee80211_sub_if_data *sdata;
	struct ieee80211_sub_if_data *sdata;
	u64 new, mask, tmp;
	u64 new, mask, tmp;
@@ -179,10 +180,13 @@ static int ieee80211_verify_mac(struct ieee80211_local *local, u8 *addr)
		((u64)m[2] << 3*8) | ((u64)m[3] << 2*8) |
		((u64)m[2] << 3*8) | ((u64)m[3] << 2*8) |
		((u64)m[4] << 1*8) | ((u64)m[5] << 0*8);
		((u64)m[4] << 1*8) | ((u64)m[5] << 0*8);


	if (!check_dup)
		return ret;


	mutex_lock(&local->iflist_mtx);
	mutex_lock(&local->iflist_mtx);
	list_for_each_entry(sdata, &local->interfaces, list) {
	list_for_each_entry(sdata, &local->interfaces, list) {
		if (sdata->vif.type == NL80211_IFTYPE_MONITOR)
		if (sdata->vif.type == NL80211_IFTYPE_MONITOR &&
		    !(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE))
			continue;
			continue;


		m = sdata->vif.addr;
		m = sdata->vif.addr;
@@ -204,12 +208,17 @@ static int ieee80211_change_mac(struct net_device *dev, void *addr)
{
{
	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
	struct sockaddr *sa = addr;
	struct sockaddr *sa = addr;
	bool check_dup = true;
	int ret;
	int ret;


	if (ieee80211_sdata_running(sdata))
	if (ieee80211_sdata_running(sdata))
		return -EBUSY;
		return -EBUSY;


	ret = ieee80211_verify_mac(sdata->local, sa->sa_data);
	if (sdata->vif.type == NL80211_IFTYPE_MONITOR &&
	    !(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE))
		check_dup = false;

	ret = ieee80211_verify_mac(sdata->local, sa->sa_data, check_dup);
	if (ret)
	if (ret)
		return ret;
		return ret;


@@ -541,7 +550,11 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
			break;
			break;
		}
		}


		if (local->monitors == 0 && local->open_count == 0) {
		if (sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE) {
			res = drv_add_interface(local, sdata);
			if (res)
				goto err_stop;
		} else if (local->monitors == 0 && local->open_count == 0) {
			res = ieee80211_add_virtual_monitor(local);
			res = ieee80211_add_virtual_monitor(local);
			if (res)
			if (res)
				goto err_stop;
				goto err_stop;
@@ -919,7 +932,11 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
		mutex_lock(&local->mtx);
		mutex_lock(&local->mtx);
		ieee80211_recalc_idle(local);
		ieee80211_recalc_idle(local);
		mutex_unlock(&local->mtx);
		mutex_unlock(&local->mtx);

		if (!(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE))
			break;
			break;

		/* fall through */
	default:
	default:
		if (going_down)
		if (going_down)
			drv_remove_interface(local, sdata);
			drv_remove_interface(local, sdata);
@@ -1068,7 +1085,7 @@ static const struct net_device_ops ieee80211_monitorif_ops = {
	.ndo_start_xmit		= ieee80211_monitor_start_xmit,
	.ndo_start_xmit		= ieee80211_monitor_start_xmit,
	.ndo_set_rx_mode	= ieee80211_set_multicast_list,
	.ndo_set_rx_mode	= ieee80211_set_multicast_list,
	.ndo_change_mtu 	= ieee80211_change_mtu,
	.ndo_change_mtu 	= ieee80211_change_mtu,
	.ndo_set_mac_address 	= eth_mac_addr,
	.ndo_set_mac_address 	= ieee80211_change_mac,
	.ndo_select_queue	= ieee80211_monitor_select_queue,
	.ndo_select_queue	= ieee80211_monitor_select_queue,
};
};


+6 −0
Original line number Original line Diff line number Diff line
@@ -560,6 +560,9 @@ void ieee80211_iterate_active_interfaces(
	list_for_each_entry(sdata, &local->interfaces, list) {
	list_for_each_entry(sdata, &local->interfaces, list) {
		switch (sdata->vif.type) {
		switch (sdata->vif.type) {
		case NL80211_IFTYPE_MONITOR:
		case NL80211_IFTYPE_MONITOR:
			if (!(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE))
				continue;
			break;
		case NL80211_IFTYPE_AP_VLAN:
		case NL80211_IFTYPE_AP_VLAN:
			continue;
			continue;
		default:
		default:
@@ -598,6 +601,9 @@ void ieee80211_iterate_active_interfaces_atomic(
	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
		switch (sdata->vif.type) {
		switch (sdata->vif.type) {
		case NL80211_IFTYPE_MONITOR:
		case NL80211_IFTYPE_MONITOR:
			if (!(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE))
				continue;
			break;
		case NL80211_IFTYPE_AP_VLAN:
		case NL80211_IFTYPE_AP_VLAN:
			continue;
			continue;
		default:
		default: