int iwm_mvm_mac_ctxt_changed(struct iwm_softc *sc, struct ieee80211vap *vap) { struct iwm_vap *iv = IWM_VAP(vap); if (iv->is_uploaded == 0) { device_printf(sc->sc_dev, "%s: called; uploaded = 0\n", __func__); return (EIO); } return iwm_mvm_mac_ctx_send(sc, vap, IWM_FW_CTXT_ACTION_MODIFY); }
int iwm_mvm_mac_ctxt_add(struct iwm_softc *sc, struct ieee80211vap *vap) { struct iwm_vap *iv = IWM_VAP(vap); int ret; if (iv->is_uploaded != 0) { device_printf(sc->sc_dev, "%s: called; uploaded != 0\n", __func__); return (EIO); } ret = iwm_mvm_mac_ctx_send(sc, vap, IWM_FW_CTXT_ACTION_ADD); if (ret) return (ret); iv->is_uploaded = 1; return (0); }
/* send station add/update command to firmware */ int iwm_mvm_sta_send_to_fw(struct iwm_softc *sc, struct iwm_node *in, boolean_t update) { struct iwm_vap *ivp = IWM_VAP(in->in_ni.ni_vap); struct iwm_mvm_add_sta_cmd add_sta_cmd = { .sta_id = IWM_STATION_ID, .mac_id_n_color = htole32(IWM_FW_CMD_ID_AND_COLOR(ivp->id, ivp->color)), .add_modify = update ? 1 : 0, .station_flags_msk = htole32(IWM_STA_FLG_FAT_EN_MSK | IWM_STA_FLG_MIMO_EN_MSK), .tid_disable_tx = htole16(0xffff), }; int ret; uint32_t status; uint32_t agg_size = 0, mpdu_dens = 0; if (!update) { int ac; for (ac = 0; ac < WME_NUM_AC; ac++) { add_sta_cmd.tfd_queue_msk |= htole32(1 << iwm_mvm_ac_to_tx_fifo[ac]); } IEEE80211_ADDR_COPY(&add_sta_cmd.addr, in->in_ni.ni_bssid); } add_sta_cmd.station_flags |= htole32(agg_size << IWM_STA_FLG_MAX_AGG_SIZE_SHIFT); add_sta_cmd.station_flags |= htole32(mpdu_dens << IWM_STA_FLG_AGG_MPDU_DENS_SHIFT); status = IWM_ADD_STA_SUCCESS; ret = iwm_mvm_send_cmd_pdu_status(sc, IWM_ADD_STA, iwm_mvm_add_sta_cmd_size(sc), &add_sta_cmd, &status); if (ret) return ret; switch (status & IWM_ADD_STA_STATUS_MASK) { case IWM_ADD_STA_SUCCESS: IWM_DPRINTF(sc, IWM_DEBUG_NODE, "IWM_ADD_STA PASSED\n"); break; default: ret = EIO; device_printf(sc->sc_dev, "IWM_ADD_STA failed\n"); break; } return ret; } int iwm_mvm_add_sta(struct iwm_softc *sc, struct iwm_node *in) { return iwm_mvm_sta_send_to_fw(sc, in, FALSE); } int iwm_mvm_update_sta(struct iwm_softc *sc, struct iwm_node *in) { return iwm_mvm_sta_send_to_fw(sc, in, TRUE); } int iwm_mvm_drain_sta(struct iwm_softc *sc, struct iwm_vap *ivp, boolean_t drain) { struct iwm_mvm_add_sta_cmd cmd = {}; int ret; uint32_t status; cmd.mac_id_n_color = htole32(IWM_FW_CMD_ID_AND_COLOR(ivp->id, ivp->color)); cmd.sta_id = IWM_STATION_ID; cmd.add_modify = IWM_STA_MODE_MODIFY; cmd.station_flags = drain ? htole32(IWM_STA_FLG_DRAIN_FLOW) : 0; cmd.station_flags_msk = htole32(IWM_STA_FLG_DRAIN_FLOW); status = IWM_ADD_STA_SUCCESS; ret = iwm_mvm_send_cmd_pdu_status(sc, IWM_ADD_STA, iwm_mvm_add_sta_cmd_size(sc), &cmd, &status); if (ret) return ret; switch (status & IWM_ADD_STA_STATUS_MASK) { case IWM_ADD_STA_SUCCESS: IWM_DPRINTF(sc, IWM_DEBUG_NODE, "Frames for staid %d will drained in fw\n", IWM_STATION_ID); break; default: ret = EIO; device_printf(sc->sc_dev, "Couldn't drain frames for staid %d\n", IWM_STATION_ID); break; } return ret; } /* * Remove a station from the FW table. Before sending the command to remove * the station validate that the station is indeed known to the driver (sanity * only). */ static int iwm_mvm_rm_sta_common(struct iwm_softc *sc) { struct iwm_mvm_rm_sta_cmd rm_sta_cmd = { .sta_id = IWM_STATION_ID, }; int ret; ret = iwm_mvm_send_cmd_pdu(sc, IWM_REMOVE_STA, 0, sizeof(rm_sta_cmd), &rm_sta_cmd); if (ret) { device_printf(sc->sc_dev, "Failed to remove station. Id=%d\n", IWM_STATION_ID); return ret; } return 0; } int iwm_mvm_rm_sta(struct iwm_softc *sc, struct ieee80211vap *vap, boolean_t is_assoc) { uint32_t tfd_queue_msk = 0; int ret; int ac; ret = iwm_mvm_drain_sta(sc, IWM_VAP(vap), TRUE); if (ret) return ret; for (ac = 0; ac < WME_NUM_AC; ac++) { tfd_queue_msk |= htole32(1 << iwm_mvm_ac_to_tx_fifo[ac]); } ret = iwm_mvm_flush_tx_path(sc, tfd_queue_msk, 0); if (ret) return ret; #ifdef notyet /* function not yet implemented */ ret = iwl_trans_wait_tx_queue_empty(mvm->trans, mvm_sta->tfd_queue_msk); if (ret) return ret; #endif ret = iwm_mvm_drain_sta(sc, IWM_VAP(vap), FALSE); /* if we are associated - we can't remove the AP STA now */ if (is_assoc) return ret; /* XXX wait until STA is drained */ ret = iwm_mvm_rm_sta_common(sc); return ret; }