Commit message: CVE-2017-13008/IEEE 802.11: Fix TIM bitmap copy to copy from p + offset.

offset has already been advanced to point to the bitmap; we shouldn't
add the amount to advance again.

This fixes a buffer over-read discovered by Brian 'geeknik' Carpenter.

Add a test using the capture file supplied by the reporter(s).

While we're at it, remove some redundant tests - we've already checked,
before the case statement, whether we have captured the entire
information element and whether the entire information element is
present in the on-the-wire packet; in the cases for particular IEs, we
only need to make sure we don't go past the end of the IE.
CVE: CVE-2017-13008
CWE: CWE-125
Vulnerability description: The IEEE 802.11 parser in tcpdump before 4.9.2 has a buffer over-read in print-802_11.c:parse_elements().

Project: tcpdump
File: print-802_11.c

ctrl_body_print(netdissect_options *ndo,
                uint16_t fc, const u_char *p)
{
	ND_PRINT((ndo, "%s", tok2str(ctrl_str, "Unknown Ctrl Subtype", FC_SUBTYPE(fc))));
	switch (FC_SUBTYPE(fc)) {
	case CTRL_CONTROL_WRAPPER:
		/* XXX - requires special handling */
		break;
	case CTRL_BAR:
		if (!ND_TTEST2(*p, CTRL_BAR_HDRLEN))
			return 0;
		if (!ndo->ndo_eflag)
			ND_PRINT((ndo, " RA:%s TA:%s CTL(%x) SEQ(%u) ",
			    etheraddr_string(ndo, ((const struct ctrl_bar_hdr_t *)p)->ra),
			    etheraddr_string(ndo, ((const struct ctrl_bar_hdr_t *)p)->ta),
			    EXTRACT_LE_16BITS(&(((const struct ctrl_bar_hdr_t *)p)->ctl)),
			    EXTRACT_LE_16BITS(&(((const struct ctrl_bar_hdr_t *)p)->seq))));
		break;
	case CTRL_BA:
		if (!ND_TTEST2(*p, CTRL_BA_HDRLEN))
			return 0;
		if (!ndo->ndo_eflag)
			ND_PRINT((ndo, " RA:%s ",
			    etheraddr_string(ndo, ((const struct ctrl_ba_hdr_t *)p)->ra)));
		break;
	case CTRL_PS_POLL:
		if (!ND_TTEST2(*p, CTRL_PS_POLL_HDRLEN))
			return 0;
		ND_PRINT((ndo, " AID(%x)",
		    EXTRACT_LE_16BITS(&(((const struct ctrl_ps_poll_hdr_t *)p)->aid))));
		break;
	case CTRL_RTS:
		if (!ND_TTEST2(*p, CTRL_RTS_HDRLEN))
			return 0;
		if (!ndo->ndo_eflag)
			ND_PRINT((ndo, " TA:%s ",
			    etheraddr_string(ndo, ((const struct ctrl_rts_hdr_t *)p)->ta)));
		break;
	case CTRL_CTS:
		if (!ND_TTEST2(*p, CTRL_CTS_HDRLEN))
			return 0;
		if (!ndo->ndo_eflag)
			ND_PRINT((ndo, " RA:%s ",
			    etheraddr_string(ndo, ((const struct ctrl_cts_hdr_t *)p)->ra)));
		break;
	case CTRL_ACK:
		if (!ND_TTEST2(*p, CTRL_ACK_HDRLEN))
			return 0;
		if (!ndo->ndo_eflag)
			ND_PRINT((ndo, " RA:%s ",
			    etheraddr_string(ndo, ((const struct ctrl_ack_hdr_t *)p)->ra)));
		break;
	case CTRL_CF_END:
		if (!ND_TTEST2(*p, CTRL_END_HDRLEN))
			return 0;
		if (!ndo->ndo_eflag)
			ND_PRINT((ndo, " RA:%s ",
			    etheraddr_string(ndo, ((const struct ctrl_end_hdr_t *)p)->ra)));
		break;
	case CTRL_END_ACK:
		if (!ND_TTEST2(*p, CTRL_END_ACK_HDRLEN))
			return 0;
		if (!ndo->ndo_eflag)
			ND_PRINT((ndo, " RA:%s ",
			    etheraddr_string(ndo, ((const struct ctrl_end_ack_hdr_t *)p)->ra)));
		break;
	}
	return 1;
}

Project: tcpdump
File: print-802_11.c

ctrl_header_print(netdissect_options *ndo, uint16_t fc, const u_char *p)
{
	switch (FC_SUBTYPE(fc)) {
	case CTRL_BAR:
		ND_PRINT((ndo, " RA:%s TA:%s CTL(%x) SEQ(%u) ",
		    etheraddr_string(ndo, ((const struct ctrl_bar_hdr_t *)p)->ra),
		    etheraddr_string(ndo, ((const struct ctrl_bar_hdr_t *)p)->ta),
		    EXTRACT_LE_16BITS(&(((const struct ctrl_bar_hdr_t *)p)->ctl)),
		    EXTRACT_LE_16BITS(&(((const struct ctrl_bar_hdr_t *)p)->seq))));
		break;
	case CTRL_BA:
		ND_PRINT((ndo, "RA:%s ",
		    etheraddr_string(ndo, ((const struct ctrl_ba_hdr_t *)p)->ra)));
		break;
	case CTRL_PS_POLL:
		ND_PRINT((ndo, "BSSID:%s TA:%s ",
		    etheraddr_string(ndo, ((const struct ctrl_ps_poll_hdr_t *)p)->bssid),
		    etheraddr_string(ndo, ((const struct ctrl_ps_poll_hdr_t *)p)->ta)));
		break;
	case CTRL_RTS:
		ND_PRINT((ndo, "RA:%s TA:%s ",
		    etheraddr_string(ndo, ((const struct ctrl_rts_hdr_t *)p)->ra),
		    etheraddr_string(ndo, ((const struct ctrl_rts_hdr_t *)p)->ta)));
		break;
	case CTRL_CTS:
		ND_PRINT((ndo, "RA:%s ",
		    etheraddr_string(ndo, ((const struct ctrl_cts_hdr_t *)p)->ra)));
		break;
	case CTRL_ACK:
		ND_PRINT((ndo, "RA:%s ",
		    etheraddr_string(ndo, ((const struct ctrl_ack_hdr_t *)p)->ra)));
		break;
	case CTRL_CF_END:
		ND_PRINT((ndo, "RA:%s BSSID:%s ",
		    etheraddr_string(ndo, ((const struct ctrl_end_hdr_t *)p)->ra),
		    etheraddr_string(ndo, ((const struct ctrl_end_hdr_t *)p)->bssid)));
		break;
	case CTRL_END_ACK:
		ND_PRINT((ndo, "RA:%s BSSID:%s ",
		    etheraddr_string(ndo, ((const struct ctrl_end_ack_hdr_t *)p)->ra),
		    etheraddr_string(ndo, ((const struct ctrl_end_ack_hdr_t *)p)->bssid)));
		break;
	default:
		/* We shouldn't get here - we should already have quit */
		break;
	}
}

