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/* \summary: IEEE 802.15.4 printer */
24
25#ifdef HAVE_CONFIG_H
26#include "config.h"
27#endif
28
29#include <netdissect-stdinc.h>
30
31#include "netdissect.h"
32#include "addrtoname.h"
33
34#include "extract.h"
35
36static const char *ftypes[] = {
37	"Beacon",			/* 0 */
38	"Data",				/* 1 */
39	"ACK",				/* 2 */
40	"Command",			/* 3 */
41	"Reserved (0x4)",		/* 4 */
42	"Reserved (0x5)",		/* 5 */
43	"Reserved (0x6)",		/* 6 */
44	"Reserved (0x7)",		/* 7 */
45};
46
47/*
48 * Frame Control subfields.
49 */
50#define FC_FRAME_TYPE(fc)		((fc) & 0x7)
51#define FC_SECURITY_ENABLED		0x0008
52#define FC_FRAME_PENDING		0x0010
53#define FC_ACK_REQUEST			0x0020
54#define FC_PAN_ID_COMPRESSION		0x0040
55#define FC_DEST_ADDRESSING_MODE(fc)	(((fc) >> 10) & 0x3)
56#define FC_FRAME_VERSION(fc)		(((fc) >> 12) & 0x3)
57#define FC_SRC_ADDRESSING_MODE(fc)	(((fc) >> 14) & 0x3)
58
59#define FC_ADDRESSING_MODE_NONE		0x00
60#define FC_ADDRESSING_MODE_RESERVED	0x01
61#define FC_ADDRESSING_MODE_SHORT	0x02
62#define FC_ADDRESSING_MODE_LONG		0x03
63
64u_int
65ieee802_15_4_if_print(netdissect_options *ndo,
66                      const struct pcap_pkthdr *h, const u_char *p)
67{
68	u_int caplen = h->caplen;
69	u_int hdrlen;
70	uint16_t fc;
71	uint8_t seq;
72	uint16_t panid = 0;
73
74	if (caplen < 3) {
75		ND_PRINT((ndo, "[|802.15.4]"));
76		return caplen;
77	}
78	hdrlen = 3;
79
80	fc = EXTRACT_LE_16BITS(p);
81	seq = EXTRACT_LE_8BITS(p + 2);
82
83	p += 3;
84	caplen -= 3;
85
86	ND_PRINT((ndo,"IEEE 802.15.4 %s packet ", ftypes[FC_FRAME_TYPE(fc)]));
87	if (ndo->ndo_vflag)
88		ND_PRINT((ndo,"seq %02x ", seq));
89
90	/*
91	 * Destination address and PAN ID, if present.
92	 */
93	switch (FC_DEST_ADDRESSING_MODE(fc)) {
94	case FC_ADDRESSING_MODE_NONE:
95		if (fc & FC_PAN_ID_COMPRESSION) {
96			/*
97			 * PAN ID compression; this requires that both
98			 * the source and destination addresses be present,
99			 * but the destination address is missing.
100			 */
101			ND_PRINT((ndo, "[|802.15.4]"));
102			return hdrlen;
103		}
104		if (ndo->ndo_vflag)
105			ND_PRINT((ndo,"none "));
106		break;
107	case FC_ADDRESSING_MODE_RESERVED:
108		if (ndo->ndo_vflag)
109			ND_PRINT((ndo,"reserved destination addressing mode"));
110		return hdrlen;
111	case FC_ADDRESSING_MODE_SHORT:
112		if (caplen < 2) {
113			ND_PRINT((ndo, "[|802.15.4]"));
114			return hdrlen;
115		}
116		panid = EXTRACT_LE_16BITS(p);
117		p += 2;
118		caplen -= 2;
119		hdrlen += 2;
120		if (caplen < 2) {
121			ND_PRINT((ndo, "[|802.15.4]"));
122			return hdrlen;
123		}
124		if (ndo->ndo_vflag)
125			ND_PRINT((ndo,"%04x:%04x ", panid, EXTRACT_LE_16BITS(p)));
126		p += 2;
127		caplen -= 2;
128		hdrlen += 2;
129		break;
130	case FC_ADDRESSING_MODE_LONG:
131		if (caplen < 2) {
132			ND_PRINT((ndo, "[|802.15.4]"));
133			return hdrlen;
134		}
135		panid = EXTRACT_LE_16BITS(p);
136		p += 2;
137		caplen -= 2;
138		hdrlen += 2;
139		if (caplen < 8) {
140			ND_PRINT((ndo, "[|802.15.4]"));
141			return hdrlen;
142		}
143		if (ndo->ndo_vflag)
144			ND_PRINT((ndo,"%04x:%s ", panid, le64addr_string(ndo, p)));
145		p += 8;
146		caplen -= 8;
147		hdrlen += 8;
148		break;
149	}
150	if (ndo->ndo_vflag)
151		ND_PRINT((ndo,"< "));
152
153	/*
154	 * Source address and PAN ID, if present.
155	 */
156	switch (FC_SRC_ADDRESSING_MODE(fc)) {
157	case FC_ADDRESSING_MODE_NONE:
158		if (ndo->ndo_vflag)
159			ND_PRINT((ndo,"none "));
160		break;
161	case FC_ADDRESSING_MODE_RESERVED:
162		if (ndo->ndo_vflag)
163			ND_PRINT((ndo,"reserved source addressing mode"));
164		return 0;
165	case FC_ADDRESSING_MODE_SHORT:
166		if (!(fc & FC_PAN_ID_COMPRESSION)) {
167			/*
168			 * The source PAN ID is not compressed out, so
169			 * fetch it.  (Otherwise, we'll use the destination
170			 * PAN ID, fetched above.)
171			 */
172			if (caplen < 2) {
173				ND_PRINT((ndo, "[|802.15.4]"));
174				return hdrlen;
175			}
176			panid = EXTRACT_LE_16BITS(p);
177			p += 2;
178			caplen -= 2;
179			hdrlen += 2;
180		}
181		if (caplen < 2) {
182			ND_PRINT((ndo, "[|802.15.4]"));
183			return hdrlen;
184		}
185		if (ndo->ndo_vflag)
186			ND_PRINT((ndo,"%04x:%04x ", panid, EXTRACT_LE_16BITS(p)));
187		p += 2;
188		caplen -= 2;
189		hdrlen += 2;
190		break;
191	case FC_ADDRESSING_MODE_LONG:
192		if (!(fc & FC_PAN_ID_COMPRESSION)) {
193			/*
194			 * The source PAN ID is not compressed out, so
195			 * fetch it.  (Otherwise, we'll use the destination
196			 * PAN ID, fetched above.)
197			 */
198			if (caplen < 2) {
199				ND_PRINT((ndo, "[|802.15.4]"));
200				return hdrlen;
201			}
202			panid = EXTRACT_LE_16BITS(p);
203			p += 2;
204			caplen -= 2;
205			hdrlen += 2;
206		}
207		if (caplen < 8) {
208			ND_PRINT((ndo, "[|802.15.4]"));
209			return hdrlen;
210		}
211		if (ndo->ndo_vflag)
212			ND_PRINT((ndo,"%04x:%s ", panid, le64addr_string(ndo, p)));
213		p += 8;
214		caplen -= 8;
215		hdrlen += 8;
216		break;
217	}
218
219	if (!ndo->ndo_suppress_default_print)
220		ND_DEFAULTPRINT(p, caplen);
221
222	return hdrlen;
223}
224