Esempio n. 1
0
u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len,
			enum nl80211_iftype type)
{
	__le16 fc = hdr->frame_control;

	 /* drop ACK/CTS frames and incorrect hdr len (ctrl) */
	if (len < 16)
		return NULL;

	if (ieee80211_is_data(fc)) {
		if (len < 24) /* drop incorrect hdr len (data) */
			return NULL;

		if (ieee80211_has_a4(fc))
			return NULL;
		if (ieee80211_has_tods(fc))
			return hdr->addr1;
		if (ieee80211_has_fromds(fc))
			return hdr->addr2;

		return hdr->addr3;
	}

	if (ieee80211_is_mgmt(fc)) {
		if (len < 24) /* drop incorrect hdr len (mgmt) */
			return NULL;
		return hdr->addr3;
	}

	if (ieee80211_is_ctl(fc)) {
		if(ieee80211_is_pspoll(fc))
			return hdr->addr1;

		if (ieee80211_is_back_req(fc)) {
			switch (type) {
			case NL80211_IFTYPE_STATION:
				return hdr->addr2;
			case NL80211_IFTYPE_AP:
			case NL80211_IFTYPE_AP_VLAN:
				return hdr->addr1;
			default:
				break; /* fall through to the return */
			}
		}
	}

	return NULL;
}
Esempio n. 2
0
static bool rtl_phydm_query_phy_status(struct rtl_priv *rtlpriv, u8 *phystrpt,
				       struct ieee80211_hdr *hdr,
				       struct rtl_stats *pstatus)
{
	/* NOTE: phystrpt may be NULL, and need to fill default value */

	struct phy_dm_struct *dm = rtlpriv_to_phydm(rtlpriv);
	struct rtl_efuse *rtlefuse = rtl_efuse(rtlpriv);
	struct rtl_mac *mac = rtl_mac(rtlpriv);
	struct dm_per_pkt_info pktinfo; /* input of pydm */
	struct dm_phy_status_info phy_info; /* output of phydm */
	__le16 fc = hdr->frame_control;

	/* fill driver pstatus */
	ether_addr_copy(pstatus->psaddr, ieee80211_get_SA(hdr));

	/* fill pktinfo */
	memset(&pktinfo, 0, sizeof(pktinfo));

	pktinfo.data_rate = pstatus->rate;

	if (rtlpriv->mac80211.opmode == NL80211_IFTYPE_STATION) {
		pktinfo.station_id = 0;
	} else {
		/* TODO: use rtl_find_sta() to find ID */
		pktinfo.station_id = 0xFF;
	}

	pktinfo.is_packet_match_bssid =
		(!ieee80211_is_ctl(fc) &&
		 (ether_addr_equal(mac->bssid,
				   ieee80211_has_tods(fc) ?
					   hdr->addr1 :
					   ieee80211_has_fromds(fc) ?
					   hdr->addr2 :
					   hdr->addr3)) &&
		 (!pstatus->hwerror) && (!pstatus->crc) && (!pstatus->icv));
	pktinfo.is_packet_to_self =
		pktinfo.is_packet_match_bssid &&
		(ether_addr_equal(hdr->addr1, rtlefuse->dev_addr));
	pktinfo.is_to_self = (!pstatus->icv) && (!pstatus->crc) &&
			     (ether_addr_equal(hdr->addr1, rtlefuse->dev_addr));
	pktinfo.is_packet_beacon = (ieee80211_is_beacon(fc) ? true : false);

	/* query phy status */
	if (phystrpt)
		odm_phy_status_query(dm, &phy_info, phystrpt, &pktinfo);
	else
		memset(&phy_info, 0, sizeof(phy_info));

	/* copy phy_info from phydm to driver */
	pstatus->rx_pwdb_all = phy_info.rx_pwdb_all;
	pstatus->bt_rx_rssi_percentage = phy_info.bt_rx_rssi_percentage;
	pstatus->recvsignalpower = phy_info.recv_signal_power;
	pstatus->signalquality = phy_info.signal_quality;
	pstatus->rx_mimo_signalquality[0] = phy_info.rx_mimo_signal_quality[0];
	pstatus->rx_mimo_signalquality[1] = phy_info.rx_mimo_signal_quality[1];
	pstatus->rx_packet_bw =
		phy_info.band_width; /* HT_CHANNEL_WIDTH_20 <- ODM_BW20M */

	/* fill driver pstatus */
	pstatus->packet_matchbssid = pktinfo.is_packet_match_bssid;
	pstatus->packet_toself = pktinfo.is_packet_to_self;
	pstatus->packet_beacon = pktinfo.is_packet_beacon;

