Commit 95ef1239 authored by Arend van Spriel's avatar Arend van Spriel Committed by Kalle Valo

brcmfmac: introduce brcmf_net_detach() function

In case of error during brcmf_bus_start() the network interfaces were
freed using free_netdev(). However, the interfaces may have additional
memory allocated which is not freed. The netdev has destructor set to
brcmf_cfg80211_free_netdev() which frees the additional memory if
allocated and call free_netdev(). The brcmf_net_detach() either calls
brcmf_cfg80211_free_netdev() directly or uses unregister_netdev() when
struct net_device::reg_state indicates the netdev was registered.
Reported-by: default avatarDaniel (Deognyoun) Kim <dekim@broadcom.com>
Reviewed-by: default avatarHante Meuleman <meuleman@broadcom.com>
Reviewed-by: default avatarFranky (Zhenhui) Lin <frankyl@broadcom.com>
Reviewed-by: default avatarPieter-Paul Giesberts <pieterpg@broadcom.com>
Signed-off-by: default avatarArend van Spriel <arend@broadcom.com>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
parent c67d41ba
...@@ -4747,7 +4747,8 @@ void brcmf_cfg80211_free_netdev(struct net_device *ndev) ...@@ -4747,7 +4747,8 @@ void brcmf_cfg80211_free_netdev(struct net_device *ndev)
ifp = netdev_priv(ndev); ifp = netdev_priv(ndev);
vif = ifp->vif; vif = ifp->vif;
brcmf_free_vif(vif); if (vif)
brcmf_free_vif(vif);
free_netdev(ndev); free_netdev(ndev);
} }
......
...@@ -718,8 +718,6 @@ int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked) ...@@ -718,8 +718,6 @@ int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked)
} }
brcmf_dbg(INFO, "%s: Broadcom Dongle Host Driver\n", ndev->name); brcmf_dbg(INFO, "%s: Broadcom Dongle Host Driver\n", ndev->name);
ndev->destructor = brcmf_cfg80211_free_netdev;
return 0; return 0;
fail: fail:
...@@ -729,6 +727,14 @@ int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked) ...@@ -729,6 +727,14 @@ int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked)
return -EBADE; return -EBADE;
} }
static void brcmf_net_detach(struct net_device *ndev)
{
if (ndev->reg_state == NETREG_REGISTERED)
unregister_netdev(ndev);
else
brcmf_cfg80211_free_netdev(ndev);
}
static int brcmf_net_p2p_open(struct net_device *ndev) static int brcmf_net_p2p_open(struct net_device *ndev)
{ {
brcmf_dbg(TRACE, "Enter\n"); brcmf_dbg(TRACE, "Enter\n");
...@@ -805,8 +811,7 @@ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, s32 ifidx, ...@@ -805,8 +811,7 @@ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, s32 ifidx,
ifp->ndev->name); ifp->ndev->name);
if (ifidx) { if (ifidx) {
netif_stop_queue(ifp->ndev); netif_stop_queue(ifp->ndev);
unregister_netdev(ifp->ndev); brcmf_net_detach(ifp->ndev);
free_netdev(ifp->ndev);
drvr->iflist[bssidx] = NULL; drvr->iflist[bssidx] = NULL;
} else { } else {
brcmf_err("ignore IF event\n"); brcmf_err("ignore IF event\n");
...@@ -828,6 +833,7 @@ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, s32 ifidx, ...@@ -828,6 +833,7 @@ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, s32 ifidx,
if (!ndev) if (!ndev)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
ndev->destructor = brcmf_cfg80211_free_netdev;
ifp = netdev_priv(ndev); ifp = netdev_priv(ndev);
ifp->ndev = ndev; ifp->ndev = ndev;
/* store mapping ifidx to bssidx */ /* store mapping ifidx to bssidx */
...@@ -879,8 +885,7 @@ static void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx) ...@@ -879,8 +885,7 @@ static void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx)
cancel_work_sync(&ifp->setmacaddr_work); cancel_work_sync(&ifp->setmacaddr_work);
cancel_work_sync(&ifp->multicast_work); cancel_work_sync(&ifp->multicast_work);
} }
/* unregister will take care of freeing it */ brcmf_net_detach(ifp->ndev);
unregister_netdev(ifp->ndev);
} }
} }
...@@ -1056,11 +1061,11 @@ int brcmf_bus_start(struct device *dev) ...@@ -1056,11 +1061,11 @@ int brcmf_bus_start(struct device *dev)
brcmf_fws_deinit(drvr); brcmf_fws_deinit(drvr);
} }
if (drvr->iflist[0]) { if (drvr->iflist[0]) {
free_netdev(ifp->ndev); brcmf_net_detach(ifp->ndev);
drvr->iflist[0] = NULL; drvr->iflist[0] = NULL;
} }
if (p2p_ifp) { if (p2p_ifp) {
free_netdev(p2p_ifp->ndev); brcmf_net_detach(p2p_ifp->ndev);
drvr->iflist[1] = NULL; drvr->iflist[1] = NULL;
} }
return ret; return ret;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment