コード例 #1
0
ファイル: mac80211.c プロジェクト: jbeagley52/mwlwifi
static int mwl_mac80211_sta_add(struct ieee80211_hw *hw,
                                struct ieee80211_vif *vif,
                                struct ieee80211_sta *sta)
{
    struct mwl_priv *priv = hw->priv;
    struct mwl_vif *mwl_vif;
    struct mwl_sta *sta_info;
    struct ieee80211_key_conf *key;
    int rc;
    int i;

    mwl_vif = mwl_dev_get_vif(vif);
    sta_info = mwl_dev_get_sta(sta);

    memset(sta_info, 0, sizeof(*sta_info));

    if (vif->type == NL80211_IFTYPE_MESH_POINT) {
        sta_info->is_mesh_node = true;
        /* Patch mesh interface for HT based on 88W8897. When authsae or
         * wpa_supplicant is used for mesh security, HT capbility wan't
         * be set. This would be removed if problem is fixed.
         */
        sta->ht_cap.ht_supported = true;
        sta->ht_cap.cap = 0x6f;
        sta->ht_cap.mcs.rx_mask[0] = 0xff;
        sta->ht_cap.mcs.rx_mask[1] = 0xff;
        sta->ht_cap.ampdu_factor = 0x3;
        sta->ht_cap.ampdu_density = 0x5;
    }

    if (sta->ht_cap.ht_supported) {
        sta_info->is_ampdu_allowed = true;
        sta_info->is_amsdu_allowed = false;
        if (sta->ht_cap.cap & IEEE80211_HT_CAP_MAX_AMSDU)
            sta_info->amsdu_ctrl.cap = MWL_AMSDU_SIZE_8K;
        else
            sta_info->amsdu_ctrl.cap = MWL_AMSDU_SIZE_4K;
    }
    sta_info->iv16 = 1;
    sta_info->iv32 = 0;
    spin_lock_init(&sta_info->amsdu_lock);
    spin_lock_bh(&priv->sta_lock);
    list_add_tail(&sta_info->list, &priv->sta_list);
    spin_unlock_bh(&priv->sta_lock);

    if (vif->type == NL80211_IFTYPE_STATION)
        mwl_fwcmd_set_new_stn_del(hw, vif, sta->addr);

    rc = mwl_fwcmd_set_new_stn_add(hw, vif, sta);

    for (i = 0; i < NUM_WEP_KEYS; i++) {
        key = (struct ieee80211_key_conf *)mwl_vif->wep_key_conf[i].key;

        if (mwl_vif->wep_key_conf[i].enabled)
            mwl_mac80211_set_key(hw, SET_KEY, vif, sta, key);
    }

    return rc;
}
コード例 #2
0
ファイル: mac80211.c プロジェクト: chinawrj/mwlwifi
static int mwl_mac80211_set_key(struct ieee80211_hw *hw,
				enum set_key_cmd cmd_param,
				struct ieee80211_vif *vif,
				struct ieee80211_sta *sta,
				struct ieee80211_key_conf *key)
{
	struct mwl_vif *mwl_vif;
	int rc = 0;
	u8 encr_type;
	u8 *addr;

	mwl_vif = mwl_dev_get_vif(vif);

	if (!sta) {
		addr = vif->addr;
	} else {
		addr = sta->addr;
		if (vif->type == NL80211_IFTYPE_STATION)
			ether_addr_copy(mwl_vif->bssid, addr);
	}

	if (cmd_param == SET_KEY) {
		rc = mwl_fwcmd_encryption_set_key(hw, vif, addr, key);

		if (rc)
			goto out;

		if ((key->cipher == WLAN_CIPHER_SUITE_WEP40) ||
		    (key->cipher == WLAN_CIPHER_SUITE_WEP104)) {
			encr_type = ENCR_TYPE_WEP;
		} else if (key->cipher == WLAN_CIPHER_SUITE_CCMP) {
			encr_type = ENCR_TYPE_AES;
			if ((key->flags & IEEE80211_KEY_FLAG_PAIRWISE) == 0) {
				if (vif->type != NL80211_IFTYPE_STATION)
					mwl_vif->keyidx = key->keyidx;
			}
		} else if (key->cipher == WLAN_CIPHER_SUITE_TKIP) {
			encr_type = ENCR_TYPE_TKIP;
		} else {
			encr_type = ENCR_TYPE_DISABLE;
		}

		rc = mwl_fwcmd_update_encryption_enable(hw, vif, addr,
							encr_type);
		if (rc)
			goto out;

		mwl_vif->is_hw_crypto_enabled = true;
	} else {
		rc = mwl_fwcmd_encryption_remove_key(hw, vif, addr, key);
		if (rc)
			goto out;
	}

out:

