Commit 6cd536fe authored by Johannes Berg's avatar Johannes Berg
Browse files

cfg80211: change internal management frame registration API



Almost all drivers below cfg80211 get the API wrong (except for
cfg80211) and are unable to cope with multiple registrations for
the same frame type, which is valid due to the match filter.
This seems to indicate the API is wrong, and we should maintain
the full information in cfg80211 instead of the drivers.

Change the API to no longer inform the driver about individual
registrations and unregistrations, but rather every time about
the entire state of the entire wiphy and single wdev, whenever
it may have changed. This also simplifies the code in cfg80211
as it no longer has to track exactly what was unregistered and
can free things immediately.

Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
Acked-by: default avatarArend van Spriel <arend.vanspriel@broadcom.com>
Reviewed-by: default avatarSergey Matyukevich <sergey.matyukevich.os@quantenna.com>
Link: https://lore.kernel.org/r/20200417124300.f47f3828afc8.I7f81ef59c2c5a340d7075fb3c6d0e08e8aeffe07@changeid


Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 9eaf183a
Loading
Loading
Loading
Loading
+12 −14
Original line number Original line Diff line number Diff line
@@ -3249,22 +3249,19 @@ static int ath6kl_get_antenna(struct wiphy *wiphy,
	return 0;
	return 0;
}
}


static void ath6kl_mgmt_frame_register(struct wiphy *wiphy,
static void ath6kl_update_mgmt_frame_registrations(struct wiphy *wiphy,
						   struct wireless_dev *wdev,
						   struct wireless_dev *wdev,
				       u16 frame_type, bool reg)
						   struct mgmt_frame_regs *upd)
{
{
	struct ath6kl_vif *vif = ath6kl_vif_from_wdev(wdev);
	struct ath6kl_vif *vif = ath6kl_vif_from_wdev(wdev);


	ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: frame_type=0x%x reg=%d\n",
		   __func__, frame_type, reg);
	if (frame_type == IEEE80211_STYPE_PROBE_REQ) {
	/*
	/*
		 * Note: This notification callback is not allowed to sleep, so
	 * FIXME: send WMI_PROBE_REQ_REPORT_CMD here instead of hardcoding
		 * we cannot send WMI_PROBE_REQ_REPORT_CMD here. Instead, we
	 *	  the reporting in the target all the time, this callback
		 * hardcode target to report Probe Request frames all the time.
	 *	  *is* allowed to sleep after all.
	 */
	 */
		vif->probe_req_report = reg;
	vif->probe_req_report =
	}
		upd->interface_stypes & BIT(IEEE80211_STYPE_PROBE_REQ >> 4);
}
}


static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,
static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,
@@ -3464,7 +3461,8 @@ static struct cfg80211_ops ath6kl_cfg80211_ops = {
	.remain_on_channel = ath6kl_remain_on_channel,
	.remain_on_channel = ath6kl_remain_on_channel,
	.cancel_remain_on_channel = ath6kl_cancel_remain_on_channel,
	.cancel_remain_on_channel = ath6kl_cancel_remain_on_channel,
	.mgmt_tx = ath6kl_mgmt_tx,
	.mgmt_tx = ath6kl_mgmt_tx,
	.mgmt_frame_register = ath6kl_mgmt_frame_register,
	.update_mgmt_frame_registrations =
		ath6kl_update_mgmt_frame_registrations,
	.get_antenna = ath6kl_get_antenna,
	.get_antenna = ath6kl_get_antenna,
	.sched_scan_start = ath6kl_cfg80211_sscan_start,
	.sched_scan_start = ath6kl_cfg80211_sscan_start,
	.sched_scan_stop = ath6kl_cfg80211_sscan_stop,
	.sched_scan_stop = ath6kl_cfg80211_sscan_stop,
+7 −12
Original line number Original line Diff line number Diff line
@@ -4979,21 +4979,15 @@ brcmf_cfg80211_change_station(struct wiphy *wiphy, struct net_device *ndev,
}
}