Project: tcpdump
File: print-802_11.c

data_header_print(netdissect_options *ndo, uint16_t fc, const u_char *p)
{
	u_int subtype = FC_SUBTYPE(fc);

	if (DATA_FRAME_IS_CF_ACK(subtype) || DATA_FRAME_IS_CF_POLL(subtype) ||
	    DATA_FRAME_IS_QOS(subtype)) {
		ND_PRINT((ndo, "CF "));
		if (DATA_FRAME_IS_CF_ACK(subtype)) {
			if (DATA_FRAME_IS_CF_POLL(subtype))
				ND_PRINT((ndo, "Ack/Poll"));
			else
				ND_PRINT((ndo, "Ack"));
		} else {
			if (DATA_FRAME_IS_CF_POLL(subtype))
				ND_PRINT((ndo, "Poll"));
		}
		if (DATA_FRAME_IS_QOS(subtype))
			ND_PRINT((ndo, "+QoS"));
		ND_PRINT((ndo, " "));
	}

#define ADDR1  (p + 4)
#define ADDR2  (p + 10)
#define ADDR3  (p + 16)
#define ADDR4  (p + 24)

	if (!FC_TO_DS(fc) && !FC_FROM_DS(fc)) {
		ND_PRINT((ndo, "DA:%s SA:%s BSSID:%s ",
		    etheraddr_string(ndo, ADDR1), etheraddr_string(ndo, ADDR2),
		    etheraddr_string(ndo, ADDR3)));
	} else if (!FC_TO_DS(fc) && FC_FROM_DS(fc)) {
		ND_PRINT((ndo, "DA:%s BSSID:%s SA:%s ",
		    etheraddr_string(ndo, ADDR1), etheraddr_string(ndo, ADDR2),
		    etheraddr_string(ndo, ADDR3)));
	} else if (FC_TO_DS(fc) && !FC_FROM_DS(fc)) {
		ND_PRINT((ndo, "BSSID:%s SA:%s DA:%s ",
		    etheraddr_string(ndo, ADDR1), etheraddr_string(ndo, ADDR2),
		    etheraddr_string(ndo, ADDR3)));
	} else if (FC_TO_DS(fc) && FC_FROM_DS(fc)) {
		ND_PRINT((ndo, "RA:%s TA:%s DA:%s SA:%s ",
		    etheraddr_string(ndo, ADDR1), etheraddr_string(ndo, ADDR2),
		    etheraddr_string(ndo, ADDR3), etheraddr_string(ndo, ADDR4)));
	}

#undef ADDR1
#undef ADDR2
#undef ADDR3
#undef ADDR4
}

Project: tcpdump
File: print-802_11.c

extract_header_length(netdissect_options *ndo,
                      uint16_t fc)
{
	int len;

	switch (FC_TYPE(fc)) {
	case T_MGMT:
		return MGMT_HDRLEN;
	case T_CTRL:
		switch (FC_SUBTYPE(fc)) {
		case CTRL_CONTROL_WRAPPER:
			return CTRL_CONTROL_WRAPPER_HDRLEN;
		case CTRL_BAR:
			return CTRL_BAR_HDRLEN;
		case CTRL_BA:
			return CTRL_BA_HDRLEN;
		case CTRL_PS_POLL:
			return CTRL_PS_POLL_HDRLEN;
		case CTRL_RTS:
			return CTRL_RTS_HDRLEN;
		case CTRL_CTS:
			return CTRL_CTS_HDRLEN;
		case CTRL_ACK:
			return CTRL_ACK_HDRLEN;
		case CTRL_CF_END:
			return CTRL_END_HDRLEN;
		case CTRL_END_ACK:
			return CTRL_END_ACK_HDRLEN;
		default:
			ND_PRINT((ndo, "unknown 802.11 ctrl frame subtype (%d)", FC_SUBTYPE(fc)));
			return 0;
		}
	case T_DATA:
		len = (FC_TO_DS(fc) && FC_FROM_DS(fc)) ? 30 : 24;
		if (DATA_FRAME_IS_QOS(FC_SUBTYPE(fc)))
			len += 2;
		return len;
	default:
		ND_PRINT((ndo, "unknown 802.11 frame type (%d)", FC_TYPE(fc)));
		return 0;
	}
}

Project: tcpdump
File: print-802_11.c

extract_mesh_header_length(const u_char *p)
{
	return (p[0] &~ 3) ? 0 : 6*(1 + (p[0] & 3));
}

Project: tcpdump
File: print-802_11.c

get_data_src_dst_mac(uint16_t fc, const u_char *p, const uint8_t **srcp,
                     const uint8_t **dstp)
{
#define ADDR1  (p + 4)
#define ADDR2  (p + 10)
#define ADDR3  (p + 16)
#define ADDR4  (p + 24)

	if (!FC_TO_DS(fc)) {
		if (!FC_FROM_DS(fc)) {
			/* not To DS and not From DS */
			*srcp = ADDR2;
			*dstp = ADDR1;
		} else {
			/* not To DS and From DS */
			*srcp = ADDR3;
			*dstp = ADDR1;
		}
	} else {
		if (!FC_FROM_DS(fc)) {
			/* From DS and not To DS */
			*srcp = ADDR2;
			*dstp = ADDR3;
		} else {
			/* To DS and From DS */
			*srcp = ADDR4;
			*dstp = ADDR3;
		}
	}

#undef ADDR1
#undef ADDR2
#undef ADDR3
#undef ADDR4
}

Project: tcpdump
File: print-802_11.c

handle_action(netdissect_options *ndo,
              const uint8_t *src, const u_char *p, u_int length)
{
	if (!ND_TTEST2(*p, 2))
		return 0;
	if (length < 2)
		return 0;
	if (ndo->ndo_eflag) {
		ND_PRINT((ndo, ": "));
	} else {
		ND_PRINT((ndo, " (%s): ", etheraddr_string(ndo, src)));
	}
	switch (p[0]) {
	case 0: ND_PRINT((ndo, "Spectrum Management Act#%d", p[1])); break;
	case 1: ND_PRINT((ndo, "QoS Act#%d", p[1])); break;
	case 2: ND_PRINT((ndo, "DLS Act#%d", p[1])); break;
	case 3: ND_PRINT((ndo, "BA ")); PRINT_BA_ACTION(p[1]); break;
	case 7: ND_PRINT((ndo, "HT ")); PRINT_HT_ACTION(p[1]); break;
	case 13: ND_PRINT((ndo, "MeshAction ")); PRINT_MESH_ACTION(p[1]); break;
	case 14:
		ND_PRINT((ndo, "MultiohopAction "));
		PRINT_MULTIHOP_ACTION(p[1]); break;
	case 15:
		ND_PRINT((ndo, "SelfprotectAction "));
		PRINT_SELFPROT_ACTION(p[1]); break;
	case 127: ND_PRINT((ndo, "Vendor Act#%d", p[1])); break;
	default:
		ND_PRINT((ndo, "Reserved(%d) Act#%d", p[0], p[1]));
		break;
	}
	return 1;
}

