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)); }
int ccmp_encrypt(struct ieee80211_key *key, wbuf_t wbuf0, int hdrlen, int mfp) { struct ccmp_ctx *ctx = key->wk_private; struct ieee80211_frame *wh; wbuf_t wbuf = wbuf0; int data_len, i, space; uint8_t aad[2 * AES_BLOCK_LEN], b0[AES_BLOCK_LEN], b[AES_BLOCK_LEN], e[AES_BLOCK_LEN], s0[AES_BLOCK_LEN]; uint8_t *pos; ctx->cc_vap->iv_stats.is_crypto_ccmp++; wh = (struct ieee80211_frame *)wbuf_header(wbuf); data_len = wbuf_get_pktlen(wbuf) - (hdrlen + ccmp.ic_header); ccmp_init_blocks(&ctx->cc_aes, wh, key->wk_keytsc, data_len, b0, aad, b, s0, mfp); i = 1; pos = (u_int8_t *)wbuf_header(wbuf) + hdrlen + ccmp.ic_header; /* NB: assumes header is entirely in first mbuf */ space = wbuf_get_pktlen(wbuf) - (hdrlen + ccmp.ic_header); for (;;) { if (space > data_len) space = data_len; /* * Do full blocks. */ while (space >= AES_BLOCK_LEN) { CCMP_ENCRYPT(i, b, b0, pos, e, AES_BLOCK_LEN); pos += AES_BLOCK_LEN, space -= AES_BLOCK_LEN; data_len -= AES_BLOCK_LEN; i++; } if (data_len <= 0) /* no more data */ break; wbuf = wbuf_next(wbuf); if (wbuf == NULL) { /* last buffer */ if (space != 0) { /* * Short last block. */ CCMP_ENCRYPT(i, b, b0, pos, e, space); } break; } #if 1 /* assume only one chunk */ break; #else if (space != 0) { uint8_t *pos_next; int space_next; int len, dl, sp; wbuf_t wbufi_new; /* * Block straddles one or more mbufs, gather data * into the block buffer b, apply the cipher, then * scatter the results back into the mbuf chain. * The buffer will automatically get space bytes * of data at offset 0 copied in+out by the * CCMP_ENCRYPT request so we must take care of * the remaining data. */ wbuf_new = wbuf; dl = data_len; sp = space; for (;;) { pos_next = (u_int8_t *)wbuf_header(wbuf_new); len = min(dl, AES_BLOCK_LEN); space_next = len > sp ? len - sp : 0; if (wbuf_get_len(wbuf_new) >= space_next) { /* * This mbuf has enough data; just grab * what we need and stop. */ xor_block(b+sp, pos_next, space_next); break; } /* * This mbuf's contents are insufficient, * take 'em all and prepare to advance to * the next mbuf. */ xor_block(b+sp, pos_next, n->m_len); sp += wbuf_get_len(wbuf_new), dl -= wbuf_get_len(wbuf_new); wbuf_next = m_next; if (n == NULL) break; } CCMP_ENCRYPT(i, b, b0, pos, e, space); /* NB: just like above, but scatter data to mbufs */ dl = data_len; sp = space; for (;;) { pos_next = mtod(m, uint8_t *); len = min(dl, AES_BLOCK_LEN); space_next = len > sp ? len - sp : 0; if (m->m_len >= space_next) { xor_block(pos_next, e+sp, space_next); break; } xor_block(pos_next, e+sp, m->m_len); sp += m->m_len, dl -= m->m_len; m = m->m_next; if (m == NULL) goto done; } /* * Do bookkeeping. m now points to the last mbuf * we grabbed data from. We know we consumed a * full block of data as otherwise we'd have hit * the end of the mbuf chain, so deduct from data_len. * Otherwise advance the block number (i) and setup * pos+space to reflect contents of the new mbuf. */ data_len -= AES_BLOCK_LEN; i++; pos = pos_next + space_next; space = m->m_len - space_next; } else {
/* * Save an outbound packet for a node in power-save sleep state. * The new packet is placed on the node's saved queue, and the TIM * is changed, if necessary. */ void ieee80211_node_saveq_queue(struct ieee80211_node *ni, wbuf_t wbuf, u_int8_t frame_type) { struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = ni->ni_ic; int qlen, age; struct node_powersave_queue *dataq,*mgtq,*psq; struct ieee80211_tx_status ts; #if LMAC_SUPPORT_POWERSAVE_QUEUE /* mark the frame and will give to ath layer */ wbuf_set_legacy_ps(wbuf); if (ic->ic_get_lmac_pwrsaveq_len(ic, ni, 0) == 0 && vap->iv_set_tim != NULL) { vap->iv_set_tim(ni, 1, false); } return; #endif dataq = IEEE80211_NODE_SAVEQ_DATAQ(ni); mgtq = IEEE80211_NODE_SAVEQ_MGMTQ(ni); IEEE80211_NODE_SAVEQ_LOCK(dataq); IEEE80211_NODE_SAVEQ_LOCK(mgtq); if (frame_type == IEEE80211_FC0_TYPE_MGT) { psq = mgtq; } else { psq = dataq; } if (IEEE80211_NODE_SAVEQ_FULL(psq)) { IEEE80211_NODE_SAVEQ_UNLOCK(mgtq); IEEE80211_NODE_SAVEQ_UNLOCK(dataq); IEEE80211_NOTE(vap, IEEE80211_MSG_ANY, ni, "%s pwr save q: overflow, drops (size %d) \n", (psq == dataq) ? "data" : "mgt", IEEE80211_PS_MAX_QUEUE); IEEE80211_NODE_STAT(ni,psq_drops); #ifdef IEEE80211_DEBUG if (ieee80211_msg_dumppkts(vap)) ieee80211_dump_pkt(ni->ni_ic, wtod(wbuf, caddr_t), wbuf_get_len(wbuf), -1, -1); #endif ts.ts_flags = IEEE80211_TX_ERROR; ieee80211_release_wbuf(ni,wbuf, &ts); return; } /* * special handling of frames with PS = 1. */ ieee80211_node_saveq_handle_ps_frames(ni,wbuf,frame_type); /* * Tag the frame with it's expiry time and insert * it in the queue. The aging interval is 4 times * the listen interval specified by the station. * Frames that sit around too long are reclaimed * using this information. */ age = ((ni->ni_intval * ic->ic_lintval) << 2) >> 10; /* TU -> secs */ /* * Note: our aging algorithm is not working well. In fact, due to the long interval * when the aging algorithm is called (IEEE80211_INACT_WAIT is 15 secs), we depend on * the associated station node to be disassociated to clear its stale frames. However, * as a temporary fix, I will make sure that the age is at least greater than * IEEE80211_INACT_WAIT. Otherwise, we will discard all frames in ps queue even though * it is just queued. */ if (age < IEEE80211_INACT_WAIT) { IEEE80211_NOTE(vap, IEEE80211_MSG_POWER, ni, "%s Note: increased age from %d to %d secs.\n", __func__, age, IEEE80211_INACT_WAIT); age = IEEE80211_INACT_WAIT; } IEEE80211_NODE_SAVEQ_ENQUEUE(psq, wbuf, qlen, age); /* * calculate the combined queue length of management and data queues. */ qlen = IEEE80211_NODE_SAVEQ_QLEN(dataq); qlen += IEEE80211_NODE_SAVEQ_QLEN(mgtq); IEEE80211_NODE_SAVEQ_UNLOCK(mgtq); IEEE80211_NODE_SAVEQ_UNLOCK(dataq); IEEE80211_NOTE(vap, IEEE80211_MSG_POWER, ni, "%s pwr queue:save frame, %u now queued \n", (psq == dataq) ? "data" : "mgt" ,qlen); if (qlen == 1 && vap->iv_set_tim != NULL) vap->iv_set_tim(ni, 1, false); }