Beispiel #1
0
static void ath9k_htc_remove_interface(struct ieee80211_hw *hw,
				       struct ieee80211_vif *vif)
{
	struct ath9k_htc_priv *priv = hw->priv;
	struct ath_common *common = ath9k_hw_common(priv->ah);
	struct ath9k_htc_vif *avp = (void *)vif->drv_priv;
	struct ath9k_htc_target_vif hvif;
	int ret = 0;
	u8 cmd_rsp;

	mutex_lock(&priv->mutex);
	ath9k_htc_ps_wakeup(priv);

	memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif));
	memcpy(&hvif.myaddr, vif->addr, ETH_ALEN);
	hvif.index = avp->index;
	WMI_CMD_BUF(WMI_VAP_REMOVE_CMDID, &hvif);
	if (ret) {
		ath_err(common, "Unable to remove interface at idx: %d\n",
			avp->index);
	}
	priv->nvifs--;
	priv->vif_slot &= ~(1 << avp->index);

	if (priv->csa_vif == vif)
		priv->csa_vif = NULL;

	ath9k_htc_remove_station(priv, vif, NULL);

	DEC_VIF(priv, vif->type);

	if ((vif->type == NL80211_IFTYPE_AP) ||
	     vif->type == NL80211_IFTYPE_MESH_POINT ||
	    (vif->type == NL80211_IFTYPE_ADHOC))
		ath9k_htc_remove_bslot(priv, vif);

	ath9k_htc_set_opmode(priv);

	ath9k_htc_set_mac_bssid_mask(priv, vif);

	/*
	 * Stop ANI only if there are no associated station interfaces.
	 */
	if ((vif->type == NL80211_IFTYPE_AP) && (priv->num_ap_vif == 0)) {
		priv->rearm_ani = false;
		ieee80211_iterate_active_interfaces_atomic(
			priv->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
			ath9k_htc_vif_iter, priv);
		if (!priv->rearm_ani)
			ath9k_htc_stop_ani(priv);
	}

	ath_dbg(common, CONFIG, "Detach Interface at idx: %d\n", avp->index);

	ath9k_htc_ps_restore(priv);
	mutex_unlock(&priv->mutex);
}
static int ath9k_htc_add_interface(struct ieee80211_hw *hw,
				   struct ieee80211_vif *vif)
{
	struct ath9k_htc_priv *priv = hw->priv;
	struct ath9k_htc_vif *avp = (void *)vif->drv_priv;
	struct ath_common *common = ath9k_hw_common(priv->ah);
	struct ath9k_htc_target_vif hvif;
	int ret = 0;
	u8 cmd_rsp;

	mutex_lock(&priv->mutex);

	ath9k_htc_ps_wakeup(priv);
	memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif));
	memcpy(&hvif.myaddr, vif->addr, ETH_ALEN);

	switch (vif->type) {
	case NL80211_IFTYPE_STATION:
		hvif.opmode = HTC_M_STA;
		break;
	case NL80211_IFTYPE_ADHOC:
		hvif.opmode = HTC_M_IBSS;
		break;
	case NL80211_IFTYPE_AP:
		hvif.opmode = HTC_M_HOSTAP;
		break;
	case NL80211_IFTYPE_MESH_POINT:
		hvif.opmode = HTC_M_WDS;	/* close enough */
		break;
	default:
		ath_err(common,
			"Interface type %d not yet supported\n", vif->type);
		ret = -EOPNOTSUPP;
		goto out;
	}

	/* Index starts from zero on the target */
	avp->index = hvif.index = ffz(priv->vif_slot);
	hvif.rtsthreshold = cpu_to_be16(2304);
	WMI_CMD_BUF(WMI_VAP_CREATE_CMDID, &hvif);
	if (ret)
		goto out;

	/*
	 * We need a node in target to tx mgmt frames
	 * before association.
	 */
	ret = ath9k_htc_add_station(priv, vif, NULL);
	if (ret) {
		WMI_CMD_BUF(WMI_VAP_REMOVE_CMDID, &hvif);
		goto out;
	}

	ath9k_htc_set_mac_bssid_mask(priv, vif);

	priv->vif_slot |= (1 << avp->index);
	priv->nvifs++;

	INC_VIF(priv, vif->type);

	if ((vif->type == NL80211_IFTYPE_AP) ||
	    (vif->type == NL80211_IFTYPE_MESH_POINT) ||
	    (vif->type == NL80211_IFTYPE_ADHOC))
		ath9k_htc_assign_bslot(priv, vif);

	ath9k_htc_set_opmode(priv);

	if ((priv->ah->opmode == NL80211_IFTYPE_AP) &&
	    !test_bit(ATH_OP_ANI_RUN, &common->op_flags)) {
		ath9k_hw_set_tsfadjust(priv->ah, true);
		ath9k_htc_start_ani(priv);
	}

	ath_dbg(common, CONFIG, "Attach a VIF of type: %d at idx: %d\n",
		vif->type, avp->index);