Project: tcpdump
File: print-802_11.c

handle_assoc_request(netdissect_options *ndo,
                     const u_char *p, u_int length)
{
	struct mgmt_body_t pbody;
	int offset = 0;
	int ret;

	memset(&pbody, 0, sizeof(pbody));

	if (!ND_TTEST2(*p, IEEE802_11_CAPINFO_LEN + IEEE802_11_LISTENINT_LEN))
		return 0;
	if (length < IEEE802_11_CAPINFO_LEN + IEEE802_11_LISTENINT_LEN)
		return 0;
	pbody.capability_info = EXTRACT_LE_16BITS(p);
	offset += IEEE802_11_CAPINFO_LEN;
	length -= IEEE802_11_CAPINFO_LEN;
	pbody.listen_interval = EXTRACT_LE_16BITS(p+offset);
	offset += IEEE802_11_LISTENINT_LEN;
	length -= IEEE802_11_LISTENINT_LEN;

	ret = parse_elements(ndo, &pbody, p, offset, length);

	PRINT_SSID(pbody);
	PRINT_RATES(pbody);
	return ret;
}

Project: tcpdump
File: print-802_11.c

handle_assoc_response(netdissect_options *ndo,
                      const u_char *p, u_int length)
{
	struct mgmt_body_t pbody;
	int offset = 0;
	int ret;

	memset(&pbody, 0, sizeof(pbody));

	if (!ND_TTEST2(*p, IEEE802_11_CAPINFO_LEN + IEEE802_11_STATUS_LEN +
	    IEEE802_11_AID_LEN))
		return 0;
	if (length < IEEE802_11_CAPINFO_LEN + IEEE802_11_STATUS_LEN +
	    IEEE802_11_AID_LEN)
		return 0;
	pbody.capability_info = EXTRACT_LE_16BITS(p);
	offset += IEEE802_11_CAPINFO_LEN;
	length -= IEEE802_11_CAPINFO_LEN;
	pbody.status_code = EXTRACT_LE_16BITS(p+offset);
	offset += IEEE802_11_STATUS_LEN;
	length -= IEEE802_11_STATUS_LEN;
	pbody.aid = EXTRACT_LE_16BITS(p+offset);
	offset += IEEE802_11_AID_LEN;
	length -= IEEE802_11_AID_LEN;

	ret = parse_elements(ndo, &pbody, p, offset, length);

	ND_PRINT((ndo, " AID(%x) :%s: %s", ((uint16_t)(pbody.aid << 2 )) >> 2 ,
	    CAPABILITY_PRIVACY(pbody.capability_info) ? " PRIVACY " : "",
	    (pbody.status_code < NUM_STATUSES
		? status_text[pbody.status_code]
		: "n/a")));

	return ret;
}

Project: tcpdump
File: print-802_11.c

handle_atim(void)
{
	/* the frame body for ATIM is null. */
	return 1;
}

Project: tcpdump
File: print-802_11.c

handle_auth(netdissect_options *ndo,
            const u_char *p, u_int length)
{
	struct mgmt_body_t  pbody;
	int offset = 0;
	int ret;

	memset(&pbody, 0, sizeof(pbody));

	if (!ND_TTEST2(*p, 6))
		return 0;
	if (length < 6)
		return 0;
	pbody.auth_alg = EXTRACT_LE_16BITS(p);
	offset += 2;
	length -= 2;
	pbody.auth_trans_seq_num = EXTRACT_LE_16BITS(p + offset);
	offset += 2;
	length -= 2;
	pbody.status_code = EXTRACT_LE_16BITS(p + offset);
	offset += 2;
	length -= 2;

	ret = parse_elements(ndo, &pbody, p, offset, length);

	if ((pbody.auth_alg == 1) &&
	    ((pbody.auth_trans_seq_num == 2) ||
	     (pbody.auth_trans_seq_num == 3))) {
		ND_PRINT((ndo, " (%s)-%x [Challenge Text] %s",
		    (pbody.auth_alg < NUM_AUTH_ALGS)
			? auth_alg_text[pbody.auth_alg]
			: "Reserved",
		    pbody.auth_trans_seq_num,
		    ((pbody.auth_trans_seq_num % 2)
		        ? ((pbody.status_code < NUM_STATUSES)
			       ? status_text[pbody.status_code]
			       : "n/a") : "")));
		return ret;
	}
	ND_PRINT((ndo, " (%s)-%x: %s",
	    (pbody.auth_alg < NUM_AUTH_ALGS)
		? auth_alg_text[pbody.auth_alg]
		: "Reserved",
	    pbody.auth_trans_seq_num,
	    (pbody.auth_trans_seq_num % 2)
	        ? ((pbody.status_code < NUM_STATUSES)
		    ? status_text[pbody.status_code]
	            : "n/a")
	        : ""));

	return ret;
}

Project: tcpdump
File: print-802_11.c

handle_beacon(netdissect_options *ndo,
              const u_char *p, u_int length)
{
	struct mgmt_body_t pbody;
	int offset = 0;
	int ret;

	memset(&pbody, 0, sizeof(pbody));

	if (!ND_TTEST2(*p, IEEE802_11_TSTAMP_LEN + IEEE802_11_BCNINT_LEN +
	    IEEE802_11_CAPINFO_LEN))
		return 0;
	if (length < IEEE802_11_TSTAMP_LEN + IEEE802_11_BCNINT_LEN +
	    IEEE802_11_CAPINFO_LEN)
		return 0;
	memcpy(&pbody.timestamp, p, IEEE802_11_TSTAMP_LEN);
	offset += IEEE802_11_TSTAMP_LEN;
	length -= IEEE802_11_TSTAMP_LEN;
	pbody.beacon_interval = EXTRACT_LE_16BITS(p+offset);
	offset += IEEE802_11_BCNINT_LEN;
	length -= IEEE802_11_BCNINT_LEN;
	pbody.capability_info = EXTRACT_LE_16BITS(p+offset);
	offset += IEEE802_11_CAPINFO_LEN;
	length -= IEEE802_11_CAPINFO_LEN;

	ret = parse_elements(ndo, &pbody, p, offset, length);

	PRINT_SSID(pbody);
	PRINT_RATES(pbody);
	ND_PRINT((ndo, " %s",
	    CAPABILITY_ESS(pbody.capability_info) ? "ESS" : "IBSS"));
	PRINT_DS_CHANNEL(pbody);

	return ret;
}

Project: tcpdump
File: print-802_11.c

handle_deauth(netdissect_options *ndo,
              const uint8_t *src, const u_char *p, u_int length)
{
	struct mgmt_body_t  pbody;
	const char *reason = NULL;

	memset(&pbody, 0, sizeof(pbody));

	if (!ND_TTEST2(*p, IEEE802_11_REASON_LEN))
		return 0;
	if (length < IEEE802_11_REASON_LEN)
		return 0;
	pbody.reason_code = EXTRACT_LE_16BITS(p);

	reason = (pbody.reason_code < NUM_REASONS)
			? reason_text[pbody.reason_code]
			: "Reserved";

	if (ndo->ndo_eflag) {
		ND_PRINT((ndo, ": %s", reason));
	} else {
		ND_PRINT((ndo, " (%s): %s", etheraddr_string(ndo, src), reason));
	}
	return 1;
}