static void
static void
brcmf_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
brcmf_cfg80211_update_mgmt_frame_registrations(struct wiphy *wiphy,
					       struct wireless_dev *wdev,
					       struct wireless_dev *wdev,
				   u16 frame_type, bool reg)
					       struct mgmt_frame_regs *upd)
{
{
	struct brcmf_cfg80211_vif *vif;
	struct brcmf_cfg80211_vif *vif;
	u16 mgmt_type;


	brcmf_dbg(TRACE, "Enter, frame_type %04x, reg=%d\n", frame_type, reg);

	mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4;
	vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
	vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
	if (reg)

		vif->mgmt_rx_reg |= BIT(mgmt_type);
	vif->mgmt_rx_reg = upd->interface_stypes;
	else
		vif->mgmt_rx_reg &= ~BIT(mgmt_type);
}
}




@@ -5408,7 +5402,8 @@ static struct cfg80211_ops brcmf_cfg80211_ops = {
	.change_station = brcmf_cfg80211_change_station,
	.change_station = brcmf_cfg80211_change_station,
	.sched_scan_start = brcmf_cfg80211_sched_scan_start,
	.sched_scan_start = brcmf_cfg80211_sched_scan_start,
	.sched_scan_stop = brcmf_cfg80211_sched_scan_stop,
	.sched_scan_stop = brcmf_cfg80211_sched_scan_stop,
	.mgmt_frame_register = brcmf_cfg80211_mgmt_frame_register,
	.update_mgmt_frame_registrations =
		brcmf_cfg80211_update_mgmt_frame_registrations,
	.mgmt_tx = brcmf_cfg80211_mgmt_tx,
	.mgmt_tx = brcmf_cfg80211_mgmt_tx,
	.remain_on_channel = brcmf_p2p_remain_on_channel,
	.remain_on_channel = brcmf_p2p_remain_on_channel,
	.cancel_remain_on_channel = brcmf_cfg80211_cancel_remain_on_channel,
	.cancel_remain_on_channel = brcmf_cfg80211_cancel_remain_on_channel,
+6 −10
Original line number Original line Diff line number Diff line
@@ -269,17 +269,12 @@ mwifiex_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
 * CFG802.11 operation handler to register a mgmt frame.
 * CFG802.11 operation handler to register a mgmt frame.
 */
 */
static void
static void
mwifiex_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
mwifiex_cfg80211_update_mgmt_frame_registrations(struct wiphy *wiphy,
						 struct wireless_dev *wdev,
						 struct wireless_dev *wdev,
				     u16 frame_type, bool reg)
						 struct mgmt_frame_regs *upd)
{
{
	struct mwifiex_private *priv = mwifiex_netdev_get_priv(wdev->netdev);
	struct mwifiex_private *priv = mwifiex_netdev_get_priv(wdev->netdev);
	u32 mask;
	u32 mask = upd->interface_stypes;

	if (reg)
		mask = priv->mgmt_frame_mask | BIT(frame_type >> 4);
	else
		mask = priv->mgmt_frame_mask & ~BIT(frame_type >> 4);


	if (mask != priv->mgmt_frame_mask) {
	if (mask != priv->mgmt_frame_mask) {
		priv->mgmt_frame_mask = mask;
		priv->mgmt_frame_mask = mask;
@@ -4189,7 +4184,8 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = {
	.del_key = mwifiex_cfg80211_del_key,
	.del_key = mwifiex_cfg80211_del_key,
	.set_default_mgmt_key = mwifiex_cfg80211_set_default_mgmt_key,
	.set_default_mgmt_key = mwifiex_cfg80211_set_default_mgmt_key,
	.mgmt_tx = mwifiex_cfg80211_mgmt_tx,
	.mgmt_tx = mwifiex_cfg80211_mgmt_tx,
	.mgmt_frame_register = mwifiex_cfg80211_mgmt_frame_register,
	.update_mgmt_frame_registrations =
		mwifiex_cfg80211_update_mgmt_frame_registrations,
	.remain_on_channel = mwifiex_cfg80211_remain_on_channel,
	.remain_on_channel = mwifiex_cfg80211_remain_on_channel,
	.cancel_remain_on_channel = mwifiex_cfg80211_cancel_remain_on_channel,
	.cancel_remain_on_channel = mwifiex_cfg80211_cancel_remain_on_channel,
	.set_default_key = mwifiex_cfg80211_set_default_key,
	.set_default_key = mwifiex_cfg80211_set_default_key,
+43 −40
Original line number Original line Diff line number Diff line
@@ -389,55 +389,57 @@ static int qtnf_set_wiphy_params(struct wiphy *wiphy, u32 changed)
}
}


static void
static void
qtnf_mgmt_frame_register(struct wiphy *wiphy, struct wireless_dev *wdev,
qtnf_update_mgmt_frame_registrations(struct wiphy *wiphy,
			 u16 frame_type, bool reg)
				     struct wireless_dev *wdev,
				     struct mgmt_frame_regs *upd)
{
{
	struct qtnf_vif *vif = qtnf_netdev_get_priv(wdev->netdev);
	struct qtnf_vif *vif = qtnf_netdev_get_priv(wdev->netdev);
	u16 mgmt_type;
	u16 new_mask = upd->interface_stypes;
	u16 new_mask;
	u16 old_mask = vif->mgmt_frames_bitmask;
	u16 qlink_frame_type = 0;
	static const struct {
		u16 mask, qlink_type;
	} updates[] = {
		{
			.mask = BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
				BIT(IEEE80211_STYPE_ASSOC_REQ >> 4),
			.qlink_type = QLINK_MGMT_FRAME_ASSOC_REQ,
		},
		{
			.mask = BIT(IEEE80211_STYPE_AUTH >> 4),
			.qlink_type = QLINK_MGMT_FRAME_AUTH,
		},
		{
			.mask = BIT(IEEE80211_STYPE_PROBE_REQ >> 4),
			.qlink_type = QLINK_MGMT_FRAME_PROBE_REQ,
		},
		{
			.mask = BIT(IEEE80211_STYPE_ACTION >> 4),
			.qlink_type = QLINK_MGMT_FRAME_ACTION,
		},
	};
	unsigned int i;


	mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4;
	if (new_mask == old_mask)
		return;


	if (reg)
	for (i = 0; i < ARRAY_SIZE(updates); i++) {
		new_mask = vif->mgmt_frames_bitmask | BIT(mgmt_type);
		u16 mask = updates[i].mask;
	else
		u16 qlink_frame_type = updates[i].qlink_type;
		new_mask = vif->mgmt_frames_bitmask & ~BIT(mgmt_type);
		bool reg;


	if (new_mask == vif->mgmt_frames_bitmask)
		/* the ! are here due to the assoc/reassoc merge */
		return;
		if (!(new_mask & mask) == !(old_mask & mask))
			continue;


	switch (frame_type & IEEE80211_FCTL_STYPE) {
		reg = new_mask & mask;
	case IEEE80211_STYPE_REASSOC_REQ:
	case IEEE80211_STYPE_ASSOC_REQ:
		qlink_frame_type = QLINK_MGMT_FRAME_ASSOC_REQ;
		break;
	case IEEE80211_STYPE_AUTH:
		qlink_frame_type = QLINK_MGMT_FRAME_AUTH;
		break;
	case IEEE80211_STYPE_PROBE_REQ:
		qlink_frame_type = QLINK_MGMT_FRAME_PROBE_REQ;
		break;
	case IEEE80211_STYPE_ACTION:
		qlink_frame_type = QLINK_MGMT_FRAME_ACTION;
		break;
	default:
		pr_warn("VIF%u.%u: unsupported frame type: %X\n",
			vif->mac->macid, vif->vifid,
			(frame_type & IEEE80211_FCTL_STYPE) >> 4);
		return;
	}


	if (qtnf_cmd_send_register_mgmt(vif, qlink_frame_type, reg)) {
		if (qtnf_cmd_send_register_mgmt(vif, qlink_frame_type, reg))
		pr_warn("VIF%u.%u: failed to %sregister mgmt frame type 0x%x\n",
			pr_warn("VIF%u.%u: failed to %sregister qlink frame type 0x%x\n",
				vif->mac->macid, vif->vifid, reg ? "" : "un",
				vif->mac->macid, vif->vifid, reg ? "" : "un",
			frame_type);
				qlink_frame_type);
		return;
	}
	}


	vif->mgmt_frames_bitmask = new_mask;
	vif->mgmt_frames_bitmask = new_mask;
	pr_debug("VIF%u.%u: %sregistered mgmt frame type 0x%x\n",
		 vif->mac->macid, vif->vifid, reg ? "" : "un", frame_type);
}
}


static int
static int
@@ -1017,7 +1019,8 @@ static struct cfg80211_ops qtn_cfg80211_ops = {
	.change_beacon		= qtnf_change_beacon,
	.change_beacon		= qtnf_change_beacon,
	.stop_ap		= qtnf_stop_ap,
	.stop_ap		= qtnf_stop_ap,
	.set_wiphy_params	= qtnf_set_wiphy_params,
	.set_wiphy_params	= qtnf_set_wiphy_params,
	.mgmt_frame_register	= qtnf_mgmt_frame_register,
	.update_mgmt_frame_registrations =
		qtnf_update_mgmt_frame_registrations,
	.mgmt_tx		= qtnf_mgmt_tx,
	.mgmt_tx		= qtnf_mgmt_tx,
	.change_station		= qtnf_change_station,
	.change_station		= qtnf_change_station,
	.del_station		= qtnf_del_station,
	.del_station		= qtnf_del_station,
+18 −5
Original line number Original line Diff line number Diff line
@@ -3384,6 +3384,17 @@ struct cfg80211_update_owe_info {
	size_t ie_len;
	size_t ie_len;
};
};


/**
 * struct mgmt_frame_regs - management frame registrations data
 * @global_stypes: bitmap of management frame subtypes registered
 *	for the entire device
 * @interface_stypes: bitmap of management frame subtypes registered
 *	for the given interface
 */
struct mgmt_frame_regs {
	u32 global_stypes, interface_stypes;
};

/**
/**
 * struct cfg80211_ops - backend description for wireless configuration
 * struct cfg80211_ops - backend description for wireless configuration
 *
 *
@@ -3608,8 +3619,8 @@ struct cfg80211_update_owe_info {
 *	The driver should not call cfg80211_sched_scan_stopped() for a requested
 *	The driver should not call cfg80211_sched_scan_stopped() for a requested
 *	stop (when this method returns 0).
 *	stop (when this method returns 0).
 *
 *
 * @mgmt_frame_register: Notify driver that a management frame type was
 * @update_mgmt_frame_registrations: Notify the driver that management frame
 *	registered. The callback is allowed to sleep.
 *	registrations were updated. The callback is allowed to sleep.
 *
 *
 * @set_antenna: Set antenna configuration (tx_ant, rx_ant) on the device.
 * @set_antenna: Set antenna configuration (tx_ant, rx_ant) on the device.
 *	Parameters are bitmaps of allowed antennas to use for TX/RX. Drivers may
 *	Parameters are bitmaps of allowed antennas to use for TX/RX. Drivers may
@@ -3932,9 +3943,9 @@ struct cfg80211_ops {
				      struct net_device *dev,
				      struct net_device *dev,
				      u32 rate, u32 pkts, u32 intvl);
				      u32 rate, u32 pkts, u32 intvl);


	void	(*mgmt_frame_register)(struct wiphy *wiphy,
	void	(*update_mgmt_frame_registrations)(struct wiphy *wiphy,
						   struct wireless_dev *wdev,
						   struct wireless_dev *wdev,
				       u16 frame_type, bool reg);
						   struct mgmt_frame_regs *upd);


	int	(*set_antenna)(struct wiphy *wiphy, u32 tx_ant, u32 rx_ant);
	int	(*set_antenna)(struct wiphy *wiphy, u32 tx_ant, u32 rx_ant);
	int	(*get_antenna)(struct wiphy *wiphy, u32 *tx_ant, u32 *rx_ant);
	int	(*get_antenna)(struct wiphy *wiphy, u32 *tx_ant, u32 *rx_ant);
@@ -5015,6 +5026,7 @@ struct cfg80211_cqm_config;
 *	by cfg80211 on change_interface
 *	by cfg80211 on change_interface
 * @mgmt_registrations: list of registrations for management frames
 * @mgmt_registrations: list of registrations for management frames
 * @mgmt_registrations_lock: lock for the list
 * @mgmt_registrations_lock: lock for the list
 * @mgmt_registrations_update_wk: update work to defer from atomic context
 * @mtx: mutex used to lock data in this struct, may be used by drivers
 * @mtx: mutex used to lock data in this struct, may be used by drivers
 *	and some API functions require it held
 *	and some API functions require it held
 * @beacon_interval: beacon interval used on this device for transmitting
 * @beacon_interval: beacon interval used on this device for transmitting
@@ -5060,6 +5072,7 @@ struct wireless_dev {


	struct list_head mgmt_registrations;
	struct list_head mgmt_registrations;
	spinlock_t mgmt_registrations_lock;
	spinlock_t mgmt_registrations_lock;
	struct work_struct mgmt_registrations_update_wk;


	struct mutex mtx;
	struct mutex mtx;


Loading