	return rc;
}
コード例 #3
0
ファイル: mac80211.c プロジェクト: chinawrj/mwlwifi
static void mwl_mac80211_remove_vif(struct mwl_priv *priv,
				    struct ieee80211_vif *vif)
{
	struct mwl_vif *mwl_vif = mwl_dev_get_vif(vif);

	if (!priv->macids_used)
		return;

	mwl_tx_del_pkts_via_vif(priv->hw, vif);

	priv->macids_used &= ~(1 << mwl_vif->macid);
	spin_lock_bh(&priv->vif_lock);
	list_del(&mwl_vif->list);
	spin_unlock_bh(&priv->vif_lock);
}
コード例 #4
0
ファイル: tx.c プロジェクト: chinawrj/mwlwifi
static inline void mwl_tx_skb(struct mwl_priv *priv, int desc_num,
			      struct sk_buff *tx_skb)
{
	struct ieee80211_tx_info *tx_info;
	struct mwl_tx_ctrl *tx_ctrl;
	struct mwl_tx_hndl *tx_hndl;
	struct mwl_tx_desc *tx_desc;
	struct ieee80211_sta *sta;
	struct ieee80211_vif *vif;
	struct mwl_vif *mwl_vif;
	struct ieee80211_key_conf *k_conf;
	bool ccmp = false;
	struct mwl_dma_data *dma_data;
	struct ieee80211_hdr *wh;
	dma_addr_t dma;

	if (WARN_ON(!tx_skb))
		return;

	tx_info = IEEE80211_SKB_CB(tx_skb);
	tx_ctrl = (struct mwl_tx_ctrl *)&tx_info->status;
	sta = (struct ieee80211_sta *)tx_ctrl->sta;
	vif = (struct ieee80211_vif *)tx_ctrl->vif;
	mwl_vif = mwl_dev_get_vif(vif);
	k_conf = (struct ieee80211_key_conf *)tx_ctrl->k_conf;

	mwl_tx_encapsulate_frame(priv, tx_skb, k_conf, &ccmp);

	dma_data = (struct mwl_dma_data *)tx_skb->data;
	wh = &dma_data->wh;

	if (ieee80211_is_data(wh->frame_control) ||
	    (ieee80211_is_mgmt(wh->frame_control) &&
	    ieee80211_has_protected(wh->frame_control) &&
	    !is_multicast_ether_addr(wh->addr1))) {
		if (is_multicast_ether_addr(wh->addr1)) {
			if (ccmp) {
				mwl_tx_insert_ccmp_hdr(dma_data->data,
						       mwl_vif->keyidx,
						       mwl_vif->iv16,
						       mwl_vif->iv32);
				INCREASE_IV(mwl_vif->iv16, mwl_vif->iv32);
			}
		} else {
			if (ccmp) {
				if (vif->type == NL80211_IFTYPE_STATION) {
					mwl_tx_insert_ccmp_hdr(dma_data->data,
							       mwl_vif->keyidx,
							       mwl_vif->iv16,
							       mwl_vif->iv32);
					INCREASE_IV(mwl_vif->iv16,
						    mwl_vif->iv32);
				} else {
					struct mwl_sta *sta_info;

					sta_info = mwl_dev_get_sta(sta);

					mwl_tx_insert_ccmp_hdr(dma_data->data,
							       0,
							       sta_info->iv16,
							       sta_info->iv32);
					INCREASE_IV(sta_info->iv16,
						    sta_info->iv32);
				}
			}
		}
	}

