print-802_11.c revision 111726
198524Sfenner/*
298524Sfenner * Copyright (c) 2001
398524Sfenner *	Fortress Technologies, Inc.  All rights reserved.
498524Sfenner *      Charlie Lenahan (clenahan@fortresstech.com)
598524Sfenner *
698524Sfenner * Redistribution and use in source and binary forms, with or without
798524Sfenner * modification, are permitted provided that: (1) source code distributions
898524Sfenner * retain the above copyright notice and this paragraph in its entirety, (2)
998524Sfenner * distributions including binary code include the above copyright notice and
1098524Sfenner * this paragraph in its entirety in the documentation or other materials
1198524Sfenner * provided with the distribution, and (3) all advertising materials mentioning
1298524Sfenner * features or use of this software display the following acknowledgement:
1398524Sfenner * ``This product includes software developed by the University of California,
1498524Sfenner * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
1598524Sfenner * the University nor the names of its contributors may be used to endorse
1698524Sfenner * or promote products derived from this software without specific prior
1798524Sfenner * written permission.
1898524Sfenner * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
1998524Sfenner * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
2098524Sfenner * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
2198524Sfenner */
2298524Sfenner
2398524Sfenner#ifndef lint
2498524Sfennerstatic const char rcsid[] =
25111726Sfenner    "@(#) $Header: /tcpdump/master/tcpdump/print-802_11.c,v 1.6.4.1 2002/05/13 08:34:50 guy Exp $ (LBL)";
2698524Sfenner#endif
2798524Sfenner
2898524Sfenner#ifdef HAVE_CONFIG_H
2998524Sfenner#include "config.h"
3098524Sfenner#endif
3198524Sfenner
3298524Sfenner#include <sys/param.h>
3398524Sfenner#include <sys/time.h>
3498524Sfenner#include <sys/socket.h>
3598524Sfenner
3698524Sfenner#include <netinet/in.h>
3798524Sfenner
3898524Sfenner#include <stdio.h>
3998524Sfenner#include <pcap.h>
4098524Sfenner#include <string.h>
4198524Sfenner
4298524Sfenner#include "interface.h"
4398524Sfenner#include "addrtoname.h"
4498524Sfenner#include "ethertype.h"
4598524Sfenner
4698524Sfenner#include "extract.h"
4798524Sfenner
4898524Sfenner#include "ieee802_11.h"
4998524Sfenner
50111726Sfenner#define PRINT_RATES(p) \
5198524Sfennerdo { \
52111726Sfenner	int z; \
53111726Sfenner	char *sep = " ["; \
54111726Sfenner	for (z = 0; z < p.rates.length ; z++) { \
55111726Sfenner		printf("%s%2.1f", sep, (.5 * (p.rates.rate[z] & 0x7f))); \
56111726Sfenner		sep = " "; \
57111726Sfenner	} \
58111726Sfenner	if (p.rates.length != 0) \
59111726Sfenner		printf(" Mbit]"); \
6098524Sfenner} while (0)
6198524Sfenner
6298524Sfennerstatic const char *auth_alg_text[]={"Open System","Shared Key","EAP"};
6398524Sfennerstatic const char *subtype_text[]={
6498524Sfenner	"Assoc Request",
6598524Sfenner	"Assoc Response",
6698524Sfenner	"ReAssoc Request",
6798524Sfenner	"ReAssoc Response",
6898524Sfenner	"Probe Request",
6998524Sfenner	"Probe Response",
7098524Sfenner	"RESERVED",
7198524Sfenner	"RESERVED",
7298524Sfenner	"Beacon",
7398524Sfenner	"ATIM",
7498524Sfenner	"Disassociation",
7598524Sfenner	"Authentication",
7698524Sfenner	"DeAuthentication",
7798524Sfenner	"RESERVED",
7898524Sfenner	"RESERVED"
7998524Sfenner};
8098524Sfenner
8198524Sfennerstatic const char *status_text[] = {
8298524Sfenner	"Succesful",  /*  0  */
8398524Sfenner	"Unspecified failure",  /*  1  */
8498524Sfenner	"Reserved",	  /*  2  */
8598524Sfenner	"Reserved",	  /*  3  */
8698524Sfenner	"Reserved",	  /*  4  */
8798524Sfenner	"Reserved",	  /*  5  */
8898524Sfenner	"Reserved",	  /*  6  */
8998524Sfenner	"Reserved",	  /*  7  */
9098524Sfenner	"Reserved",	  /*  8  */
9198524Sfenner	"Reserved",	  /*  9  */
9298524Sfenner	"Cannot Support all requested capabilities in the Capability Information field",	  /*  10  */
9398524Sfenner	"Reassociation denied due to inability to confirm that association exists",	  /*  11  */
9498524Sfenner	"Association denied due to reason outside the scope of the standard",	  /*  12  */
9598524Sfenner	"Responding station does not support the specified authentication algorithm ",	  /*  13  */
9698524Sfenner	"Received an Authentication frame with authentication transaction " \
9798524Sfenner		"sequence number out of expected sequence",	  /*  14  */
9898524Sfenner	"Authentication rejected because of challenge failure",	  /*  15 */
9998524Sfenner	"Authentication rejected due to timeout waiting for next frame in sequence",	  /*  16 */
10098524Sfenner	"Association denied because AP is unable to handle additional associated stations",	  /*  17 */
10198524Sfenner	"Association denied due to requesting station not supporting all of the " \
10298524Sfenner		"data rates in BSSBasicRateSet parameter",	  /*  18 */
10398524Sfenner	NULL
10498524Sfenner};
10598524Sfenner
10698524Sfennerstatic const char *reason_text[] = {
10798524Sfenner	"Reserved", /* 0 */
10898524Sfenner	"Unspecified reason", /* 1 */
10998524Sfenner	"Previous authentication no longer valid",  /* 2 */
11098524Sfenner	"Deauthenticated because sending station is leaving (or has left) IBSS or ESS", /* 3 */
11198524Sfenner	"Disassociated due to inactivity", /* 4 */
11298524Sfenner	"Disassociated because AP is unable to handle all currently associated stations", /* 5 */
11398524Sfenner	"Class 2 frame receivedfrom nonauthenticated station", /* 6 */
11498524Sfenner	"Class 3 frame received from nonassociated station", /* 7 */
11598524Sfenner	"Disassociated because sending station is leaving (or has left) BSS", /* 8 */
11698524Sfenner	"Station requesting (re)association is not authenticated with responding station", /* 9 */
11798524Sfenner	NULL
11898524Sfenner};
11998524Sfenner
12098524Sfennerstatic int wep_print(const u_char *p,u_int length)
12198524Sfenner{
12298524Sfenner	u_int32_t iv;
12398524Sfenner
12498524Sfenner	if (!TTEST2(*p, 4))
12598524Sfenner		return 0;
12698524Sfenner	iv = EXTRACT_LE_32BITS(p);
12798524Sfenner
12898524Sfenner	printf("Data IV:%3x Pad %x KeyID %x", IV_IV(iv), IV_PAD(iv),
12998524Sfenner	    IV_KEYID(iv));
13098524Sfenner
13198524Sfenner	return 1;
13298524Sfenner}
13398524Sfenner
13498524Sfenner
13598524Sfennerstatic int parse_elements(struct mgmt_body_t *pbody,const u_char *p,int offset)
13698524Sfenner{
13798524Sfenner	for (;;) {
13898524Sfenner		if (!TTEST2(*(p + offset), 1))
139111726Sfenner			return 1;
14098524Sfenner		switch (*(p + offset)) {
14198524Sfenner		case E_SSID:
14298524Sfenner			if (!TTEST2(*(p+offset), 2))
14398524Sfenner				return 0;
14498524Sfenner			memcpy(&(pbody->ssid),p+offset,2); offset += 2;
14598524Sfenner			if (pbody->ssid.length > 0)
14698524Sfenner			{
14798524Sfenner				if (!TTEST2(*(p+offset), pbody->ssid.length))
14898524Sfenner					return 0;
14998524Sfenner				memcpy(&(pbody->ssid.ssid),p+offset,pbody->ssid.length); offset += pbody->ssid.length;
15098524Sfenner				pbody->ssid.ssid[pbody->ssid.length]='\0';
15198524Sfenner			}
15298524Sfenner			break;
15398524Sfenner		case E_CHALLENGE:
15498524Sfenner			if (!TTEST2(*(p+offset), 2))
15598524Sfenner				return 0;
15698524Sfenner			memcpy(&(pbody->challenge),p+offset,2); offset += 2;
15798524Sfenner			if (pbody->challenge.length > 0)
15898524Sfenner			{
15998524Sfenner				if (!TTEST2(*(p+offset), pbody->challenge.length))
16098524Sfenner					return 0;
16198524Sfenner				memcpy(&(pbody->challenge.text),p+offset,pbody->challenge.length); offset += pbody->challenge.length;
16298524Sfenner				pbody->challenge.text[pbody->challenge.length]='\0';
16398524Sfenner			}
16498524Sfenner			break;
16598524Sfenner		case E_RATES:
16698524Sfenner			if (!TTEST2(*(p+offset), 2))
16798524Sfenner				return 0;
16898524Sfenner			memcpy(&(pbody->rates),p+offset,2); offset += 2;
16998524Sfenner			if (pbody->rates.length > 0) {
17098524Sfenner				if (!TTEST2(*(p+offset), pbody->rates.length))
17198524Sfenner					return 0;
17298524Sfenner				memcpy(&(pbody->rates.rate),p+offset,pbody->rates.length); offset += pbody->rates.length;
17398524Sfenner			}
17498524Sfenner			break;
17598524Sfenner		case E_DS:
17698524Sfenner			if (!TTEST2(*(p+offset), 3))
17798524Sfenner				return 0;
17898524Sfenner			memcpy(&(pbody->ds),p+offset,3); offset +=3;
17998524Sfenner			break;
18098524Sfenner		case E_CF:
18198524Sfenner			if (!TTEST2(*(p+offset), 8))
18298524Sfenner				return 0;
18398524Sfenner			memcpy(&(pbody->cf),p+offset,8); offset +=8;
18498524Sfenner			break;
18598524Sfenner		case E_TIM:
18698524Sfenner			if (!TTEST2(*(p+offset), 2))
18798524Sfenner				return 0;
18898524Sfenner			memcpy(&(pbody->tim),p+offset,2); offset +=2;
18998524Sfenner			if (!TTEST2(*(p+offset), 3))
19098524Sfenner				return 0;
19198524Sfenner			memcpy(&(pbody->tim.count),p+offset,3); offset +=3;
19298524Sfenner
19398524Sfenner			if ((pbody->tim.length -3) > 0)
19498524Sfenner			{
19598524Sfenner				if (!TTEST2(*(p+offset), pbody->tim.length -3))
19698524Sfenner					return 0;
19798524Sfenner				memcpy((pbody->tim.bitmap),p+(pbody->tim.length -3),(pbody->tim.length -3));
19898524Sfenner				offset += pbody->tim.length -3;
19998524Sfenner			}
20098524Sfenner
20198524Sfenner			break;
20298524Sfenner		default:
20398524Sfenner#if 0
20498524Sfenner			printf("(1) unhandled element_id (%d)  ", *(p+offset) );
20598524Sfenner#endif
20698524Sfenner			offset+= *(p+offset+1) + 2;
20798524Sfenner			break;
20898524Sfenner		}
20998524Sfenner	}
21098524Sfenner	return 1;
21198524Sfenner}
21298524Sfenner
21398524Sfenner/*********************************************************************************
21498524Sfenner * Print Handle functions for the management frame types
21598524Sfenner *********************************************************************************/
21698524Sfenner
21798524Sfennerstatic int handle_beacon(u_int16_t fc, const struct mgmt_header_t *pmh,
21898524Sfenner    const u_char *p)
21998524Sfenner{
22098524Sfenner	struct mgmt_body_t pbody;
22198524Sfenner	int offset = 0;
22298524Sfenner
22398524Sfenner	memset(&pbody, 0, sizeof(pbody));
22498524Sfenner
22598524Sfenner	if (!TTEST2(*p, 12))
22698524Sfenner		return 0;
22798524Sfenner	memcpy(&pbody.timestamp, p, 8);
22898524Sfenner	offset += 8;
22998524Sfenner	pbody.beacon_interval = EXTRACT_LE_16BITS(p+offset);
23098524Sfenner	offset += 2;
23198524Sfenner	pbody.capability_info = EXTRACT_LE_16BITS(p+offset);
23298524Sfenner	offset += 2;
23398524Sfenner
23498524Sfenner	if (!parse_elements(&pbody,p,offset))
23598524Sfenner		return 0;
23698524Sfenner
237111726Sfenner	printf("%s (", subtype_text[FC_SUBTYPE(fc)]);
238111726Sfenner	fn_print(pbody.ssid.ssid, NULL);
239111726Sfenner	printf(")");
240111726Sfenner	PRINT_RATES(pbody);
241111726Sfenner	printf(" %s CH: %u %s",
24298524Sfenner	    CAPABILITY_ESS(pbody.capability_info) ? "ESS" : "IBSS",
24398524Sfenner	    pbody.ds.channel,
24498524Sfenner	    CAPABILITY_PRIVACY(pbody.capability_info) ? ", PRIVACY" : "" );
24598524Sfenner
24698524Sfenner	return 1;
24798524Sfenner}
24898524Sfenner
24998524Sfennerstatic int handle_assoc_request(u_int16_t fc, const struct mgmt_header_t *pmh,
25098524Sfenner    const u_char *p)
25198524Sfenner{
25298524Sfenner	struct mgmt_body_t pbody;
25398524Sfenner	int offset = 0;
25498524Sfenner
25598524Sfenner	memset(&pbody, 0, sizeof(pbody));
25698524Sfenner
25798524Sfenner	if (!TTEST2(*p, 4))
25898524Sfenner		return 0;
25998524Sfenner	pbody.capability_info = EXTRACT_LE_16BITS(p);
26098524Sfenner	offset += 2;
26198524Sfenner	pbody.listen_interval = EXTRACT_LE_16BITS(p+offset);
26298524Sfenner	offset += 2;
26398524Sfenner
26498524Sfenner	if (!parse_elements(&pbody,p,offset))
26598524Sfenner		return 0;
26698524Sfenner
267111726Sfenner	printf("%s (", subtype_text[FC_SUBTYPE(fc)]);
268111726Sfenner	fn_print(pbody.ssid.ssid, NULL);
269111726Sfenner	printf(")");
270111726Sfenner	PRINT_RATES(pbody);
27198524Sfenner	return 1;
27298524Sfenner}
27398524Sfenner
27498524Sfennerstatic int handle_assoc_response(u_int16_t fc, const struct mgmt_header_t *pmh,
27598524Sfenner    const u_char *p)
27698524Sfenner{
27798524Sfenner	struct mgmt_body_t pbody;
27898524Sfenner	int offset = 0;
27998524Sfenner
28098524Sfenner	memset(&pbody, 0, sizeof(pbody));
28198524Sfenner
28298524Sfenner	if (!TTEST2(*p, 6))
28398524Sfenner		return 0;
28498524Sfenner	pbody.capability_info = EXTRACT_LE_16BITS(p);
28598524Sfenner	offset += 2;
28698524Sfenner	pbody.status_code = EXTRACT_LE_16BITS(p+offset);
28798524Sfenner	offset += 2;
28898524Sfenner	pbody.aid = EXTRACT_LE_16BITS(p+offset);
28998524Sfenner	offset += 2;
29098524Sfenner
29198524Sfenner	if (!parse_elements(&pbody,p,offset))
29298524Sfenner		return 0;
29398524Sfenner
294111726Sfenner	printf("%s AID(%x) :%s: %s", subtype_text[FC_SUBTYPE(fc)],
29598524Sfenner	    ((u_int16_t)(pbody.aid << 2 )) >> 2 ,
29698524Sfenner	    CAPABILITY_PRIVACY(pbody.capability_info) ? " PRIVACY " : "",
29798524Sfenner	    (pbody.status_code < 19 ? status_text[pbody.status_code] : "n/a"));
29898524Sfenner
29998524Sfenner	return 1;
30098524Sfenner}
30198524Sfenner
30298524Sfenner
30398524Sfennerstatic int handle_reassoc_request(u_int16_t fc, const struct mgmt_header_t *pmh,
30498524Sfenner    const u_char *p)
30598524Sfenner{
30698524Sfenner	struct mgmt_body_t pbody;
30798524Sfenner	int offset = 0;
30898524Sfenner
30998524Sfenner	memset(&pbody, 0, sizeof(pbody));
31098524Sfenner
31198524Sfenner	if (!TTEST2(*p, 10))
31298524Sfenner		return 0;
31398524Sfenner	pbody.capability_info = EXTRACT_LE_16BITS(p);
31498524Sfenner	offset += 2;
31598524Sfenner	pbody.listen_interval = EXTRACT_LE_16BITS(p+offset);
31698524Sfenner	offset += 2;
31798524Sfenner	memcpy(&pbody.ap,p+offset,6);
31898524Sfenner	offset += 6;
31998524Sfenner
32098524Sfenner	if (!parse_elements(&pbody,p,offset))
32198524Sfenner		return 0;
32298524Sfenner
323111726Sfenner	printf("%s (", subtype_text[FC_SUBTYPE(fc)]);
324111726Sfenner	fn_print(pbody.ssid.ssid, NULL);
325111726Sfenner	printf(") AP : %s", etheraddr_string( pbody.ap ));
32698524Sfenner
32798524Sfenner	return 1;
32898524Sfenner}
32998524Sfenner
33098524Sfennerstatic int handle_reassoc_response(u_int16_t fc, const struct mgmt_header_t *pmh,
33198524Sfenner    const u_char *p)
33298524Sfenner{
33398524Sfenner	/* Same as a Association Reponse */
33498524Sfenner	return handle_assoc_response(fc,pmh,p);
33598524Sfenner}
33698524Sfenner
33798524Sfennerstatic int handle_probe_request(u_int16_t fc, const struct mgmt_header_t *pmh,
33898524Sfenner    const u_char *p)
33998524Sfenner{
34098524Sfenner	struct mgmt_body_t  pbody;
34198524Sfenner	int offset = 0;
34298524Sfenner
34398524Sfenner	memset(&pbody, 0, sizeof(pbody));
34498524Sfenner
34598524Sfenner	if (!parse_elements(&pbody, p, offset))
34698524Sfenner		return 0;
34798524Sfenner
348111726Sfenner	printf("%s (", subtype_text[FC_SUBTYPE(fc)]);
349111726Sfenner	fn_print(pbody.ssid.ssid, NULL);
350111726Sfenner	printf(")");
351111726Sfenner	PRINT_RATES(pbody);
35298524Sfenner
35398524Sfenner	return 1;
35498524Sfenner}
35598524Sfenner
35698524Sfennerstatic int handle_probe_response(u_int16_t fc, const struct mgmt_header_t *pmh,
35798524Sfenner    const u_char *p)
35898524Sfenner{
35998524Sfenner	struct mgmt_body_t  pbody;
36098524Sfenner	int offset = 0;
36198524Sfenner
36298524Sfenner	memset(&pbody, 0, sizeof(pbody));
36398524Sfenner
36498524Sfenner	if (!TTEST2(*p, 12))
36598524Sfenner		return 0;
36698524Sfenner	memcpy(&pbody.timestamp,p,8);
36798524Sfenner	offset += 8;
36898524Sfenner	pbody.beacon_interval = EXTRACT_LE_16BITS(p+offset);
36998524Sfenner	offset += 2;
37098524Sfenner	pbody.capability_info = EXTRACT_LE_16BITS(p+offset);
37198524Sfenner	offset += 2;
37298524Sfenner
37398524Sfenner	if (!parse_elements(&pbody, p, offset))
37498524Sfenner		return 0;
37598524Sfenner
376111726Sfenner	printf("%s (", subtype_text[FC_SUBTYPE(fc)]);
377111726Sfenner	fn_print(pbody.ssid.ssid, NULL);
378111726Sfenner	printf(") ");
379111726Sfenner	PRINT_RATES(pbody);
380111726Sfenner	printf(" CH: %u%s", pbody.ds.channel,
381111726Sfenner	    CAPABILITY_PRIVACY(pbody.capability_info) ? ", PRIVACY" : "" );
38298524Sfenner
38398524Sfenner	return 1;
38498524Sfenner}
38598524Sfenner
38698524Sfennerstatic int handle_atim(u_int16_t fc, const struct mgmt_header_t *pmh,
38798524Sfenner    const u_char *p)
38898524Sfenner{
38998524Sfenner	/* the frame body for ATIM is null. */
39098524Sfenner	printf("ATIM");
39198524Sfenner	return 1;
39298524Sfenner}
39398524Sfenner
39498524Sfennerstatic int handle_disassoc(u_int16_t fc, const struct mgmt_header_t *pmh,
39598524Sfenner    const u_char *p)
39698524Sfenner{
39798524Sfenner	struct mgmt_body_t  pbody;
39898524Sfenner	int offset = 0;
39998524Sfenner
40098524Sfenner	memset(&pbody, 0, sizeof(pbody));
40198524Sfenner
40298524Sfenner	if (!TTEST2(*p, 2))
40398524Sfenner		return 0;
40498524Sfenner	pbody.reason_code = EXTRACT_LE_16BITS(p);
40598524Sfenner	offset += 2;
40698524Sfenner
407111726Sfenner	printf("%s: %s", subtype_text[FC_SUBTYPE(fc)],
40898524Sfenner	    pbody.reason_code < 10 ? reason_text[pbody.reason_code] : "Reserved" );
40998524Sfenner
41098524Sfenner	return 1;
41198524Sfenner}
41298524Sfenner
41398524Sfennerstatic int handle_auth(u_int16_t fc, const struct mgmt_header_t *pmh,
41498524Sfenner    const u_char *p)
41598524Sfenner{
41698524Sfenner	struct mgmt_body_t  pbody;
41798524Sfenner	int offset = 0;
41898524Sfenner
41998524Sfenner	memset(&pbody, 0, sizeof(pbody));
42098524Sfenner
42198524Sfenner	if (!TTEST2(*p, 6))
42298524Sfenner		return 0;
42398524Sfenner	pbody.auth_alg = EXTRACT_LE_16BITS(p);
42498524Sfenner	offset += 2;
42598524Sfenner	pbody.auth_trans_seq_num = EXTRACT_LE_16BITS(p + offset);
42698524Sfenner	offset += 2;
42798524Sfenner	pbody.status_code = EXTRACT_LE_16BITS(p + offset);
42898524Sfenner	offset += 2;
42998524Sfenner
43098524Sfenner	if (!parse_elements(&pbody,p,offset))
43198524Sfenner		return 0;
43298524Sfenner
43398524Sfenner	if ((pbody.auth_alg == 1) &&
43498524Sfenner	    ((pbody.auth_trans_seq_num == 2) || (pbody.auth_trans_seq_num == 3))) {
43598524Sfenner		printf("%s (%s)-%x [Challenge Text] %s",
43698524Sfenner			subtype_text[FC_SUBTYPE(fc)],
43798524Sfenner			pbody.auth_alg < 4 ? auth_alg_text[pbody.auth_alg] : "Reserved" ,
43898524Sfenner			pbody.auth_trans_seq_num,
43998524Sfenner			 ((pbody.auth_trans_seq_num % 2) ?
44098524Sfenner				(pbody.status_code < 19 ? status_text[pbody.status_code] : "n/a") : "" ));
44198524Sfenner	} else {
44298524Sfenner		printf("%s (%s)-%x: %s",
44398524Sfenner		    subtype_text[FC_SUBTYPE(fc)],
44498524Sfenner		    pbody.auth_alg < 4 ? auth_alg_text[pbody.auth_alg] : "Reserved" ,
44598524Sfenner		    pbody.auth_trans_seq_num,
44698524Sfenner		    ((pbody.auth_trans_seq_num % 2) ? (pbody.status_code < 19 ? status_text[pbody.status_code] : "n/a")  : ""));
44798524Sfenner	}
44898524Sfenner
44998524Sfenner	return 1;
45098524Sfenner}
45198524Sfenner
45298524Sfennerstatic int handle_deauth(u_int16_t fc, const struct mgmt_header_t *pmh,
45398524Sfenner    const u_char *p)
45498524Sfenner{
45598524Sfenner	struct mgmt_body_t  pbody;
45698524Sfenner	int offset = 0;
45798524Sfenner
45898524Sfenner	memset(&pbody, 0, sizeof(pbody));
45998524Sfenner
46098524Sfenner	if (!TTEST2(*p, 2))
46198524Sfenner		return 0;
46298524Sfenner	pbody.reason_code = EXTRACT_LE_16BITS(p);
46398524Sfenner	offset += 2;
46498524Sfenner
46598524Sfenner	if (eflag) {
46698524Sfenner		printf("%s: %s",
46798524Sfenner		    subtype_text[FC_SUBTYPE(fc)],
46898524Sfenner		    pbody.reason_code < 10 ? reason_text[pbody.reason_code] : "Reserved" );
46998524Sfenner	} else {
47098524Sfenner		printf("%s (%s): %s",
47198524Sfenner		    subtype_text[FC_SUBTYPE(fc)], etheraddr_string(pmh->sa),
47298524Sfenner		    pbody.reason_code < 10 ? reason_text[pbody.reason_code] : "Reserved" );
47398524Sfenner	}
47498524Sfenner
47598524Sfenner	return 1;
47698524Sfenner}
47798524Sfenner
47898524Sfenner
47998524Sfenner/*********************************************************************************
48098524Sfenner * Print Body funcs
48198524Sfenner *********************************************************************************/
48298524Sfenner
48398524Sfenner
48498524Sfennerstatic int mgmt_body_print(u_int16_t fc, const struct mgmt_header_t *pmh,
48598524Sfenner    const u_char *p, u_int length)
48698524Sfenner{
48798524Sfenner	switch (FC_SUBTYPE(fc)) {
48898524Sfenner	case ST_ASSOC_REQUEST:
48998524Sfenner		return (handle_assoc_request(fc, pmh, p));
49098524Sfenner	case ST_ASSOC_RESPONSE:
49198524Sfenner		return (handle_assoc_response(fc, pmh, p));
49298524Sfenner	case ST_REASSOC_REQUEST:
49398524Sfenner		return (handle_reassoc_request(fc, pmh, p));
49498524Sfenner	case ST_REASSOC_RESPONSE:
49598524Sfenner		return (handle_reassoc_response(fc, pmh, p));
49698524Sfenner	case ST_PROBE_REQUEST:
49798524Sfenner		return (handle_probe_request(fc, pmh, p));
49898524Sfenner	case ST_PROBE_RESPONSE:
49998524Sfenner		return (handle_probe_response(fc, pmh, p));
50098524Sfenner	case ST_BEACON:
50198524Sfenner		return (handle_beacon(fc, pmh, p));
50298524Sfenner	case ST_ATIM:
50398524Sfenner		return (handle_atim(fc, pmh, p));
50498524Sfenner	case ST_DISASSOC:
50598524Sfenner		return (handle_disassoc(fc, pmh, p));
50698524Sfenner	case ST_AUTH:
50798524Sfenner		if (!TTEST2(*p, 3))
50898524Sfenner			return 0;
50998524Sfenner		if ((p[0] == 0 ) && (p[1] == 0) && (p[2] == 0)) {
51098524Sfenner			printf("Authentication (Shared-Key)-3 ");
51198524Sfenner			return (wep_print(p, length));
51298524Sfenner		}
51398524Sfenner		else
51498524Sfenner			return (handle_auth(fc, pmh, p));
51598524Sfenner	case ST_DEAUTH:
51698524Sfenner		return (handle_deauth(fc, pmh, p));
51798524Sfenner		break;
51898524Sfenner	default:
51998524Sfenner		printf("Unhandled Managment subtype(%x)",
52098524Sfenner		    FC_SUBTYPE(fc));
52198524Sfenner		return 1;
52298524Sfenner	}
52398524Sfenner}
52498524Sfenner
52598524Sfenner
52698524Sfenner/*********************************************************************************
52798524Sfenner * Handles printing all the control frame types
52898524Sfenner *********************************************************************************/
52998524Sfenner
53098524Sfennerstatic int ctrl_body_print(u_int16_t fc,const u_char *p, u_int length)
53198524Sfenner{
53298524Sfenner	switch (FC_SUBTYPE(fc)) {
53398524Sfenner	case CTRL_PS_POLL:
53498524Sfenner		if (!TTEST2(*p, CTRL_PS_POLL_LEN))
53598524Sfenner			return 0;
53698524Sfenner		printf("Power Save-Poll AID(%x)",
53798524Sfenner		    EXTRACT_LE_16BITS(&(((const struct ctrl_ps_poll_t *)p)->aid)));
53898524Sfenner		break;
53998524Sfenner	case CTRL_RTS:
54098524Sfenner		if (!TTEST2(*p, CTRL_RTS_LEN))
54198524Sfenner			return 0;
54298524Sfenner		if (eflag)
54398524Sfenner			printf("Request-To-Send");
54498524Sfenner		else
54598524Sfenner			printf("Request-To-Send TA:%s ",
54698524Sfenner			    etheraddr_string(((const struct ctrl_rts_t *)p)->ta));
54798524Sfenner		break;
54898524Sfenner	case CTRL_CTS:
54998524Sfenner		if (!TTEST2(*p, CTRL_CTS_LEN))
55098524Sfenner			return 0;
55198524Sfenner		if (eflag)
55298524Sfenner			printf("Clear-To-Send");
55398524Sfenner		else
55498524Sfenner			printf("Clear-To-Send RA:%s ",
55598524Sfenner			    etheraddr_string(((const struct ctrl_cts_t *)p)->ra));
55698524Sfenner		break;
55798524Sfenner	case CTRL_ACK:
55898524Sfenner		if (!TTEST2(*p, CTRL_ACK_LEN))
55998524Sfenner			return 0;
56098524Sfenner		if (eflag)
56198524Sfenner			printf("Acknowledgment");
56298524Sfenner		else
56398524Sfenner			printf("Acknowledgment RA:%s ",
56498524Sfenner			    etheraddr_string(((const struct ctrl_ack_t *)p)->ra));
56598524Sfenner		break;
56698524Sfenner	case CTRL_CF_END:
56798524Sfenner		if (!TTEST2(*p, CTRL_END_LEN))
56898524Sfenner			return 0;
56998524Sfenner		if (eflag)
57098524Sfenner			printf("CF-End");
57198524Sfenner		else
57298524Sfenner			printf("CF-End RA:%s ",
57398524Sfenner			    etheraddr_string(((const struct ctrl_end_t *)p)->ra));
57498524Sfenner		break;
57598524Sfenner	case CTRL_END_ACK:
57698524Sfenner		if (!TTEST2(*p, CTRL_END_ACK_LEN))
57798524Sfenner			return 0;
57898524Sfenner		if (eflag)
57998524Sfenner			printf("CF-End+CF-Ack");
58098524Sfenner		else
58198524Sfenner			printf("CF-End+CF-Ack RA:%s ",
58298524Sfenner			    etheraddr_string(((const struct ctrl_end_ack_t *)p)->ra));
58398524Sfenner		break;
58498524Sfenner	default:
58598524Sfenner		printf("(B) Unknown Ctrl Subtype");
58698524Sfenner	}
58798524Sfenner	return 1;
58898524Sfenner}
58998524Sfenner
59098524Sfenner
59198524Sfenner
59298524Sfenner/*
59398524Sfenner * Print Header funcs
59498524Sfenner */
59598524Sfenner
59698524Sfenner/*
59798524Sfenner *  Data Frame - Address field contents
59898524Sfenner *
59998524Sfenner *  To Ds  | From DS | Addr 1 | Addr 2 | Addr 3 | Addr 4
60098524Sfenner *    0    |  0      |  DA    | SA     | BSSID  | n/a
60198524Sfenner *    0    |  1      |  DA    | BSSID  | SA     | n/a
60298524Sfenner *    1    |  0      |  BSSID | SA     | DA     | n/a
60398524Sfenner *    1    |  1      |  RA    | TA     | DA     | SA
60498524Sfenner */
60598524Sfenner
60698524Sfennerstatic void data_header_print(u_int16_t fc,const u_char *p, u_int length)
60798524Sfenner{
60898524Sfenner#define ADDR1  (p + 4)
60998524Sfenner#define ADDR2  (p + 10)
61098524Sfenner#define ADDR3  (p + 16)
61198524Sfenner#define ADDR4  (p + 24)
61298524Sfenner
61398524Sfenner	if (!FC_TO_DS(fc)) {
61498524Sfenner		if (!FC_FROM_DS(fc))
61598524Sfenner			printf("DA:%s SA:%s BSSID:%s ",
61698524Sfenner			    etheraddr_string(ADDR1), etheraddr_string(ADDR2),
61798524Sfenner			    etheraddr_string(ADDR3));
61898524Sfenner		else
61998524Sfenner			printf("DA:%s BSSID:%s SA:%s ",
62098524Sfenner			    etheraddr_string(ADDR1), etheraddr_string(ADDR2),
62198524Sfenner			    etheraddr_string(ADDR3));
62298524Sfenner	} else {
62398524Sfenner		if (!FC_FROM_DS(fc))
62498524Sfenner			printf("BSSID:%s SA:%s DA:%s ",
62598524Sfenner			    etheraddr_string(ADDR1), etheraddr_string(ADDR2),
62698524Sfenner			    etheraddr_string(ADDR3));
62798524Sfenner		else
62898524Sfenner			printf("RA:%s TA:%s DA:%s SA:%s ",
62998524Sfenner			    etheraddr_string(ADDR1), etheraddr_string(ADDR2),
63098524Sfenner			    etheraddr_string(ADDR3), etheraddr_string(ADDR4));
63198524Sfenner	}
63298524Sfenner
63398524Sfenner#undef ADDR1
63498524Sfenner#undef ADDR2
63598524Sfenner#undef ADDR3
63698524Sfenner#undef ADDR4
63798524Sfenner}
63898524Sfenner
63998524Sfenner
64098524Sfennerstatic void mgmt_header_print(const u_char *p, u_int length)
64198524Sfenner{
64298524Sfenner	const struct mgmt_header_t *hp = (const struct mgmt_header_t *) p;
64398524Sfenner
64498524Sfenner	printf("BSSID:%s DA:%s SA:%s ",
64598524Sfenner	    etheraddr_string((hp)->bssid), etheraddr_string((hp)->da),
64698524Sfenner	    etheraddr_string((hp)->sa));
64798524Sfenner}
64898524Sfenner
64998524Sfennerstatic void ctrl_header_print(u_int16_t fc,const u_char *p, u_int length)
65098524Sfenner{
65198524Sfenner	switch (FC_SUBTYPE(fc)) {
65298524Sfenner	case CTRL_PS_POLL:
65398524Sfenner		printf("BSSID:%s TA:%s ",
65498524Sfenner		    etheraddr_string(((const struct ctrl_ps_poll_t *)p)->bssid),
65598524Sfenner		    etheraddr_string(((const struct ctrl_ps_poll_t *)p)->ta));
65698524Sfenner		break;
65798524Sfenner	case CTRL_RTS:
65898524Sfenner		printf("RA:%s TA:%s ",
65998524Sfenner		    etheraddr_string(((const struct ctrl_rts_t *)p)->ra),
66098524Sfenner		    etheraddr_string(((const struct ctrl_rts_t *)p)->ta));
66198524Sfenner		break;
66298524Sfenner	case CTRL_CTS:
66398524Sfenner		printf("RA:%s ",
66498524Sfenner		    etheraddr_string(((const struct ctrl_cts_t *)p)->ra));
66598524Sfenner		break;
66698524Sfenner	case CTRL_ACK:
66798524Sfenner		printf("RA:%s ",
66898524Sfenner		    etheraddr_string(((const struct ctrl_ack_t *)p)->ra));
66998524Sfenner		break;
67098524Sfenner	case CTRL_CF_END:
67198524Sfenner		printf("RA:%s BSSID:%s ",
67298524Sfenner		    etheraddr_string(((const struct ctrl_end_t *)p)->ra),
67398524Sfenner		    etheraddr_string(((const struct ctrl_end_t *)p)->bssid));
67498524Sfenner		break;
67598524Sfenner	case CTRL_END_ACK:
67698524Sfenner		printf("RA:%s BSSID:%s ",
67798524Sfenner		    etheraddr_string(((const struct ctrl_end_ack_t *)p)->ra),
67898524Sfenner		    etheraddr_string(((const struct ctrl_end_ack_t *)p)->bssid));
67998524Sfenner		break;
68098524Sfenner	default:
68198524Sfenner		printf("(H) Unknown Ctrl Subtype");
68298524Sfenner	}
68398524Sfenner}
68498524Sfenner
68598524Sfennerstatic int GetHeaderLength(u_int16_t fc)
68698524Sfenner{
68798524Sfenner	int iLength=0;
68898524Sfenner
68998524Sfenner	switch (FC_TYPE(fc)) {
69098524Sfenner	case T_MGMT:
69198524Sfenner		iLength = MGMT_HEADER_LEN;
69298524Sfenner		break;
69398524Sfenner	case T_CTRL:
69498524Sfenner		switch (FC_SUBTYPE(fc)) {
69598524Sfenner		case CTRL_PS_POLL:
69698524Sfenner			iLength = CTRL_PS_POLL_LEN;
69798524Sfenner			break;
69898524Sfenner		case CTRL_RTS:
69998524Sfenner			iLength = CTRL_RTS_LEN;
70098524Sfenner			break;
70198524Sfenner		case CTRL_CTS:
70298524Sfenner			iLength = CTRL_CTS_LEN;
70398524Sfenner			break;
70498524Sfenner		case CTRL_ACK:
70598524Sfenner			iLength = CTRL_ACK_LEN;
70698524Sfenner			break;
70798524Sfenner		case CTRL_CF_END:
70898524Sfenner			iLength = CTRL_END_LEN;
70998524Sfenner			break;
71098524Sfenner		case CTRL_END_ACK:
71198524Sfenner			iLength = CTRL_END_ACK_LEN;
71298524Sfenner			break;
71398524Sfenner		default:
71498524Sfenner			iLength = 0;
71598524Sfenner			break;
71698524Sfenner		}
71798524Sfenner		break;
71898524Sfenner	case T_DATA:
71998524Sfenner		if (FC_TO_DS(fc) && FC_FROM_DS(fc))
72098524Sfenner			iLength = 30;
72198524Sfenner		else
72298524Sfenner			iLength = 24;
72398524Sfenner		break;
72498524Sfenner	default:
72598524Sfenner		printf("unknown IEEE802.11 frame type (%d)",
72698524Sfenner		    FC_TYPE(fc));
72798524Sfenner		break;
72898524Sfenner	}
72998524Sfenner
73098524Sfenner	return iLength;
73198524Sfenner}
73298524Sfenner
73398524Sfenner/*
73498524Sfenner * Print the 802.11 MAC header
73598524Sfenner */
73698524Sfennerstatic inline void
73798524Sfennerieee_802_11_print(u_int16_t fc, const u_char *p, u_int length)
73898524Sfenner{
73998524Sfenner	switch (FC_TYPE(fc)) {
74098524Sfenner	case T_MGMT:
74198524Sfenner		mgmt_header_print(p, length);
74298524Sfenner		break;
74398524Sfenner
74498524Sfenner	case T_CTRL:
74598524Sfenner		ctrl_header_print(fc, p, length);
74698524Sfenner		break;
74798524Sfenner
74898524Sfenner	case T_DATA:
74998524Sfenner		data_header_print(fc, p, length);
75098524Sfenner		break;
75198524Sfenner
75298524Sfenner	default:
75398524Sfenner		printf("(header) unknown IEEE802.11 frame type (%d)",
75498524Sfenner		    FC_TYPE(fc));
75598524Sfenner		break;
75698524Sfenner	}
75798524Sfenner}
75898524Sfenner
75998524Sfenner/*
76098524Sfenner * This is the top level routine of the printer.  'p' is the points
76198524Sfenner * to the ether header of the packet, 'h->tv' is the timestamp,
76298524Sfenner * 'h->length' is the length of the packet off the wire, and 'h->caplen'
76398524Sfenner * is the number of bytes actually captured.
76498524Sfenner */
76598524Sfennervoid
76698524Sfennerieee802_11_if_print(u_char *user, const struct pcap_pkthdr *h, const u_char *p)
76798524Sfenner{
76898524Sfenner	u_int caplen = h->caplen;
76998524Sfenner	u_int length = h->len;
77098524Sfenner	u_int16_t fc;
77198524Sfenner	u_int HEADER_LENGTH;
77298524Sfenner	u_short extracted_ethertype;
77398524Sfenner
77498524Sfenner	++infodelay;
77598524Sfenner	ts_print(&h->ts);
77698524Sfenner
77798524Sfenner	if (caplen < IEEE802_11_FC_LEN) {
77898524Sfenner		printf("[|802.11]");
77998524Sfenner		goto out;
78098524Sfenner	}
78198524Sfenner
78298524Sfenner	fc=EXTRACT_LE_16BITS(p);
78398524Sfenner
78498524Sfenner	if (eflag)
78598524Sfenner		ieee_802_11_print(fc, p, length);
78698524Sfenner
78798524Sfenner	/*
78898524Sfenner	 * Some printers want to get back at the ethernet addresses,
78998524Sfenner	 * and/or check that they're not walking off the end of the packet.
79098524Sfenner	 * Rather than pass them all the way down, we set these globals.
79198524Sfenner	 */
79298524Sfenner	packetp = p;
79398524Sfenner	snapend = p + caplen;
79498524Sfenner
79598524Sfenner	HEADER_LENGTH=GetHeaderLength(fc);
79698524Sfenner
79798524Sfenner	length -= HEADER_LENGTH;
79898524Sfenner	caplen -= HEADER_LENGTH;
79998524Sfenner	p += HEADER_LENGTH;
80098524Sfenner
80198524Sfenner	switch (FC_TYPE(fc)) {
80298524Sfenner	case T_MGMT:
80398524Sfenner		if (!mgmt_body_print(fc, (const struct mgmt_header_t *)packetp,
80498524Sfenner		    p, length)) {
80598524Sfenner			printf("[|802.11]");
80698524Sfenner			goto out;
80798524Sfenner		}
80898524Sfenner		break;
80998524Sfenner
81098524Sfenner	case T_CTRL:
81198524Sfenner		if (!ctrl_body_print(fc, p - HEADER_LENGTH,
81298524Sfenner		    length + HEADER_LENGTH)) {
81398524Sfenner			printf("[|802.11]");
81498524Sfenner			goto out;
81598524Sfenner		}
81698524Sfenner		break;
81798524Sfenner
81898524Sfenner	case T_DATA:
81998524Sfenner		/* There may be a problem w/ AP not having this bit set */
82098524Sfenner 		if (FC_WEP(fc)) {
82198524Sfenner			if (!wep_print(p,length)) {
82298524Sfenner				printf("[|802.11]");
82398524Sfenner				goto out;
82498524Sfenner			}
82598524Sfenner		} else {
82698524Sfenner			if (llc_print(p, length, caplen, packetp + 10,
82798524Sfenner			    packetp + 4, &extracted_ethertype) == 0) {
82898524Sfenner				/*
82998524Sfenner				 * Some kinds of LLC packet we cannot
83098524Sfenner				 * handle intelligently
83198524Sfenner				 */
83298524Sfenner				if (!eflag)
83398524Sfenner					ieee_802_11_print(fc, p - HEADER_LENGTH,
83498524Sfenner					    length + HEADER_LENGTH);
83598524Sfenner				if (extracted_ethertype) {
83698524Sfenner					printf("(LLC %s) ",
83798524Sfenner					    etherproto_string(htons(extracted_ethertype)));
83898524Sfenner				}
83998524Sfenner				if (!xflag && !qflag)
84098524Sfenner					default_print(p, caplen);
84198524Sfenner			}
84298524Sfenner		}
84398524Sfenner		break;
84498524Sfenner
84598524Sfenner	default:
84698524Sfenner		printf("(body) unhandled IEEE802.11 frame type (%d)",
84798524Sfenner		    FC_TYPE(fc));
84898524Sfenner		break;
84998524Sfenner	}
85098524Sfenner
85198524Sfenner	if (xflag)
85298524Sfenner		default_print(p, caplen);
85398524Sfenner out:
85498524Sfenner	putchar('\n');
85598524Sfenner	--infodelay;
85698524Sfenner	if (infoprint)
85798524Sfenner		info(0);
85898524Sfenner}
859