1235427Sdelphij/*
2235427Sdelphij * Copyright (c) 2009
3235427Sdelphij * 	Siemens AG, All rights reserved.
4235427Sdelphij * 	Dmitry Eremin-Solenikov (dbaryshkov@gmail.com)
5235427Sdelphij *
6235427Sdelphij * Redistribution and use in source and binary forms, with or without
7235427Sdelphij * modification, are permitted provided that: (1) source code distributions
8235427Sdelphij * retain the above copyright notice and this paragraph in its entirety, (2)
9235427Sdelphij * distributions including binary code include the above copyright notice and
10235427Sdelphij * this paragraph in its entirety in the documentation or other materials
11235427Sdelphij * provided with the distribution, and (3) all advertising materials mentioning
12235427Sdelphij * features or use of this software display the following acknowledgement:
13235427Sdelphij * ``This product includes software developed by the University of California,
14235427Sdelphij * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
15235427Sdelphij * the University nor the names of its contributors may be used to endorse
16235427Sdelphij * or promote products derived from this software without specific prior
17235427Sdelphij * written permission.
18235427Sdelphij * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
19235427Sdelphij * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
20235427Sdelphij * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
21235427Sdelphij */
22235427Sdelphij
23313537Sglebius/* \summary: IEEE 802.15.4 printer */
24313537Sglebius
25235427Sdelphij#ifdef HAVE_CONFIG_H
26235427Sdelphij#include "config.h"
27235427Sdelphij#endif
28235427Sdelphij
29313537Sglebius#include <netdissect-stdinc.h>
30235427Sdelphij
31313537Sglebius#include "netdissect.h"
32235427Sdelphij#include "addrtoname.h"
33235427Sdelphij
34235427Sdelphij#include "extract.h"
35235427Sdelphij
36235427Sdelphijstatic const char *ftypes[] = {
37235427Sdelphij	"Beacon",			/* 0 */
38235427Sdelphij	"Data",				/* 1 */
39235427Sdelphij	"ACK",				/* 2 */
40235427Sdelphij	"Command",			/* 3 */
41327234Semaste	"Reserved (0x4)",		/* 4 */
42327234Semaste	"Reserved (0x5)",		/* 5 */
43327234Semaste	"Reserved (0x6)",		/* 6 */
44327234Semaste	"Reserved (0x7)",		/* 7 */
45235427Sdelphij};
46235427Sdelphij
47327234Semaste/*
48327234Semaste * Frame Control subfields.
49327234Semaste */
50327234Semaste#define FC_FRAME_TYPE(fc)		((fc) & 0x7)
51327234Semaste#define FC_SECURITY_ENABLED		0x0008
52327234Semaste#define FC_FRAME_PENDING		0x0010
53327234Semaste#define FC_ACK_REQUEST			0x0020
54327234Semaste#define FC_PAN_ID_COMPRESSION		0x0040
55327234Semaste#define FC_DEST_ADDRESSING_MODE(fc)	(((fc) >> 10) & 0x3)
56327234Semaste#define FC_FRAME_VERSION(fc)		(((fc) >> 12) & 0x3)
57327234Semaste#define FC_SRC_ADDRESSING_MODE(fc)	(((fc) >> 14) & 0x3)
58235427Sdelphij
59327234Semaste#define FC_ADDRESSING_MODE_NONE		0x00
60327234Semaste#define FC_ADDRESSING_MODE_RESERVED	0x01
61327234Semaste#define FC_ADDRESSING_MODE_SHORT	0x02
62327234Semaste#define FC_ADDRESSING_MODE_LONG		0x03
63235427Sdelphij
64235427Sdelphiju_int
65276788Sdelphijieee802_15_4_if_print(netdissect_options *ndo,
66235427Sdelphij                      const struct pcap_pkthdr *h, const u_char *p)
67235427Sdelphij{
68235427Sdelphij	u_int caplen = h->caplen;
69327234Semaste	u_int hdrlen;
70276788Sdelphij	uint16_t fc;
71276788Sdelphij	uint8_t seq;
72327234Semaste	uint16_t panid = 0;
73235427Sdelphij
74235427Sdelphij	if (caplen < 3) {
75327234Semaste		ND_PRINT((ndo, "[|802.15.4]"));
76235427Sdelphij		return caplen;
77235427Sdelphij	}
78327234Semaste	hdrlen = 3;
79235427Sdelphij
80235427Sdelphij	fc = EXTRACT_LE_16BITS(p);
81235427Sdelphij	seq = EXTRACT_LE_8BITS(p + 2);
82235427Sdelphij
83235427Sdelphij	p += 3;
84235427Sdelphij	caplen -= 3;
85235427Sdelphij
86327234Semaste	ND_PRINT((ndo,"IEEE 802.15.4 %s packet ", ftypes[FC_FRAME_TYPE(fc)]));
87276788Sdelphij	if (ndo->ndo_vflag)
88235427Sdelphij		ND_PRINT((ndo,"seq %02x ", seq));
89235427Sdelphij
90327234Semaste	/*
91327234Semaste	 * Destination address and PAN ID, if present.
92327234Semaste	 */
93327234Semaste	switch (FC_DEST_ADDRESSING_MODE(fc)) {
94327234Semaste	case FC_ADDRESSING_MODE_NONE:
95327234Semaste		if (fc & FC_PAN_ID_COMPRESSION) {
96327234Semaste			/*
97327234Semaste			 * PAN ID compression; this requires that both
98327234Semaste			 * the source and destination addresses be present,
99327234Semaste			 * but the destination address is missing.
100327234Semaste			 */
101327234Semaste			ND_PRINT((ndo, "[|802.15.4]"));
102327234Semaste			return hdrlen;
103327234Semaste		}
104327234Semaste		if (ndo->ndo_vflag)
105235427Sdelphij			ND_PRINT((ndo,"none "));
106327234Semaste		break;
107327234Semaste	case FC_ADDRESSING_MODE_RESERVED:
108327234Semaste		if (ndo->ndo_vflag)
109235427Sdelphij			ND_PRINT((ndo,"reserved destination addressing mode"));
110327234Semaste		return hdrlen;
111327234Semaste	case FC_ADDRESSING_MODE_SHORT:
112327234Semaste		if (caplen < 2) {
113327234Semaste			ND_PRINT((ndo, "[|802.15.4]"));
114327234Semaste			return hdrlen;
115327234Semaste		}
116327234Semaste		panid = EXTRACT_LE_16BITS(p);
117327234Semaste		p += 2;
118327234Semaste		caplen -= 2;
119327234Semaste		hdrlen += 2;
120327234Semaste		if (caplen < 2) {
121327234Semaste			ND_PRINT((ndo, "[|802.15.4]"));
122327234Semaste			return hdrlen;
123327234Semaste		}
124327234Semaste		if (ndo->ndo_vflag)
125235427Sdelphij			ND_PRINT((ndo,"%04x:%04x ", panid, EXTRACT_LE_16BITS(p)));
126327234Semaste		p += 2;
127327234Semaste		caplen -= 2;
128327234Semaste		hdrlen += 2;
129327234Semaste		break;
130327234Semaste	case FC_ADDRESSING_MODE_LONG:
131327234Semaste		if (caplen < 2) {
132327234Semaste			ND_PRINT((ndo, "[|802.15.4]"));
133327234Semaste			return hdrlen;
134327234Semaste		}
135327234Semaste		panid = EXTRACT_LE_16BITS(p);
136327234Semaste		p += 2;
137327234Semaste		caplen -= 2;
138327234Semaste		hdrlen += 2;
139327234Semaste		if (caplen < 8) {
140327234Semaste			ND_PRINT((ndo, "[|802.15.4]"));
141327234Semaste			return hdrlen;
142327234Semaste		}
143327234Semaste		if (ndo->ndo_vflag)
144313537Sglebius			ND_PRINT((ndo,"%04x:%s ", panid, le64addr_string(ndo, p)));
145327234Semaste		p += 8;
146327234Semaste		caplen -= 8;
147327234Semaste		hdrlen += 8;
148327234Semaste		break;
149327234Semaste	}
150327234Semaste	if (ndo->ndo_vflag)
151276788Sdelphij		ND_PRINT((ndo,"< "));
152235427Sdelphij
153327234Semaste	/*
154327234Semaste	 * Source address and PAN ID, if present.
155327234Semaste	 */
156327234Semaste	switch (FC_SRC_ADDRESSING_MODE(fc)) {
157327234Semaste	case FC_ADDRESSING_MODE_NONE:
158327234Semaste		if (ndo->ndo_vflag)
159235427Sdelphij			ND_PRINT((ndo,"none "));
160327234Semaste		break;
161327234Semaste	case FC_ADDRESSING_MODE_RESERVED:
162327234Semaste		if (ndo->ndo_vflag)
163235427Sdelphij			ND_PRINT((ndo,"reserved source addressing mode"));
164327234Semaste		return 0;
165327234Semaste	case FC_ADDRESSING_MODE_SHORT:
166327234Semaste		if (!(fc & FC_PAN_ID_COMPRESSION)) {
167327234Semaste			/*
168327234Semaste			 * The source PAN ID is not compressed out, so
169327234Semaste			 * fetch it.  (Otherwise, we'll use the destination
170327234Semaste			 * PAN ID, fetched above.)
171327234Semaste			 */
172327234Semaste			if (caplen < 2) {
173327234Semaste				ND_PRINT((ndo, "[|802.15.4]"));
174327234Semaste				return hdrlen;
175235427Sdelphij			}
176327234Semaste			panid = EXTRACT_LE_16BITS(p);
177327234Semaste			p += 2;
178327234Semaste			caplen -= 2;
179327234Semaste			hdrlen += 2;
180327234Semaste		}
181327234Semaste		if (caplen < 2) {
182327234Semaste			ND_PRINT((ndo, "[|802.15.4]"));
183327234Semaste			return hdrlen;
184327234Semaste		}
185327234Semaste		if (ndo->ndo_vflag)
186235427Sdelphij			ND_PRINT((ndo,"%04x:%04x ", panid, EXTRACT_LE_16BITS(p)));
187327234Semaste		p += 2;
188327234Semaste		caplen -= 2;
189327234Semaste		hdrlen += 2;
190327234Semaste		break;
191327234Semaste	case FC_ADDRESSING_MODE_LONG:
192327234Semaste		if (!(fc & FC_PAN_ID_COMPRESSION)) {
193327234Semaste			/*
194327234Semaste			 * The source PAN ID is not compressed out, so
195327234Semaste			 * fetch it.  (Otherwise, we'll use the destination
196327234Semaste			 * PAN ID, fetched above.)
197327234Semaste			 */
198327234Semaste			if (caplen < 2) {
199327234Semaste				ND_PRINT((ndo, "[|802.15.4]"));
200327234Semaste				return hdrlen;
201327234Semaste			}
202327234Semaste			panid = EXTRACT_LE_16BITS(p);
203235427Sdelphij			p += 2;
204327234Semaste			caplen -= 2;
205327234Semaste			hdrlen += 2;
206235427Sdelphij		}
207327234Semaste		if (caplen < 8) {
208327234Semaste			ND_PRINT((ndo, "[|802.15.4]"));
209327234Semaste			return hdrlen;
210327234Semaste		}
211327234Semaste		if (ndo->ndo_vflag)
212327234Semaste			ND_PRINT((ndo,"%04x:%s ", panid, le64addr_string(ndo, p)));
213327234Semaste		p += 8;
214327234Semaste		caplen -= 8;
215327234Semaste		hdrlen += 8;
216327234Semaste		break;
217235427Sdelphij	}
218235427Sdelphij
219276788Sdelphij	if (!ndo->ndo_suppress_default_print)
220276788Sdelphij		ND_DEFAULTPRINT(p, caplen);
221235427Sdelphij
222327234Semaste	return hdrlen;
223235427Sdelphij}
224