@@ -230,6 +230,9 @@ struct parsed_vndr_ies {
struct parsed_vndr_ie_info ie_info[VNDR_IE_PARSE_LIMIT];
};
+#define WLC_E_IF_ROLE_STA 0 /* Infra STA */
+#define WLC_E_IF_ROLE_AP 1 /* Access Point */
+
static u8 nl80211_band_to_fwil(enum nl80211_band band)
{
switch (band) {
@@ -5532,8 +5535,10 @@ void brcmf_cfg80211_free_netdev(struct net_device *ndev)
ifp = netdev_priv(ndev);
vif = ifp->vif;
- if (vif)
+ if (vif) {
brcmf_free_vif(vif);
+ ifp->vif = NULL;
+ }
}
static bool brcmf_is_linkup(struct brcmf_cfg80211_vif *vif,
@@ -6090,6 +6095,9 @@ static s32 brcmf_notify_vif_event(struct brcmf_if *ifp,
struct brcmf_if_event *ifevent = (struct brcmf_if_event *)data;
struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
struct brcmf_cfg80211_vif *vif;
+ enum nl80211_iftype iftype = NL80211_IFTYPE_UNSPECIFIED;
+ bool vif_pend = false;
+ int err;
brcmf_dbg(TRACE, "Enter: action %u flags %u ifidx %u bsscfgidx %u\n",
ifevent->action, ifevent->flags, ifevent->ifidx,
@@ -6102,9 +6110,28 @@ static s32 brcmf_notify_vif_event(struct brcmf_if *ifp,
switch (ifevent->action) {
case BRCMF_E_IF_ADD:
/* waiting process may have timed out */
- if (!cfg->vif_event.vif) {
+ if (!vif) {
+ /* handle IF_ADD event from firmware */
spin_unlock(&event->vif_event_lock);
- return -EBADF;
+ vif_pend = true;
+ if (ifevent->role == WLC_E_IF_ROLE_STA)
+ iftype = NL80211_IFTYPE_STATION;
+ else if (ifevent->role == WLC_E_IF_ROLE_AP)
+ iftype = NL80211_IFTYPE_AP;
+ else
+ vif_pend = false;
+
+ if (vif_pend) {
+ vif = brcmf_alloc_vif(cfg, iftype);
+ if (IS_ERR(vif)) {
+ brcmf_err("Role:%d failed to alloc vif\n",
+ ifevent->role);
+ return PTR_ERR(vif);
+ }
+ } else {
+ brcmf_err("Invalid Role:%d\n", ifevent->role);
+ return -EBADF;
+ }
}
ifp->vif = vif;
@@ -6114,6 +6141,19 @@ static s32 brcmf_notify_vif_event(struct brcmf_if *ifp,
ifp->ndev->ieee80211_ptr = &vif->wdev;
SET_NETDEV_DEV(ifp->ndev, wiphy_dev(cfg->wiphy));
}
+
+ if (vif_pend) {
+ err = brcmf_net_attach(ifp, false);
+ if (err) {
+ brcmf_err("netdevice register failed with err:%d\n",
+ err);
+ brcmf_free_vif(vif);
+ free_netdev(ifp->ndev);
+ }
+ spin_unlock(&event->vif_event_lock);
+ return err;
+ }
+
spin_unlock(&event->vif_event_lock);
wake_up(&event->vif_wq);
return 0;