	tx_hndl = priv->desc_data[desc_num].pnext_tx_hndl;
	tx_hndl->psk_buff = tx_skb;
	tx_desc = tx_hndl->pdesc;
	tx_desc->tx_priority = tx_ctrl->tx_priority;
	tx_desc->qos_ctrl = cpu_to_le16(tx_ctrl->qos_ctrl);
	tx_desc->pkt_len = cpu_to_le16(tx_skb->len);
	tx_desc->packet_info = 0;
	tx_desc->data_rate = 0;
	tx_desc->type = tx_ctrl->type;
	tx_desc->xmit_control = tx_ctrl->xmit_control;
	tx_desc->sap_pkt_info = 0;
	dma = pci_map_single(priv->pdev, tx_skb->data,
			     tx_skb->len, PCI_DMA_TODEVICE);
	if (pci_dma_mapping_error(priv->pdev, dma)) {
		dev_kfree_skb_any(tx_skb);
		wiphy_err(priv->hw->wiphy,
			  "failed to map pci memory!\n");
		return;
	}
	tx_desc->pkt_ptr = cpu_to_le32(dma);
	tx_desc->status = cpu_to_le32(EAGLE_TXD_STATUS_FW_OWNED);
	/* make sure all the memory transactions done by cpu were completed */
	wmb();	/*Data Memory Barrier*/
	writel(MACREG_H2ARIC_BIT_PPA_READY,
	       priv->iobase1 + MACREG_REG_H2A_INTERRUPT_EVENTS);
	priv->desc_data[desc_num].pnext_tx_hndl = tx_hndl->pnext;
	priv->fw_desc_cnt[desc_num]++;
}
コード例 #5
0
ファイル: mac80211.c プロジェクト: chinawrj/mwlwifi
static int mwl_mac80211_add_interface(struct ieee80211_hw *hw,
				      struct ieee80211_vif *vif)
{
	struct mwl_priv *priv = hw->priv;
	struct mwl_vif *mwl_vif;
	u32 macids_supported;
	int macid;

	switch (vif->type) {
	case NL80211_IFTYPE_AP:
	case NL80211_IFTYPE_MESH_POINT:
		macids_supported = priv->ap_macids_supported;
		break;
	case NL80211_IFTYPE_STATION:
		macids_supported = priv->sta_macids_supported;
		break;
	default:
		return -EINVAL;
	}

	macid = ffs(macids_supported & ~priv->macids_used);

	if (!macid) {
		wiphy_warn(hw->wiphy, "no macid can be allocated\n");
		return -EBUSY;
	}
	macid--;

	/* Setup driver private area. */
	mwl_vif = mwl_dev_get_vif(vif);
	memset(mwl_vif, 0, sizeof(*mwl_vif));
	mwl_vif->macid = macid;
	mwl_vif->seqno = 0;
	mwl_vif->is_hw_crypto_enabled = false;
	mwl_vif->beacon_info.valid = false;
	mwl_vif->iv16 = 1;
	mwl_vif->iv32 = 0;
	mwl_vif->keyidx = 0;

	switch (vif->type) {
	case NL80211_IFTYPE_AP:
		ether_addr_copy(mwl_vif->bssid, vif->addr);
		mwl_fwcmd_set_new_stn_add_self(hw, vif);
		break;
	case NL80211_IFTYPE_MESH_POINT:
		ether_addr_copy(mwl_vif->bssid, vif->addr);
		mwl_fwcmd_set_new_stn_add_self(hw, vif);
		break;
	case NL80211_IFTYPE_STATION:
		ether_addr_copy(mwl_vif->sta_mac, vif->addr);
		mwl_fwcmd_bss_start(hw, vif, true);
		mwl_fwcmd_set_infra_mode(hw, vif);
		mwl_fwcmd_set_mac_addr_client(hw, vif, vif->addr);
		break;
	default:
		return -EINVAL;
	}

	priv->macids_used |= 1 << mwl_vif->macid;
	spin_lock_bh(&priv->vif_lock);
	list_add_tail(&mwl_vif->list, &priv->vif_list);
	spin_unlock_bh(&priv->vif_lock);

