From patchwork Fri May 27 19:53:14 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?b?UmFmYcWCIE1pxYJlY2tp?= X-Patchwork-Id: 9138925 X-Patchwork-Delegate: kvalo@adurom.com Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 834CD60759 for ; Fri, 27 May 2016 19:54:19 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 750F92819C for ; Fri, 27 May 2016 19:54:19 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 69A9D2823E; Fri, 27 May 2016 19:54:19 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=2.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED,FREEMAIL_FROM,RCVD_IN_DNSWL_HI,T_DKIM_INVALID autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id D4EB82819C for ; Fri, 27 May 2016 19:54:18 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756119AbcE0Tx4 (ORCPT ); Fri, 27 May 2016 15:53:56 -0400 Received: from mail-wm0-f68.google.com ([74.125.82.68]:34562 "EHLO mail-wm0-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755355AbcE0Txy (ORCPT ); Fri, 27 May 2016 15:53:54 -0400 Received: by mail-wm0-f68.google.com with SMTP id n129so1467620wmn.1; Fri, 27 May 2016 12:53:53 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=hDWtgkNt2X/DsHkdxnlPq//0+Jsggx82xtCQ15yJnGI=; b=fGFRe69pt1zJWfYPw1FwlMMTf4JOOHvBeb1UG0osWdX9/6kRRzqJlVaIzuGDlOIs28 /4yCpBFZSX5TeZhWfOzCXi3v9nnCkrFK2y6UM4tnf+2lcysH+3+6bY6ncRIklNDCxNJA JIXcNlWCJr0gQRp4cMTiMNApC4grzcay9UW3mWVWG1g6RuxFIce1+8A143n3IokyTCq3 yPaZgjeHEZuT2UJr171b8JjqkH4KH6WlmwqC5SsJ27WhsPUR9xdh58ruvS2HF0cwI/mm Et+Dd/3qegJaxndWnDy+7aKMzWK8rNEkBsqdv8/h/LK25TceiD2TlNvKk1IEEiENJAdU HG3A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=hDWtgkNt2X/DsHkdxnlPq//0+Jsggx82xtCQ15yJnGI=; b=abBuYwJvjUX1DD8CJ+1g9R6d2tK7Gm39pFjK/ulRdEFttOLqVDM7GojGzIX9JIM0zQ ArwA+2JGgIW4+ziHBg6o7O1DMIsaMYsZFpgOVSDS+YI4XPlvKJ8zJ8xdzKxG68FW5oU3 APfrcY6jAllCRuzcs7L5aW8sSEXmW5+rkTRaxG55x+nP2R3Midp4nHcOchMu+g7VKrFj cecGdl+JtAhtBQdsuBGEwO0LZSpnhUertD7aSkS9Mh1WuZKxqkkdurdTtkm4aXMfqvua MFotYO7XCBU31py18DxxRgBbPGd9Dt95ELy/hka9pmFseBCrMa4/ugQjvosODzIY64k0 yeFA== X-Gm-Message-State: ALyK8tJfayrVb6LPFfyjfTjebHW8nH9StxC5m0UFMA5kA5HQrQ3u6XeRf1tr8P70GlsbFA== X-Received: by 10.194.23.33 with SMTP id j1mr17753258wjf.160.1464378832569; Fri, 27 May 2016 12:53:52 -0700 (PDT) Received: from linux-samsung.lan (euj241.neoplus.adsl.tpnet.pl. [83.20.181.241]) by smtp.gmail.com with ESMTPSA id i4sm20920137wjj.49.2016.05.27.12.53.50 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 27 May 2016 12:53:51 -0700 (PDT) From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= To: Kalle Valo Cc: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= , Brett Rudley , Arend van Spriel , "Franky (Zhenhui) Lin" , Hante Meuleman , Pieter-Paul Giesberts , Franky Lin , linux-wireless@vger.kernel.org (open list:BROADCOM BRCM80211 IEEE802.11n WIRELESS DRIVER), brcm80211-dev-list@broadcom.com (open list:BROADCOM BRCM80211 IEEE802.11n WIRELESS DRIVER), netdev@vger.kernel.org (open list:NETWORKING DRIVERS), linux-kernel@vger.kernel.org (open list) Subject: [PATCH 4.7 FIX] brcmfmac: fix lockup when removing P2P interface after event timeout Date: Fri, 27 May 2016 21:53:14 +0200 Message-Id: <1464378815-23282-1-git-send-email-zajec5@gmail.com> X-Mailer: git-send-email 1.8.4.5 MIME-Version: 1.0 Sender: linux-wireless-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Removing P2P interface is handled by sending a proper request to the firmware. On success firmware triggers an event and driver's handler removes a matching interface. However on event timeout we remove interface directly from the cfg80211 callback. Current code doesn't handle this case correctly as it always assumes rtnl to be unlocked. Fix it by adding an extra rtnl_locked parameter to functions and calling unregister_netdevice when needed. Signed-off-by: Rafał Miłecki --- .../broadcom/brcm80211/brcmfmac/cfg80211.c | 2 +- .../wireless/broadcom/brcm80211/brcmfmac/core.c | 29 +++++++++++++--------- .../wireless/broadcom/brcm80211/brcmfmac/core.h | 2 +- .../wireless/broadcom/brcm80211/brcmfmac/fweh.c | 2 +- .../net/wireless/broadcom/brcm80211/brcmfmac/p2p.c | 4 +-- 5 files changed, 22 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index 62f475e..ef09382 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -5364,7 +5364,7 @@ brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg, brcmf_dbg(CONN, "AP mode link down\n"); complete(&cfg->vif_disabled); if (ifp->vif->mbss) - brcmf_remove_interface(ifp); + brcmf_remove_interface(ifp, false); return 0; } diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c index b590499..7f8ba48c 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c @@ -548,12 +548,16 @@ fail: return -EBADE; } -static void brcmf_net_detach(struct net_device *ndev) +static void brcmf_net_detach(struct net_device *ndev, bool rtnl_locked) { - if (ndev->reg_state == NETREG_REGISTERED) - unregister_netdev(ndev); - else + if (ndev->reg_state == NETREG_REGISTERED) { + if (rtnl_locked) + unregister_netdevice(ndev); + else + unregister_netdev(ndev); + } else { brcmf_cfg80211_free_netdev(ndev); + } } void brcmf_net_setcarrier(struct brcmf_if *ifp, bool on) @@ -651,7 +655,7 @@ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bsscfgidx, s32 ifidx, brcmf_err("ERROR: netdev:%s already exists\n", ifp->ndev->name); netif_stop_queue(ifp->ndev); - brcmf_net_detach(ifp->ndev); + brcmf_net_detach(ifp->ndev, false); drvr->iflist[bsscfgidx] = NULL; } else { brcmf_dbg(INFO, "netdev:%s ignore IF event\n", @@ -699,7 +703,8 @@ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bsscfgidx, s32 ifidx, return ifp; } -static void brcmf_del_if(struct brcmf_pub *drvr, s32 bsscfgidx) +static void brcmf_del_if(struct brcmf_pub *drvr, s32 bsscfgidx, + bool rtnl_locked) { struct brcmf_if *ifp; @@ -729,7 +734,7 @@ static void brcmf_del_if(struct brcmf_pub *drvr, s32 bsscfgidx) cancel_work_sync(&ifp->multicast_work); cancel_work_sync(&ifp->ndoffload_work); } - brcmf_net_detach(ifp->ndev); + brcmf_net_detach(ifp->ndev, rtnl_locked); } else { /* Only p2p device interfaces which get dynamically created * end up here. In this case the p2p module should be informed @@ -743,14 +748,14 @@ static void brcmf_del_if(struct brcmf_pub *drvr, s32 bsscfgidx) } } -void brcmf_remove_interface(struct brcmf_if *ifp) +void brcmf_remove_interface(struct brcmf_if *ifp, bool rtnl_locked) { if (!ifp || WARN_ON(ifp->drvr->iflist[ifp->bsscfgidx] != ifp)) return; brcmf_dbg(TRACE, "Enter, bsscfgidx=%d, ifidx=%d\n", ifp->bsscfgidx, ifp->ifidx); brcmf_fws_del_interface(ifp); - brcmf_del_if(ifp->drvr, ifp->bsscfgidx); + brcmf_del_if(ifp->drvr, ifp->bsscfgidx, rtnl_locked); } int brcmf_get_next_free_bsscfgidx(struct brcmf_pub *drvr) @@ -1081,9 +1086,9 @@ fail: brcmf_fws_deinit(drvr); } if (ifp) - brcmf_net_detach(ifp->ndev); + brcmf_net_detach(ifp->ndev, false); if (p2p_ifp) - brcmf_net_detach(p2p_ifp->ndev); + brcmf_net_detach(p2p_ifp->ndev, false); drvr->iflist[0] = NULL; drvr->iflist[1] = NULL; if (drvr->settings->ignore_probe_fail) @@ -1152,7 +1157,7 @@ void brcmf_detach(struct device *dev) /* make sure primary interface removed last */ for (i = BRCMF_MAX_IFS-1; i > -1; i--) - brcmf_remove_interface(drvr->iflist[i]); + brcmf_remove_interface(drvr->iflist[i], false); brcmf_cfg80211_detach(drvr->config); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h index 647d3cc..5c5a392 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h @@ -216,7 +216,7 @@ struct brcmf_if *brcmf_get_ifp(struct brcmf_pub *drvr, int ifidx); int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked); struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bsscfgidx, s32 ifidx, bool is_p2pdev, char *name, u8 *mac_addr); -void brcmf_remove_interface(struct brcmf_if *ifp); +void brcmf_remove_interface(struct brcmf_if *ifp, bool rtnl_locked); int brcmf_get_next_free_bsscfgidx(struct brcmf_pub *drvr); void brcmf_txflowblock_if(struct brcmf_if *ifp, enum brcmf_netif_stop_reason reason, bool state); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c index b390561..9da7a4c 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c @@ -183,7 +183,7 @@ static void brcmf_fweh_handle_if_event(struct brcmf_pub *drvr, err = brcmf_fweh_call_event_handler(ifp, emsg->event_code, emsg, data); if (ifp && ifevent->action == BRCMF_E_IF_DEL) - brcmf_remove_interface(ifp); + brcmf_remove_interface(ifp, false); } /** diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c index a70cda6..c4dc6be 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c @@ -2290,7 +2290,7 @@ int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev) err = 0; } if (err) - brcmf_remove_interface(vif->ifp); + brcmf_remove_interface(vif->ifp, true); brcmf_cfg80211_arm_vif_event(cfg, NULL); if (vif->wdev.iftype != NL80211_IFTYPE_P2P_DEVICE) @@ -2396,7 +2396,7 @@ void brcmf_p2p_detach(struct brcmf_p2p_info *p2p) if (vif != NULL) { brcmf_p2p_cancel_remain_on_channel(vif->ifp); brcmf_p2p_deinit_discovery(p2p); - brcmf_remove_interface(vif->ifp); + brcmf_remove_interface(vif->ifp, false); } /* just set it all to zero */ memset(p2p, 0, sizeof(*p2p));