Index: freebsd/sys/net80211/ieee80211_crypto_ccmp.c
===================================================================
--- freebsd/sys/net80211/ieee80211_crypto_ccmp.c	(revision 66659ff1ad6831b0ea7425fa6ecd8a8687523658)
+++ freebsd/sys/net80211/ieee80211_crypto_ccmp.c	(revision a241ea8e924154a217768b6e4910a62e0d25cfe2)
@@ -66,5 +66,6 @@
 static	void ccmp_detach(struct ieee80211_key *);
 static	int ccmp_setkey(struct ieee80211_key *);
-static	int ccmp_encap(struct ieee80211_key *k, struct mbuf *, uint8_t keyid);
+static	void ccmp_setiv(struct ieee80211_key *, uint8_t *);
+static	int ccmp_encap(struct ieee80211_key *, struct mbuf *);
 static	int ccmp_decap(struct ieee80211_key *, struct mbuf *, int);
 static	int ccmp_enmic(struct ieee80211_key *, struct mbuf *, int);
@@ -81,4 +82,5 @@
 	.ic_detach	= ccmp_detach,
 	.ic_setkey	= ccmp_setkey,
+	.ic_setiv	= ccmp_setiv,
 	.ic_encap	= ccmp_encap,
 	.ic_decap	= ccmp_decap,
@@ -99,6 +101,6 @@
 	struct ccmp_ctx *ctx;
 
-	ctx = (struct ccmp_ctx *) malloc(sizeof(struct ccmp_ctx),
-		M_80211_CRYPTO, M_NOWAIT | M_ZERO);
+	ctx = (struct ccmp_ctx *) IEEE80211_MALLOC(sizeof(struct ccmp_ctx),
+		M_80211_CRYPTO, IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
 	if (ctx == NULL) {
 		vap->iv_stats.is_crypto_nomem++;
@@ -116,5 +118,5 @@
 	struct ccmp_ctx *ctx = k->wk_private;
 
-	free(ctx, M_80211_CRYPTO);
+	IEEE80211_FREE(ctx, M_80211_CRYPTO);
 	KASSERT(nrefs > 0, ("imbalanced attach/detach"));
 	nrefs--;			/* NB: we assume caller locking */
@@ -137,28 +139,14 @@
 }
 
-/*
- * Add privacy headers appropriate for the specified key.
- */
-static int
-ccmp_encap(struct ieee80211_key *k, struct mbuf *m, uint8_t keyid)
+static void
+ccmp_setiv(struct ieee80211_key *k, uint8_t *ivp)
 {
 	struct ccmp_ctx *ctx = k->wk_private;
-	struct ieee80211com *ic = ctx->cc_ic;
-	uint8_t *ivp;
-	int hdrlen;
-
-	hdrlen = ieee80211_hdrspace(ic, mtod(m, void *));
-
-	/*
-	 * Copy down 802.11 header and add the IV, KeyID, and ExtIV.
-	 */
-	M_PREPEND(m, ccmp.ic_header, M_NOWAIT);
-	if (m == NULL)
-		return 0;
-	ivp = mtod(m, uint8_t *);
-	ovbcopy(ivp + ccmp.ic_header, ivp, hdrlen);
-	ivp += hdrlen;
-
-	k->wk_keytsc++;		/* XXX wrap at 48 bits */
+	struct ieee80211vap *vap = ctx->cc_vap;
+	uint8_t keyid;
+
+	keyid = ieee80211_crypto_get_keyid(vap, k) << 6;
+
+	k->wk_keytsc++;
 	ivp[0] = k->wk_keytsc >> 0;		/* PN0 */
 	ivp[1] = k->wk_keytsc >> 8;		/* PN1 */
@@ -169,7 +157,48 @@
 	ivp[6] = k->wk_keytsc >> 32;		/* PN4 */
 	ivp[7] = k->wk_keytsc >> 40;		/* PN5 */
-
-	/*
-	 * Finally, do software encrypt if neeed.
+}
+
+/*
+ * Add privacy headers appropriate for the specified key.
+ */
+static int
+ccmp_encap(struct ieee80211_key *k, struct mbuf *m)
+{
+	const struct ieee80211_frame *wh;
+	struct ccmp_ctx *ctx = k->wk_private;
+	struct ieee80211com *ic = ctx->cc_ic;
+	uint8_t *ivp;
+	int hdrlen;
+	int is_mgmt;
+
+	hdrlen = ieee80211_hdrspace(ic, mtod(m, void *));
+	wh = mtod(m, const struct ieee80211_frame *);
+	is_mgmt = IEEE80211_IS_MGMT(wh);
+
+	/*
+	 * Check to see if we need to insert IV/MIC.
+	 *
+	 * Some offload devices don't require the IV to be inserted
+	 * as part of the hardware encryption.
+	 */
+	if (is_mgmt && (k->wk_flags & IEEE80211_KEY_NOIVMGT))
+		return 1;
+	if ((! is_mgmt) && (k->wk_flags & IEEE80211_KEY_NOIV))
+		return 1;
+
+	/*
+	 * Copy down 802.11 header and add the IV, KeyID, and ExtIV.
+	 */
+	M_PREPEND(m, ccmp.ic_header, M_NOWAIT);
+	if (m == NULL)
+		return 0;
+	ivp = mtod(m, uint8_t *);
+	ovbcopy(ivp + ccmp.ic_header, ivp, hdrlen);
+	ivp += hdrlen;
+
+	ccmp_setiv(k, ivp);
+
+	/*
+	 * Finally, do software encrypt if needed.
 	 */
 	if ((k->wk_flags & IEEE80211_KEY_SWENCRYPT) &&
@@ -206,4 +235,5 @@
 ccmp_decap(struct ieee80211_key *k, struct mbuf *m, int hdrlen)
 {
+	const struct ieee80211_rx_stats *rxs;
 	struct ccmp_ctx *ctx = k->wk_private;
 	struct ieee80211vap *vap = ctx->cc_vap;
@@ -211,4 +241,9 @@
 	uint8_t *ivp, tid;
 	uint64_t pn;
+
+	rxs = ieee80211_get_rx_params_ptr(m);
+
+	if ((rxs != NULL) && (rxs->c_pktflags & IEEE80211_RX_F_IV_STRIP))
+		goto finish;
 
 	/*
@@ -250,15 +285,26 @@
 		return 0;
 
+finish:
 	/*
 	 * Copy up 802.11 header and strip crypto bits.
 	 */
-	ovbcopy(mtod(m, void *), mtod(m, uint8_t *) + ccmp.ic_header, hdrlen);
-	m_adj(m, ccmp.ic_header);
-	m_adj(m, -ccmp.ic_trailer);
+	if (! ((rxs != NULL) && (rxs->c_pktflags & IEEE80211_RX_F_IV_STRIP))) {
+		ovbcopy(mtod(m, void *), mtod(m, uint8_t *) + ccmp.ic_header,
+		    hdrlen);
+		m_adj(m, ccmp.ic_header);
+	}
+
+	/*
+	 * XXX TODO: see if MMIC_STRIP also covers CCMP MIC trailer.
+	 */
+	if (! ((rxs != NULL) && (rxs->c_pktflags & IEEE80211_RX_F_MMIC_STRIP)))
+		m_adj(m, -ccmp.ic_trailer);
 
 	/*
 	 * Ok to update rsc now.
 	 */
-	k->wk_keyrsc[tid] = pn;
+	if (! ((rxs != NULL) && (rxs->c_pktflags & IEEE80211_RX_F_IV_STRIP))) {
+		k->wk_keyrsc[tid] = pn;
+	}
 
 	return 1;
