void
wep_dump(struct ieee80211_key *k, wbuf_t wbuf, int hdrlen)
{
	struct ieee80211_frame *wh;
    	struct wep_ctx *ctx = k->wk_private;
    	struct ieee80211vap *vap = ctx->wc_vap;
	unsigned int iv,idx,icv;
	unsigned char *ptr;
	unsigned char kbuf[64];


	wh = (struct ieee80211_frame *)wbuf_header(wbuf);
	ptr = (unsigned char*)wh;       

	idx = iv = 0;
	memcpy(&iv, ptr+hdrlen, 3);
	idx = ptr[hdrlen+3];
	memcpy(&icv, ptr+wbuf_get_pktlen(wbuf)-4, 4);

	memcpy(kbuf, k->wk_key, k->wk_keylen);
 
	IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr1,
            "%s and seq=%02x-%02x\n", "addr1", wh->i_seq[0], wh->i_seq[1]);
	IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr3,
            "%s", "addr3");
	IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2,
            "IV=%08x idx=%d ICV=%08x, hdrlen=%d",iv, idx&0xff, icv, hdrlen);

	printk("key dump:len=%d\n", k->wk_keylen);
	dump_hex_buf(kbuf, (int)k->wk_keylen);
	printk("packet dump:pktlen=%d,len=%d\n", wbuf_get_pktlen(wbuf), wbuf_get_len(wbuf));
	dump_hex_buf((uint8_t*)ptr/*wbuf_raw_data(wbuf)*/, (int)wbuf_get_pktlen(wbuf));
}
示例#2
0
/*
 * Add privacy headers appropriate for the specified key.
 */
struct ieee80211_key *
ieee80211_crypto_encap(struct ieee80211_node *ni, struct mbuf *m)
{
	struct ieee80211vap *vap = ni->ni_vap;
	struct ieee80211_key *k;
	struct ieee80211_frame *wh;
	const struct ieee80211_cipher *cip;
	uint8_t keyid;

	/*
	 * Multicast traffic always uses the multicast key.
	 * Otherwise if a unicast key is set we use that and
	 * it is always key index 0.  When no unicast key is
	 * set we fall back to the default transmit key.
	 */
	wh = mtod(m, struct ieee80211_frame *);
	if (IEEE80211_IS_MULTICAST(wh->i_addr1) ||
	    IEEE80211_KEY_UNDEFINED(&ni->ni_ucastkey)) {
		if (vap->iv_def_txkey == IEEE80211_KEYIX_NONE) {
			IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO,
			    wh->i_addr1,
			    "no default transmit key (%s) deftxkey %u",
			    __func__, vap->iv_def_txkey);
			vap->iv_stats.is_tx_nodefkey++;
			return NULL;
		}
		keyid = vap->iv_def_txkey;
		k = &vap->iv_nw_keys[vap->iv_def_txkey];
	} else {
		keyid = 0;
		k = &ni->ni_ucastkey;
	}
	cip = k->wk_cipher;
	return (cip->ic_encap(k, m, keyid<<6) ? k : NULL);
}
示例#3
0
struct ieee80211_key *
ieee80211_crypto_get_txkey(struct ieee80211_node *ni, struct mbuf *m)
{
	struct ieee80211vap *vap = ni->ni_vap;
	struct ieee80211_frame *wh;

	/*
	 * Multicast traffic always uses the multicast key.
	 * Otherwise if a unicast key is set we use that and
	 * it is always key index 0.  When no unicast key is
	 * set we fall back to the default transmit key.
	 */
	wh = mtod(m, struct ieee80211_frame *);
	if (IEEE80211_IS_MULTICAST(wh->i_addr1) ||
	    IEEE80211_KEY_UNDEFINED(&ni->ni_ucastkey)) {
		if (vap->iv_def_txkey == IEEE80211_KEYIX_NONE) {
			IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO,
			    wh->i_addr1,
			    "no default transmit key (%s) deftxkey %u",
			    __func__, vap->iv_def_txkey);
			vap->iv_stats.is_tx_nodefkey++;
			return NULL;
		}
		return &vap->iv_nw_keys[vap->iv_def_txkey];
	}

	return &ni->ni_ucastkey;
}
示例#4
0
void
ieee80211_notify_replay_failure(struct ieee80211vap *vap,
	const struct ieee80211_frame *wh, const struct ieee80211_key *k,
	u_int64_t rsc, int tid)
{
	struct ifnet *ifp = vap->iv_ifp;

	IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2,
	    "%s replay detected tid %d <rsc %ju, csc %ju, keyix %u rxkeyix %u>",
	    k->wk_cipher->ic_name, tid, (intmax_t) rsc,
	    (intmax_t) k->wk_keyrsc[tid],
	    k->wk_keyix, k->wk_rxkeyix);

	if (ifp != NULL) {		/* NB: for cipher test modules */
		struct ieee80211_replay_event iev;

		IEEE80211_ADDR_COPY(iev.iev_dst, wh->i_addr1);
		IEEE80211_ADDR_COPY(iev.iev_src, wh->i_addr2);
		iev.iev_cipher = k->wk_cipher->ic_cipher;
		if (k->wk_rxkeyix != IEEE80211_KEYIX_NONE)
			iev.iev_keyix = k->wk_rxkeyix;
		else
			iev.iev_keyix = k->wk_keyix;
		iev.iev_keyrsc = k->wk_keyrsc[tid];
		iev.iev_rsc = rsc;
		CURVNET_SET(ifp->if_vnet);
		rt_ieee80211msg(ifp, RTM_IEEE80211_REPLAY, &iev, sizeof(iev));
		CURVNET_RESTORE();
	}
}
示例#5
0
/*
 * Add privacy headers appropriate for the specified key.
 */