Project: tcpdump
File: print-802_11.c

handle_disassoc(netdissect_options *ndo,
                const u_char *p, u_int length)
{
	struct mgmt_body_t  pbody;

	memset(&pbody, 0, sizeof(pbody));

	if (!ND_TTEST2(*p, IEEE802_11_REASON_LEN))
		return 0;
	if (length < IEEE802_11_REASON_LEN)
		return 0;
	pbody.reason_code = EXTRACT_LE_16BITS(p);

	ND_PRINT((ndo, ": %s",
	    (pbody.reason_code < NUM_REASONS)
		? reason_text[pbody.reason_code]
		: "Reserved"));

	return 1;
}

Project: tcpdump
File: print-802_11.c

handle_probe_request(netdissect_options *ndo,
                     const u_char *p, u_int length)
{
	struct mgmt_body_t  pbody;
	int offset = 0;
	int ret;

	memset(&pbody, 0, sizeof(pbody));

	ret = parse_elements(ndo, &pbody, p, offset, length);

	PRINT_SSID(pbody);
	PRINT_RATES(pbody);

	return ret;
}

Project: tcpdump
File: print-802_11.c

handle_probe_response(netdissect_options *ndo,
                      const u_char *p, u_int length)
{
	struct mgmt_body_t  pbody;
	int offset = 0;
	int ret;

	memset(&pbody, 0, sizeof(pbody));

	if (!ND_TTEST2(*p, IEEE802_11_TSTAMP_LEN + IEEE802_11_BCNINT_LEN +
	    IEEE802_11_CAPINFO_LEN))
		return 0;
	if (length < IEEE802_11_TSTAMP_LEN + IEEE802_11_BCNINT_LEN +
	    IEEE802_11_CAPINFO_LEN)
		return 0;
	memcpy(&pbody.timestamp, p, IEEE802_11_TSTAMP_LEN);
	offset += IEEE802_11_TSTAMP_LEN;
	length -= IEEE802_11_TSTAMP_LEN;
	pbody.beacon_interval = EXTRACT_LE_16BITS(p+offset);
	offset += IEEE802_11_BCNINT_LEN;
	length -= IEEE802_11_BCNINT_LEN;
	pbody.capability_info = EXTRACT_LE_16BITS(p+offset);
	offset += IEEE802_11_CAPINFO_LEN;
	length -= IEEE802_11_CAPINFO_LEN;

	ret = parse_elements(ndo, &pbody, p, offset, length);

	PRINT_SSID(pbody);
	PRINT_RATES(pbody);
	PRINT_DS_CHANNEL(pbody);

	return ret;
}

Project: tcpdump
File: print-802_11.c

handle_reassoc_request(netdissect_options *ndo,
                       const u_char *p, u_int length)
{
	struct mgmt_body_t pbody;
	int offset = 0;
	int ret;

	memset(&pbody, 0, sizeof(pbody));

	if (!ND_TTEST2(*p, IEEE802_11_CAPINFO_LEN + IEEE802_11_LISTENINT_LEN +
	    IEEE802_11_AP_LEN))
		return 0;
	if (length < IEEE802_11_CAPINFO_LEN + IEEE802_11_LISTENINT_LEN +
	    IEEE802_11_AP_LEN)
		return 0;
	pbody.capability_info = EXTRACT_LE_16BITS(p);
	offset += IEEE802_11_CAPINFO_LEN;
	length -= IEEE802_11_CAPINFO_LEN;
	pbody.listen_interval = EXTRACT_LE_16BITS(p+offset);
	offset += IEEE802_11_LISTENINT_LEN;
	length -= IEEE802_11_LISTENINT_LEN;
	memcpy(&pbody.ap, p+offset, IEEE802_11_AP_LEN);
	offset += IEEE802_11_AP_LEN;
	length -= IEEE802_11_AP_LEN;

	ret = parse_elements(ndo, &pbody, p, offset, length);

	PRINT_SSID(pbody);
	ND_PRINT((ndo, " AP : %s", etheraddr_string(ndo,  pbody.ap )));

	return ret;
}

Project: tcpdump
File: print-802_11.c

handle_reassoc_response(netdissect_options *ndo,
                        const u_char *p, u_int length)
{
	/* Same as a Association Reponse */
	return handle_assoc_response(ndo, p, length);
}

Project: tcpdump
File: print-802_11.c

ieee802_11_avs_radio_print(netdissect_options *ndo,
                           const u_char *p, u_int length, u_int caplen)
{
	uint32_t caphdr_len;

	if (caplen < 8) {
		ND_PRINT((ndo, "%s", tstr));
		return caplen;
	}

	caphdr_len = EXTRACT_32BITS(p + 4);
	if (caphdr_len < 8) {
		/*
		 * Yow!  The capture header length is claimed not
		 * to be large enough to include even the version
		 * cookie or capture header length!
		 */
		ND_PRINT((ndo, "%s", tstr));
		return caplen;
	}

	if (caplen < caphdr_len) {
		ND_PRINT((ndo, "%s", tstr));
		return caplen;
	}

	return caphdr_len + ieee802_11_print(ndo, p + caphdr_len,
	    length - caphdr_len, caplen - caphdr_len, 0, 0);
}

Project: tcpdump
File: print-802_11.c

ieee802_11_if_print(netdissect_options *ndo,
                    const struct pcap_pkthdr *h, const u_char *p)
{
	return ieee802_11_print(ndo, p, h->len, h->caplen, 0, 0);
}

Project: tcpdump
File: print-802_11.c

ieee802_11_radio_if_print(netdissect_options *ndo,
                          const struct pcap_pkthdr *h, const u_char *p)
{
	return ieee802_11_radio_print(ndo, p, h->len, h->caplen);
}

Project: tcpdump
File: print-802_11.c