out:
	ath9k_htc_ps_restore(priv);
	mutex_unlock(&priv->mutex);

	return ret;
}
static int ath9k_htc_add_interface(struct ieee80211_hw *hw,
				   struct ieee80211_vif *vif)
{
	struct ath9k_htc_priv *priv = hw->priv;
	struct ath9k_htc_vif *avp = (void *)vif->drv_priv;
	struct ath_common *common = ath9k_hw_common(priv->ah);
	struct ath9k_htc_target_vif hvif;
	int ret = 0;
	u8 cmd_rsp;

	mutex_lock(&priv->mutex);

	if (priv->nvifs >= ATH9K_HTC_MAX_VIF) {
		mutex_unlock(&priv->mutex);
		return -ENOBUFS;
	}

	if (priv->num_ibss_vif ||
	    (priv->nvifs && vif->type == NL80211_IFTYPE_ADHOC)) {
		ath_err(common, "IBSS coexistence with other modes is not allowed\n");
		mutex_unlock(&priv->mutex);
		return -ENOBUFS;
	}

	if (((vif->type == NL80211_IFTYPE_AP) ||
	     (vif->type == NL80211_IFTYPE_ADHOC)) &&
	    ((priv->num_ap_vif + priv->num_ibss_vif) >= ATH9K_HTC_MAX_BCN_VIF)) {
		ath_err(common, "Max. number of beaconing interfaces reached\n");
		mutex_unlock(&priv->mutex);
		return -ENOBUFS;
	}

	ath9k_htc_ps_wakeup(priv);
	memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif));
	memcpy(&hvif.myaddr, vif->addr, ETH_ALEN);

	switch (vif->type) {
	case NL80211_IFTYPE_STATION:
		hvif.opmode = HTC_M_STA;
		break;
	case NL80211_IFTYPE_ADHOC:
		hvif.opmode = HTC_M_IBSS;
		break;
	case NL80211_IFTYPE_AP:
		hvif.opmode = HTC_M_HOSTAP;
		break;
	default:
		ath_err(common,
			"Interface type %d not yet supported\n", vif->type);
		ret = -EOPNOTSUPP;
		goto out;
	}

	/* Index starts from zero on the target */
	avp->index = hvif.index = ffz(priv->vif_slot);
	hvif.rtsthreshold = cpu_to_be16(2304);
	WMI_CMD_BUF(WMI_VAP_CREATE_CMDID, &hvif);
	if (ret)
		goto out;

	/*
	 * We need a node in target to tx mgmt frames
	 * before association.
	 */
	ret = ath9k_htc_add_station(priv, vif, NULL);
	if (ret) {
		WMI_CMD_BUF(WMI_VAP_REMOVE_CMDID, &hvif);
		goto out;
	}

	ath9k_htc_set_mac_bssid_mask(priv, vif);

	priv->vif_slot |= (1 << avp->index);
	priv->nvifs++;

	INC_VIF(priv, vif->type);

	if ((vif->type == NL80211_IFTYPE_AP) ||
	    (vif->type == NL80211_IFTYPE_ADHOC))
		ath9k_htc_assign_bslot(priv, vif);

	ath9k_htc_set_opmode(priv);

	if ((priv->ah->opmode == NL80211_IFTYPE_AP) &&
	    !(priv->op_flags & OP_ANI_RUNNING)) {
		ath9k_hw_set_tsfadjust(priv->ah, 1);
		ath9k_htc_start_ani(priv);
	}

	ath_dbg(common, CONFIG, "Attach a VIF of type: %d at idx: %d\n",
		vif->type, avp->index);

out:
	ath9k_htc_ps_restore(priv);
	mutex_unlock(&priv->mutex);

	return ret;
}