An access point has a flowring per destination: one for each station and one for its broadcast and multicast frames. The ring of a station is deleted when the station leaves, by brcmf_proto_delete_peer() with its address, but nothing deletes the broadcast ring, nor any ring of an AP that stops: brcmf_cfg80211_stop_ap() deletes none, and on the link-down event of an AP delete_peer gets the address of the event, which names no station. A new start of the same interface then keeps the old rings. Seen with a BCM43684 whose AP OpenWrt starts twice at boot, 1.2 s apart: the firmware never read again the broadcast ring opened as the first start ended. ARP and every other broadcast of that BSS were lost, and once the ring was full flow control stopped the interface for all of its stations, until the ring was deleted hours later by a change of the interface type; the firmware then served new rings normally. The vendor driver deletes all the rings of an interface on a link-down event. Do the same, and when the AP stops: brcmf_flowring_delete_peer() without a peer now deletes every ring of the interface. Fixes: 9a1bb60250d2 ("brcmfmac: Adding msgbuf protocol.") Signed-off-by: Kordian Chmielewski (mlody1212) --- .../broadcom/brcm80211/brcmfmac/cfg80211.c | 14 +++++++++++++- .../broadcom/brcm80211/brcmfmac/flowring.c | 5 +++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index b0eaf9641..91184bdcf 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -5480,6 +5480,11 @@ static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev, /* first to make sure they get processed by fw. */ msleep(400); + /* the BSS goes away and its rings with it: nothing else + * deletes the one for broadcast and multicast frames + */ + brcmf_proto_delete_peer(ifp->drvr, ifp->ifidx, NULL); + if (profile->use_fwauth != BIT(BRCMF_PROFILE_FWAUTH_NONE)) { struct cfg80211_crypto_settings crypto = {}; @@ -6750,7 +6755,14 @@ brcmf_notify_connect_status(struct brcmf_if *ifp, (e->event_code == BRCMF_E_DEAUTH_IND) || (e->event_code == BRCMF_E_DISASSOC_IND) || ((e->event_code == BRCMF_E_LINK) && (!e->flags))) { - brcmf_proto_delete_peer(ifp->drvr, ifp->ifidx, (u8 *)e->addr); + /* the address of a link event of an AP names no station: + * the BSS is down, and so are all of its rings + */ + if (e->event_code == BRCMF_E_LINK && brcmf_is_apmode(ifp->vif)) + brcmf_proto_delete_peer(ifp->drvr, ifp->ifidx, NULL); + else + brcmf_proto_delete_peer(ifp->drvr, ifp->ifidx, + (u8 *)e->addr); } if (brcmf_is_apmode(ifp->vif)) { diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c index 35cbcea0a..b9570d638 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c @@ -432,9 +432,10 @@ void brcmf_flowring_delete_peer(struct brcmf_flowring *flow, int ifidx, u16 flowid; bool sta; - sta = (flow->addr_mode[ifidx] == ADDR_INDIRECT); + /* without a peer: every ring of the interface */ + sta = (flow->addr_mode[ifidx] == ADDR_INDIRECT) || !peer; - search = flow->tdls_entry; + search = peer ? flow->tdls_entry : NULL; prev = NULL; while (search) { if (memcmp(search->mac, peer, ETH_ALEN) == 0) { -- 2.56.0