ieee802_11_radio_print(netdissect_options *ndo,
                       const u_char *p, u_int length, u_int caplen)
{
#define	BIT(n)	(1U << n)
#define	IS_EXTENDED(__p)	\
	    (EXTRACT_LE_32BITS(__p) & BIT(IEEE80211_RADIOTAP_EXT)) != 0

	struct cpack_state cpacker;
	const struct ieee80211_radiotap_header *hdr;
	uint32_t presentflags;
	const uint32_t *presentp, *last_presentp;
	int vendor_namespace;
	uint8_t vendor_oui[3];
	uint8_t vendor_subnamespace;
	uint16_t skip_length;
	int bit0;
	u_int len;
	uint8_t flags;
	int pad;
	u_int fcslen;

	if (caplen < sizeof(*hdr)) {
		ND_PRINT((ndo, "%s", tstr));
		return caplen;
	}

	hdr = (const struct ieee80211_radiotap_header *)p;

	len = EXTRACT_LE_16BITS(&hdr->it_len);

	/*
	 * If we don't have the entire radiotap header, just give up.
	 */
	if (caplen < len) {
		ND_PRINT((ndo, "%s", tstr));
		return caplen;
	}
	cpack_init(&cpacker, (const uint8_t *)hdr, len); /* align against header start */
	cpack_advance(&cpacker, sizeof(*hdr)); /* includes the 1st bitmap */
	for (last_presentp = &hdr->it_present;
	     (const u_char*)(last_presentp + 1) <= p + len &&
	     IS_EXTENDED(last_presentp);
	     last_presentp++)
	  cpack_advance(&cpacker, sizeof(hdr->it_present)); /* more bitmaps */

	/* are there more bitmap extensions than bytes in header? */
	if ((const u_char*)(last_presentp + 1) > p + len) {
		ND_PRINT((ndo, "%s", tstr));
		return caplen;
	}

	/*
	 * Start out at the beginning of the default radiotap namespace.
	 */
	bit0 = 0;
	vendor_namespace = 0;
	memset(vendor_oui, 0, 3);
	vendor_subnamespace = 0;
	skip_length = 0;
	/* Assume no flags */
	flags = 0;
	/* Assume no Atheros padding between 802.11 header and body */
	pad = 0;
	/* Assume no FCS at end of frame */
	fcslen = 0;
	for (presentp = &hdr->it_present; presentp <= last_presentp;
	    presentp++) {
		presentflags = EXTRACT_LE_32BITS(presentp);

		/*
		 * If this is a vendor namespace, we don't handle it.
		 */
		if (vendor_namespace) {
			/*
			 * Skip past the stuff we don't understand.
			 * If we add support for any vendor namespaces,
			 * it'd be added here; use vendor_oui and
			 * vendor_subnamespace to interpret the fields.
			 */
			if (cpack_advance(&cpacker, skip_length) != 0) {
				/*
				 * Ran out of space in the packet.
				 */
				break;
			}

			/*
			 * We've skipped it all; nothing more to
			 * skip.
			 */
			skip_length = 0;
		} else {
			if (print_in_radiotap_namespace(ndo, &cpacker,
			    &flags, presentflags, bit0) != 0) {
				/*
				 * Fatal error - can't process anything
				 * more in the radiotap header.
				 */
				break;
			}
		}

		/*
		 * Handle the namespace switch bits; we've already handled
		 * the extension bit in all but the last word above.
		 */
		switch (presentflags &
		    (BIT(IEEE80211_RADIOTAP_NAMESPACE)|BIT(IEEE80211_RADIOTAP_VENDOR_NAMESPACE))) {

		case 0:
			/*
			 * We're not changing namespaces.
			 * advance to the next 32 bits in the current
			 * namespace.
			 */
			bit0 += 32;
			break;

		case BIT(IEEE80211_RADIOTAP_NAMESPACE):
			/*
			 * We're switching to the radiotap namespace.
			 * Reset the presence-bitmap index to 0, and
			 * reset the namespace to the default radiotap
			 * namespace.
			 */
			bit0 = 0;
			vendor_namespace = 0;
			memset(vendor_oui, 0, 3);
			vendor_subnamespace = 0;
			skip_length = 0;
			break;

		case BIT(IEEE80211_RADIOTAP_VENDOR_NAMESPACE):
			/*
			 * We're switching to a vendor namespace.
			 * Reset the presence-bitmap index to 0,
			 * note that we're in a vendor namespace,
			 * and fetch the fields of the Vendor Namespace
			 * item.
			 */
			bit0 = 0;
			vendor_namespace = 1;
			if ((cpack_align_and_reserve(&cpacker, 2)) == NULL) {
				ND_PRINT((ndo, "%s", tstr));
				break;
			}
			if (cpack_uint8(&cpacker, &vendor_oui[0]) != 0) {
				ND_PRINT((ndo, "%s", tstr));
				break;
			}
			if (cpack_uint8(&cpacker, &vendor_oui[1]) != 0) {
				ND_PRINT((ndo, "%s", tstr));
				break;
			}
			if (cpack_uint8(&cpacker, &vendor_oui[2]) != 0) {
				ND_PRINT((ndo, "%s", tstr));
				break;
			}
			if (cpack_uint8(&cpacker, &vendor_subnamespace) != 0) {
				ND_PRINT((ndo, "%s", tstr));
				break;
			}
			if (cpack_uint16(&cpacker, &skip_length) != 0) {
				ND_PRINT((ndo, "%s", tstr));
				break;
			}
			break;

		default:
			/*
			 * Illegal combination.  The behavior in this
			 * case is undefined by the radiotap spec; we
			 * just ignore both bits.
			 */
			break;
		}
	}

	if (flags & IEEE80211_RADIOTAP_F_DATAPAD)
		pad = 1;	/* Atheros padding */
	if (flags & IEEE80211_RADIOTAP_F_FCS)
		fcslen = 4;	/* FCS at end of packet */
	return len + ieee802_11_print(ndo, p + len, length - len, caplen - len, pad,
	    fcslen);
#undef BITNO_32
#undef BITNO_16
#undef BITNO_8
#undef BITNO_4
#undef BITNO_2
#undef BIT
}

Project: tcpdump
File: print-802_11.c

mgmt_body_print(netdissect_options *ndo,
                uint16_t fc, const uint8_t *src, const u_char *p, u_int length)
{
	ND_PRINT((ndo, "%s", tok2str(st_str, "Unhandled Management subtype(%x)", FC_SUBTYPE(fc))));

	/* There may be a problem w/ AP not having this bit set */
	if (FC_PROTECTED(fc))
		return wep_print(ndo, p);
	switch (FC_SUBTYPE(fc)) {
	case ST_ASSOC_REQUEST:
		return handle_assoc_request(ndo, p, length);
	case ST_ASSOC_RESPONSE:
		return handle_assoc_response(ndo, p, length);
	case ST_REASSOC_REQUEST:
		return handle_reassoc_request(ndo, p, length);
	case ST_REASSOC_RESPONSE:
		return handle_reassoc_response(ndo, p, length);
	case ST_PROBE_REQUEST:
		return handle_probe_request(ndo, p, length);
	case ST_PROBE_RESPONSE:
		return handle_probe_response(ndo, p, length);
	case ST_BEACON:
		return handle_beacon(ndo, p, length);
	case ST_ATIM:
		return handle_atim();
	case ST_DISASSOC:
		return handle_disassoc(ndo, p, length);
	case ST_AUTH:
		return handle_auth(ndo, p, length);
	case ST_DEAUTH:
		return handle_deauth(ndo, src, p, length);
	case ST_ACTION:
		return handle_action(ndo, src, p, length);
	default:
		return 1;
	}
}

Project: tcpdump
File: print-802_11.c

mgmt_header_print(netdissect_options *ndo, const u_char *p)
{
	const struct mgmt_header_t *hp = (const struct mgmt_header_t *) p;

	ND_PRINT((ndo, "BSSID:%s DA:%s SA:%s ",
	    etheraddr_string(ndo, (hp)->bssid), etheraddr_string(ndo, (hp)->da),
	    etheraddr_string(ndo, (hp)->sa)));
}

