Ejemplo n.º 1
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;
}
Ejemplo n.º 2
0
/*
 * Context: softIRQ (tasklet)
 */
void
ieee80211_input_monitor(struct ieee80211com *ic, struct sk_buff *skb,
	const struct ath_buf *bf, int tx, u_int64_t mactime, struct ath_softc *sc)
{
	struct ieee80211vap *vap, *next;
	struct ath_desc *ds = bf->bf_desc;
	int noise = 0, antenna = 0, ieeerate = 0;
	u_int32_t rssi = 0;
	u_int8_t pkttype = 0;
	unsigned int mon_hdrspace = A_MAX(sizeof(struct ath_tx_radiotap_header),
				    (A_MAX(sizeof(struct wlan_ng_prism2_header),
					   ATHDESC_HEADER_SIZE)));

	if ((skb_headroom(skb) < mon_hdrspace) &&
			pskb_expand_head(skb, mon_hdrspace, 0, GFP_ATOMIC)) {
		printk("No headroom for monitor header - %s:%d %s\n", 
				__FILE__, __LINE__, __func__);
		return;
	}

	if (tx) {
		rssi = bf->bf_dsstatus.ds_txstat.ts_rssi;
		antenna = bf->bf_dsstatus.ds_txstat.ts_antenna;
		ieeerate = sc->sc_hwmap[bf->bf_dsstatus.ds_txstat.ts_rate].ieeerate;
	} else {
		rssi = bf->bf_dsstatus.ds_rxstat.rs_rssi;
		antenna = bf->bf_dsstatus.ds_rxstat.rs_antenna;
		ieeerate = sc->sc_hwmap[bf->bf_dsstatus.ds_rxstat.rs_rate].ieeerate;
	}

	noise = bf->bf_channoise;

	/* XXX locking */
	for (vap = TAILQ_FIRST(&ic->ic_vaps); vap != NULL; vap = next) {
		struct sk_buff *skb1;
		struct net_device *dev = vap->iv_dev;
		struct ieee80211_frame *wh = (struct ieee80211_frame *)skb->data;
		u_int8_t dir = wh->i_fc[1] & IEEE80211_FC1_DIR_MASK;

		next = TAILQ_NEXT(vap, iv_next);
		/* If we have rx'd an error frame... */
		if (!tx && bf->bf_dsstatus.ds_rxstat.rs_status != 0) {

			/* Discard PHY errors if necessary */
			if (bf->bf_dsstatus.ds_rxstat.rs_status & HAL_RXERR_PHY) {
				if (vap->iv_monitor_phy_errors == 0) continue;
			}

			/* Discard CRC errors if necessary */
			if (bf->bf_dsstatus.ds_rxstat.rs_status & HAL_RXERR_CRC) {
				if (vap->iv_monitor_crc_errors == 0) continue;
			}

			/* Accept PHY, CRC and decrypt errors. Discard the rest. */
			if (bf->bf_dsstatus.ds_rxstat.rs_status &~
					(HAL_RXERR_DECRYPT | HAL_RXERR_MIC |
					 HAL_RXERR_PHY | HAL_RXERR_CRC))
				continue;

			/* We can't use addr1 to determine direction at this point */
			pkttype = PACKET_HOST;
		} else {
			/* 
			 * The frame passed its CRC, so we can rely
			 * on the contents of the frame to set pkttype.
			 */
			if (tx)
				pkttype = PACKET_OUTGOING;
			else if (IEEE80211_IS_MULTICAST(wh->i_addr1)) {
				if (IEEE80211_ADDR_EQ(wh->i_addr1, dev->broadcast))
					pkttype = PACKET_BROADCAST;
				else
					pkttype = PACKET_MULTICAST;
			} else
				pkttype = PACKET_HOST;
		}

		if (vap->iv_opmode != IEEE80211_M_MONITOR ||
		    vap->iv_state != IEEE80211_S_RUN)
			continue;
		if (vap->iv_monitor_nods_only &&
		    dir != IEEE80211_FC1_DIR_NODS) {
			/* don't rx fromds, tods, or dstods packets */
			continue;
		}
		skb1 = skb_copy(skb, GFP_ATOMIC);
		if (skb1 == NULL) {
			/* XXX stat+msg */
			continue;
		}
		ieee80211_skb_copy_noderef(skb, skb1);

		if (vap->iv_monitor_txf_len && tx) {
			/* truncate transmit feedback packets */
			skb_trim(skb1, vap->iv_monitor_txf_len);
			skb_reset_network_header(skb1);
		}
		switch (vap->iv_dev->type) {
		case ARPHRD_IEEE80211:
			break;
		case ARPHRD_IEEE80211_PRISM: {
			struct wlan_ng_prism2_header *ph;
			if (skb_headroom(skb1) < sizeof(struct wlan_ng_prism2_header)) {
				ieee80211_dev_kfree_skb(&skb1);
				break;
			}

			ph = (struct wlan_ng_prism2_header *)
				skb_push(skb1, sizeof(struct wlan_ng_prism2_header));
			memset(ph, 0, sizeof(struct wlan_ng_prism2_header));

			ph->msgcode = DIDmsg_lnxind_wlansniffrm;
			ph->msglen = sizeof(struct wlan_ng_prism2_header);
			strncpy(ph->devname, dev->name, sizeof(ph->devname));

			ph->hosttime.did = DIDmsg_lnxind_wlansniffrm_hosttime;
			ph->hosttime.status = 0;
			ph->hosttime.len = 4;
			ph->hosttime.data = jiffies;

			/* Pass up tsf clock in mactime */
			/* NB: the prism mactime field is 32bit, so we lose TSF precision here */
			ph->mactime.did = DIDmsg_lnxind_wlansniffrm_mactime;
			ph->mactime.status = 0;
			ph->mactime.len = 4;
			ph->mactime.data = mactime;

			ph->istx.did = DIDmsg_lnxind_wlansniffrm_istx;
			ph->istx.status = 0;
			ph->istx.len = 4;
			ph->istx.data = tx ? P80211ENUM_truth_true : P80211ENUM_truth_false;

			ph->frmlen.did = DIDmsg_lnxind_wlansniffrm_frmlen;
			ph->frmlen.status = 0;
			ph->frmlen.len = 4;
			ph->frmlen.data = skb->len;

			ph->channel.did = DIDmsg_lnxind_wlansniffrm_channel;
			ph->channel.status = 0;
			ph->channel.len = 4;
			ph->channel.data =
				ieee80211_mhz2ieee(ic->ic_curchan->ic_freq,
					ic->ic_curchan->ic_flags);

			ph->rssi.did = DIDmsg_lnxind_wlansniffrm_rssi;
			ph->rssi.status = 0;
			ph->rssi.len = 4;
			ph->rssi.data = rssi;

			ph->noise.did = DIDmsg_lnxind_wlansniffrm_noise;
			ph->noise.status = 0;
			ph->noise.len = 4;
			ph->noise.data = noise;

			ph->signal.did = DIDmsg_lnxind_wlansniffrm_signal;
			ph->signal.status = 0;
			ph->signal.len = 4;
			ph->signal.data = rssi + noise;

			ph->rate.did = DIDmsg_lnxind_wlansniffrm_rate;
			ph->rate.status = 0;
			ph->rate.len = 4;
			ph->rate.data = ieeerate;
			break;
		}
		case ARPHRD_IEEE80211_RADIOTAP: {
			if (tx) {
				struct ath_tx_radiotap_header *th;
				if (skb_headroom(skb1) < sizeof(struct ath_tx_radiotap_header)) {
					printk("%s:%d %s\n", __FILE__, __LINE__, __func__);
					ieee80211_dev_kfree_skb(&skb1);
					break;
				}

				th = (struct ath_tx_radiotap_header *) skb_push(skb1,
					sizeof(struct ath_tx_radiotap_header));
				memset(th, 0, sizeof(struct ath_tx_radiotap_header));
				th->wt_ihdr.it_version = 0;
				th->wt_ihdr.it_len = cpu_to_le16(sizeof(struct ath_tx_radiotap_header));
				th->wt_ihdr.it_present = cpu_to_le32(ATH_TX_RADIOTAP_PRESENT);

				/* radiotap's TSF field is the full 64 bits, so we don't lose
				 * any TSF precision when using radiotap */
				th->wt_tsft = cpu_to_le64(mactime);

				th->wt_flags = 0;
				th->wt_rate = ieeerate;
				th->wt_antenna = antenna;
				th->wt_pad = 0;

				if (bf->bf_dsstatus.ds_txstat.ts_status & HAL_TXERR_XRETRY)
					th->wt_txflags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_FAIL);

				th->wt_dataretries = bf->bf_dsstatus.ds_txstat.ts_shortretry + bf->bf_dsstatus.ds_txstat.ts_longretry;

			} else {
				struct ath_rx_radiotap_header *th;
				if (skb_headroom(skb1) < sizeof(struct ath_rx_radiotap_header)) {
					printk("%s:%d %s\n", __FILE__, __LINE__, __func__);
					ieee80211_dev_kfree_skb(&skb1);
					break;
				}

				th = (struct ath_rx_radiotap_header *) skb_push(skb1,
					sizeof(struct ath_rx_radiotap_header));
				memset(th, 0, sizeof(struct ath_rx_radiotap_header));
				th->wr_ihdr.it_version = 0;
				th->wr_ihdr.it_len = cpu_to_le16(sizeof(struct ath_rx_radiotap_header));
				th->wr_ihdr.it_present = cpu_to_le32(ATH_RX_RADIOTAP_PRESENT);

				if (ic->ic_flags & IEEE80211_F_SHPREAMBLE)
					th->wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
				if (bf->bf_dsstatus.ds_rxstat.rs_status & HAL_RXERR_CRC)
					th->wr_flags |= IEEE80211_RADIOTAP_F_BADFCS;
				if (skb->len >= IEEE80211_CRC_LEN)
					th->wr_flags |= IEEE80211_RADIOTAP_F_FCS;

				th->wr_rate = ieeerate;
				th->wr_chan_freq = cpu_to_le16(ic->ic_curchan->ic_freq);

				/* Define the channel flags for radiotap */
				switch (sc->sc_curmode) {
					case IEEE80211_MODE_11A:
						th->wr_chan_flags =
							cpu_to_le16(IEEE80211_CHAN_A);
						break;
					case IEEE80211_MODE_TURBO_A:
						th->wr_chan_flags =
							cpu_to_le16(IEEE80211_CHAN_TA);
						break;
					case IEEE80211_MODE_11B:
						th->wr_chan_flags =
							cpu_to_le16(IEEE80211_CHAN_B);
						break;
					case IEEE80211_MODE_11G:
						th->wr_chan_flags =
							cpu_to_le16(IEEE80211_CHAN_G);
						break;
					case IEEE80211_MODE_TURBO_G:
						th->wr_chan_flags =
							cpu_to_le16(IEEE80211_CHAN_TG);
						break;
					default:
						th->wr_chan_flags = 0; /* unknown */
						break;
				}

				th->wr_dbm_antnoise = (int8_t) noise;
				th->wr_dbm_antsignal = 
					th->wr_dbm_antnoise + rssi;
				th->wr_antenna = antenna;
				th->wr_antsignal = rssi;

				th->wr_tsft = cpu_to_le64(mactime);
			}
			break;
		}
		case ARPHRD_IEEE80211_ATHDESC: {
			if (skb_headroom(skb1) < ATHDESC_HEADER_SIZE) {
				printk("%s:%d %s\n", __FILE__, 
						__LINE__, __func__);
				ieee80211_dev_kfree_skb(&skb1);
				break;
			}
			memcpy(skb_push(skb1, ATHDESC_HEADER_SIZE), 
					ds, ATHDESC_HEADER_SIZE);
			break;
		}
		default:
			break;
		}
		if (skb1 != NULL) {
			if (!tx && (skb1->len >= IEEE80211_CRC_LEN) && 
					(vap->iv_dev->type != 
					 ARPHRD_IEEE80211_RADIOTAP)) {
				/* Remove FCS from end of RX frames when
				 * delivering to non-Radiotap VAPs. */
				skb_trim(skb1, skb1->len - IEEE80211_CRC_LEN);
			}
			skb1->dev = dev; /* NB: deliver to wlanX */
			skb_reset_mac_header(skb1);

			skb1->ip_summed = CHECKSUM_NONE;
			skb1->pkt_type = pkttype;
			skb1->protocol = 
				__constant_htons(0x0019); /* ETH_P_80211_RAW */

			if (netif_rx(skb1) == NET_RX_DROP) {
				/* If netif_rx dropped the packet because 
				 * device was too busy, reclaim the ref. in 
				 * the skb. */
				if (SKB_CB(skb1)->ni != NULL)
					ieee80211_unref_node(&SKB_CB(skb1)->ni);
				vap->iv_devstats.rx_dropped++;
			}

			vap->iv_devstats.rx_packets++;
			vap->iv_devstats.rx_bytes += skb1->len;
		}
	}
}
Ejemplo n.º 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 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;
}
Ejemplo n.º 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];
	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;
	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 = ieee80211_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;
	}
	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;
}