Beispiel #1
0
static inline void
ol_rx_decap_to_native_wifi(
    struct ol_txrx_vdev_t *vdev,
    adf_nbuf_t msdu,
    struct ol_rx_decap_info_t *info,
    struct ethernet_hdr_t *ethr_hdr)
{
    struct ieee80211_frame_addr4 *wh;
    u_int16_t hdsize;

    /*
     * we need to remove Qos control field and HT control.
     * MSFT: http://msdn.microsoft.com/en-us/library/windows/hardware/ff552608(v=vs.85).aspx
     */
    wh = (struct ieee80211_frame_addr4 *)info->hdr;
    if ( (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS) {
        hdsize = sizeof(struct ieee80211_frame_addr4);
    }
    else {
        hdsize = sizeof(struct ieee80211_frame);
    }
    wh = (struct ieee80211_frame_addr4 *) adf_nbuf_push_head(msdu, hdsize);
    TXRX_ASSERT2(wh != NULL);
    TXRX_ASSERT2(hdsize <= info->hdr_len);
    adf_os_mem_copy ((u_int8_t *)wh, info->hdr, hdsize);

    /* amsdu subfrm handling if ethr_hdr is not NULL  */
    if (ethr_hdr != NULL) {
        switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) {
        case IEEE80211_FC1_DIR_NODS:
            adf_os_mem_copy(wh->i_addr1, ethr_hdr->dest_addr, ETHERNET_ADDR_LEN);
            adf_os_mem_copy(wh->i_addr2, ethr_hdr->src_addr, ETHERNET_ADDR_LEN);
            break;
        case IEEE80211_FC1_DIR_TODS:
            adf_os_mem_copy(wh->i_addr2, ethr_hdr->src_addr, ETHERNET_ADDR_LEN);
            adf_os_mem_copy(wh->i_addr3, ethr_hdr->dest_addr, ETHERNET_ADDR_LEN);
            break;
        case IEEE80211_FC1_DIR_FROMDS:
            adf_os_mem_copy(wh->i_addr1, ethr_hdr->dest_addr, ETHERNET_ADDR_LEN);
            adf_os_mem_copy(wh->i_addr3, ethr_hdr->src_addr, ETHERNET_ADDR_LEN);
            break;
        case IEEE80211_FC1_DIR_DSTODS:
            adf_os_mem_copy(wh->i_addr3, ethr_hdr->dest_addr, ETHERNET_ADDR_LEN);
            adf_os_mem_copy(wh->i_addr4, ethr_hdr->src_addr, ETHERNET_ADDR_LEN);
            break;
        }
    }
    if (IEEE80211_QOS_HAS_SEQ(wh) ) {
        if (wh->i_fc[1] & IEEE80211_FC1_ORDER) {
            wh->i_fc[1] &= ~IEEE80211_FC1_ORDER;
        }
        wh->i_fc[0] &= ~IEEE80211_FC0_SUBTYPE_QOS;
    }
}
Beispiel #2
0
void
r12a_fill_tx_desc_raw(struct rtwn_softc *sc, struct ieee80211_node *ni,
    struct mbuf *m, void *buf, const struct ieee80211_bpf_params *params)
{
	struct ieee80211vap *vap = ni->ni_vap;
	struct rtwn_vap *uvp = RTWN_VAP(vap);
	struct ieee80211_frame *wh;
	struct r12a_tx_desc *txd;
	uint8_t ridx;
	int ismcast;

	/* XXX TODO: 11n checks, matching rtwn_fill_tx_desc() */