Project: tcpdump
File: print-802_11.c

print_chaninfo(netdissect_options *ndo,
               uint16_t freq, int flags, int presentflags)
{
	ND_PRINT((ndo, "%u MHz", freq));
	if (presentflags & (1 << IEEE80211_RADIOTAP_MCS)) {
		/*
		 * We have the MCS field, so this is 11n, regardless
		 * of what the channel flags say.
		 */
		ND_PRINT((ndo, " 11n"));
	} else {
		if (IS_CHAN_FHSS(flags))
			ND_PRINT((ndo, " FHSS"));
		if (IS_CHAN_A(flags)) {
			if (flags & IEEE80211_CHAN_HALF)
				ND_PRINT((ndo, " 11a/10Mhz"));
			else if (flags & IEEE80211_CHAN_QUARTER)
				ND_PRINT((ndo, " 11a/5Mhz"));
			else
				ND_PRINT((ndo, " 11a"));
		}
		if (IS_CHAN_ANYG(flags)) {
			if (flags & IEEE80211_CHAN_HALF)
				ND_PRINT((ndo, " 11g/10Mhz"));
			else if (flags & IEEE80211_CHAN_QUARTER)
				ND_PRINT((ndo, " 11g/5Mhz"));
			else
				ND_PRINT((ndo, " 11g"));
		} else if (IS_CHAN_B(flags))
			ND_PRINT((ndo, " 11b"));
		if (flags & IEEE80211_CHAN_TURBO)
			ND_PRINT((ndo, " Turbo"));
	}
	/*
	 * These apply to 11n.
	 */
	if (flags & IEEE80211_CHAN_HT20)
		ND_PRINT((ndo, " ht/20"));
	else if (flags & IEEE80211_CHAN_HT40D)
		ND_PRINT((ndo, " ht/40-"));
	else if (flags & IEEE80211_CHAN_HT40U)
		ND_PRINT((ndo, " ht/40+"));
	ND_PRINT((ndo, " "));
}

Project: tcpdump
File: print-802_11.c

print_in_radiotap_namespace(netdissect_options *ndo,
                            struct cpack_state *s, uint8_t *flags,
                            uint32_t presentflags, int bit0)
{
#define	BITNO_32(x) (((x) >> 16) ? 16 + BITNO_16((x) >> 16) : BITNO_16((x)))
#define	BITNO_16(x) (((x) >> 8) ? 8 + BITNO_8((x) >> 8) : BITNO_8((x)))
#define	BITNO_8(x) (((x) >> 4) ? 4 + BITNO_4((x) >> 4) : BITNO_4((x)))
#define	BITNO_4(x) (((x) >> 2) ? 2 + BITNO_2((x) >> 2) : BITNO_2((x)))
#define	BITNO_2(x) (((x) & 2) ? 1 : 0)
	uint32_t present, next_present;
	int bitno;
	enum ieee80211_radiotap_type bit;
	int rc;

	for (present = presentflags; present; present = next_present) {
		/*
		 * Clear the least significant bit that is set.
		 */
		next_present = present & (present - 1);

		/*
		 * Get the bit number, within this presence word,
		 * of the remaining least significant bit that
		 * is set.
		 */
		bitno = BITNO_32(present ^ next_present);

		/*
		 * Stop if this is one of the "same meaning
		 * in all presence flags" bits.
		 */
		if (bitno >= IEEE80211_RADIOTAP_NAMESPACE)
			break;

		/*
		 * Get the radiotap bit number of that bit.
		 */
		bit = (enum ieee80211_radiotap_type)(bit0 + bitno);

		rc = print_radiotap_field(ndo, s, bit, flags, presentflags);
		if (rc != 0)
			return rc;
	}

	return 0;
}

Project: tcpdump
File: print-802_11.c

