Ejemplo n.º 1
0
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);
}
Ejemplo n.º 2
0
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);
}
Ejemplo n.º 3
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;
}