	wh = mtod(m, struct ieee80211_frame *);
	ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1);
	ridx = rate2ridx(params->ibp_rate0);

	/* Fill Tx descriptor. */
	txd = (struct r12a_tx_desc *)buf;
	txd->flags0 |= R12A_FLAGS0_LSG | R12A_FLAGS0_FSG;
	if (ismcast)
		txd->flags0 |= R12A_FLAGS0_BMCAST;

	if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0) {
		txd->txdw4 = htole32(R12A_TXDW4_RETRY_LMT_ENA);
		txd->txdw4 |= htole32(SM(R12A_TXDW4_RETRY_LMT,
		    params->ibp_try0));
	}
	if (params->ibp_flags & IEEE80211_BPF_RTS)
		r12a_tx_protection(sc, txd, IEEE80211_PROT_RTSCTS, ridx);
	if (params->ibp_flags & IEEE80211_BPF_CTS)
		r12a_tx_protection(sc, txd, IEEE80211_PROT_CTSONLY, ridx);

	txd->txdw1 |= htole32(SM(R12A_TXDW1_MACID, RTWN_MACID_BC));
	txd->txdw1 |= htole32(SM(R12A_TXDW1_QSEL, R12A_TXDW1_QSEL_MGNT));

	/* Set TX rate index. */
	txd->txdw4 |= htole32(SM(R12A_TXDW4_DATARATE, ridx));
	txd->txdw4 |= htole32(SM(R12A_TXDW4_DATARATE_FB_LMT, 0x1f));
	txd->txdw6 |= htole32(SM(R21A_TXDW6_MBSSID, uvp->id));
	txd->txdw3 |= htole32(R12A_TXDW3_DRVRATE);
	r12a_tx_raid(sc, txd, ni, ismcast);

	if (!IEEE80211_QOS_HAS_SEQ(wh)) {
		/* Use HW sequence numbering for non-QoS frames. */
		txd->txdw8 |= htole32(R12A_TXDW8_HWSEQ_EN);
		txd->txdw3 |= htole32(SM(R12A_TXDW3_SEQ_SEL, uvp->id));
	} else {
		/* Set sequence number. */
		txd->txdw9 |= htole32(SM(R12A_TXDW9_SEQ,
		    M_SEQNO_GET(m) % IEEE80211_SEQ_RANGE));
	}
}
Beispiel #3
0
void
ieee80211_dump_pkt(struct ieee80211com *ic,
	const u_int8_t *buf, int len, int rate, int rssi)
{
	const struct ieee80211_frame *wh;
	int i;

	wh = (const struct ieee80211_frame *)buf;
	switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) {
	case IEEE80211_FC1_DIR_NODS:
		printf("NODS %s", ether_sprintf(wh->i_addr2));
		printf("->%s", ether_sprintf(wh->i_addr1));
		printf("(%s)", ether_sprintf(wh->i_addr3));
		break;
	case IEEE80211_FC1_DIR_TODS:
		printf("TODS %s", ether_sprintf(wh->i_addr2));
		printf("->%s", ether_sprintf(wh->i_addr3));
		printf("(%s)", ether_sprintf(wh->i_addr1));
		break;
	case IEEE80211_FC1_DIR_FROMDS:
		printf("FRDS %s", ether_sprintf(wh->i_addr3));
		printf("->%s", ether_sprintf(wh->i_addr1));
		printf("(%s)", ether_sprintf(wh->i_addr2));
		break;
	case IEEE80211_FC1_DIR_DSTODS:
		printf("DSDS %s", ether_sprintf((u_int8_t *)&wh[1]));
		printf("->%s", ether_sprintf(wh->i_addr3));
		printf("(%s", ether_sprintf(wh->i_addr2));
		printf("->%s)", ether_sprintf(wh->i_addr1));
		break;
	}
	switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) {
	case IEEE80211_FC0_TYPE_DATA:
		printf(" data");
		break;
	case IEEE80211_FC0_TYPE_MGT:
		printf(" %s", ieee80211_mgt_subtype_name[
			(wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK)
			>> IEEE80211_FC0_SUBTYPE_SHIFT]);
		break;
	default:
		printf(" type#%d", wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK);
		break;
	}
	if (IEEE80211_QOS_HAS_SEQ(wh)) {
		const struct ieee80211_qosframe *qwh = 
			(const struct ieee80211_qosframe *)buf;
		printf(" QoS [TID %u%s]", qwh->i_qos[0] & IEEE80211_QOS_TID,
			qwh->i_qos[0] & IEEE80211_QOS_ACKPOLICY ? " ACM" : "");
	}
	if (wh->i_fc[1] & IEEE80211_FC1_PROT) {
		int off;

		off = ieee80211_anyhdrspace(ic, wh);
		printf(" WEP [IV %.02x %.02x %.02x",
			buf[off+0], buf[off+1], buf[off+2]);
		if (buf[off+IEEE80211_WEP_IVLEN] & IEEE80211_WEP_EXTIV)
			printf(" %.02x %.02x %.02x",
				buf[off+4], buf[off+5], buf[off+6]);
		printf(" KID %u]", buf[off+IEEE80211_WEP_IVLEN] >> 6);
	}
