1/*
2 * Copyright (c) 2009
3 * 	Siemens AG, All rights reserved.
4 * 	Dmitry Eremin-Solenikov (dbaryshkov@gmail.com)
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that: (1) source code distributions
8 * retain the above copyright notice and this paragraph in its entirety, (2)
9 * distributions including binary code include the above copyright notice and
10 * this paragraph in its entirety in the documentation or other materials
11 * provided with the distribution, and (3) all advertising materials mentioning
12 * features or use of this software display the following acknowledgement:
13 * ``This product includes software developed by the University of California,
14 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
15 * the University nor the names of its contributors may be used to endorse
16 * or promote products derived from this software without specific prior
17 * written permission.
18 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
19 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
20 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
21 */
22
23#define NETDISSECT_REWORKED
24#ifdef HAVE_CONFIG_H
25#include "config.h"
26#endif
27
28#include <tcpdump-stdinc.h>
29
30#include "interface.h"
31#include "addrtoname.h"
32
33#include "extract.h"
34
35static const char *ftypes[] = {
36	"Beacon",			/* 0 */
37	"Data",				/* 1 */
38	"ACK",				/* 2 */
39	"Command",			/* 3 */
40	"Reserved",			/* 4 */
41	"Reserved",			/* 5 */
42	"Reserved",			/* 6 */
43	"Reserved",			/* 7 */
44};
45
46static int
47extract_header_length(uint16_t fc)
48{
49	int len = 0;
50
51	switch ((fc >> 10) & 0x3) {
52	case 0x00:
53		if (fc & (1 << 6)) /* intra-PAN with none dest addr */
54			return -1;
55		break;
56	case 0x01:
57		return -1;
58	case 0x02:
59		len += 4;
60		break;
61	case 0x03:
62		len += 10;
63		break;
64	}
65
66	switch ((fc >> 14) & 0x3) {
67	case 0x00:
68		break;
69	case 0x01:
70		return -1;
71	case 0x02:
72		len += 4;
73		break;
74	case 0x03:
75		len += 10;
76		break;
77	}
78
79	if (fc & (1 << 6)) {
80		if (len < 2)
81			return -1;
82		len -= 2;
83	}
84
85	return len;
86}
87
88
89u_int
90ieee802_15_4_if_print(netdissect_options *ndo,
91                      const struct pcap_pkthdr *h, const u_char *p)
92{
93	u_int caplen = h->caplen;
94	int hdrlen;
95	uint16_t fc;
96	uint8_t seq;
97
98	if (caplen < 3) {
99		ND_PRINT((ndo, "[|802.15.4] %x", caplen));
100		return caplen;
101	}
102
103	fc = EXTRACT_LE_16BITS(p);
104	hdrlen = extract_header_length(fc);
105
106	seq = EXTRACT_LE_8BITS(p + 2);
107
108	p += 3;
109	caplen -= 3;
110
111	ND_PRINT((ndo,"IEEE 802.15.4 %s packet ", ftypes[fc & 0x7]));
112	if (ndo->ndo_vflag)
113		ND_PRINT((ndo,"seq %02x ", seq));
114	if (hdrlen == -1) {
115		ND_PRINT((ndo,"malformed! "));
116		return caplen;
117	}
118
119
120	if (!ndo->ndo_vflag) {
121		p+= hdrlen;
122		caplen -= hdrlen;
123	} else {
124		uint16_t panid = 0;
125
126		switch ((fc >> 10) & 0x3) {
127		case 0x00:
128			ND_PRINT((ndo,"none "));
129			break;
130		case 0x01:
131			ND_PRINT((ndo,"reserved destination addressing mode"));
132			return 0;
133		case 0x02:
134			panid = EXTRACT_LE_16BITS(p);
135			p += 2;
136			ND_PRINT((ndo,"%04x:%04x ", panid, EXTRACT_LE_16BITS(p)));
137			p += 2;
138			break;
139		case 0x03:
140			panid = EXTRACT_LE_16BITS(p);
141			p += 2;
142			ND_PRINT((ndo,"%04x:%s ", panid, le64addr_string(p)));
143			p += 8;
144			break;
145		}
146		ND_PRINT((ndo,"< "));
147
148		switch ((fc >> 14) & 0x3) {
149		case 0x00:
150			ND_PRINT((ndo,"none "));
151			break;
152		case 0x01:
153			ND_PRINT((ndo,"reserved source addressing mode"));
154			return 0;
155		case 0x02:
156			if (!(fc & (1 << 6))) {
157				panid = EXTRACT_LE_16BITS(p);
158				p += 2;
159			}
160			ND_PRINT((ndo,"%04x:%04x ", panid, EXTRACT_LE_16BITS(p)));
161			p += 2;
162			break;
163		case 0x03:
164			if (!(fc & (1 << 6))) {
165				panid = EXTRACT_LE_16BITS(p);
166				p += 2;
167			}
168                        ND_PRINT((ndo,"%04x:%s ", panid, le64addr_string(p)));
169			p += 8;
170			break;
171		}
172
173		caplen -= hdrlen;
174	}
175
176	if (!ndo->ndo_suppress_default_print)
177		ND_DEFAULTPRINT(p, caplen);
178
179	return 0;
180}
181