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, rtnl_locked); }
/** * brcmf_fweh_handle_if_event() - handle IF event. * * @drvr: driver information object. * @item: queue entry. * @ifpp: interface object (may change upon ADD action). */ static void brcmf_fweh_handle_if_event(struct brcmf_pub *drvr, struct brcmf_event_msg *emsg, void *data) { struct brcmf_if_event *ifevent = data; struct brcmf_if *ifp; int err = 0; brcmf_dbg(EVENT, "action: %u idx: %u bsscfg: %u flags: %u role: %u\n", ifevent->action, ifevent->ifidx, ifevent->bssidx, ifevent->flags, ifevent->role); /* The P2P Device interface event must not be ignored * contrary to what firmware tells us. The only way to * distinguish the P2P Device is by looking at the ifidx * and bssidx received. */ if (!(ifevent->ifidx == 0 && ifevent->bssidx == 1) && (ifevent->flags & BRCMF_E_IF_FLAG_NOIF)) { brcmf_dbg(EVENT, "event can be ignored\n"); return; } if (ifevent->ifidx >= BRCMF_MAX_IFS) { brcmf_err("invalid interface index: %u\n", ifevent->ifidx); return; } ifp = drvr->iflist[ifevent->bssidx]; if (ifevent->action == BRCMF_E_IF_ADD) { brcmf_dbg(EVENT, "adding %s (%pM)\n", emsg->ifname, emsg->addr); ifp = brcmf_add_if(drvr, ifevent->bssidx, ifevent->ifidx, emsg->ifname, emsg->addr); if (IS_ERR(ifp)) return; brcmf_fws_add_interface(ifp); if (!drvr->fweh.evt_handler[BRCMF_E_IF]) if (brcmf_net_attach(ifp, false) < 0) return; } if (ifp && ifevent->action == BRCMF_E_IF_CHANGE) brcmf_fws_reset_interface(ifp); err = brcmf_fweh_call_event_handler(ifp, emsg->event_code, emsg, data); if (ifp && ifevent->action == BRCMF_E_IF_DEL) { brcmf_fws_del_interface(ifp); brcmf_del_if(drvr, ifevent->bssidx); } }
/** * brcmf_fweh_handle_if_event() - handle IF event. * * @drvr: driver information object. * @item: queue entry. * @ifpp: interface object (may change upon ADD action). */ static void brcmf_fweh_handle_if_event(struct brcmf_pub *drvr, struct brcmf_event_msg *emsg, void *data) { struct brcmf_if_event *ifevent = data; struct brcmf_if *ifp; int err = 0; brcmf_dbg(EVENT, "action: %u idx: %u bsscfg: %u flags: %u role: %u\n", ifevent->action, ifevent->ifidx, ifevent->bssidx, ifevent->flags, ifevent->role); if (ifevent->flags & BRCMF_E_IF_FLAG_NOIF) { brcmf_dbg(EVENT, "event can be ignored\n"); return; } if (ifevent->ifidx >= BRCMF_MAX_IFS) { brcmf_err("invalid interface index: %u\n", ifevent->ifidx); return; } ifp = drvr->iflist[ifevent->bssidx]; if (ifevent->action == BRCMF_E_IF_ADD) { brcmf_dbg(EVENT, "adding %s (%pM)\n", emsg->ifname, emsg->addr); ifp = brcmf_add_if(drvr, ifevent->bssidx, ifevent->ifidx, emsg->ifname, emsg->addr); if (IS_ERR(ifp)) return; brcmf_fws_add_interface(ifp); if (!drvr->fweh.evt_handler[BRCMF_E_IF]) if (brcmf_net_attach(ifp, false) < 0) return; } if (ifevent->action == BRCMF_E_IF_CHANGE) brcmf_fws_reset_interface(ifp); err = brcmf_fweh_call_event_handler(ifp, emsg->event_code, emsg, data); if (ifevent->action == BRCMF_E_IF_DEL) { brcmf_fws_del_interface(ifp); brcmf_del_if(drvr, ifevent->bssidx); } }
int brcmf_c_host_event(struct brcmf_info *drvr_priv, int *ifidx, void *pktdata, struct brcmf_event_msg *event, void **data_ptr) { /* check whether packet is a BRCM event pkt */ struct brcmf_event *pvt_data = (struct brcmf_event *) pktdata; char *event_data; u32 type, status; u16 flags; int evlen; if (memcmp(BRCM_OUI, &pvt_data->hdr.oui[0], DOT11_OUI_LEN)) { BRCMF_ERROR(("%s: mismatched OUI, bailing\n", __func__)); return -EBADE; } /* BRCM event pkt may be unaligned - use xxx_ua to load user_subtype. */ if (get_unaligned_be16(&pvt_data->hdr.usr_subtype) != BCMILCP_BCM_SUBTYPE_EVENT) { BRCMF_ERROR(("%s: mismatched subtype, bailing\n", __func__)); return -EBADE; } *data_ptr = &pvt_data[1]; event_data = *data_ptr; /* memcpy since BRCM event pkt may be unaligned. */ memcpy(event, &pvt_data->msg, sizeof(struct brcmf_event_msg)); type = get_unaligned_be32(&event->event_type); flags = get_unaligned_be16(&event->flags); status = get_unaligned_be32(&event->status); evlen = get_unaligned_be32(&event->datalen) + sizeof(struct brcmf_event); switch (type) { case BRCMF_E_IF: { struct brcmf_if_event *ifevent = (struct brcmf_if_event *) event_data; BRCMF_TRACE(("%s: if event\n", __func__)); if (ifevent->ifidx > 0 && ifevent->ifidx < BRCMF_MAX_IFS) { if (ifevent->action == BRCMF_E_IF_ADD) brcmf_add_if(drvr_priv, ifevent->ifidx, NULL, event->ifname, pvt_data->eth.h_dest, ifevent->flags, ifevent->bssidx); else brcmf_del_if(drvr_priv, ifevent->ifidx); } else { BRCMF_ERROR(("%s: Invalid ifidx %d for %s\n", __func__, ifevent->ifidx, event->ifname)); } } /* send up the if event: btamp user needs it */ *ifidx = brcmf_ifname2idx(drvr_priv, event->ifname); break; /* These are what external supplicant/authenticator wants */ case BRCMF_E_LINK: case BRCMF_E_ASSOC_IND: case BRCMF_E_REASSOC_IND: case BRCMF_E_DISASSOC_IND: case BRCMF_E_MIC_ERROR: default: /* Fall through: this should get _everything_ */ *ifidx = brcmf_ifname2idx(drvr_priv, event->ifname); BRCMF_TRACE(("%s: MAC event %d, flags %x, status %x\n", __func__, type, flags, status)); /* put it back to BRCMF_E_NDIS_LINK */ if (type == BRCMF_E_NDIS_LINK) { u32 temp; temp = get_unaligned_be32(&event->event_type); BRCMF_TRACE(("Converted to WLC_E_LINK type %d\n", temp)); temp = be32_to_cpu(BRCMF_E_NDIS_LINK); memcpy((void *)(&pvt_data->msg.event_type), &temp, sizeof(pvt_data->msg.event_type)); } break; } #ifdef SHOW_EVENTS brcmf_c_show_host_event(event, event_data); #endif /* SHOW_EVENTS */ return 0; }
int brcmf_c_host_event(struct brcmf_pub *drvr, int *ifidx, void *pktdata, struct brcmf_event_msg *event, void **data_ptr) { struct brcmf_event *pvt_data = (struct brcmf_event *) pktdata; struct brcmf_if_event *ifevent; char *event_data; u32 type, status; u16 flags; int evlen; if (memcmp(BRCM_OUI, &pvt_data->hdr.oui[0], DOT11_OUI_LEN)) { brcmf_dbg(ERROR, "mismatched OUI, bailing\n"); return -EBADE; } if (get_unaligned_be16(&pvt_data->hdr.usr_subtype) != BCMILCP_BCM_SUBTYPE_EVENT) { brcmf_dbg(ERROR, "mismatched subtype, bailing\n"); return -EBADE; } *data_ptr = &pvt_data[1]; event_data = *data_ptr; memcpy(event, &pvt_data->msg, sizeof(struct brcmf_event_msg)); type = get_unaligned_be32(&event->event_type); flags = get_unaligned_be16(&event->flags); status = get_unaligned_be32(&event->status); evlen = get_unaligned_be32(&event->datalen) + sizeof(struct brcmf_event); switch (type) { case BRCMF_E_IF: ifevent = (struct brcmf_if_event *) event_data; brcmf_dbg(TRACE, "if event\n"); if (ifevent->ifidx > 0 && ifevent->ifidx < BRCMF_MAX_IFS) { if (ifevent->action == BRCMF_E_IF_ADD) brcmf_add_if(drvr->dev, ifevent->ifidx, event->ifname, pvt_data->eth.h_dest); else brcmf_del_if(drvr, ifevent->ifidx); } else { brcmf_dbg(ERROR, "Invalid ifidx %d for %s\n", ifevent->ifidx, event->ifname); } *ifidx = brcmf_ifname2idx(drvr, event->ifname); break; case BRCMF_E_LINK: case BRCMF_E_ASSOC_IND: case BRCMF_E_REASSOC_IND: case BRCMF_E_DISASSOC_IND: case BRCMF_E_MIC_ERROR: default: *ifidx = brcmf_ifname2idx(drvr, event->ifname); brcmf_dbg(TRACE, "MAC event %d, flags %x, status %x\n", type, flags, status); if (type == BRCMF_E_NDIS_LINK) { u32 temp1; __be32 temp2; temp1 = get_unaligned_be32(&event->event_type); brcmf_dbg(TRACE, "Converted to WLC_E_LINK type %d\n", temp1); temp2 = cpu_to_be32(BRCMF_E_NDIS_LINK); memcpy((void *)(&pvt_data->msg.event_type), &temp2, sizeof(pvt_data->msg.event_type)); } break; } #ifdef DEBUG brcmf_c_show_host_event(event, event_data); #endif return 0; }