struct ieee80211_key *
ieee80211_crypto_encap(struct ieee80211_node *ni, struct sk_buff *skb)
{
	struct ieee80211vap *vap = ni->ni_vap;
	struct ieee80211_key *k;
	struct ieee80211_frame *wh;
	const struct ieee80211_cipher *cip;
	u_int8_t keyid;

	/*
	 * Multicast traffic always uses the multicast key.
	 * Otherwise if a unicast key is set we use that and
	 * it is always key index 0.  When no unicast key is
	 * set we fall back to the default transmit key.
	 */
	wh = (struct ieee80211_frame *)skb->data;
	if (IEEE80211_IS_MULTICAST(wh->i_addr1) ||
	    ni->ni_ucastkey.wk_cipher == &ieee80211_cipher_none) {
		if (vap->iv_def_txkey == IEEE80211_KEYIX_NONE) {
			IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO,
				wh->i_addr1,
				"no default transmit key (%s) deftxkey %u",
				__func__, vap->iv_def_txkey);
			vap->iv_stats.is_tx_nodefkey++;
			return NULL;
		}
		keyid = vap->iv_def_txkey;
		k = &vap->iv_nw_keys[vap->iv_def_txkey];
	} else {
		keyid = 0;
		k = &ni->ni_ucastkey;
	}
	cip = k->wk_cipher;
	if (skb_headroom(skb) < cip->ic_header) {
		/*
		 * Should not happen; ieee80211_skbhdr_adjust should
		 * have allocated enough space for all headers.
		 */
		IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr1,
			"%s: malformed packet for cipher %s; headroom %u",
			__func__, cip->ic_name, skb_headroom(skb));
		vap->iv_stats.is_tx_noheadroom++;
		return NULL;
	}
	return (cip->ic_encap(k, skb, keyid << 6) ? k : NULL);
}
示例#6
0
/*
 * Mark a scan cache entry after a successful associate.
 */
void
ieee80211_scan_assoc_success(struct ieee80211vap *vap, const uint8_t mac[])
{
	struct ieee80211_scan_state *ss = vap->iv_ic->ic_scan;

	if (ss->ss_ops != NULL) {
		IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_SCAN,
			mac, "%s",  __func__);
		ss->ss_ops->scan_assoc_success(ss, mac);
	}
}
/*
 * Add privacy headers and do any s/w encryption required.
 */
