示例#1
0
void read_real_data(struct params *p, struct ieee80211_frame *wh, int len)
{
	char dst[6];
	int rc;
	char *ptr = (char*) (wh+1);

	/* stuff not for this net */
	if (memcmp(wh->i_addr1, p->mac, 6) != 0)
		return;

	/* relay data */
	if (memcmp(wh->i_addr3, p->mac, 6) != 0)
		relay_data(p, wh, len);

	memcpy(dst, wh->i_addr3, 6);


	if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
		if (!p->wep_len) {
			printf("Got wep but i aint wep\n");
			return;
		}
		
		if (wep_decrypt(wh, len, p->wep_key, p->wep_len) == -1){
			printf("Can't decrypt\n");
			return;
		}

		ptr += 4;
		len -= 8;
	}

	/* ether header */
	ptr += 8 - 2;
	ptr -= 6;
	memcpy(ptr, wh->i_addr2, 6);
	ptr -= 6;
	memcpy(ptr, dst, 6);

	len -= sizeof(*wh);
	len -= 8;
	len += 14;

	/* send to tap */
	rc = write(p->tap, ptr, len);
	if (rc == -1)
		err(1, "write()");
	if (rc != len) {
		printf("Wrote %d/%d\n", rc, len);
		exit(1);
	}
}
示例#2
0
/*----------------------------------------------------------------
* p80211pb_80211_to_ether
*
* Uses the contents of a received 802.11 frame and the etherconv
* setting to build an ether frame.
*
* This function extracts the src and dest address from the 802.11
* frame to use in the construction of the eth frame.
*
* Arguments:
*	ethconv		Conversion type to perform
*	skb		Packet buffer containing the 802.11 frame
*
* Returns:
*	0 on success, non-zero otherwise
*
* Call context:
*	May be called in interrupt or non-interrupt context
----------------------------------------------------------------*/
int skb_p80211_to_ether(wlandevice_t *wlandev, u32 ethconv,
			struct sk_buff *skb)
{
	netdevice_t *netdev = wlandev->netdev;
	u16 fc;
	unsigned int payload_length;
	unsigned int payload_offset;
	u8 daddr[WLAN_ETHADDR_LEN];
	u8 saddr[WLAN_ETHADDR_LEN];
	union p80211_hdr *w_hdr;
	struct wlan_ethhdr *e_hdr;
	struct wlan_llc *e_llc;
	struct wlan_snap *e_snap;

	int foo;

	payload_length = skb->len - WLAN_HDR_A3_LEN - WLAN_CRC_LEN;
	payload_offset = WLAN_HDR_A3_LEN;

	w_hdr = (union p80211_hdr *) skb->data;

	/* setup some vars for convenience */
	fc = le16_to_cpu(w_hdr->a3.fc);
	if ((WLAN_GET_FC_TODS(fc) == 0) && (WLAN_GET_FC_FROMDS(fc) == 0)) {
		memcpy(daddr, w_hdr->a3.a1, WLAN_ETHADDR_LEN);
		memcpy(saddr, w_hdr->a3.a2, WLAN_ETHADDR_LEN);
	} else if ((WLAN_GET_FC_TODS(fc) == 0)
			&& (WLAN_GET_FC_FROMDS(fc) == 1)) {
		memcpy(daddr, w_hdr->a3.a1, WLAN_ETHADDR_LEN);
		memcpy(saddr, w_hdr->a3.a3, WLAN_ETHADDR_LEN);
	} else if ((WLAN_GET_FC_TODS(fc) == 1)
			&& (WLAN_GET_FC_FROMDS(fc) == 0)) {
		memcpy(daddr, w_hdr->a3.a3, WLAN_ETHADDR_LEN);
		memcpy(saddr, w_hdr->a3.a2, WLAN_ETHADDR_LEN);
	} else {
		payload_offset = WLAN_HDR_A4_LEN;
		if (payload_length < WLAN_HDR_A4_LEN - WLAN_HDR_A3_LEN) {
;
			return 1;
		}
		payload_length -= (WLAN_HDR_A4_LEN - WLAN_HDR_A3_LEN);
		memcpy(daddr, w_hdr->a4.a3, WLAN_ETHADDR_LEN);
		memcpy(saddr, w_hdr->a4.a4, WLAN_ETHADDR_LEN);
	}