Beispiel #4
0
int
iwl_tx_data(struct iwl_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
{
	struct iwl_ops *ops = &sc->ops;
	const struct ieee80211_txparam *tp;
	struct ieee80211vap *vap = ni->ni_vap;
	struct ieee80211com *ic = ni->ni_ic;
	struct iwl_node *wn = (void *)ni;
	struct iwl_tx_ring *ring;
	struct iwl_tx_desc *desc;
	struct iwl_tx_data *data;
	struct iwl_tx_cmd *cmd;
	struct iwl_cmd_data *tx;
	struct ieee80211_frame *wh;
	struct ieee80211_key *k = NULL;
	struct mbuf *m1;
	uint32_t flags;
	uint16_t qos;
	u_int hdrlen;
	bus_dma_segment_t *seg, segs[IWL_MAX_SCATTER];
	uint8_t tid, ridx, txant, type;
	int ac, i, totlen, error, pad, nsegs = 0, rate;
	struct iwl_vap *ivp = IWL_VAP(vap);

	IWL_LOCK_ASSERT(sc);

	wh = mtod(m, struct ieee80211_frame *);
	hdrlen = ieee80211_anyhdrsize(wh);
	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;

	/* Select EDCA Access Category and TX ring for this frame. */
	if (IEEE80211_QOS_HAS_SEQ(wh)) {
		qos = ((const struct ieee80211_qosframe *)wh)->i_qos[0];
		tid = qos & IEEE80211_QOS_TID;
	} else {
		qos = 0;
		tid = 0;
	}

	if(ivp->ctx == IWL_RXON_PAN_CTX)
		ac = iwl_pan_ac_to_queue[M_WME_GETAC(m)];
	else
		ac = iwl_bss_ac_to_queue[M_WME_GETAC(m)];

	if (IEEE80211_QOS_HAS_SEQ(wh) &&
	    IEEE80211_AMPDU_RUNNING(&ni->ni_tx_ampdu[ac])) {
		struct ieee80211_tx_ampdu *tap = &ni->ni_tx_ampdu[ac];

		ring = &sc->txq[*(int *)tap->txa_private];
		*(uint16_t *)wh->i_seq =
		    htole16(ni->ni_txseqs[tid] << IEEE80211_SEQ_SEQ_SHIFT);
		ni->ni_txseqs[tid]++;
	} else 
		ring = &sc->txq[ac];

	desc = &ring->desc[ring->cur];
	data = &ring->data[ring->cur];

	/* Choose a TX rate index. */
	tp = &vap->iv_txparms[ieee80211_chan2mode(ni->ni_chan)];
	if (type == IEEE80211_FC0_TYPE_MGT)
		rate = tp->mgmtrate;
	else if (IEEE80211_IS_MULTICAST(wh->i_addr1))
		rate = tp->mcastrate;
	else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE)
		rate = tp->ucastrate;
	else
		rate = ni->ni_txrate;

	ridx = ic->ic_rt->rateCodeToIndex[rate];

	/* Encrypt the frame if need be. */
	if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
		/* Retrieve key for TX. */
		k = ieee80211_crypto_encap(ni, m);
		if (k == NULL) {
			m_freem(m);
			return ENOBUFS;
		}
		/* 802.11 header may have moved. */
		wh = mtod(m, struct ieee80211_frame *);
	}
