Skip to content

Commit

Permalink
cfg80211: change netdev registration/unregistration semantics
Browse files Browse the repository at this point in the history
We used to not require anything in terms of registering netdevs
with cfg80211, using a netdev notifier instead. However, in the
next patch reducing RTNL locking, this causes big problems, and
the simplest way is to just require drivers to do things better.

Change the registration/unregistration semantics to require the
drivers to call cfg80211_(un)register_netdevice() when this is
happening due to a cfg80211 request, i.e. add_virtual_intf() or
del_virtual_intf() (or if it somehow has to happen in any other
cfg80211 callback).

Otherwise, in other contexts, drivers may continue to use the
normal netdev (un)registration functions as usual.

Internally, we still use the netdev notifier and track (by the
new wdev->registered bool) if the wdev had already been added
to cfg80211 or not.

Link: https://lore.kernel.org/r/20210122161942.cf2f4b65e4e9.Ida8234e50da13eb675b557bac52a713ad4eddf71@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
  • Loading branch information
jmberg-intel committed Jan 22, 2021
1 parent 347c298 commit 2fe8ef1
Show file tree
Hide file tree
Showing 12 changed files with 123 additions and 77 deletions.
4 changes: 2 additions & 2 deletions drivers/net/wireless/ath/ath6kl/cfg80211.c
Original file line number Diff line number Diff line change
Expand Up @@ -3648,7 +3648,7 @@ void ath6kl_cfg80211_vif_cleanup(struct ath6kl_vif *vif)
kfree(mc_filter);
}

unregister_netdevice(vif->ndev);
cfg80211_unregister_netdevice(vif->ndev);

ar->num_vif--;
}
Expand Down Expand Up @@ -3821,7 +3821,7 @@ struct wireless_dev *ath6kl_interface_add(struct ath6kl *ar, const char *name,

netdev_set_default_ethtool_ops(ndev, &ath6kl_ethtool_ops);

if (register_netdevice(ndev))
if (cfg80211_register_netdevice(ndev))
goto err;

ar->avail_idx_map &= ~BIT(fw_vif_idx);
Expand Down
4 changes: 2 additions & 2 deletions drivers/net/wireless/ath/wil6210/netdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -424,7 +424,7 @@ int wil_vif_add(struct wil6210_priv *wil, struct wil6210_vif *vif)
if (rc)
return rc;
}
rc = register_netdevice(ndev);
rc = cfg80211_register_netdevice(ndev);
if (rc < 0) {
dev_err(&ndev->dev, "Failed to register netdev: %d\n", rc);
if (any_active && vif->mid != 0)
Expand Down Expand Up @@ -511,7 +511,7 @@ void wil_vif_remove(struct wil6210_priv *wil, u8 mid)
/* during unregister_netdevice cfg80211_leave may perform operations
* such as stop AP, disconnect, so we only clear the VIF afterwards
*/
unregister_netdevice(ndev);
cfg80211_unregister_netdevice(ndev);

if (any_active && vif->mid != 0)
wmi_port_delete(wil, vif->mid);
Expand Down
6 changes: 3 additions & 3 deletions drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -657,7 +657,7 @@ int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked)
INIT_WORK(&ifp->ndoffload_work, _brcmf_update_ndtable);