static int
tkip_encap(struct ieee80211_key *k, struct mbuf *m, uint8_t keyid)
{
	struct tkip_ctx *ctx = k->wk_private;
	struct ieee80211vap *vap = ctx->tc_vap;
	struct ieee80211com *ic = vap->iv_ic;
	uint8_t *ivp;
	int hdrlen;

	/*
	 * Handle TKIP counter measures requirement.
	 */
	if (vap->iv_flags & IEEE80211_F_COUNTERM) {
#ifdef IEEE80211_DEBUG
		struct ieee80211_frame *wh = mtod(m, struct ieee80211_frame *);
#endif

		IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2,
		    "discard frame due to countermeasures (%s)", __func__);
		vap->iv_stats.is_crypto_tkipcm++;
		return 0;
	}
	hdrlen = ieee80211_hdrspace(ic, mtod(m, void *));

	/*
	 * Copy down 802.11 header and add the IV, KeyID, and ExtIV.
	 */
	M_PREPEND(m, tkip.ic_header, M_NOWAIT);
	if (m == NULL)
		return 0;
	ivp = mtod(m, uint8_t *);
	memmove(ivp, ivp + tkip.ic_header, hdrlen);
	ivp += hdrlen;

	ivp[0] = k->wk_keytsc >> 8;		/* TSC1 */
	ivp[1] = (ivp[0] | 0x20) & 0x7f;	/* WEP seed */
	ivp[2] = k->wk_keytsc >> 0;		/* TSC0 */
	ivp[3] = keyid | IEEE80211_WEP_EXTIV;	/* KeyID | ExtID */
	ivp[4] = k->wk_keytsc >> 16;		/* TSC2 */
	ivp[5] = k->wk_keytsc >> 24;		/* TSC3 */
	ivp[6] = k->wk_keytsc >> 32;		/* TSC4 */
	ivp[7] = k->wk_keytsc >> 40;		/* TSC5 */
#if 0
	if (hdrlen == 24)
	{
		M_PREPEND(m, tkip.ic_miclen + 12, M_NOWAIT);
		if (m == NULL)
			return 0;
		ivp = mtod(m, uint8_t *);
		memmove(ivp, ivp + tkip.ic_miclen + 12, hdrlen + tkip.ic_header);
		ivp += hdrlen + tkip.ic_header;
		bzero(ivp, 20);
		memcpy((ivp+12), k->wk_txmic, tkip.ic_header);
	}
示例#8
0
/*
 * Demerit a scan cache entry after failing to associate.
 */
void
ieee80211_scan_assoc_fail(struct ieee80211vap *vap,
	const uint8_t mac[], int reason)
{
	struct ieee80211_scan_state *ss = vap->iv_ic->ic_scan;

	if (ss->ss_ops != NULL) {
		IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_SCAN, mac,
			"%s: reason %u", __func__, reason);
		ss->ss_ops->scan_assoc_fail(ss, mac, reason);
	}
}
static int
none_encap(struct ieee80211_key *k, struct mbuf *m)
{
	struct ieee80211vap *vap = k->wk_private;
#ifdef IEEE80211_DEBUG
	struct ieee80211_frame *wh = mtod(m, struct ieee80211_frame *);
#endif
	uint8_t keyid;

	keyid = ieee80211_crypto_get_keyid(vap, k);

	/*
	 * The specified key is not setup; this can
	 * happen, at least, when changing keys.
	 */
	IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr1,
	    "key id %u is not set (encap)", keyid);
	vap->iv_stats.is_tx_badcipher++;
	return 0;
}
示例#10
0
void
ieee80211_notify_michael_failure(struct ieee80211vap *vap,
	const struct ieee80211_frame *wh, u_int keyix)
{
	struct ifnet *ifp = vap->iv_ifp;

	IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2,
	    "michael MIC verification failed <keyix %u>", keyix);
	vap->iv_stats.is_rx_tkipmic++;

	if (ifp != NULL) {		/* NB: for cipher test modules */
		struct ieee80211_michael_event iev;

		IEEE80211_ADDR_COPY(iev.iev_dst, wh->i_addr1);
		IEEE80211_ADDR_COPY(iev.iev_src, wh->i_addr2);
		iev.iev_cipher = IEEE80211_CIPHER_TKIP;
		iev.iev_keyix = keyix;
		CURVNET_SET(ifp->if_vnet);
		rt_ieee80211msg(ifp, RTM_IEEE80211_MICHAEL, &iev, sizeof(iev));
		CURVNET_RESTORE();
	}
}
示例#11
0
/*zhaoyang1 add start for interfere ap*/
wbuf_t
autelan_beacon_alloc(struct ieee80211_node *ni,
                       struct ieee80211_beacon_offsets *bo, u_int8_t *ap_mac, u_int8_t chan)
{
    struct ieee80211vap *vap = ni->ni_vap;
    struct ieee80211com *ic = ni->ni_ic;
    wbuf_t wbuf;
    struct ieee80211_frame *wh;
    u_int8_t *frm;
	