print_radiotap_field(netdissect_options *ndo,
                     struct cpack_state *s, uint32_t bit, uint8_t *flagsp,
                     uint32_t presentflags)
{
	u_int i;
	int rc;

	switch (bit) {

	case IEEE80211_RADIOTAP_TSFT: {
		uint64_t tsft;

		rc = cpack_uint64(s, &tsft);
		if (rc != 0)
			goto trunc;
		ND_PRINT((ndo, "%" PRIu64 "us tsft ", tsft));
		break;
		}

	case IEEE80211_RADIOTAP_FLAGS: {
		uint8_t flagsval;

		rc = cpack_uint8(s, &flagsval);
		if (rc != 0)
			goto trunc;
		*flagsp = flagsval;
		if (flagsval & IEEE80211_RADIOTAP_F_CFP)
			ND_PRINT((ndo, "cfp "));
		if (flagsval & IEEE80211_RADIOTAP_F_SHORTPRE)
			ND_PRINT((ndo, "short preamble "));
		if (flagsval & IEEE80211_RADIOTAP_F_WEP)
			ND_PRINT((ndo, "wep "));
		if (flagsval & IEEE80211_RADIOTAP_F_FRAG)
			ND_PRINT((ndo, "fragmented "));
		if (flagsval & IEEE80211_RADIOTAP_F_BADFCS)
			ND_PRINT((ndo, "bad-fcs "));
		break;
		}

	case IEEE80211_RADIOTAP_RATE: {
		uint8_t rate;

		rc = cpack_uint8(s, &rate);
		if (rc != 0)
			goto trunc;
		/*
		 * XXX On FreeBSD rate & 0x80 means we have an MCS. On
		 * Linux and AirPcap it does not.  (What about
		 * Mac OS X, NetBSD, OpenBSD, and DragonFly BSD?)
		 *
		 * This is an issue either for proprietary extensions
		 * to 11a or 11g, which do exist, or for 11n
		 * implementations that stuff a rate value into
		 * this field, which also appear to exist.
		 *
		 * We currently handle that by assuming that
		 * if the 0x80 bit is set *and* the remaining
		 * bits have a value between 0 and 15 it's
		 * an MCS value, otherwise it's a rate.  If
		 * there are cases where systems that use
		 * "0x80 + MCS index" for MCS indices > 15,
		 * or stuff a rate value here between 64 and
		 * 71.5 Mb/s in here, we'll need a preference
		 * setting.  Such rates do exist, e.g. 11n
		 * MCS 7 at 20 MHz with a long guard interval.
		 */
		if (rate >= 0x80 && rate <= 0x8f) {
			/*
			 * XXX - we don't know the channel width
			 * or guard interval length, so we can't
			 * convert this to a data rate.
			 *
			 * If you want us to show a data rate,
			 * use the MCS field, not the Rate field;
			 * the MCS field includes not only the
			 * MCS index, it also includes bandwidth
			 * and guard interval information.
			 *
			 * XXX - can we get the channel width
			 * from XChannel and the guard interval
			 * information from Flags, at least on
			 * FreeBSD?
			 */
			ND_PRINT((ndo, "MCS %u ", rate & 0x7f));
		} else
			ND_PRINT((ndo, "%2.1f Mb/s ", .5 * rate));
		break;
		}

	case IEEE80211_RADIOTAP_CHANNEL: {
		uint16_t frequency;
		uint16_t flags;

		rc = cpack_uint16(s, &frequency);
		if (rc != 0)
			goto trunc;
		rc = cpack_uint16(s, &flags);
		if (rc != 0)
			goto trunc;
		/*
		 * If CHANNEL and XCHANNEL are both present, skip
		 * CHANNEL.
		 */
		if (presentflags & (1 << IEEE80211_RADIOTAP_XCHANNEL))
			break;
		print_chaninfo(ndo, frequency, flags, presentflags);
		break;
		}

	case IEEE80211_RADIOTAP_FHSS: {
		uint8_t hopset;
		uint8_t hoppat;

		rc = cpack_uint8(s, &hopset);
		if (rc != 0)
			goto trunc;
		rc = cpack_uint8(s, &hoppat);
		if (rc != 0)
			goto trunc;
		ND_PRINT((ndo, "fhset %d fhpat %d ", hopset, hoppat));
		break;
		}

	case IEEE80211_RADIOTAP_DBM_ANTSIGNAL: {
		int8_t dbm_antsignal;

		rc = cpack_int8(s, &dbm_antsignal);
		if (rc != 0)
			goto trunc;
		ND_PRINT((ndo, "%ddBm signal ", dbm_antsignal));
		break;
		}

	case IEEE80211_RADIOTAP_DBM_ANTNOISE: {
		int8_t dbm_antnoise;

		rc = cpack_int8(s, &dbm_antnoise);
		if (rc != 0)
			goto trunc;
		ND_PRINT((ndo, "%ddBm noise ", dbm_antnoise));
		break;
		}

	case IEEE80211_RADIOTAP_LOCK_QUALITY: {
		uint16_t lock_quality;

		rc = cpack_uint16(s, &lock_quality);
		if (rc != 0)
			goto trunc;
		ND_PRINT((ndo, "%u sq ", lock_quality));
		break;
		}

	case IEEE80211_RADIOTAP_TX_ATTENUATION: {
		uint16_t tx_attenuation;

		rc = cpack_uint16(s, &tx_attenuation);
		if (rc != 0)
			goto trunc;
		ND_PRINT((ndo, "%d tx power ", -(int)tx_attenuation));
		break;
		}

	case IEEE80211_RADIOTAP_DB_TX_ATTENUATION: {
		uint8_t db_tx_attenuation;

		rc = cpack_uint8(s, &db_tx_attenuation);
		if (rc != 0)
			goto trunc;
		ND_PRINT((ndo, "%ddB tx attenuation ", -(int)db_tx_attenuation));
		break;
		}

	case IEEE80211_RADIOTAP_DBM_TX_POWER: {
		int8_t dbm_tx_power;

		rc = cpack_int8(s, &dbm_tx_power);
		if (rc != 0)
			goto trunc;
		ND_PRINT((ndo, "%ddBm tx power ", dbm_tx_power));
		break;
		}

	case IEEE80211_RADIOTAP_ANTENNA: {
		uint8_t antenna;

		rc = cpack_uint8(s, &antenna);
		if (rc != 0)
			goto trunc;
		ND_PRINT((ndo, "antenna %u ", antenna));
		break;
		}

	case IEEE80211_RADIOTAP_DB_ANTSIGNAL: {
		uint8_t db_antsignal;

		rc = cpack_uint8(s, &db_antsignal);
		if (rc != 0)
			goto trunc;
		ND_PRINT((ndo, "%ddB signal ", db_antsignal));
		break;
		}

	case IEEE80211_RADIOTAP_DB_ANTNOISE: {
		uint8_t db_antnoise;

		rc = cpack_uint8(s, &db_antnoise);
		if (rc != 0)
			goto trunc;
		ND_PRINT((ndo, "%ddB noise ", db_antnoise));
		break;
		}

	case IEEE80211_RADIOTAP_RX_FLAGS: {
		uint16_t rx_flags;

		rc = cpack_uint16(s, &rx_flags);
		if (rc != 0)
			goto trunc;
		/* Do nothing for now */
		break;
		}

	case IEEE80211_RADIOTAP_XCHANNEL: {
		uint32_t flags;
		uint16_t frequency;
		uint8_t channel;
		uint8_t maxpower;

		rc = cpack_uint32(s, &flags);
		if (rc != 0)
			goto trunc;
		rc = cpack_uint16(s, &frequency);
		if (rc != 0)
			goto trunc;
		rc = cpack_uint8(s, &channel);
		if (rc != 0)
			goto trunc;
		rc = cpack_uint8(s, &maxpower);
		if (rc != 0)
			goto trunc;
		print_chaninfo(ndo, frequency, flags, presentflags);
		break;
		}

	case IEEE80211_RADIOTAP_MCS: {
		uint8_t known;
		uint8_t flags;
		uint8_t mcs_index;
		static const char *ht_bandwidth[4] = {
			"20 MHz",
			"40 MHz",
			"20 MHz (L)",
			"20 MHz (U)"
		};
		float htrate;

		rc = cpack_uint8(s, &known);
		if (rc != 0)
			goto trunc;
		rc = cpack_uint8(s, &flags);
		if (rc != 0)
			goto trunc;
		rc = cpack_uint8(s, &mcs_index);
		if (rc != 0)
			goto trunc;
		if (known & IEEE80211_RADIOTAP_MCS_MCS_INDEX_KNOWN) {
			/*
			 * We know the MCS index.
			 */
			if (mcs_index <= MAX_MCS_INDEX) {
				/*
				 * And it's in-range.
				 */
				if (known & (IEEE80211_RADIOTAP_MCS_BANDWIDTH_KNOWN|IEEE80211_RADIOTAP_MCS_GUARD_INTERVAL_KNOWN)) {
					/*
					 * And we know both the bandwidth and
					 * the guard interval, so we can look
					 * up the rate.
					 */
					htrate =
						ieee80211_float_htrates \
							[mcs_index] \
							[((flags & IEEE80211_RADIOTAP_MCS_BANDWIDTH_MASK) == IEEE80211_RADIOTAP_MCS_BANDWIDTH_40 ? 1 : 0)] \
							[((flags & IEEE80211_RADIOTAP_MCS_SHORT_GI) ? 1 : 0)];
				} else {
					/*
					 * We don't know both the bandwidth
					 * and the guard interval, so we can
					 * only report the MCS index.
					 */
					htrate = 0.0;
				}
			} else {
				/*
				 * The MCS value is out of range.
				 */
				htrate = 0.0;
			}
			if (htrate != 0.0) {
				/*
				 * We have the rate.
				 * Print it.
				 */
				ND_PRINT((ndo, "%.1f Mb/s MCS %u ", htrate, mcs_index));
			} else {
				/*
				 * We at least have the MCS index.
				 * Print it.
				 */
				ND_PRINT((ndo, "MCS %u ", mcs_index));
			}
		}
		if (known & IEEE80211_RADIOTAP_MCS_BANDWIDTH_KNOWN) {
			ND_PRINT((ndo, "%s ",
				ht_bandwidth[flags & IEEE80211_RADIOTAP_MCS_BANDWIDTH_MASK]));
		}
		if (known & IEEE80211_RADIOTAP_MCS_GUARD_INTERVAL_KNOWN) {
			ND_PRINT((ndo, "%s GI ",
				(flags & IEEE80211_RADIOTAP_MCS_SHORT_GI) ?
				"short" : "long"));
		}
		if (known & IEEE80211_RADIOTAP_MCS_HT_FORMAT_KNOWN) {
			ND_PRINT((ndo, "%s ",
				(flags & IEEE80211_RADIOTAP_MCS_HT_GREENFIELD) ?
				"greenfield" : "mixed"));
		}
		if (known & IEEE80211_RADIOTAP_MCS_FEC_TYPE_KNOWN) {
			ND_PRINT((ndo, "%s FEC ",
				(flags & IEEE80211_RADIOTAP_MCS_FEC_LDPC) ?
				"LDPC" : "BCC"));
		}
		if (known & IEEE80211_RADIOTAP_MCS_STBC_KNOWN) {
			ND_PRINT((ndo, "RX-STBC%u ",
				(flags & IEEE80211_RADIOTAP_MCS_STBC_MASK) >> IEEE80211_RADIOTAP_MCS_STBC_SHIFT));
		}
		break;
		}

	case IEEE80211_RADIOTAP_AMPDU_STATUS: {
		uint32_t reference_num;
		uint16_t flags;
		uint8_t delim_crc;
		uint8_t reserved;

		rc = cpack_uint32(s, &reference_num);
		if (rc != 0)
			goto trunc;
		rc = cpack_uint16(s, &flags);
		if (rc != 0)
			goto trunc;
		rc = cpack_uint8(s, &delim_crc);
		if (rc != 0)
			goto trunc;
		rc = cpack_uint8(s, &reserved);
		if (rc != 0)
			goto trunc;
		/* Do nothing for now */
		break;
		}

	case IEEE80211_RADIOTAP_VHT: {
		uint16_t known;
		uint8_t flags;
		uint8_t bandwidth;
		uint8_t mcs_nss[4];
		uint8_t coding;
		uint8_t group_id;
		uint16_t partial_aid;
		static const char *vht_bandwidth[32] = {
			"20 MHz",
			"40 MHz",
			"20 MHz (L)",
			"20 MHz (U)",
			"80 MHz",
			"80 MHz (L)",
			"80 MHz (U)",
			"80 MHz (LL)",
			"80 MHz (LU)",
			"80 MHz (UL)",
			"80 MHz (UU)",
			"160 MHz",
			"160 MHz (L)",
			"160 MHz (U)",
			"160 MHz (LL)",
			"160 MHz (LU)",
			"160 MHz (UL)",
			"160 MHz (UU)",
			"160 MHz (LLL)",
			"160 MHz (LLU)",
			"160 MHz (LUL)",
			"160 MHz (UUU)",
			"160 MHz (ULL)",
			"160 MHz (ULU)",
			"160 MHz (UUL)",
			"160 MHz (UUU)",
			"unknown (26)",
			"unknown (27)",
			"unknown (28)",
			"unknown (29)",
			"unknown (30)",
			"unknown (31)"
		};

		rc = cpack_uint16(s, &known);
		if (rc != 0)
			goto trunc;
		rc = cpack_uint8(s, &flags);
		if (rc != 0)
			goto trunc;
		rc = cpack_uint8(s, &bandwidth);
		if (rc != 0)
			goto trunc;
		for (i = 0; i < 4; i++) {
			rc = cpack_uint8(s, &mcs_nss[i]);
			if (rc != 0)
				goto trunc;
		}
		rc = cpack_uint8(s, &coding);
		if (rc != 0)
			goto trunc;
		rc = cpack_uint8(s, &group_id);
		if (rc != 0)
			goto trunc;
		rc = cpack_uint16(s, &partial_aid);
		if (rc != 0)
			goto trunc;
		for (i = 0; i < 4; i++) {
			u_int nss, mcs;
			nss = mcs_nss[i] & IEEE80211_RADIOTAP_VHT_NSS_MASK;
			mcs = (mcs_nss[i] & IEEE80211_RADIOTAP_VHT_MCS_MASK) >> IEEE80211_RADIOTAP_VHT_MCS_SHIFT;

			if (nss == 0)
				continue;

			ND_PRINT((ndo, "User %u MCS %u ", i, mcs));
			ND_PRINT((ndo, "%s FEC ",
				(coding & (IEEE80211_RADIOTAP_CODING_LDPC_USERn << i)) ?
				"LDPC" : "BCC"));
		}
		if (known & IEEE80211_RADIOTAP_VHT_BANDWIDTH_KNOWN) {
			ND_PRINT((ndo, "%s ",
				vht_bandwidth[bandwidth & IEEE80211_RADIOTAP_VHT_BANDWIDTH_MASK]));
		}
		if (known & IEEE80211_RADIOTAP_VHT_GUARD_INTERVAL_KNOWN) {
			ND_PRINT((ndo, "%s GI ",
				(flags & IEEE80211_RADIOTAP_VHT_SHORT_GI) ?
				"short" : "long"));
		}
		break;
		}

	default:
		/* this bit indicates a field whose
		 * size we do not know, so we cannot
		 * proceed.  Just print the bit number.
		 */
		ND_PRINT((ndo, "[bit %u] ", bit));
		return -1;
	}

	return 0;

trunc:
	ND_PRINT((ndo, "%s", tstr));
	return rc;
}