	return 0;
}
コード例 #6
0
ファイル: tx_ndp.c プロジェクト: e88z4/mwlwifi
void pcie_tx_xmit_ndp(struct ieee80211_hw *hw,
		      struct ieee80211_tx_control *control,
		      struct sk_buff *skb)
{
	struct mwl_priv *priv = hw->priv;
	struct pcie_priv *pcie_priv = priv->hif.priv;
	struct ieee80211_tx_info *tx_info;
	struct ieee80211_key_conf *k_conf;
	struct mwl_vif *mwl_vif;
	int index;
	struct ieee80211_sta *sta;
	struct mwl_sta *sta_info;
	struct ieee80211_hdr *wh;
	u8 *da;
	u16 qos;
	u8 tid = 0;
	struct mwl_ampdu_stream *stream = NULL;
	u16 tx_que_priority;
	bool mgmtframe = false;
	struct ieee80211_mgmt *mgmt;
	bool eapol_frame = false;
	bool start_ba_session = false;
	struct pcie_tx_ctrl_ndp *tx_ctrl;

	tx_info = IEEE80211_SKB_CB(skb);
	k_conf = tx_info->control.hw_key;
	mwl_vif = mwl_dev_get_vif(tx_info->control.vif);
	index = skb_get_queue_mapping(skb);
	sta = control->sta;
	sta_info = sta ? mwl_dev_get_sta(sta) : NULL;

	wh = (struct ieee80211_hdr *)skb->data;

	if (ieee80211_is_data_qos(wh->frame_control))
		qos = le16_to_cpu(*((__le16 *)ieee80211_get_qos_ctl(wh)));
	else
		qos = 0xFFFF;

	if (skb->protocol == cpu_to_be16(ETH_P_PAE)) {
		index = IEEE80211_AC_VO;
		eapol_frame = true;
	}

	if (ieee80211_is_mgmt(wh->frame_control)) {
		mgmtframe = true;
		mgmt = (struct ieee80211_mgmt *)skb->data;
	}

	if (mgmtframe) {
		u16 capab;

		if (unlikely(ieee80211_is_action(wh->frame_control) &&
			     mgmt->u.action.category == WLAN_CATEGORY_BACK &&
			     mgmt->u.action.u.addba_req.action_code ==
			     WLAN_ACTION_ADDBA_REQ)) {
			capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab);
			tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
			index = utils_tid_to_ac(tid);
		}

		if (unlikely(ieee80211_is_assoc_req(wh->frame_control)))
			utils_add_basic_rates(hw->conf.chandef.chan->band, skb);

		if (ieee80211_is_probe_req(wh->frame_control) ||
		    ieee80211_is_probe_resp(wh->frame_control))
			tx_que_priority = PROBE_RESPONSE_TXQNUM;
		else {
			if ((
			    (mwl_vif->macid == SYSADPT_NUM_OF_AP) &&
			    (!ieee80211_has_protected(wh->frame_control) ||
			    (ieee80211_has_protected(wh->frame_control) &&
			    ieee80211_is_auth(wh->frame_control)))
			    ) ||
			    !sta ||
			    ieee80211_is_auth(wh->frame_control) ||
			    ieee80211_is_assoc_req(wh->frame_control) ||
			    ieee80211_is_assoc_resp(wh->frame_control))
				tx_que_priority = MGMT_TXQNUM;
			else {
				if (is_multicast_ether_addr(wh->addr1) &&
				    (mwl_vif->macid != SYSADPT_NUM_OF_AP))
					tx_que_priority = mwl_vif->macid *
						SYSADPT_MAX_TID;
				else
					tx_que_priority = SYSADPT_MAX_TID *
						(sta_info->stnid +
						QUEUE_STAOFFSET) + 6;
			}
		}

		if (ieee80211_is_assoc_resp(wh->frame_control) ||
		    ieee80211_is_reassoc_resp(wh->frame_control)) {
			struct sk_buff *ack_skb;
			struct ieee80211_tx_info *ack_info;

			ack_skb = skb_copy(skb, GFP_ATOMIC);
			ack_info = IEEE80211_SKB_CB(ack_skb);
			pcie_tx_prepare_info(priv, 0, ack_info);
			ieee80211_tx_status(hw, ack_skb);
		}

		pcie_tx_encapsulate_frame(priv, skb, k_conf, NULL);
	} else {