Beispiel #5
0
/*
 * Process a received frame.  The node associated with the sender
 * should be supplied.  If nothing was found in the node table then
 * the caller is assumed to supply a reference to ic_bss instead.
 * The RSSI and a timestamp are also supplied.  The RSSI data is used
 * during AP scanning to select a AP to associate with; it can have
 * any units so long as values have consistent units and higher values
 * mean ``better signal''.  The receive timestamp is currently not used
 * by the 802.11 layer.
 */
int
ieee80211_input(ieee80211com_t *ic, mblk_t *mp, struct ieee80211_node *in,
    int32_t rssi, uint32_t rstamp)
{
	struct ieee80211_frame *wh;
	struct ieee80211_key *key;
	uint8_t *bssid;
	int hdrspace;
	int len;
	uint16_t rxseq;
	uint8_t dir;
	uint8_t type;
	uint8_t subtype;
	uint8_t tid;
	uint8_t qos;

	if (mp->b_flag & M_AMPDU) {
		/*
		 * Fastpath for A-MPDU reorder q resubmission.  Frames
		 * w/ M_AMPDU marked have already passed through here
		 * but were received out of order and been held on the
		 * reorder queue.  When resubmitted they are marked
		 * with the M_AMPDU flag and we can bypass most of the
		 * normal processing.
		 */
		IEEE80211_LOCK(ic);
		wh = (struct ieee80211_frame *)mp->b_rptr;
		type = IEEE80211_FC0_TYPE_DATA;
		dir = wh->i_fc[1] & IEEE80211_FC1_DIR_MASK;
		subtype = IEEE80211_FC0_SUBTYPE_QOS;
		hdrspace = ieee80211_hdrspace(ic, wh);	/* optimize */
		/* clear driver/net80211 flags before passing up */
		mp->b_flag &= ~M_AMPDU;
		goto resubmit_ampdu;
	}

	ASSERT(in != NULL);
	in->in_inact = in->in_inact_reload;
	type = (uint8_t)-1;		/* undefined */
	len = MBLKL(mp);
	if (len < sizeof (struct ieee80211_frame_min)) {
		ieee80211_dbg(IEEE80211_MSG_ANY, "ieee80211_input: "
		    "too short (1): len %u", len);
		goto out;
	}
	/*
	 * Bit of a cheat here, we use a pointer for a 3-address
	 * frame format but don't reference fields past outside
	 * ieee80211_frame_min w/o first validating the data is
	 * present.
	 */
	wh = (struct ieee80211_frame *)mp->b_rptr;
	if ((wh->i_fc[0] & IEEE80211_FC0_VERSION_MASK) !=
	    IEEE80211_FC0_VERSION_0) {
		ieee80211_dbg(IEEE80211_MSG_ANY, "ieee80211_input: "
		    "discard pkt with wrong version %x", wh->i_fc[0]);
		goto out;
	}

	dir = wh->i_fc[1] & IEEE80211_FC1_DIR_MASK;
	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
	subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;

	IEEE80211_LOCK(ic);
	if (!(ic->ic_flags & IEEE80211_F_SCAN)) {
		switch (ic->ic_opmode) {
		case IEEE80211_M_STA:
			bssid = wh->i_addr2;
			if (!IEEE80211_ADDR_EQ(bssid, in->in_bssid))
				goto out_exit_mutex;
			break;
		case IEEE80211_M_IBSS:
		case IEEE80211_M_AHDEMO:
			if (dir != IEEE80211_FC1_DIR_NODS) {
				bssid = wh->i_addr1;
			} else if (type == IEEE80211_FC0_TYPE_CTL) {
				bssid = wh->i_addr1;
			} else {
				if (len < sizeof (struct ieee80211_frame)) {
					ieee80211_dbg(IEEE80211_MSG_ANY,
					    "ieee80211_input: too short(2):"
					    "len %u\n", len);
					goto out_exit_mutex;
				}
				bssid = wh->i_addr3;
			}
			if (type != IEEE80211_FC0_TYPE_DATA)
				break;
			/*
			 * Data frame, validate the bssid.
			 */
			if (!IEEE80211_ADDR_EQ(bssid, ic->ic_bss->in_bssid) &&
			    !IEEE80211_ADDR_EQ(bssid, wifi_bcastaddr)) {
				/* not interested in */
				ieee80211_dbg(IEEE80211_MSG_INPUT,
				    "ieee80211_input: not to bss %s\n",
				    ieee80211_macaddr_sprintf(bssid));
				goto out_exit_mutex;
			}
			/*
			 * For adhoc mode we cons up a node when it doesn't
			 * exist. This should probably done after an ACL check.
			 */
			if (in == ic->ic_bss &&
			    ic->ic_opmode != IEEE80211_M_HOSTAP &&
			    !IEEE80211_ADDR_EQ(wh->i_addr2, in->in_macaddr)) {
				/*
				 * Fake up a node for this newly
				 * discovered member of the IBSS.
				 */
				in = ieee80211_fakeup_adhoc_node(&ic->ic_sta,
				    wh->i_addr2);
				if (in == NULL) {
					/* NB: stat kept for alloc failure */
					goto out_exit_mutex;
				}
			}
			break;
		default:
			goto out_exit_mutex;
		}
		in->in_rssi = (uint8_t)rssi;
		in->in_rstamp = rstamp;
		if (!(type & IEEE80211_FC0_TYPE_CTL)) {
			if (IEEE80211_QOS_HAS_SEQ(wh)) {
				tid = ((struct ieee80211_qosframe *)wh)->
				    i_qos[0] & IEEE80211_QOS_TID;
				if (TID_TO_WME_AC(tid) >= WME_AC_VI)
					ic->ic_wme.wme_hipri_traffic++;
				tid++;
			} else {
				tid = IEEE80211_NONQOS_TID;
			}
			rxseq = LE_16(*(uint16_t *)wh->i_seq);
			if ((in->in_flags & IEEE80211_NODE_HT) == 0 &&
			    (wh->i_fc[1] & IEEE80211_FC1_RETRY) &&
			    (rxseq - in->in_rxseqs[tid]) <= 0) {
				/* duplicate, discard */
				ieee80211_dbg(IEEE80211_MSG_INPUT,
				    "ieee80211_input: duplicate",
				    "seqno <%u,%u> fragno <%u,%u> tid %u",
				    rxseq >> IEEE80211_SEQ_SEQ_SHIFT,
				    in->in_rxseqs[tid] >>
				    IEEE80211_SEQ_SEQ_SHIFT,
				    rxseq & IEEE80211_SEQ_FRAG_MASK,
				    in->in_rxseqs[tid] &
				    IEEE80211_SEQ_FRAG_MASK,
				    tid);
				ic->ic_stats.is_rx_dups++;
				goto out_exit_mutex;
			}
			in->in_rxseqs[tid] = rxseq;
		}
	}
Beispiel #6
0
/*
 * Validate and strip privacy headers (and trailer) for a
 * received frame. The specified key should be correct but
 * is also verified.
 */
static int
ccmp_decap(struct ieee80211_key *k, wbuf_t wbuf, int hdrlen, struct ieee80211_rx_status *rs)
{
    struct ccmp_ctx *ctx = k->wk_private;
    struct ieee80211vap *vap = ctx->cc_vap;
    struct ieee80211_frame *wh;
    uint8_t *ivp, *origHdr;
    u_int64_t pn;
    u_int8_t tid;
    struct ieee80211_mac_stats *mac_stats;
    u_int32_t hwmfp;
    uint8_t  update_keyrsc = 1;

    /*
     * Header should have extended IV and sequence number;
     * verify the former and validate the latter.
     */
    origHdr = (u_int8_t *)wbuf_header(wbuf);
    wh = (struct ieee80211_frame *)origHdr;
    mac_stats = IEEE80211_IS_MULTICAST(wh->i_addr1) ? &vap->iv_multicast_stats : &vap->iv_unicast_stats;
    if (IEEE80211_IS_MFP_FRAME(wh)) {
            IEEE80211_DPRINTF(vap, IEEE80211_MSG_CRYPTO, "%s MFP frame\n", __func__);
    }

    if (rs->rs_flags & IEEE80211_RX_DECRYPT_ERROR) {
        IEEE80211_DPRINTF(vap, IEEE80211_MSG_CRYPTO, "%s decrypt error\n", __func__);
        if (IEEE80211_IS_MFP_FRAME(wh)) {
            /* It may not be real crypto error, but hardware didn't do correct
             * decryption. Try software decrypt later.
             */
            rs->rs_flags &= ~IEEE80211_RX_DECRYPT_ERROR;
            rs->rs_flags |= IEEE80211_RX_MIC_ERROR;
        } else {
            /* The frame already failed decryption in hardware,
             * just update statistics and return. */
            mac_stats->ims_rx_ccmpmic++;
            return 0;
        }
    }

    ivp = origHdr + hdrlen;
    if ((ivp[IEEE80211_WEP_IVLEN] & IEEE80211_WEP_EXTIV) == 0) {
        /*
         * No extended IV; discard frame.
         */
        IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2,
                           "%s", "Missing ExtIV for AES-CCM cipher");
        mac_stats->ims_rx_ccmpformat++;
        return 0;
    }
    tid = IEEE80211_NON_QOS_SEQ;
    if (IEEE80211_QOS_HAS_SEQ(wh)) {
        if ( (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) 
             == IEEE80211_FC1_DIR_DSTODS ) {
            tid = ((struct ieee80211_qosframe_addr4 *)wh)->i_qos[0] & IEEE80211_QOS_TID;
        } else {
            tid = ((struct ieee80211_qosframe *)wh)->i_qos[0] & IEEE80211_QOS_TID;
        }
    }

    /* NB: assume IEEEE80211_WEP_MINLEN covers the extended IV */ 
    pn = READ_6(ivp[0], ivp[1], ivp[4], ivp[5], ivp[6], ivp[7]);
    if (pn <= k->wk_keyrsc[tid]) {
        /*
         * Replay violation.
         */
        IEEE80211_DPRINTF(vap, IEEE80211_MSG_CRYPTO,
                          "%s: CCMP Replay! Throw away. new pn=0x%x%x, "
                          "current pn=0x%x%x. seq=0x%x,Rsvd=0x%x,keyID=0x%x,tid=%d\n", 
                           __func__,
                           (u_int32_t)(pn>>32), (u_int32_t)pn, 
                           (u_int32_t)(k->wk_keyrsc[tid] >> 32), (u_int32_t)k->wk_keyrsc[tid],
                           *(u_int16_t*)(wh->i_seq), 
                           ivp[2], ivp[3],
                           tid
                           );
        ieee80211_notify_replay_failure(vap, wh, k, pn);
        mac_stats->ims_rx_ccmpreplay++;
        return 0;
    }
Beispiel #7
0
/*
 * Add privacy headers appropriate for the specified key.
 */
static int
ccmp_encap(struct ieee80211_key *k, wbuf_t wbuf, u_int8_t keyid)
{
    struct ccmp_ctx *ctx = k->wk_private;
    struct ieee80211com *ic = ctx->cc_ic;
    u_int8_t *ivp;
    int hdrlen;
    int is4addr, isqos, owl_wdswar;
    struct ieee80211_frame *wh;
    struct ieee80211_node *ni = wbuf_get_node(wbuf);

    wh = (struct ieee80211_frame *)wbuf_header(wbuf);
    is4addr = ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS) ? 1 : 0;
    isqos = IEEE80211_QOS_HAS_SEQ(wh);
    owl_wdswar = (ni->ni_flags & IEEE80211_NODE_OWL_WDSWAR);

    hdrlen = ieee80211_hdrspace(ic, wbuf_header(wbuf));

    /*
     * Copy down 802.11 header and add the IV, KeyID, and ExtIV.
     */
#ifndef __CARRIER_PLATFORM__
    ivp = (u_int8_t *)wbuf_push(wbuf, ccmp.ic_header);

    /* 
     * refresh the wh pointer,
     * wbuf header  pointer is changed with wbuf_push.
     */
    wh = (struct ieee80211_frame *) wbuf_header(wbuf); /* recompute wh */

    memmove(ivp, ivp + ccmp.ic_header, hdrlen);
#else
    if (wbuf_is_encap_done(wbuf)) {
        ivp = (u_int8_t *)wbuf_header(wbuf);
    }
    else { 
        ivp = (u_int8_t *)wbuf_push(wbuf, ccmp.ic_header);
        memmove(ivp, ivp + ccmp.ic_header, hdrlen);
        /* 
         * refresh the wh pointer,
         * wbuf header  pointer is changed with wbuf_push.
         */
        wh = (struct ieee80211_frame *) wbuf_header(wbuf); /* recompute wh */
    }
#endif
    ivp += hdrlen;

    /*
     * Due to OWL specific HW bug, increment key tsc by 16, since
     * we're copying the TID into bits [3:0] of IV0.
     * XXX: Need logic to not implement workaround for SOWL or greater.
     */
    if (is4addr && isqos && owl_wdswar)
        k->wk_keytsc += 16;
    else
        k->wk_keytsc++;		/* XXX wrap at 48 bits */

    ivp[0] = k->wk_keytsc >> 0;		/* PN0 */
    ivp[1] = k->wk_keytsc >> 8;		/* PN1 */
    ivp[2] = 0;				/* Reserved */
    ivp[3] = keyid | IEEE80211_WEP_EXTIV;	/* KeyID | ExtID */
    ivp[4] = k->wk_keytsc >> 16;		/* PN2 */
    ivp[5] = k->wk_keytsc >> 24;		/* PN3 */
    ivp[6] = k->wk_keytsc >> 32;		/* PN4 */
    ivp[7] = k->wk_keytsc >> 40;		/* PN5 */

    /*
     * Finally, do software encrypt if neeed.
     */
    if (k->wk_flags & IEEE80211_KEY_SWCRYPT) {
        if (!ccmp_encrypt(k, wbuf, hdrlen, 0)) {
            return 0;
        }
    }
    if ((k->wk_flags & IEEE80211_KEY_MFP) && IEEE80211_IS_MFP_FRAME(wh)) {
        if (ic->ic_get_mfpsupport(ic) != IEEE80211_MFP_HW_CRYPTO) {
            /* HW MFP is not enabled - do software encrypt */
            if (!ccmp_encrypt(k, wbuf, hdrlen, 1)) {
                return 0;
            }
        }
    }
    return 1;
}
Beispiel #8
0
void
r12a_fill_tx_desc(struct rtwn_softc *sc, struct ieee80211_node *ni,
    struct mbuf *m, void *buf, uint8_t ridx, int maxretry)
{
	struct ieee80211com *ic = &sc->sc_ic;
	struct ieee80211vap *vap = ni->ni_vap;
	struct rtwn_vap *uvp = RTWN_VAP(vap);
	struct ieee80211_frame *wh;
	struct r12a_tx_desc *txd;
	enum ieee80211_protmode prot;
	uint8_t type, tid, qos, qsel;
	int hasqos, ismcast, macid;