Project: tcpdump
File: print-802_11.c

prism_if_print(netdissect_options *ndo,
               const struct pcap_pkthdr *h, const u_char *p)
{
	u_int caplen = h->caplen;
	u_int length = h->len;
	uint32_t msgcode;

	if (caplen < 4) {
		ND_PRINT((ndo, "%s", tstr));
		return caplen;
	}

	msgcode = EXTRACT_32BITS(p);
	if (msgcode == WLANCAP_MAGIC_COOKIE_V1 ||
	    msgcode == WLANCAP_MAGIC_COOKIE_V2)
		return ieee802_11_avs_radio_print(ndo, p, length, caplen);

	if (caplen < PRISM_HDR_LEN) {
		ND_PRINT((ndo, "%s", tstr));
		return caplen;
	}

	return PRISM_HDR_LEN + ieee802_11_print(ndo, p + PRISM_HDR_LEN,
	    length - PRISM_HDR_LEN, caplen - PRISM_HDR_LEN, 0, 0);
}

Project: tcpdump
File: print-802_11.c

wep_print(netdissect_options *ndo,
          const u_char *p)
{
	uint32_t iv;

	if (!ND_TTEST2(*p, IEEE802_11_IV_LEN + IEEE802_11_KID_LEN))
		return 0;
	iv = EXTRACT_LE_32BITS(p);

	ND_PRINT((ndo, " IV:%3x Pad %x KeyID %x", IV_IV(iv), IV_PAD(iv),
	    IV_KEYID(iv)));

	return 1;
}