	/* perform de-wep if necessary.. */
	if ((wlandev->hostwep & HOSTWEP_PRIVACYINVOKED) && WLAN_GET_FC_ISWEP(fc)
	    && (wlandev->hostwep & HOSTWEP_DECRYPT)) {
		if (payload_length <= 8) {
//			printk(KERN_ERR "WEP frame too short (%u).\n",
;
			return 1;
		}
		foo = wep_decrypt(wlandev, skb->data + payload_offset + 4,
				       payload_length - 8, -1,
				       skb->data + payload_offset,
				       skb->data + payload_offset +
				       payload_length - 4);
		if (foo) {
			/* de-wep failed, drop skb. */
			pr_debug("Host de-WEP failed, dropping frame (%d).\n",
				 foo);
			wlandev->rx.decrypt_err++;
			return 2;
		}

		/* subtract the IV+ICV length off the payload */
		payload_length -= 8;
		/* chop off the IV */
		skb_pull(skb, 4);
		/* chop off the ICV. */
		skb_trim(skb, skb->len - 4);

		wlandev->rx.decrypt++;
	}

	e_hdr = (struct wlan_ethhdr *) (skb->data + payload_offset);

	e_llc = (struct wlan_llc *) (skb->data + payload_offset);
	e_snap =
	    (struct wlan_snap *) (skb->data + payload_offset +
		sizeof(struct wlan_llc));

