From patchwork Fri Jun 17 10:29:21 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: 9183337 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 A4BFD60573 for ; Fri, 17 Jun 2016 10:30:15 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 934D42837A for ; Fri, 17 Jun 2016 10:30:15 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 87D3328399; Fri, 17 Jun 2016 10:30:15 +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 0906E2837A for ; Fri, 17 Jun 2016 10:30:15 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755491AbcFQK3y (ORCPT ); Fri, 17 Jun 2016 06:29:54 -0400 Received: from mail-lf0-f67.google.com ([209.85.215.67]:35442 "EHLO mail-lf0-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752818AbcFQK3v (ORCPT ); Fri, 17 Jun 2016 06:29:51 -0400 Received: by mail-lf0-f67.google.com with SMTP id w130so7935471lfd.2; Fri, 17 Jun 2016 03:29:50 -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:in-reply-to:references :mime-version:content-transfer-encoding; bh=nYIYC0do57kyMhuKVbLnPRY6Pl3DbpNKzYidTWa/Kms=; b=N3rfwjgxvTg7WXzsZOnKAN4NX8P4FbiQKhh5Kkf2Mhn51B1dw4nvGdOtxJqGoAy1Sf 0h96vDK6/F7O0D5zaKg41uztB7OT+BosfqprmxUbkJgL+gOMIAbhqBCSzLDI+vmKmGyk dfYyvGh5f/VEtzuvX3xlSSgco2ZgpyzSiHCWEReTVWhLD2wKmqIYD/FbiaUb5Rrv+N2O pc8SCRzkR9r+S/qg1V9poTKBVMZ4rYTJgK3E5BzfDOwZW0kEqa/EMlAfbRoNwTtjLTEz NJmaf7fU5UzchaifqOnJBuptgdq/dquIttNaMsMuRRpDaifTEhMa27JwrhkQ3O8delrG YG+Q== 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:in-reply-to :references:mime-version:content-transfer-encoding; bh=nYIYC0do57kyMhuKVbLnPRY6Pl3DbpNKzYidTWa/Kms=; b=br5Ed3Ir5iiOv5SP/T4ubGNh2d857/FnkKJQGcA/QAJl+v/eAcs2GRcezfIh/UQTPW 5htZaCfY4r59+Sjq4Wm59xMvVWmYocb95y+oisi18t4wC4y00dKbCgTo7g7rjgRDLnXE qfNgf2UYPAmgmp0gOSS44g0k/YTBohEuIkw412rJMLl52DmfTi1ObEcbFzOkdOXfzL7U u3j5/Edqbq5HWLVbVq/NIL62teYMTuKBezShOo3IBtwMY3cFHKCagTlQyBDmcrJ9ZwD7 099xBOxkot/XdKP2/SIZ733WC1YJfNlYVtuq6dOX0ScYzixQGBQzmLUoWXogj/1fxK/9 56CA== X-Gm-Message-State: ALyK8tIoQBf5edxYmEfd+m2tHyhLM1FSH2IWxpI46jH9fBve+v/srMzVsNqQXJ95PxgoQA== X-Received: by 10.25.213.200 with SMTP id m191mr458555lfg.52.1466159389537; Fri, 17 Jun 2016 03:29:49 -0700 (PDT) Received: from linux-samsung.lan (ip-194-187-74-233.konfederacka.maverick.com.pl. [194.187.74.233]) by smtp.gmail.com with ESMTPSA id 76sm5012366ljj.3.2016.06.17.03.29.47 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 17 Jun 2016 03:29:48 -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?= , Arend van Spriel , Franky Lin , Hante Meuleman , Pieter-Paul Giesberts , "Franky (Zhenhui) Lin" , Johannes Berg , linux-wireless@vger.kernel.org (open list:BROADCOM BRCM80211 IEEE802.11n WIRELESS DRIVER), brcm80211-dev-list.pdl@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 REBASED] brcmfmac: fix lockup when removing P2P interface after event timeout Date: Fri, 17 Jun 2016 12:29:21 +0200 Message-Id: <1466159371-19968-1-git-send-email-zajec5@gmail.com> X-Mailer: git-send-email 1.8.4.5 In-Reply-To: <1464378815-23282-1-git-send-email-zajec5@gmail.com> References: <1464378815-23282-1-git-send-email-zajec5@gmail.com> 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 --- REBASED on top of wireless-drivers-next. This bug isn't very common and changes may conflict with other patches, so it makes more sense to pick it for -next. --- .../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 +-- 4 files changed, 21 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c index faf4e46..7b38c2b 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); } #ifdef CONFIG_INET @@ -1057,9 +1062,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) @@ -1128,7 +1133,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 2a075c5..a0a6f7f 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); void brcmf_txflowblock_if(struct brcmf_if *ifp, enum brcmf_netif_stop_reason reason, bool state); void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success); 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 f38a821..426ff05 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c @@ -2287,7 +2287,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) @@ -2393,7 +2393,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));