	wh = mtod(m, struct ieee80211_frame *);
	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
	hasqos = IEEE80211_QOS_HAS_SEQ(wh);
	ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1);

	/* Select TX ring for this frame. */
	if (hasqos) {
		qos = ((const struct ieee80211_qosframe *)wh)->i_qos[0];
		tid = qos & IEEE80211_QOS_TID;
	} else {
		qos = 0;
		tid = 0;
	}

	/* Fill Tx descriptor. */
	txd = (struct r12a_tx_desc *)buf;
	txd->flags0 |= R12A_FLAGS0_LSG | R12A_FLAGS0_FSG;
	if (ismcast)
		txd->flags0 |= R12A_FLAGS0_BMCAST;

	if (!ismcast) {
		/* Unicast frame, check if an ACK is expected. */
		if (!qos || (qos & IEEE80211_QOS_ACKPOLICY) !=
		    IEEE80211_QOS_ACKPOLICY_NOACK) {
			txd->txdw4 = htole32(R12A_TXDW4_RETRY_LMT_ENA);
			txd->txdw4 |= htole32(SM(R12A_TXDW4_RETRY_LMT,
			    maxretry));
		}

		struct rtwn_node *un = RTWN_NODE(ni);
		macid = un->id;

		if (type == IEEE80211_FC0_TYPE_DATA) {
			qsel = tid % RTWN_MAX_TID;

			if (m->m_flags & M_AMPDU_MPDU) {
				txd->txdw2 |= htole32(R12A_TXDW2_AGGEN);
				txd->txdw2 |= htole32(SM(R12A_TXDW2_AMPDU_DEN,
				    vap->iv_ampdu_density));
				txd->txdw3 |= htole32(SM(R12A_TXDW3_MAX_AGG,
				    0x1f));	/* XXX */
			} else
				txd->txdw2 |= htole32(R12A_TXDW2_AGGBK);

			if (sc->sc_ratectl == RTWN_RATECTL_NET80211) {
				txd->txdw2 |= htole32(R12A_TXDW2_SPE_RPT);
				sc->sc_tx_n_active++;
			}

			if (RTWN_RATE_IS_CCK(ridx) && ridx != RTWN_RIDX_CCK1 &&
			    (ic->ic_flags & IEEE80211_F_SHPREAMBLE))
				txd->txdw5 |= htole32(R12A_TXDW5_DATA_SHORT);

			prot = IEEE80211_PROT_NONE;
			if (ridx >= RTWN_RIDX_MCS(0)) {
				r12a_tx_set_ht40(sc, txd, ni);
				r12a_tx_set_sgi(sc, txd, ni);
				prot = ic->ic_htprotmode;
			} else if (ic->ic_flags & IEEE80211_F_USEPROT)
				prot = ic->ic_protmode;

			/* XXX fix last comparison for A-MSDU (in net80211) */
			/* XXX A-MPDU? */
			if (m->m_pkthdr.len + IEEE80211_CRC_LEN >
			    vap->iv_rtsthreshold &&
			    vap->iv_rtsthreshold != IEEE80211_RTS_MAX)
				prot = IEEE80211_PROT_RTSCTS;

			if (prot != IEEE80211_PROT_NONE)
				r12a_tx_protection(sc, txd, prot, ridx);
		} else	/* IEEE80211_FC0_TYPE_MGT */
			qsel = R12A_TXDW1_QSEL_MGNT;
	} else {
		macid = RTWN_MACID_BC;
		qsel = R12A_TXDW1_QSEL_MGNT;
	}

	txd->txdw1 |= htole32(SM(R12A_TXDW1_QSEL, qsel));
	txd->txdw1 |= htole32(SM(R12A_TXDW1_MACID, macid));
	txd->txdw4 |= htole32(SM(R12A_TXDW4_DATARATE, ridx));
	/* Data rate fallback limit (max). */
	txd->txdw4 |= htole32(SM(R12A_TXDW4_DATARATE_FB_LMT, 0x1f));
	/* XXX recheck for non-21au */
	txd->txdw6 |= htole32(SM(R21A_TXDW6_MBSSID, uvp->id));
	r12a_tx_raid(sc, txd, ni, ismcast);

	/* Force this rate if needed. */
	if (sc->sc_ratectl != RTWN_RATECTL_FW)
		txd->txdw3 |= htole32(R12A_TXDW3_DRVRATE);

	if (!hasqos) {
		/* Use HW sequence numbering for non-QoS frames. */
		txd->txdw8 |= htole32(R12A_TXDW8_HWSEQ_EN);
		txd->txdw3 |= htole32(SM(R12A_TXDW3_SEQ_SEL, uvp->id));
	} else {
		uint16_t seqno;

		if (m->m_flags & M_AMPDU_MPDU) {
			seqno = ni->ni_txseqs[tid];
			/* NB: clear Fragment Number field. */
			*(uint16_t *)wh->i_seq = 0;
			ni->ni_txseqs[tid]++;
		} else
			seqno = M_SEQNO_GET(m) % IEEE80211_SEQ_RANGE;

		/* Set sequence number. */
		txd->txdw9 |= htole32(SM(R12A_TXDW9_SEQ, seqno));
	}
}