	/* Test for the various encodings */
	if ((payload_length >= sizeof(struct wlan_ethhdr)) &&
	    (e_llc->dsap != 0xaa || e_llc->ssap != 0xaa) &&
	    ((memcmp(daddr, e_hdr->daddr, WLAN_ETHADDR_LEN) == 0) ||
	     (memcmp(saddr, e_hdr->saddr, WLAN_ETHADDR_LEN) == 0))) {
		pr_debug("802.3 ENCAP len: %d\n", payload_length);
		/* 802.3 Encapsulated */
		/* Test for an overlength frame */
		if (payload_length > (netdev->mtu + WLAN_ETHHDR_LEN)) {
			/* A bogus length ethfrm has been encap'd. */
			/* Is someone trying an oflow attack? */
//			printk(KERN_ERR "ENCAP frame too large (%d > %d)\n",
;
			return 1;
		}

		/* Chop off the 802.11 header.  it's already sane. */
		skb_pull(skb, payload_offset);
		/* chop off the 802.11 CRC */
		skb_trim(skb, skb->len - WLAN_CRC_LEN);

	} else if ((payload_length >= sizeof(struct wlan_llc) +
		sizeof(struct wlan_snap))
		&& (e_llc->dsap == 0xaa)
		&& (e_llc->ssap == 0xaa)
		&& (e_llc->ctl == 0x03)
		   &&
		   (((memcmp(e_snap->oui, oui_rfc1042, WLAN_IEEE_OUI_LEN) == 0)
		     && (ethconv == WLAN_ETHCONV_8021h)
		     && (p80211_stt_findproto(le16_to_cpu(e_snap->type))))
		    || (memcmp(e_snap->oui, oui_rfc1042, WLAN_IEEE_OUI_LEN) !=
			0))) {
		pr_debug("SNAP+RFC1042 len: %d\n", payload_length);
		/* it's a SNAP + RFC1042 frame && protocol is in STT */
		/* build 802.3 + RFC1042 */

		/* Test for an overlength frame */
		if (payload_length > netdev->mtu) {
			/* A bogus length ethfrm has been sent. */
			/* Is someone trying an oflow attack? */
//			printk(KERN_ERR "SNAP frame too large (%d > %d)\n",
;
			return 1;
		}

		/* chop 802.11 header from skb. */
		skb_pull(skb, payload_offset);

		/* create 802.3 header at beginning of skb. */
		e_hdr = (struct wlan_ethhdr *) skb_push(skb, WLAN_ETHHDR_LEN);
		memcpy(e_hdr->daddr, daddr, WLAN_ETHADDR_LEN);
		memcpy(e_hdr->saddr, saddr, WLAN_ETHADDR_LEN);
		e_hdr->type = htons(payload_length);

		/* chop off the 802.11 CRC */
		skb_trim(skb, skb->len - WLAN_CRC_LEN);

	} else if ((payload_length >= sizeof(struct wlan_llc) +
		sizeof(struct wlan_snap))
		&& (e_llc->dsap == 0xaa)
		&& (e_llc->ssap == 0xaa)
		&& (e_llc->ctl == 0x03)) {
		pr_debug("802.1h/RFC1042 len: %d\n", payload_length);
		/* it's an 802.1h frame || (an RFC1042 && protocol not in STT)
		   build a DIXII + RFC894 */

		/* Test for an overlength frame */
		if ((payload_length - sizeof(struct wlan_llc) -
			sizeof(struct wlan_snap))
			> netdev->mtu) {
			/* A bogus length ethfrm has been sent. */
			/* Is someone trying an oflow attack? */
//			printk(KERN_ERR "DIXII frame too large (%ld > %d)\n",
//			       (long int)(payload_length -
//					sizeof(struct wlan_llc) -
;
			return 1;
		}

		/* chop 802.11 header from skb. */
		skb_pull(skb, payload_offset);

		/* chop llc header from skb. */
		skb_pull(skb, sizeof(struct wlan_llc));

		/* chop snap header from skb. */
		skb_pull(skb, sizeof(struct wlan_snap));

		/* create 802.3 header at beginning of skb. */
		e_hdr = (struct wlan_ethhdr *) skb_push(skb, WLAN_ETHHDR_LEN);
		e_hdr->type = e_snap->type;
		memcpy(e_hdr->daddr, daddr, WLAN_ETHADDR_LEN);
		memcpy(e_hdr->saddr, saddr, WLAN_ETHADDR_LEN);

		/* chop off the 802.11 CRC */
		skb_trim(skb, skb->len - WLAN_CRC_LEN);
	} else {
		pr_debug("NON-ENCAP len: %d\n", payload_length);
		/* any NON-ENCAP */
		/* it's a generic 80211+LLC or IPX 'Raw 802.3' */
		/*  build an 802.3 frame */
		/* allocate space and setup hostbuf */

		/* Test for an overlength frame */
		if (payload_length > netdev->mtu) {
			/* A bogus length ethfrm has been sent. */
			/* Is someone trying an oflow attack? */
//			printk(KERN_ERR "OTHER frame too large (%d > %d)\n",
;
			return 1;
		}

		/* Chop off the 802.11 header. */
		skb_pull(skb, payload_offset);

		/* create 802.3 header at beginning of skb. */
		e_hdr = (struct wlan_ethhdr *) skb_push(skb, WLAN_ETHHDR_LEN);
		memcpy(e_hdr->daddr, daddr, WLAN_ETHADDR_LEN);
		memcpy(e_hdr->saddr, saddr, WLAN_ETHADDR_LEN);
		e_hdr->type = htons(payload_length);

		/* chop off the 802.11 CRC */
		skb_trim(skb, skb->len - WLAN_CRC_LEN);

	}

	/*
	 * Note that eth_type_trans() expects an skb w/ skb->data pointing
	 * at the MAC header, it then sets the following skb members:
	 * skb->mac_header,
	 * skb->data, and
	 * skb->pkt_type.
	 * It then _returns_ the value that _we're_ supposed to stuff in
	 * skb->protocol.  This is nuts.
	 */
	skb->protocol = eth_type_trans(skb, netdev);

	/* jkriegl: process signal and noise as set in hfa384x_int_rx() */
	/* jkriegl: only process signal/noise if requested by iwspy */
	if (wlandev->spy_number)
		orinoco_spy_gather(wlandev, eth_hdr(skb)->h_source,
				   P80211SKB_RXMETA(skb));

	/* Free the metadata */
	p80211skb_rxmeta_detach(skb);

