brcmfmac: use struct net_device::destructor to remove interfaces
authorArend van Spriel <arend@broadcom.com>
Mon, 27 May 2013 19:09:57 +0000 (21:09 +0200)
committerJohn W. Linville <linville@tuxdriver.com>
Tue, 28 May 2013 17:43:09 +0000 (13:43 -0400)
Upon deleting a P2P_CLIENT/GO interface the vif and consequently
the wdev is freed before the net_device is actually being unregistered
but cfg80211 still needs to access the wdev. Using destructor field
to free the net_device and vif.

Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
Signed-off-by: Arend van Spriel <arend@broadcom.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
drivers/net/wireless/brcm80211/brcmfmac/p2p.c
drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c

index f04e3555dca39168daebdd8293e96eda692328da..b98f2235978e80269be1861b26ba019398591bae 100644 (file)
@@ -653,6 +653,7 @@ int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked)
 
        brcmf_dbg(INFO, "%s: Broadcom Dongle Host Driver\n", ndev->name);
 
+       ndev->destructor = free_netdev;
        return 0;
 
 fail:
@@ -793,6 +794,7 @@ void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx)
        struct brcmf_if *ifp;
 
        ifp = drvr->iflist[bssidx];
+       drvr->iflist[bssidx] = NULL;
        if (!ifp) {
                brcmf_err("Null interface, idx=%d\n", bssidx);
                return;
@@ -813,15 +815,13 @@ void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx)
                        cancel_work_sync(&ifp->setmacaddr_work);
                        cancel_work_sync(&ifp->multicast_work);
                }
-
+               /* unregister will take care of freeing it */
                unregister_netdev(ifp->ndev);
                if (bssidx == 0)
                        brcmf_cfg80211_detach(drvr->config);
-               free_netdev(ifp->ndev);
        } else {
                kfree(ifp);
        }
-       drvr->iflist[bssidx] = NULL;
 }
 
 int brcmf_attach(uint bus_hdrlen, struct device *dev)
index 167b7afdf0d8cdb18739718ff0c59ea373eaa63a..79555f006d53d170e6186a76f3111b6d16b299ee 100644 (file)
@@ -2239,6 +2239,25 @@ static void brcmf_p2p_delete_p2pdev(struct brcmf_cfg80211_info *cfg,
        brcmf_free_vif(cfg, vif);
 }
 
+/**
+ * brcmf_p2p_free_p2p_if() - free up net device related data.
+ *
+ * @ndev: net device that needs to be freed.
+ */
+static void brcmf_p2p_free_p2p_if(struct net_device *ndev)
+{
+       struct brcmf_cfg80211_info *cfg;
+       struct brcmf_cfg80211_vif *vif;
+       struct brcmf_if *ifp;
+
+       ifp = netdev_priv(ndev);
+       cfg = ifp->drvr->config;
+       vif = ifp->vif;
+
+       brcmf_free_vif(cfg, vif);
+       free_netdev(ifp->ndev);
+}
+
 /**
  * brcmf_p2p_add_vif() - create a new P2P virtual interface.
  *
@@ -2316,6 +2335,9 @@ struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name,
                brcmf_err("Registering netdevice failed\n");
                goto fail;
        }
+       /* override destructor */
+       ifp->ndev->destructor = brcmf_p2p_free_p2p_if;
+
        cfg->p2p.bss_idx[P2PAPI_BSSCFG_CONNECTION].vif = vif;
        /* Disable firmware roaming for P2P interface  */
        brcmf_fil_iovar_int_set(ifp, "roam_off", 1);
@@ -2391,7 +2413,6 @@ int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev)
                        err = 0;
        }
        brcmf_cfg80211_arm_vif_event(cfg, NULL);
-       brcmf_free_vif(cfg, vif);
        p2p->bss_idx[P2PAPI_BSSCFG_CONNECTION].vif = NULL;
 
        return err;
index f8c86b58a6d1806849a79fc87b8949251d0c6c2d..656ce8765863b140515262936bd92044dc983e03 100644 (file)
@@ -4678,7 +4678,6 @@ static s32 brcmf_notify_vif_event(struct brcmf_if *ifp,
                return 0;
 
        case BRCMF_E_IF_DEL:
-               ifp->vif = NULL;
                mutex_unlock(&event->vif_event_lock);
                /* event may not be upon user request */
                if (brcmf_cfg80211_vif_event_armed(cfg))