/* * 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; }
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; }
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; }
/* * 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; } }
/* * 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 */