	return 0;
}
示例#3
0
static void rx_data_bss_prot(struct wlantest *wt,
			     const struct ieee80211_hdr *hdr, const u8 *qos,
			     const u8 *dst, const u8 *src, const u8 *data,
			     size_t len)
{
	struct wlantest_bss *bss;
	struct wlantest_sta *sta, *sta2;
	int keyid;
	u16 fc = le_to_host16(hdr->frame_control);
	u8 *decrypted;
	size_t dlen;
	int tid;
	u8 pn[6], *rsc;
	struct wlantest_tdls *tdls = NULL, *found;
	const u8 *tk = NULL;
	int ptk_iter_done = 0;
	int try_ptk_iter = 0;

	if (hdr->addr1[0] & 0x01) {
		rx_data_bss_prot_group(wt, hdr, qos, dst, src, data, len);
		return;
	}

	if (fc & WLAN_FC_TODS) {
		bss = bss_get(wt, hdr->addr1);
		if (bss == NULL)
			return;
		sta = sta_get(bss, hdr->addr2);
		if (sta)
			sta->counters[WLANTEST_STA_COUNTER_PROT_DATA_TX]++;
	} else if (fc & WLAN_FC_FROMDS) {
		bss = bss_get(wt, hdr->addr2);
		if (bss == NULL)
			return;
		sta = sta_get(bss, hdr->addr1);
	} else {
		bss = bss_get(wt, hdr->addr3);
		if (bss == NULL)
			return;
		sta = sta_find(bss, hdr->addr2);
		sta2 = sta_find(bss, hdr->addr1);
		if (sta == NULL || sta2 == NULL)
			return;
		found = NULL;
		dl_list_for_each(tdls, &bss->tdls, struct wlantest_tdls, list)
		{
			if ((tdls->init == sta && tdls->resp == sta2) ||
			    (tdls->init == sta2 && tdls->resp == sta)) {
				found = tdls;
				if (tdls->link_up)
					break;
			}
		}
		if (found) {
			if (!found->link_up)
				add_note(wt, MSG_DEBUG,
					 "TDLS: Link not up, but Data "
					 "frame seen");
			tk = found->tpk.tk;
			tdls = found;
		}
	}
	if ((sta == NULL ||
	     (!sta->ptk_set && sta->pairwise_cipher != WPA_CIPHER_WEP40)) &&
	    tk == NULL) {
		add_note(wt, MSG_MSGDUMP, "No PTK known to decrypt the frame");
		if (dl_list_empty(&wt->ptk))
			return;
		try_ptk_iter = 1;
	}

	if (len < 4) {
		add_note(wt, MSG_INFO, "Too short encrypted data frame");
		return;
	}

	if (sta == NULL)
		return;
	if (sta->pairwise_cipher & (WPA_CIPHER_TKIP | WPA_CIPHER_CCMP) &&
	    !(data[3] & 0x20)) {
		add_note(wt, MSG_INFO, "Expected TKIP/CCMP frame from "
			 MACSTR " did not have ExtIV bit set to 1",
			 MAC2STR(src));
		return;
	}

	if (tk == NULL && sta->pairwise_cipher == WPA_CIPHER_TKIP) {
		if (data[3] & 0x1f) {
			add_note(wt, MSG_INFO, "TKIP frame from " MACSTR
				 " used non-zero reserved bit",
				 MAC2STR(hdr->addr2));
		}
		if (data[1] != ((data[0] | 0x20) & 0x7f)) {
			add_note(wt, MSG_INFO, "TKIP frame from " MACSTR
				 " used incorrect WEPSeed[1] (was 0x%x, "
				 "expected 0x%x)",
				 MAC2STR(hdr->addr2), data[1],
				 (data[0] | 0x20) & 0x7f);
		}
	} else if (tk || sta->pairwise_cipher == WPA_CIPHER_CCMP) {
		if (data[2] != 0 || (data[3] & 0x1f) != 0) {
			add_note(wt, MSG_INFO, "CCMP frame from " MACSTR
				 " used non-zero reserved bit",
				 MAC2STR(hdr->addr2));
		}
	}

	keyid = data[3] >> 6;
	if (keyid != 0) {
		add_note(wt, MSG_INFO, "Unexpected non-zero KeyID %d in "
			 "individually addressed Data frame from " MACSTR,
			 keyid, MAC2STR(hdr->addr2));
	}

	if (qos) {
		tid = qos[0] & 0x0f;
		if (fc & WLAN_FC_TODS)
			sta->tx_tid[tid]++;
		else
			sta->rx_tid[tid]++;
	} else {
		tid = 0;
		if (fc & WLAN_FC_TODS)
			sta->tx_tid[16]++;
		else
			sta->rx_tid[16]++;
	}
	if (tk) {
		if (os_memcmp(hdr->addr2, tdls->init->addr, ETH_ALEN) == 0)
			rsc = tdls->rsc_init[tid];
		else
			rsc = tdls->rsc_resp[tid];
	} else if (fc & WLAN_FC_TODS)
		rsc = sta->rsc_tods[tid];
	else
		rsc = sta->rsc_fromds[tid];


	if (tk == NULL && sta->pairwise_cipher == WPA_CIPHER_TKIP)
		tkip_get_pn(pn, data);
	else if (sta->pairwise_cipher == WPA_CIPHER_WEP40)
		goto skip_replay_det;
	else
		ccmp_get_pn(pn, data);
	if (os_memcmp(pn, rsc, 6) <= 0) {
		u16 seq_ctrl = le_to_host16(hdr->seq_ctrl);
		add_note(wt, MSG_INFO, "CCMP/TKIP replay detected: A1=" MACSTR
			 " A2=" MACSTR " A3=" MACSTR " seq=%u frag=%u",
			 MAC2STR(hdr->addr1), MAC2STR(hdr->addr2),
			 MAC2STR(hdr->addr3),
			 WLAN_GET_SEQ_SEQ(seq_ctrl),
			 WLAN_GET_SEQ_FRAG(seq_ctrl));
		wpa_hexdump(MSG_INFO, "RX PN", pn, 6);
		wpa_hexdump(MSG_INFO, "RSC", rsc, 6);
	}

skip_replay_det:
	if (tk)
		decrypted = ccmp_decrypt(tk, hdr, data, len, &dlen);
	else if (sta->pairwise_cipher == WPA_CIPHER_TKIP)
		decrypted = tkip_decrypt(sta->ptk.tk1, hdr, data, len, &dlen);
	else if (sta->pairwise_cipher == WPA_CIPHER_WEP40)
		decrypted = wep_decrypt(wt, hdr, data, len, &dlen);
	else if (sta->ptk_set)
		decrypted = ccmp_decrypt(sta->ptk.tk1, hdr, data, len, &dlen);
	else {
		decrypted = try_all_ptk(wt, sta->pairwise_cipher, hdr, data,
					len, &dlen);
		ptk_iter_done = 1;
	}
	if (!decrypted && !ptk_iter_done) {
		decrypted = try_all_ptk(wt, sta->pairwise_cipher, hdr, data,
					len, &dlen);
		if (decrypted) {
			add_note(wt, MSG_DEBUG, "Current PTK did not work, but found a match from all known PTKs");
		}
	}
	if (decrypted) {
		u16 fc = le_to_host16(hdr->frame_control);
		const u8 *peer_addr = NULL;
		if (!(fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)))
			peer_addr = hdr->addr1;
		os_memcpy(rsc, pn, 6);
		rx_data_process(wt, bss->bssid, sta->addr, dst, src, decrypted,
				dlen, 1, peer_addr);
		write_pcap_decrypted(wt, (const u8 *) hdr, 24 + (qos ? 2 : 0),
				     decrypted, dlen);
	} else if (!try_ptk_iter)
		add_note(wt, MSG_DEBUG, "Failed to decrypt frame");
	os_free(decrypted);
}
示例#4
0
static void rx_data_bss_prot_group(struct wlantest *wt,
				   const struct ieee80211_hdr *hdr,
				   const u8 *qos, const u8 *dst, const u8 *src,
				   const u8 *data, size_t len)
{
	struct wlantest_bss *bss;
	int keyid;
	u8 *decrypted;
	size_t dlen;
	u8 pn[6];

	bss = bss_get(wt, hdr->addr2);
	if (bss == NULL)
		return;
	if (len < 4) {
		add_note(wt, MSG_INFO, "Too short group addressed data frame");
		return;
	}

	if (bss->group_cipher & (WPA_CIPHER_TKIP | WPA_CIPHER_CCMP) &&
	    !(data[3] & 0x20)) {
		add_note(wt, MSG_INFO, "Expected TKIP/CCMP frame from "
			 MACSTR " did not have ExtIV bit set to 1",
			 MAC2STR(bss->bssid));
		return;
	}

	if (bss->group_cipher == WPA_CIPHER_TKIP) {
		if (data[3] & 0x1f) {
			add_note(wt, MSG_INFO, "TKIP frame from " MACSTR
				 " used non-zero reserved bit",
				 MAC2STR(bss->bssid));
		}
		if (data[1] != ((data[0] | 0x20) & 0x7f)) {
			add_note(wt, MSG_INFO, "TKIP frame from " MACSTR
				 " used incorrect WEPSeed[1] (was 0x%x, "
				 "expected 0x%x)",
				 MAC2STR(bss->bssid), data[1],
				 (data[0] | 0x20) & 0x7f);
		}
	} else if (bss->group_cipher == WPA_CIPHER_CCMP) {
		if (data[2] != 0 || (data[3] & 0x1f) != 0) {
			add_note(wt, MSG_INFO, "CCMP frame from " MACSTR
				 " used non-zero reserved bit",
				 MAC2STR(bss->bssid));
		}
	}

	keyid = data[3] >> 6;
	if (bss->gtk_len[keyid] == 0 && bss->group_cipher != WPA_CIPHER_WEP40)
	{
		add_note(wt, MSG_MSGDUMP, "No GTK known to decrypt the frame "
			 "(A2=" MACSTR " KeyID=%d)",
			 MAC2STR(hdr->addr2), keyid);
		return;
	}

	if (bss->group_cipher == WPA_CIPHER_TKIP)
		tkip_get_pn(pn, data);
	else if (bss->group_cipher == WPA_CIPHER_WEP40)
		goto skip_replay_det;
	else
		ccmp_get_pn(pn, data);
	if (os_memcmp(pn, bss->rsc[keyid], 6) <= 0) {
		u16 seq_ctrl = le_to_host16(hdr->seq_ctrl);
		add_note(wt, MSG_INFO, "CCMP/TKIP replay detected: A1=" MACSTR
			 " A2=" MACSTR " A3=" MACSTR " seq=%u frag=%u",
			 MAC2STR(hdr->addr1), MAC2STR(hdr->addr2),
			 MAC2STR(hdr->addr3),
			 WLAN_GET_SEQ_SEQ(seq_ctrl),
			 WLAN_GET_SEQ_FRAG(seq_ctrl));
		wpa_hexdump(MSG_INFO, "RX PN", pn, 6);
		wpa_hexdump(MSG_INFO, "RSC", bss->rsc[keyid], 6);
	}

skip_replay_det:
	if (bss->group_cipher == WPA_CIPHER_TKIP)
		decrypted = tkip_decrypt(bss->gtk[keyid], hdr, data, len,
					 &dlen);
	else if (bss->group_cipher == WPA_CIPHER_WEP40)
		decrypted = wep_decrypt(wt, hdr, data, len, &dlen);
	else
		decrypted = ccmp_decrypt(bss->gtk[keyid], hdr, data, len,
					 &dlen);
	if (decrypted) {
		rx_data_process(wt, bss->bssid, NULL, dst, src, decrypted,
				dlen, 1, NULL);
		os_memcpy(bss->rsc[keyid], pn, 6);
		write_pcap_decrypted(wt, (const u8 *) hdr, 24 + (qos ? 2 : 0),
				     decrypted, dlen);
	} else
		add_note(wt, MSG_DEBUG, "Failed to decrypt frame");
	os_free(decrypted);
}
示例#5
0
/*
 * Called by pcap_loop for every packet that passes the (optional) bpf
 * filter
 */
