Beispiel #1
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 iv_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.
 */
static int
adhoc_input(struct ieee80211_node *ni, struct mbuf *m,
    const struct ieee80211_rx_stats *rxs, int rssi, int nf)
{
	struct ieee80211vap *vap = ni->ni_vap;
	struct ieee80211com *ic = ni->ni_ic;
	struct ifnet *ifp = vap->iv_ifp;
	struct ieee80211_frame *wh;
	struct ieee80211_key *key;
	struct ether_header *eh;
	int hdrspace, need_tap = 1;	/* mbuf need to be tapped. */	
	uint8_t dir, type, subtype, qos;
	uint8_t *bssid;

	if (m->m_flags & M_AMPDU_MPDU) {
		/*
		 * Fastpath for A-MPDU reorder q resubmission.  Frames
		 * w/ M_AMPDU_MPDU 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_MPDU flag and we can bypass most of
		 * the normal processing.
		 */
		wh = mtod(m, struct ieee80211_frame *);
		type = IEEE80211_FC0_TYPE_DATA;
		dir = wh->i_fc[1] & IEEE80211_FC1_DIR_MASK;
		subtype = IEEE80211_FC0_SUBTYPE_QOS;
		hdrspace = ieee80211_hdrspace(ic, wh);	/* XXX optimize? */
		goto resubmit_ampdu;
	}
/*
 * 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 iv_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.
 */
static int
adhoc_input(struct ieee80211_node *ni, struct mbuf *m,
    const struct ieee80211_rx_stats *rxs, int rssi, int nf)
{
	struct ieee80211vap *vap = ni->ni_vap;
	struct ieee80211com *ic = ni->ni_ic;
	struct ifnet *ifp = vap->iv_ifp;
	struct ieee80211_frame *wh;
	struct ieee80211_key *key;
	struct ether_header *eh;
	int hdrspace, need_tap = 1;	/* mbuf need to be tapped. */	
	uint8_t dir, type, subtype, qos;
	uint8_t *bssid;
	int is_hw_decrypted = 0;
	int has_decrypted = 0;

	/*
	 * Some devices do hardware decryption all the way through
	 * to pretending the frame wasn't encrypted in the first place.
	 * So, tag it appropriately so it isn't discarded inappropriately.
	 */
	if ((rxs != NULL) && (rxs->c_pktflags & IEEE80211_RX_F_DECRYPTED))
		is_hw_decrypted = 1;

	if (m->m_flags & M_AMPDU_MPDU) {
		/*
		 * Fastpath for A-MPDU reorder q resubmission.  Frames
		 * w/ M_AMPDU_MPDU 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_MPDU flag and we can bypass most of
		 * the normal processing.
		 */
		wh = mtod(m, struct ieee80211_frame *);
		type = IEEE80211_FC0_TYPE_DATA;
		dir = wh->i_fc[1] & IEEE80211_FC1_DIR_MASK;
		subtype = IEEE80211_FC0_SUBTYPE_QOS;
		hdrspace = ieee80211_hdrspace(ic, wh);	/* XXX optimize? */
		goto resubmit_ampdu;
	}
Beispiel #3
0
static int
runtest(struct ieee80211vap *vap, struct ciphertest *t)
{
	struct ieee80211_key *key;
	struct sk_buff *skb = NULL;
	const struct ieee80211_cipher *cip;
	u_int8_t mac[IEEE80211_ADDR_LEN];
	struct wep_ctx_hw *ctx;
	int hdrlen;

	printk("%s: ", t->name);

	if (!ieee80211_crypto_available(vap, t->cipher)) {
		printk("FAIL: ieee80211_crypto_available failed\n");
		return 0;
	}

	/*
	 * Setup key.
	 */
	key = &vap->iv_nw_keys[t->keyix];
	key->wk_keyix = t->keyix;
	if (!ieee80211_crypto_newkey(vap, t->cipher,
				     IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV,
				     key)) {
		printk("FAIL: ieee80211_crypto_newkey failed\n");
		goto bad;
	}

	memcpy(key->wk_key, t->key, t->key_len);
	key->wk_keylen = t->key_len;
	if (!ieee80211_crypto_setkey(vap, key, mac, NULL)) {
		printk("FAIL: ieee80211_crypto_setkey failed\n");
		goto bad;
	}
	cip = key->wk_cipher;

	/*
	 * Craft encrypted frame from known data.
	 */
	skb = ieee80211_dev_alloc_skb(t->encrypted_len);
	if (skb == NULL) {
		printk("FAIL: unable to allocate skbuff\n");
		goto bad;
	}
	memcpy(skb_put(skb, t->encrypted_len), t->encrypted, t->encrypted_len);

	/*
	 * Decrypt frame.
	 */
	hdrlen = ieee80211_hdrspace(vap->iv_ic, skb->data);
	if (!(*cip->ic_decap)(key, skb, hdrlen)) {
		printk("FAIL: wep decap failed\n");
		cmpfail(skb->data, skb->len,
			t->plaintext, t->plaintext_len);
		goto bad;
	}
	/*
	 * Verify: frame length, frame contents.
	 */
	if (skb->len != t->plaintext_len) {
		printk("FAIL: decap botch; length mismatch\n");
		cmpfail(skb->data, skb->len,
			t->plaintext, t->plaintext_len);
		goto bad;
	} else if (memcmp(skb->data, t->plaintext, t->plaintext_len)) {
		printk("FAIL: decap botch; data does not compare\n");
		cmpfail(skb->data, skb->len,
			t->plaintext, sizeof(t->plaintext));
		goto bad;
	}

	/*
	 * Encrypt frame.
	 */
	ctx = (struct wep_ctx_hw *) key->wk_private;
	memcpy(&ctx->wc_iv, t->iv, sizeof(t->iv));	/* for encap/encrypt */
	if (!(*cip->ic_encap)(key, skb, t->keyix << 6)) {
		printk("FAIL: wep encap failed\n");
		goto bad;
	}
	/*
	 * Verify: frame length, frame contents.
	 */
	if (skb->len != t->encrypted_len) {
		printk("FAIL: encap data length mismatch\n");
		cmpfail(skb->data, skb->len,
			t->encrypted, t->encrypted_len);
		goto bad;
	} else if (memcmp(skb->data, t->encrypted, skb->len)) {
		printk("FAIL: encrypt data does not compare\n");
		cmpfail(skb->data, skb->len,
			t->encrypted, t->encrypted_len);
		dumpdata("Plaintext", t->plaintext, t->plaintext_len);
		goto bad;
	}
	if (skb != NULL)
		ieee80211_dev_kfree_skb(&skb);
	ieee80211_crypto_delkey(vap, key, NULL);
	printk("PASS\n");
	return 1;
bad:
	if (skb != NULL)
		ieee80211_dev_kfree_skb(&skb);
	ieee80211_crypto_delkey(vap, key, NULL);
	return 0;
}
Beispiel #4
0
static int
runtest(struct ieee80211vap *vap, struct ciphertest *t)
{
	struct ieee80211_key *key;
	struct sk_buff *skb = NULL;
	const struct ieee80211_cipher *cip;
	u_int8_t mac[IEEE80211_ADDR_LEN];
	struct tkip_ctx *ctx;
	int hdrlen;

	printk("%s: ", t->name);

	if (!ieee80211_crypto_available(vap, t->cipher)) {
		printk("FAIL: ieee80211_crypto_available failed\n");
		return 0;
	}

	/*
	 * Setup key.
	 */
	key = &vap->iv_nw_keys[t->keyix];
	key->wk_keyix = t->keyix;
	if (!ieee80211_crypto_newkey(vap, t->cipher,
				     IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV,
				     key)) {
		printk("FAIL: ieee80211_crypto_newkey failed\n");
		goto bad;
	}

	memcpy(key->wk_key, t->key, t->key_len);
	key->wk_keylen = 128 / NBBY;
	memset(key->wk_keyrsc, 0, sizeof(key->wk_keyrsc));
	key->wk_keytsc = 0;
	if (!ieee80211_crypto_setkey(vap, key, mac, NULL)) {
		printk("FAIL: ieee80211_crypto_setkey failed\n");
		goto bad;
	}

	/*
	 * Craft frame from plaintext data.  Note that
	 * we leave the MIC off as we'll add it ourself
	 * and then check it against the reference data.
	 */
	cip = key->wk_cipher;
	skb = ieee80211_dev_alloc_skb(t->plaintext_len +
		cip->ic_miclen + cip->ic_header + cip->ic_trailer);
	if (skb == NULL) {
		printk("FAIL: unable to allocate skbuff\n");
		goto bad;
	}
	skb_reserve(skb, cip->ic_header);
	memcpy(skb_put(skb, t->plaintext_len - cip->ic_miclen),
		t->plaintext, t->plaintext_len - cip->ic_miclen);

	/*
	 * Add MIC.
	 */
	if (!ieee80211_crypto_enmic(vap, key, skb, 0)) {
		printk("FAIL: tkip enmic failed\n");
		goto bad;
	}
	/*
	 * Verify: frame length, frame contents.
	 */
	if (skb->len != t->plaintext_len) {
		printk("FAIL: enmic botch; length mismatch\n");
		cmpfail(skb->data, skb->len,
			t->plaintext, t->plaintext_len);
		goto bad;
	}
	if (memcmp(skb->data, t->plaintext, t->plaintext_len)) {
		printk("FAIL: enmic botch\n");
		cmpfail(skb->data, skb->len,
			t->plaintext, t->plaintext_len);
		goto bad;
	}
	/*
	 * Encrypt frame w/ MIC.
	 */
	if (!(*cip->ic_encap)(key, skb, t->keyix << 6)) {
		printk("FAIL: tkip encap failed\n");
		goto bad;
	}
	/*
	 * Verify: phase1, phase2, frame length, frame contents.
	 */
	ctx = key->wk_private;
	if (memcmp(ctx->tx_ttak, t->phase1, t->phase1_len)) {
		printk("FAIL: encrypt phase1 botch\n");
		cmpfail(ctx->tx_ttak, sizeof(ctx->tx_ttak),
			t->phase1, t->phase1_len);
		goto bad;
	} else if (memcmp(ctx->tx_rc4key, t->phase2, t->phase2_len)) {
		printf("FAIL: encrypt phase2 botch\n");
		cmpfail(ctx->tx_rc4key, sizeof(ctx->tx_rc4key),
			t->phase2, t->phase2_len);
		goto bad;
	} else if (skb->len != t->encrypted_len) {
		printk("FAIL: encrypt data length mismatch\n");
		cmpfail(skb->data, skb->len,
			t->encrypted, t->encrypted_len);
		goto bad;
	} else if (memcmp(skb->data, t->encrypted, skb->len)) {
		printk("FAIL: encrypt data does not compare\n");
		cmpfail(skb->data, skb->len,
			t->encrypted, t->encrypted_len);
		dumpdata("Plaintext", t->plaintext, t->plaintext_len);
		goto bad;
	}

	/*
	 * Decrypt frame.
	 */
	hdrlen = ieee80211_hdrspace(vap->iv_ic, skb->data);
	if (!(*cip->ic_decap)(key, skb, hdrlen)) {
		printk("FAIL: tkip decap failed\n");
		/*
		 * Check reason for failure: phase1, phase2, frame data (ICV).
		 */
		if (memcmp(ctx->rx_ttak, t->phase1, t->phase1_len)) {
			printk("decrypt phase1 botch\n");
			cmpfail(ctx->rx_ttak, sizeof(ctx->rx_ttak),
				t->phase1, t->phase1_len);
		} else if (memcmp(ctx->rx_rc4key, t->phase2, t->phase2_len)) {
			printf("decrypt phase2 botch\n");
			cmpfail(ctx->rx_rc4key, sizeof(ctx->rx_rc4key),
				t->phase2, t->phase2_len);
		} else {
			printk("decrypt data does not compare\n");
			cmpfail(skb->data, skb->len,
				t->plaintext, t->plaintext_len);
		}
		goto bad;
	}
	/*
	 * Verify: frame length, frame contents.
	 */
	if (skb->len != t->plaintext_len) {
		printk("FAIL: decap botch; length mismatch\n");
		cmpfail(skb->data, skb->len,
			t->plaintext, t->plaintext_len);
		goto bad;
	}
	if (memcmp(skb->data, t->plaintext, t->plaintext_len)) {
		printk("FAIL: decap botch; data does not compare\n");
		cmpfail(skb->data, skb->len,
			t->plaintext, t->plaintext_len);
		goto bad;
	}
	/*
	 * De-MIC decrypted frame.
	 */
	if (!ieee80211_crypto_demic(vap, key, skb, hdrlen, 0)) {
		printk("FAIL: tkip demic failed\n");
		goto bad;
	}
	/* XXX check frame length and contents... */
	ieee80211_dev_kfree_skb(&skb);
	ieee80211_crypto_delkey(vap, key, NULL);
	printk("PASS\n");
	return 1;
bad:
	if (skb != NULL)
		ieee80211_dev_kfree_skb(&skb);
	ieee80211_crypto_delkey(vap, key, NULL);
	return 0;
}
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
/*
 * 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;
}
static int
runtest(struct ieee80211vap *vap, struct ciphertest *t)
{
	struct ieee80211_key *key;
	struct sk_buff *skb = NULL;
	const struct ieee80211_cipher *cip;
	u_int8_t mac[IEEE80211_ADDR_LEN];
	int hdrlen;

	printk("%s: ", t->name);

	if (!ieee80211_crypto_available(t->cipher)) {
		printk("FAIL: ieee80211_crypto_available failed\n");
		return 0;
	}

	/*
	 * Setup key.
	 */
	key = &vap->iv_nw_keys[t->keyix];
	key->wk_keyix = t->keyix;
	if (!ieee80211_crypto_newkey(vap, t->cipher,
				     IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV,
				     key)) {
		printk("FAIL: ieee80211_crypto_newkey failed\n");
		goto bad;
	}

	memcpy(key->wk_key, t->key, t->key_len);
	key->wk_keylen = t->key_len;
	memset(key->wk_keyrsc, 0, sizeof(key->wk_keyrsc));
	key->wk_keytsc = t->pn - 1;	/* PN-1 since we do encap */
	if (!ieee80211_crypto_setkey(vap, key, mac, NULL)) {
		printk("FAIL: ieee80211_crypto_setkey failed\n");
		goto bad;
	}

	/*
	 * Craft frame from plaintext data.
	 */
	cip = key->wk_cipher;
	skb = dev_alloc_skb(t->plaintext_len +
		cip->ic_header + cip->ic_trailer);
	if (skb == NULL) {
		printk("FAIL: unable to allocate skbuff\n");
		goto bad;
	}
	skb_reserve(skb, cip->ic_header);
	memcpy(skb_put(skb, t->plaintext_len), t->plaintext, t->plaintext_len);

	/*
	 * Encrypt frame w/ MIC.
	 */
	if (!(*cip->ic_encap)(key, skb, t->keyix << 6)) {
		printk("FAIL: ccmp encap failed\n");
		goto bad;
	}
	/*
	 * Verify: frame length, frame contents.
	 */
	if (skb->len != t->encrypted_len) {
		printk("FAIL: encap data length mismatch\n");
		cmpfail(skb->data, skb->len,
			t->encrypted, t->encrypted_len);
		goto bad;
	} else if (memcmp(skb->data, t->encrypted, skb->len)) {
		printk("FAIL: encrypt data does not compare\n");
		cmpfail(skb->data, skb->len,
			t->encrypted, t->encrypted_len);
		dumpdata("Plaintext", t->plaintext, t->plaintext_len);
		goto bad;
	}

	/*
	 * Decrypt frame; strip MIC.
	 */
	hdrlen = ieee80211_hdrspace(vap->iv_ic, skb->data);
	if (!(*cip->ic_decap)(key, skb, hdrlen)) {
		printk("FAIL: ccmp decap failed\n");
		cmpfail(skb->data, skb->len,
			t->plaintext, t->plaintext_len);
		goto bad;
	}
	/*
	 * Verify: frame length, frame contents.
	 */
	if (skb->len != t->plaintext_len) {
		printk("FAIL: decap botch; length mismatch\n");
		cmpfail(skb->data, skb->len,
			t->plaintext, t->plaintext_len);
		goto bad;
	} else if (memcmp(skb->data, t->plaintext, t->plaintext_len)) {
		printk("FAIL: decap botch; data does not compare\n");
		cmpfail(skb->data, skb->len,
			t->plaintext, sizeof(t->plaintext));
		goto bad;
	}
	dev_kfree_skb(skb);
	ieee80211_crypto_delkey(vap, key, NULL);
	printk("PASS\n");
	return 1;
bad:
	if (skb != NULL)
		dev_kfree_skb(skb);
	ieee80211_crypto_delkey(vap, key, NULL);
	return 0;
}
static int ieee80211_crypto_keymiss(struct ieee80211_node *ni, wbuf_t wbuf, struct ieee80211_rx_status *rs)
{
    struct ieee80211vap *vap = ni->ni_vap;
    struct ieee80211com *ic = vap->iv_ic;
    struct ieee80211_frame *wh;
    int off, kid, hdrspace;
    u_int8_t *buf = NULL;
    struct ieee80211_key k, *key = NULL; 
    const struct ieee80211_cipher *cip;
    struct ieee80211_node_table *nt = &ic->ic_sta;
    struct ieee80211_node *sender=NULL;

    /* 
     * Verify if WEP is set and
     * retrieve the key index from the packet.
     */
    wh = (struct ieee80211_frame *)wbuf_header(wbuf);
    buf = (u_int8_t*)wbuf_raw_data(wbuf);

    if (wh->i_fc[1] & IEEE80211_FC1_WEP) {

        off = ieee80211_anyhdrspace(ic, wh);
        kid = buf[off+IEEE80211_WEP_IVLEN] >> 6;

        sender = ieee80211_find_node(nt, wh->i_addr2);
        if(sender == NULL) {
            IEEE80211_DPRINTF(vap, IEEE80211_MSG_CRYPTO, "%s: Node not found\n",
                                                __func__);
            goto bad; 
        }

        /* 
         * Using the key index specified in the packet.
         */
        if (kid >= IEEE80211_WEP_NKID) {
	    IEEE80211_DPRINTF(vap, IEEE80211_MSG_CRYPTO, "%s: Incorrect keyid (%d) specified in the packet!\n",
                                             __func__, kid);
            goto bad;
        }
        key = &vap->iv_nw_keys[kid];
        cip = key->wk_cipher;
        if (cip->ic_cipher != IEEE80211_CIPHER_WEP) {
            ieee80211_free_node(sender);
            return 1;
        }
        hdrspace = ieee80211_hdrspace(ic, wh);

        IEEE80211_DPRINTF(vap, IEEE80211_MSG_CRYPTO, "%s: kid=%d, ni=0x%p, sender=0x%p, vap=0x%p\n",
                                             __func__, kid, ni, sender, vap);
        /*
         * Create a temporary key for installing the
         * rx key for the station.
         */
        OS_MEMCPY(&k, key, sizeof(*key));
        k.wk_flags |= IEEE80211_KEY_SWCRYPT;

        if (cip->ic_decap(&k, wbuf, hdrspace, rs) ) {
            IEEE80211_DPRINTF(vap, IEEE80211_MSG_CRYPTO, "Decrypt using entry(s) %d worked.\n",
                                                 key->wk_keyix);
            wh = (struct ieee80211_frame *)wbuf_header(wbuf);
            /*
             * The packet has been decrypted correctly, therefore the WEP bit 
             * should be cleared.
             */
            wh->i_fc[1] &= ~IEEE80211_FC1_WEP;
            k.wk_flags &= ~IEEE80211_KEY_SWCRYPT;

            if (!crypto_installkey(&k, vap, sender))
                goto bad; 
            sender->ni_wep_mbssid.rxvapkey = key;
	    
            if(vap->iv_opmode == IEEE80211_M_STA) {
                if (!crypto_install_mcastkey(&k, vap, sender))
                    goto bad;
            }
            ieee80211_free_node(sender);
            key->wk_private = k.wk_private;
            return 1;
        } else 
            IEEE80211_DPRINTF(vap, IEEE80211_MSG_CRYPTO, "Decrypt using entry(s) %d didn't work.\n", 
                                                  key->wk_keyix);
    } /* if wep is enabled */