if (rtnl_locked)
err = register_netdevice(ndev);
err = cfg80211_register_netdevice(ndev);
else
err = register_netdev(ndev);
if (err != 0) {
Expand All @@ -681,7 +681,7 @@ void brcmf_net_detach(struct net_device *ndev, bool rtnl_locked)
{
if (ndev->reg_state == NETREG_REGISTERED) {
if (rtnl_locked)
unregister_netdevice(ndev);
cfg80211_unregister_netdevice(ndev);
else
unregister_netdev(ndev);
} else {
Expand Down Expand Up @@ -758,7 +758,7 @@ int brcmf_net_mon_attach(struct brcmf_if *ifp)
ndev = ifp->ndev;
ndev->netdev_ops = &brcmf_netdev_ops_mon;

err = register_netdevice(ndev);
err = cfg80211_register_netdevice(ndev);
if (err)
bphy_err(drvr, "Failed to register %s device\n", ndev->name);

Expand Down
4 changes: 2 additions & 2 deletions drivers/net/wireless/marvell/mwifiex/cfg80211.c
Original file line number Diff line number Diff line change
Expand Up @@ -3081,7 +3081,7 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
mutex_init(&priv->async_mutex);

/* Register network device */
if (register_netdevice(dev)) {
if (cfg80211_register_netdevice(dev)) {
mwifiex_dbg(adapter, ERROR, "cannot register network device\n");
ret = -EFAULT;
goto err_reg_netdev;
Expand Down Expand Up @@ -3160,7 +3160,7 @@ int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev)
netif_carrier_off(priv->netdev);

if (wdev->netdev->reg_state == NETREG_REGISTERED)
unregister_netdevice(wdev->netdev);
cfg80211_unregister_netdevice(wdev->netdev);

if (priv->dfs_cac_workqueue) {
flush_workqueue(priv->dfs_cac_workqueue);
Expand Down
2 changes: 1 addition & 1 deletion drivers/net/wireless/microchip/wilc1000/cfg80211.c
Original file line number Diff line number Diff line change
Expand Up @@ -1538,7 +1538,7 @@ static int del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev)
wilc_wfi_deinit_mon_interface(wl, true);
vif = netdev_priv(wdev->netdev);
cfg80211_stop_iface(wiphy, wdev, GFP_KERNEL);
unregister_netdevice(vif->ndev);
cfg80211_unregister_netdevice(vif->ndev);
vif->monitor_flag = 0;

wilc_set_operation_mode(vif, 0, 0, 0);
Expand Down
4 changes: 2 additions & 2 deletions drivers/net/wireless/microchip/wilc1000/mon.c
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ struct net_device *wilc_wfi_init_mon_interface(struct wilc *wl,
wl->monitor_dev->netdev_ops = &wilc_wfi_netdev_ops;
wl->monitor_dev->needs_free_netdev = true;

if (register_netdevice(wl->monitor_dev)) {
if (cfg80211_register_netdevice(wl->monitor_dev)) {
netdev_err(real_dev, "register_netdevice failed\n");
free_netdev(wl->monitor_dev);
return NULL;
Expand All @@ -251,7 +251,7 @@ void wilc_wfi_deinit_mon_interface(struct wilc *wl, bool rtnl_locked)
return;

if (rtnl_locked)
unregister_netdevice(wl->monitor_dev);
cfg80211_unregister_netdevice(wl->monitor_dev);
else
unregister_netdev(wl->monitor_dev);
wl->monitor_dev = NULL;
Expand Down
2 changes: 1 addition & 1 deletion drivers/net/wireless/microchip/wilc1000/netdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -950,7 +950,7 @@ struct wilc_vif *wilc_netdev_ifc_init(struct wilc *wl, const char *name,
vif->priv.dev = ndev;

if (rtnl_locked)
ret = register_netdevice(ndev);
ret = cfg80211_register_netdevice(ndev);
else
ret = register_netdev(ndev);

Expand Down
4 changes: 2 additions & 2 deletions drivers/net/wireless/quantenna/qtnfmac/cfg80211.c
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ int qtnf_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev)
cancel_work_sync(&vif->high_pri_tx_work);

if (netdev->reg_state == NETREG_REGISTERED)
unregister_netdevice(netdev);
cfg80211_unregister_netdevice(netdev);

if (qtnf_cmd_send_del_intf(vif))
pr_err("VIF%u.%u: failed to delete VIF\n", vif->mac->macid,
Expand Down Expand Up @@ -267,7 +267,7 @@ static struct wireless_dev *qtnf_add_virtual_intf(struct wiphy *wiphy,
if (qtnf_hwcap_is_set(&mac->bus->hw_info, QLINK_HW_CAPAB_HW_BRIDGE)) {
ret = qtnf_cmd_netdev_changeupper(vif, vif->netdev->ifindex);
if (ret) {
unregister_netdevice(vif->netdev);
cfg80211_unregister_netdevice(vif->netdev);
vif->netdev = NULL;
goto error_del_vif;
}
Expand Down
2 changes: 1 addition & 1 deletion drivers/net/wireless/quantenna/qtnfmac/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -492,7 +492,7 @@ int qtnf_core_net_attach(struct qtnf_wmac *mac, struct qtnf_vif *vif,

SET_NETDEV_DEV(dev, wiphy_dev(wiphy));

ret = register_netdevice(dev);
ret = cfg80211_register_netdevice(dev);
if (ret) {
free_netdev(dev);
vif->netdev = NULL;
Expand Down
40 changes: 32 additions & 8 deletions include/net/cfg80211.h
Original file line number Diff line number Diff line change
Expand Up @@ -5228,6 +5228,7 @@ struct cfg80211_cqm_config;
*
* @wiphy: pointer to hardware description
* @iftype: interface type
* @registered: is this wdev already registered with cfg80211
* @list: (private) Used to collect the interfaces
* @netdev: (private) Used to reference back to the netdev, may be %NULL
* @identifier: (private) Identifier used in nl80211 to identify this
Expand Down Expand Up @@ -5311,7 +5312,7 @@ struct wireless_dev {

struct mutex mtx;

bool use_4addr, is_running;
bool use_4addr, is_running, registered;

u8 address[ETH_ALEN] __aligned(sizeof(u16));

Expand Down Expand Up @@ -7654,18 +7655,41 @@ u32 cfg80211_calculate_bitrate(struct rate_info *rate);
* cfg80211_unregister_wdev - remove the given wdev
* @wdev: struct wireless_dev to remove
*
* Call this function only for wdevs that have no netdev assigned,
* e.g. P2P Devices. It removes the device from the list so that
* it can no longer be used. It is necessary to call this function
* even when cfg80211 requests the removal of the interface by
* calling the del_virtual_intf() callback. The function must also
* be called when the driver wishes to unregister the wdev, e.g.
* when the device is unbound from the driver.
* This function removes the device so it can no longer be used. It is necessary
* to call this function even when cfg80211 requests the removal of the device
* by calling the del_virtual_intf() callback. The function must also be called
* when the driver wishes to unregister the wdev, e.g. when the hardware device
* is unbound from the driver.
*
* Requires the RTNL to be held.
*/
void cfg80211_unregister_wdev(struct wireless_dev *wdev);

/**
* cfg80211_register_netdevice - register the given netdev
* @dev: the netdev to register
*
* Note: In contexts coming from cfg80211 callbacks, you must call this rather
* than register_netdevice(), unregister_netdev() is impossible as the RTNL is
* held. Otherwise, both register_netdevice() and register_netdev() are usable
* instead as well.
*/
int cfg80211_register_netdevice(struct net_device *dev);

/**
* cfg80211_unregister_netdevice - unregister the given netdev
* @dev: the netdev to register
*
* Note: In contexts coming from cfg80211 callbacks, you must call this rather
* than unregister_netdevice(), unregister_netdev() is impossible as the RTNL
* is held. Otherwise, both unregister_netdevice() and unregister_netdev() are
* usable instead as well.
*/
static inline void cfg80211_unregister_netdevice(struct net_device *dev)
{
cfg80211_unregister_wdev(dev->ieee80211_ptr);
}

/**
* struct cfg80211_ft_event_params - FT Information Elements
* @ies: FT IEs
Expand Down
9 changes: 4 additions & 5 deletions net/mac80211/iface.c
Original file line number Diff line number Diff line change
Expand Up @@ -1976,7 +1976,7 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
ndev->min_mtu = 256;
ndev->max_mtu = local->hw.max_mtu;

ret = register_netdevice(ndev);
ret = cfg80211_register_netdevice(ndev);
if (ret) {
free_netdev(ndev);
return ret;
Expand Down Expand Up @@ -2006,10 +2006,9 @@ void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata)

synchronize_rcu();

if (sdata->dev) {
unregister_netdevice(sdata->dev);
} else {
cfg80211_unregister_wdev(&sdata->wdev);
cfg80211_unregister_wdev(&sdata->wdev);

if (!sdata->dev) {
ieee80211_teardown_sdata(sdata);
kfree(sdata);
}
Expand Down
Loading

0 comments on commit 2fe8ef1

Please sign in to comment.