void pckt_callback(u_char *user, const struct pcap_pkthdr *pkthdr, 
    const u_char *packet_data)
{
  ieee80211_hdr w_hdr;
  airpwn_ctx *ctx = (airpwn_ctx *)user;
  char ssid_name[256];
  uint32_t packetlen;

  packetlen = pkthdr->len;

  // code to handle skipping past "prism monitoring header" blocks
  if(*((unsigned int*)packet_data) == htonl(0x44000000)){
    uint32_t len = *((uint32_t*)(packet_data+4));
    packet_data = packet_data + len;
    packetlen -= len;
  }

  // same for radiotap headers, which have a first 16 bits of 0x0000
  if(*((uint16_t*)packet_data) == htons(0x0000)) {
    uint16_t len = *((uint16_t*)(packet_data+2));
    packet_data = packet_data + len;
    packetlen -= len;
  }

  switch(packet_data[0]){
    // data packet
    case 0x08:
      memcpy(&w_hdr, packet_data, sizeof(w_hdr));
      printlog(ctx, 3, "  data packet len: %u, flags: %hhu %s DS\n", 
	  pkthdr->len, w_hdr.flags, 
	  w_hdr.flags & IEEE80211_FROM_DS ? "<--" : "-->");
      
      if(w_hdr.flags & IEEE80211_FROM_DS) // ignore packets from the AP
	break;
      
      if(IS_WEP(w_hdr.flags)){ // the packet is WEP encrypted
	uint8_t cleartext[0x10000];
	int32_t clearlen;
	wepkey *key;
	printlog(ctx, 3, "    WEP encrypted packet found.\n");

	if(!ctx->keys) // no WEP keys so ignore this packet
	  break;
	
	//TODO: some packets may not have a frame check sequence at the
	//end, need to figure this out instead of always subtracting 4
	//bytes.
	for(key = ctx->keys; key != NULL; key = key->next){
	  clearlen = wep_decrypt(packet_data + IEEE80211_HDR_LEN_NO_LLC,
	      cleartext, 
	      packetlen - IEEE80211_HDR_LEN_NO_LLC - (ctx->fcs_present ? IEEE80211_FCS_LEN : 0),
	      key->key, key->keylen);

	  if(clearlen > 0){
	    printlog(ctx, 3, "    WEP decryption succesful.\n");
	    //dumphex(cleartext, clearlen);
	  
	    memcpy(&w_hdr.llc, cleartext, sizeof(LLC_hdr));
	    
	    if(w_hdr.llc.type == LLC_TYPE_IP){
	      process_ip_packet(ctx, &w_hdr, cleartext+LLC_HDR_LEN, 
		  clearlen-LLC_HDR_LEN, key->key, key->keylen);
	    }
	  } else { printlog(ctx, 3, "    WEP decryption failed..\n"); }
	}
      } else if(w_hdr.llc.type == LLC_TYPE_IP)
	process_ip_packet(ctx, &w_hdr, packet_data + IEEE80211_HDR_LEN, 
	    pkthdr->len, NULL, 0);
      break;
    case 0x80:
      get_ssid(packet_data, ssid_name, sizeof(ssid_name));
      printlog(ctx, 4, "  beacon frame (%s)\n", ssid_name);
      break;
    case 0x40:
      get_ssid(packet_data, ssid_name, sizeof(ssid_name));
      printlog(ctx, 4, "  probe request (%s)\n", ssid_name);
      break;
    case 0x50:
      get_ssid(packet_data, ssid_name, sizeof(ssid_name));
      printlog(ctx, 4, "  probe response (%s)\n", ssid_name);
      break;
    case 0xd4:
      printlog(ctx, 4, "  acknowledgement\n");
      break;
    case 0x48:
      printlog(ctx, 4, "  null function\n");
      break;
    case 0xb0:
      printlog(ctx, 4, "  authentication\n");
      break;
    case 0xc0:
      printlog(ctx, 4, "  deauthentication\n");
      break;
    case 0x30:
      printlog(ctx, 4, "  reassociation response\n");
      break;
    case 0xc4:
      printlog(ctx, 4, "  clear to send\n");
      break;
    default:
      printlog(ctx, 5, " ***  unknown type %x\n", packet_data[0]);
  }
}