	return true;
}
Esempio n. 3
0
void mwl_rx_recv(unsigned long data)
{
	struct ieee80211_hw *hw = (struct ieee80211_hw *)data;
	struct mwl_priv *priv;
	struct mwl_rx_desc *curr_desc;
	int work_done = 0;
	struct sk_buff *prx_skb = NULL;
	int pkt_len;
	struct ieee80211_rx_status status;
	struct mwl_vif *mwl_vif = NULL;
	struct ieee80211_hdr *wh;
	u32 status_mask;

	WLDBG_ENTER(DBG_LEVEL_4);

	BUG_ON(!hw);
	priv = hw->priv;
	BUG_ON(!priv);

	curr_desc = priv->desc_data[0].pnext_rx_desc;

	if (curr_desc == NULL) {
		status_mask = readl(priv->iobase1 + MACREG_REG_A2H_INTERRUPT_STATUS_MASK);
		writel(status_mask | MACREG_A2HRIC_BIT_RX_RDY,
		       priv->iobase1 + MACREG_REG_A2H_INTERRUPT_STATUS_MASK);

		priv->is_rx_schedule = false;

		WLDBG_EXIT_INFO(DBG_LEVEL_4, "busy or no receiving packets");
		return;
	}

	while ((curr_desc->rx_control == EAGLE_RXD_CTRL_DMA_OWN)
		&& (work_done < priv->recv_limit)) {
		prx_skb = curr_desc->psk_buff;
		if (prx_skb == NULL)
			goto out;
		pci_unmap_single(priv->pdev,
				 ENDIAN_SWAP32(curr_desc->pphys_buff_data),
				 priv->desc_data[0].rx_buf_size,
				 PCI_DMA_FROMDEVICE);
		pkt_len = curr_desc->pkt_len;

		if (skb_tailroom(prx_skb) < pkt_len) {
			WLDBG_PRINT("Critical error: not enough tail room =%x pkt_len=%x, curr_desc=%x, curr_desc_data=%x",
				    skb_tailroom(prx_skb), pkt_len, curr_desc, curr_desc->pbuff_data);
			dev_kfree_skb_any(prx_skb);
			goto out;
		}

		if (curr_desc->channel != hw->conf.chandef.chan->hw_value) {
			dev_kfree_skb_any(prx_skb);
			goto out;
		}

		mwl_rx_prepare_status(curr_desc, &status);

		priv->noise = -curr_desc->noise_floor;

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

		if (ieee80211_has_protected(wh->frame_control)) {
			/* Check if hw crypto has been enabled for
			 * this bss. If yes, set the status flags
			 * accordingly
			 */
			if (ieee80211_has_tods(wh->frame_control))
				mwl_vif = mwl_rx_find_vif_bss(&priv->vif_list,
							      wh->addr1);
			else
				mwl_vif = mwl_rx_find_vif_bss(&priv->vif_list,
							      wh->addr2);

			if (mwl_vif != NULL &&
			    mwl_vif->is_hw_crypto_enabled) {
				/*
				 * When MMIC ERROR is encountered
				 * by the firmware, payload is
				 * dropped and only 32 bytes of
				 * mwl8k Firmware header is sent
				 * to the host.
				 *
				 * We need to add four bytes of
				 * key information.  In it
				 * MAC80211 expects keyidx set to
				 * 0 for triggering Counter
				 * Measure of MMIC failure.
				 */
				if (status.flag & RX_FLAG_MMIC_ERROR) {
					struct mwl_dma_data *tr;

					tr = (struct mwl_dma_data *)prx_skb->data;
					memset((void *)&(tr->data), 0, 4);
					pkt_len += 4;
				}

				if (!ieee80211_is_auth(wh->frame_control))
					status.flag |= RX_FLAG_IV_STRIPPED |
						       RX_FLAG_DECRYPTED |
						       RX_FLAG_MMIC_STRIPPED;
			}
		}

		skb_put(prx_skb, pkt_len);
		mwl_rx_remove_dma_header(prx_skb, curr_desc->qos_ctrl);
		memcpy(IEEE80211_SKB_RXCB(prx_skb), &status, sizeof(status));
		ieee80211_rx(hw, prx_skb);
out:
		mwl_rx_refill(priv, curr_desc);
		curr_desc->rx_control = EAGLE_RXD_CTRL_DRIVER_OWN;
		curr_desc->qos_ctrl = 0;
		curr_desc = curr_desc->pnext;
		work_done++;
	}

	priv->desc_data[0].pnext_rx_desc = curr_desc;

	status_mask = readl(priv->iobase1 + MACREG_REG_A2H_INTERRUPT_STATUS_MASK);
	writel(status_mask | MACREG_A2HRIC_BIT_RX_RDY,
	       priv->iobase1 + MACREG_REG_A2H_INTERRUPT_STATUS_MASK);

	priv->is_rx_schedule = false;

	WLDBG_EXIT(DBG_LEVEL_4);
}