    wbuf = wbuf_alloc(ic->ic_osdev, WBUF_TX_BEACON, MAX_TX_RX_PACKET_SIZE);
    if (wbuf == NULL)
        return NULL;

    wh = (struct ieee80211_frame *)wbuf_header(wbuf);
    wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT |
        IEEE80211_FC0_SUBTYPE_BEACON;
    wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
    *(u_int16_t *)wh->i_dur = 0;
    IEEE80211_ADDR_COPY(wh->i_addr1, IEEE80211_GET_BCAST_ADDR(ic));
    IEEE80211_ADDR_COPY(wh->i_addr2, ap_mac);
    IEEE80211_ADDR_COPY(wh->i_addr3, ap_mac);
    *(u_int16_t *)wh->i_seq = 0;

    frm = (u_int8_t *)&wh[1];
    frm = autelan_beacon_init(ni, bo, frm, chan);
    if (ieee80211_vap_copy_beacon_is_set(vap)) {
        store_beacon_frame(vap, (u_int8_t *)wh, (frm - (u_int8_t *)wh));
    }

    wbuf_set_pktlen(wbuf, (frm - (u_int8_t *) wbuf_header(wbuf)));
    wbuf_set_node(wbuf, ieee80211_ref_node(ni));

    IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_MLME, vap->iv_myaddr,
                       "%s \n", __func__);
    return wbuf;
}
示例#12
0
static struct ieee80211_node *
hwmp_discover(struct ieee80211vap *vap,
    const uint8_t dest[IEEE80211_ADDR_LEN], struct mbuf *m)
{
	struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
	struct ieee80211_mesh_state *ms = vap->iv_mesh;
	struct ieee80211_mesh_route *rt = NULL;
	struct ieee80211_hwmp_route *hr;
	struct ieee80211_meshpreq_ie preq;
	struct ieee80211_node *ni;
	int sendpreq = 0;
#ifdef IEEE80211_DEBUG
	char ethstr[ETHER_ADDRSTRLEN + 1];
#endif

	KASSERT(vap->iv_opmode == IEEE80211_M_MBSS,
	    ("not a mesh vap, opmode %d", vap->iv_opmode));

	KASSERT(!IEEE80211_ADDR_EQ(vap->iv_myaddr, dest),
	    ("%s: discovering self!", __func__));

	ni = NULL;
	if (!IEEE80211_IS_MULTICAST(dest)) {
		rt = ieee80211_mesh_rt_find(vap, dest);
		if (rt == NULL) {
			rt = ieee80211_mesh_rt_add(vap, dest);
			if (rt == NULL) {
				IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP,
				    ni, "unable to add discovery path to %s",
				    kether_ntoa(dest, ethstr));
				vap->iv_stats.is_mesh_rtaddfailed++;
				goto done;
			}
		}
		hr = IEEE80211_MESH_ROUTE_PRIV(rt,
		    struct ieee80211_hwmp_route);
		if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0) {
			if (hr->hr_origseq == 0)
				hr->hr_origseq = ++hs->hs_seq;
			rt->rt_metric = IEEE80211_MESHLMETRIC_INITIALVAL;
			rt->rt_lifetime =
			    ticks_to_msecs(ieee80211_hwmp_pathtimeout);
			/* XXX check preq retries */
			sendpreq = 1;
			if (m != NULL) {
				IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_HWMP,
				    dest, "%s",
				    "start path discovery (src <none>)");
			} else {
				IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_HWMP,
				    dest,
				    "start path discovery (src %s)",
				    kether_ntoa(
					    mtod(m, struct ether_header *)->ether_shost,
					    ethstr));
			}
			/*
			 * Try to discover the path for this node.
			 */
			preq.preq_flags = 0;
			preq.preq_hopcount = 0;
			preq.preq_ttl = ms->ms_ttl;
			preq.preq_id = ++hs->hs_preqid;
			IEEE80211_ADDR_COPY(preq.preq_origaddr, vap->iv_myaddr);
			preq.preq_origseq = hr->hr_origseq;
			preq.preq_lifetime = rt->rt_lifetime;
			preq.preq_metric = rt->rt_metric;
			preq.preq_tcount = 1;
			IEEE80211_ADDR_COPY(PREQ_TADDR(0), dest);
			PREQ_TFLAGS(0) = 0;
			if (ieee80211_hwmp_targetonly)
				PREQ_TFLAGS(0) |= IEEE80211_MESHPREQ_TFLAGS_TO;
			if (ieee80211_hwmp_replyforward)
				PREQ_TFLAGS(0) |= IEEE80211_MESHPREQ_TFLAGS_RF;
			PREQ_TFLAGS(0) |= IEEE80211_MESHPREQ_TFLAGS_USN;
			PREQ_TSEQ(0) = 0;
			/* XXX check return value */
			hwmp_send_preq(vap->iv_bss, vap->iv_myaddr,
			    broadcastaddr, &preq);
		}
		if (rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID)
			ni = ieee80211_find_txnode(vap, rt->rt_nexthop);
	} else {
示例#13
0
void mlme_recv_auth_btamp(struct ieee80211_node *ni,
                          u_int16_t algo, u_int16_t seq, u_int16_t status_code,
                          u_int8_t *challenge, u_int8_t challenge_length, wbuf_t wbuf)
{

    struct ieee80211vap           *vap = ni->ni_vap;
    struct ieee80211_mlme_priv    *mlme_priv = vap->iv_mlme_priv;
    struct ieee80211_frame        *wh;
    u_int16_t                     indication_status = IEEE80211_STATUS_SUCCESS,response_status = IEEE80211_STATUS_SUCCESS ;
    bool                          send_auth_response=true, indicate=true;

    wh = (struct ieee80211_frame *) wbuf_header(wbuf);
    /* AP must be up and running */
    if (!mlme_priv->im_connection_up || ieee80211_vap_ready_is_clear(vap)) {
        return;
    }

    IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_AUTH, wh->i_addr2,
                       "recv auth frame with algorithm %d seq %d \n", algo, seq);

    do {

        /* Check node existance for the peer */
        if (ni == vap->iv_bss) {
            return;
        } else {
            ieee80211_ref_node(ni);
        }

        /* Validate algo */
        if (algo == IEEE80211_AUTH_ALG_OPEN) {
            if (mlme_priv->im_expected_auth_seq_number) {
                send_auth_response = false;
                indicate = false;
                if (seq == mlme_priv->im_expected_auth_seq_number) {
                    if (!OS_CANCEL_TIMER(&mlme_priv->im_timeout_timer)) {
                        IEEE80211_DPRINTF(vap, IEEE80211_MSG_MLME, "%s: Timed-out already\n", __func__);
                        break;
                    }

                    IEEE80211_DPRINTF(vap, IEEE80211_MSG_MLME, "%s: mlme_auth_complete\n", __func__);

                    /* Request complete */
                    mlme_priv->im_request_type = MLME_REQ_NONE;

                    /* Authentication complete (success or failure) */
                    IEEE80211_DELIVER_EVENT_MLME_AUTH_COMPLETE(vap, status_code);
                    vap->iv_mlme_priv->im_expected_auth_seq_number = 0;
                } else {
                    break;
                }
            } else {
                if (seq != IEEE80211_AUTH_OPEN_REQUEST) {
                    response_status = IEEE80211_STATUS_SEQUENCE;
                    indication_status = IEEE80211_STATUS_SEQUENCE;
                    break;
                } else {
                    indicate = true;
                    send_auth_response = true;
                }
            }
        } else if (algo == IEEE80211_AUTH_ALG_SHARED) {
            response_status = IEEE80211_STATUS_ALG;
            indication_status = IEEE80211_STATUS_ALG;
            break;
        } else {
            IEEE80211_DPRINTF(vap, IEEE80211_MSG_AUTH | IEEE80211_MSG_CRYPTO,
                              "[%s] auth: unsupported algorithm %d \n",ether_sprintf(wh->i_addr2),algo);
            vap->iv_stats.is_rx_auth_unsupported++;
            response_status = IEEE80211_STATUS_ALG;
            indication_status = IEEE80211_STATUS_ALG;
            break;
        }
    } while (FALSE);

    IEEE80211_DELIVER_EVENT_MLME_AUTH_INDICATION(vap, ni->ni_macaddr, indication_status);

    if (send_auth_response) {
        ieee80211_send_auth(ni, seq + 1, response_status, NULL, 0);
    }

    if (ni) {
        if (indication_status != IEEE80211_STATUS_SUCCESS ){
            /* auth is not success, remove the node from node table*/
            ieee80211_node_leave(ni);
        }
        /*
         * release the reference created at the begining of the case above
         * either by alloc_node or ref_node.
         */ 
        ieee80211_free_node(ni);
    }
}
示例#14
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;
    }