xref: /netbsd-src/external/bsd/tcpdump/dist/print-802_15_4.c (revision 26ba0b503b498a5194a71ac319838b7f5497f3fe)
19546e36dSchristos /*
29546e36dSchristos  * Copyright (c) 2009
39546e36dSchristos  *	Siemens AG, All rights reserved.
49546e36dSchristos  *	Dmitry Eremin-Solenikov (dbaryshkov@gmail.com)
59546e36dSchristos  *
69546e36dSchristos  * Redistribution and use in source and binary forms, with or without
79546e36dSchristos  * modification, are permitted provided that: (1) source code distributions
89546e36dSchristos  * retain the above copyright notice and this paragraph in its entirety, (2)
99546e36dSchristos  * distributions including binary code include the above copyright notice and
109546e36dSchristos  * this paragraph in its entirety in the documentation or other materials
119546e36dSchristos  * provided with the distribution, and (3) all advertising materials mentioning
129546e36dSchristos  * features or use of this software display the following acknowledgement:
139546e36dSchristos  * ``This product includes software developed by the University of California,
149546e36dSchristos  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
159546e36dSchristos  * the University nor the names of its contributors may be used to endorse
169546e36dSchristos  * or promote products derived from this software without specific prior
179546e36dSchristos  * written permission.
189546e36dSchristos  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
199546e36dSchristos  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
209546e36dSchristos  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
219546e36dSchristos  */
229546e36dSchristos 
23fdccd7e4Schristos #include <sys/cdefs.h>
24fdccd7e4Schristos #ifndef lint
25*26ba0b50Schristos __RCSID("$NetBSD: print-802_15_4.c,v 1.6 2024/09/02 16:15:30 christos Exp $");
26fdccd7e4Schristos #endif
27fdccd7e4Schristos 
28dc860a36Sspz /* \summary: IEEE 802.15.4 printer */
29dc860a36Sspz 
30c74ad251Schristos #include <config.h>
319546e36dSchristos 
32c74ad251Schristos #include "netdissect-stdinc.h"
339546e36dSchristos 
34c74ad251Schristos #define ND_LONGJMP_FROM_TCHECK
35784088dfSchristos #include "netdissect.h"
369546e36dSchristos #include "addrtoname.h"
379546e36dSchristos 
389546e36dSchristos #include "extract.h"
399546e36dSchristos 
40c74ad251Schristos #define CHECK_BIT(num,bit) (((num) >> (bit)) & 0x1)
41c74ad251Schristos 
42c74ad251Schristos #define BROKEN_6TISCH_PAN_ID_COMPRESSION 0
43c74ad251Schristos 
44c74ad251Schristos /* Frame types from Table 7-1 of 802.15.4-2015 */
459546e36dSchristos static const char *ftypes[] = {
469546e36dSchristos 	"Beacon",			/* 0 */
479546e36dSchristos 	"Data",				/* 1 */
489546e36dSchristos 	"ACK",				/* 2 */
499546e36dSchristos 	"Command",			/* 3 */
50c74ad251Schristos 	"Reserved",			/* 4 */
51c74ad251Schristos 	"Multipurpose",			/* 5 */
52c74ad251Schristos 	"Fragment",			/* 6 */
53c74ad251Schristos 	"Extended"			/* 7 */
54c74ad251Schristos };
55c74ad251Schristos 
56c74ad251Schristos /* Element IDs for Header IEs from Table 7-7 of 802.15.4-2015 */
57c74ad251Schristos static const char *h_ie_names[] = {
58c74ad251Schristos 	"Vendor Specific Header IE",			/* 0x00 */
59c74ad251Schristos 	"Reserved 0x01",				/* 0x01 */
60c74ad251Schristos 	"Reserved 0x02",				/* 0x02 */
61c74ad251Schristos 	"Reserved 0x03",				/* 0x03 */
62c74ad251Schristos 	"Reserved 0x04",				/* 0x04 */
63c74ad251Schristos 	"Reserved 0x05",				/* 0x05 */
64c74ad251Schristos 	"Reserved 0x06",				/* 0x06 */
65c74ad251Schristos 	"Reserved 0x07",				/* 0x07 */
66c74ad251Schristos 	"Reserved 0x08",				/* 0x08 */
67c74ad251Schristos 	"Reserved 0x09",				/* 0x09 */
68c74ad251Schristos 	"Reserved 0x0a",				/* 0x0a */
69c74ad251Schristos 	"Reserved 0x0b",				/* 0x0b */
70c74ad251Schristos 	"Reserved 0x0c",				/* 0x0c */
71c74ad251Schristos 	"Reserved 0x0d",				/* 0x0d */
72c74ad251Schristos 	"Reserved 0x0e",				/* 0x0e */
73c74ad251Schristos 	"Reserved 0x0f",				/* 0x0f */
74c74ad251Schristos 	"Reserved 0x10",				/* 0x10 */
75c74ad251Schristos 	"Reserved 0x11",				/* 0x11 */
76c74ad251Schristos 	"Reserved 0x12",				/* 0x12 */
77c74ad251Schristos 	"Reserved 0x13",				/* 0x13 */
78c74ad251Schristos 	"Reserved 0x14",				/* 0x14 */
79c74ad251Schristos 	"Reserved 0x15",				/* 0x15 */
80c74ad251Schristos 	"Reserved 0x16",				/* 0x16 */
81c74ad251Schristos 	"Reserved 0x17",				/* 0x17 */
82c74ad251Schristos 	"Reserved 0x18",				/* 0x18 */
83c74ad251Schristos 	"Reserved 0x19",				/* 0x19 */
84c74ad251Schristos 	"LE CSL IE",					/* 0x1a */
85c74ad251Schristos 	"LE RIT IE",					/* 0x1b */
86c74ad251Schristos 	"DSME PAN descriptor IE",			/* 0x1c */
87c74ad251Schristos 	"Rendezvous Time IE",				/* 0x1d */
88c74ad251Schristos 	"Time Correction IE",				/* 0x1e */
89c74ad251Schristos 	"Reserved 0x1f",				/* 0x1f */
90c74ad251Schristos 	"Reserved 0x20",				/* 0x20 */
91c74ad251Schristos 	"Extended DSME PAN descriptor IE",		/* 0x21 */
92c74ad251Schristos 	"Fragment Sequence Context Description IE",	/* 0x22 */
93c74ad251Schristos 	"Simplified Superframe Specification IE",	/* 0x23 */
94c74ad251Schristos 	"Simplified GTS Specification IE",		/* 0x24 */
95c74ad251Schristos 	"LECIM Capabilities IE",			/* 0x25 */
96c74ad251Schristos 	"TRLE Descriptor IE",				/* 0x26 */
97c74ad251Schristos 	"RCC Capabilities IE",				/* 0x27 */
98c74ad251Schristos 	"RCCN Descriptor IE",				/* 0x28 */
99c74ad251Schristos 	"Global Time IE",				/* 0x29 */
100c74ad251Schristos 	"Omnibus Header IE",				/* 0x2a */
101c74ad251Schristos 	"DA IE",					/* 0x2b */
102c74ad251Schristos 	"Reserved 0x2c",				/* 0x2c */
103c74ad251Schristos 	"Reserved 0x2d",				/* 0x2d */
104c74ad251Schristos 	"Reserved 0x2e",				/* 0x2e */
105c74ad251Schristos 	"Reserved 0x2f",				/* 0x2f */
106c74ad251Schristos 	"Reserved 0x30",				/* 0x30 */
107c74ad251Schristos 	"Reserved 0x31",				/* 0x31 */
108c74ad251Schristos 	"Reserved 0x32",				/* 0x32 */
109c74ad251Schristos 	"Reserved 0x33",				/* 0x33 */
110c74ad251Schristos 	"Reserved 0x34",				/* 0x34 */
111c74ad251Schristos 	"Reserved 0x35",				/* 0x35 */
112c74ad251Schristos 	"Reserved 0x36",				/* 0x36 */
113c74ad251Schristos 	"Reserved 0x37",				/* 0x37 */
114c74ad251Schristos 	"Reserved 0x38",				/* 0x38 */
115c74ad251Schristos 	"Reserved 0x39",				/* 0x39 */
116c74ad251Schristos 	"Reserved 0x3a",				/* 0x3a */
117c74ad251Schristos 	"Reserved 0x3b",				/* 0x3b */
118c74ad251Schristos 	"Reserved 0x3c",				/* 0x3c */
119c74ad251Schristos 	"Reserved 0x3d",				/* 0x3d */
120c74ad251Schristos 	"Reserved 0x3e",				/* 0x3e */
121c74ad251Schristos 	"Reserved 0x3f",				/* 0x3f */
122c74ad251Schristos 	"Reserved 0x40",				/* 0x40 */
123c74ad251Schristos 	"Reserved 0x41",				/* 0x41 */
124c74ad251Schristos 	"Reserved 0x42",				/* 0x42 */
125c74ad251Schristos 	"Reserved 0x43",				/* 0x43 */
126c74ad251Schristos 	"Reserved 0x44",				/* 0x44 */
127c74ad251Schristos 	"Reserved 0x45",				/* 0x45 */
128c74ad251Schristos 	"Reserved 0x46",				/* 0x46 */
129c74ad251Schristos 	"Reserved 0x47",				/* 0x47 */
130c74ad251Schristos 	"Reserved 0x48",				/* 0x48 */
131c74ad251Schristos 	"Reserved 0x49",				/* 0x49 */
132c74ad251Schristos 	"Reserved 0x4a",				/* 0x4a */
133c74ad251Schristos 	"Reserved 0x4b",				/* 0x4b */
134c74ad251Schristos 	"Reserved 0x4c",				/* 0x4c */
135c74ad251Schristos 	"Reserved 0x4d",				/* 0x4d */
136c74ad251Schristos 	"Reserved 0x4e",				/* 0x4e */
137c74ad251Schristos 	"Reserved 0x4f",				/* 0x4f */
138c74ad251Schristos 	"Reserved 0x50",				/* 0x50 */
139c74ad251Schristos 	"Reserved 0x51",				/* 0x51 */
140c74ad251Schristos 	"Reserved 0x52",				/* 0x52 */
141c74ad251Schristos 	"Reserved 0x53",				/* 0x53 */
142c74ad251Schristos 	"Reserved 0x54",				/* 0x54 */
143c74ad251Schristos 	"Reserved 0x55",				/* 0x55 */
144c74ad251Schristos 	"Reserved 0x56",				/* 0x56 */
145c74ad251Schristos 	"Reserved 0x57",				/* 0x57 */
146c74ad251Schristos 	"Reserved 0x58",				/* 0x58 */
147c74ad251Schristos 	"Reserved 0x59",				/* 0x59 */
148c74ad251Schristos 	"Reserved 0x5a",				/* 0x5a */
149c74ad251Schristos 	"Reserved 0x5b",				/* 0x5b */
150c74ad251Schristos 	"Reserved 0x5c",				/* 0x5c */
151c74ad251Schristos 	"Reserved 0x5d",				/* 0x5d */
152c74ad251Schristos 	"Reserved 0x5e",				/* 0x5e */
153c74ad251Schristos 	"Reserved 0x5f",				/* 0x5f */
154c74ad251Schristos 	"Reserved 0x60",				/* 0x60 */
155c74ad251Schristos 	"Reserved 0x61",				/* 0x61 */
156c74ad251Schristos 	"Reserved 0x62",				/* 0x62 */
157c74ad251Schristos 	"Reserved 0x63",				/* 0x63 */
158c74ad251Schristos 	"Reserved 0x64",				/* 0x64 */
159c74ad251Schristos 	"Reserved 0x65",				/* 0x65 */
160c74ad251Schristos 	"Reserved 0x66",				/* 0x66 */
161c74ad251Schristos 	"Reserved 0x67",				/* 0x67 */
162c74ad251Schristos 	"Reserved 0x68",				/* 0x68 */
163c74ad251Schristos 	"Reserved 0x69",				/* 0x69 */
164c74ad251Schristos 	"Reserved 0x6a",				/* 0x6a */
165c74ad251Schristos 	"Reserved 0x6b",				/* 0x6b */
166c74ad251Schristos 	"Reserved 0x6c",				/* 0x6c */
167c74ad251Schristos 	"Reserved 0x6d",				/* 0x6d */
168c74ad251Schristos 	"Reserved 0x6e",				/* 0x6e */
169c74ad251Schristos 	"Reserved 0x6f",				/* 0x6f */
170c74ad251Schristos 	"Reserved 0x70",				/* 0x70 */
171c74ad251Schristos 	"Reserved 0x71",				/* 0x71 */
172c74ad251Schristos 	"Reserved 0x72",				/* 0x72 */
173c74ad251Schristos 	"Reserved 0x73",				/* 0x73 */
174c74ad251Schristos 	"Reserved 0x74",				/* 0x74 */
175c74ad251Schristos 	"Reserved 0x75",				/* 0x75 */
176c74ad251Schristos 	"Reserved 0x76",				/* 0x76 */
177c74ad251Schristos 	"Reserved 0x77",				/* 0x77 */
178c74ad251Schristos 	"Reserved 0x78",				/* 0x78 */
179c74ad251Schristos 	"Reserved 0x79",				/* 0x79 */
180c74ad251Schristos 	"Reserved 0x7a",				/* 0x7a */
181c74ad251Schristos 	"Reserved 0x7b",				/* 0x7b */
182c74ad251Schristos 	"Reserved 0x7c",				/* 0x7c */
183c74ad251Schristos 	"Reserved 0x7d",				/* 0x7d */
184c74ad251Schristos 	"Header Termination 1 IE",			/* 0x7e */
185c74ad251Schristos 	"Header Termination 2 IE"			/* 0x7f */
186c74ad251Schristos };
187c74ad251Schristos 
188c74ad251Schristos /* Payload IE Group IDs from Table 7-15 of 802.15.4-2015 */
189c74ad251Schristos static const char *p_ie_names[] = {
190c74ad251Schristos 	"ESDU IE",			/* 0x00 */
191c74ad251Schristos 	"MLME IE",			/* 0x01 */
192c74ad251Schristos 	"Vendor Specific Nested IE",	/* 0x02 */
193c74ad251Schristos 	"Multiplexed IE (802.15.9)",	/* 0x03 */
194c74ad251Schristos 	"Omnibus Payload Group IE",	/* 0x04 */
195c74ad251Schristos 	"IETF IE",			/* 0x05 */
196c74ad251Schristos 	"Reserved 0x06",		/* 0x06 */
197c74ad251Schristos 	"Reserved 0x07",		/* 0x07 */
198c74ad251Schristos 	"Reserved 0x08",		/* 0x08 */
199c74ad251Schristos 	"Reserved 0x09",		/* 0x09 */
200c74ad251Schristos 	"Reserved 0x0a",		/* 0x0a */
201c74ad251Schristos 	"Reserved 0x0b",		/* 0x0b */
202c74ad251Schristos 	"Reserved 0x0c",		/* 0x0c */
203c74ad251Schristos 	"Reserved 0x0d",		/* 0x0d */
204c74ad251Schristos 	"Reserved 0x0e",		/* 0x0e */
205c74ad251Schristos 	"List termination"		/* 0x0f */
206c74ad251Schristos };
207c74ad251Schristos 
208c74ad251Schristos /* Sub-ID for short format from Table 7-16 of 802.15.4-2015 */
209c74ad251Schristos static const char *p_mlme_short_names[] = {
210c74ad251Schristos 	"Reserved for long format 0x0",			/* 0x00 */
211c74ad251Schristos 	"Reserved for long format 0x1",			/* 0x01 */
212c74ad251Schristos 	"Reserved for long format 0x2",			/* 0x02 */
213c74ad251Schristos 	"Reserved for long format 0x3",			/* 0x03 */
214c74ad251Schristos 	"Reserved for long format 0x4",			/* 0x04 */
215c74ad251Schristos 	"Reserved for long format 0x5",			/* 0x05 */
216c74ad251Schristos 	"Reserved for long format 0x6",			/* 0x06 */
217c74ad251Schristos 	"Reserved for long format 0x7",			/* 0x07 */
218c74ad251Schristos 	"Reserved for long format 0x8",			/* 0x08 */
219c74ad251Schristos 	"Reserved for long format 0x9",			/* 0x09 */
220c74ad251Schristos 	"Reserved for long format 0xa",			/* 0x0a */
221c74ad251Schristos 	"Reserved for long format 0xb",			/* 0x0b */
222c74ad251Schristos 	"Reserved for long format 0xc",			/* 0x0c */
223c74ad251Schristos 	"Reserved for long format 0xd",			/* 0x0d */
224c74ad251Schristos 	"Reserved for long format 0xe",			/* 0x0e */
225c74ad251Schristos 	"Reserved for long format 0xf",			/* 0x0f */
226c74ad251Schristos 	"Reserved 0x10",				/* 0x10 */
227c74ad251Schristos 	"Reserved 0x11",				/* 0x11 */
228c74ad251Schristos 	"Reserved 0x12",				/* 0x12 */
229c74ad251Schristos 	"Reserved 0x13",				/* 0x13 */
230c74ad251Schristos 	"Reserved 0x14",				/* 0x14 */
231c74ad251Schristos 	"Reserved 0x15",				/* 0x15 */
232c74ad251Schristos 	"Reserved 0x16",				/* 0x16 */
233c74ad251Schristos 	"Reserved 0x17",				/* 0x17 */
234c74ad251Schristos 	"Reserved 0x18",				/* 0x18 */
235c74ad251Schristos 	"Reserved 0x19",				/* 0x19 */
236c74ad251Schristos 	"TSCH Synchronization IE",			/* 0x1a */
237c74ad251Schristos 	"TSCH Slotframe and Link IE",			/* 0x1b */
238c74ad251Schristos 	"TSCH Timeslot IE",				/* 0x1c */
239c74ad251Schristos 	"Hopping timing IE",				/* 0x1d */
240c74ad251Schristos 	"Enhanced Beacon Filter IE",			/* 0x1e */
241c74ad251Schristos 	"MAC Metrics IE",				/* 0x1f */
242c74ad251Schristos 	"All MAC Metrics IE",				/* 0x20 */
243c74ad251Schristos 	"Coexistence Specification IE",			/* 0x21 */
244c74ad251Schristos 	"SUN Device Capabilities IE",			/* 0x22 */
245c74ad251Schristos 	"SUN FSK Generic PHY IE",			/* 0x23 */
246c74ad251Schristos 	"Mode Switch Parameter IE",			/* 0x24 */
247c74ad251Schristos 	"PHY Parameter Change IE",			/* 0x25 */
248c74ad251Schristos 	"O-QPSK PHY Mode IE",				/* 0x26 */
249c74ad251Schristos 	"PCA Allocation IE",				/* 0x27 */
250c74ad251Schristos 	"LECIM DSSS Operating Mode IE",			/* 0x28 */
251c74ad251Schristos 	"LECIM FSK Operating Mode IE",			/* 0x29 */
252c74ad251Schristos 	"Reserved 0x2a",				/* 0x2a */
253c74ad251Schristos 	"TVWS PHY Operating Mode Description IE",	/* 0x2b */
254c74ad251Schristos 	"TVWS Device Capabilities IE",			/* 0x2c */
255c74ad251Schristos 	"TVWS Device Category IE",			/* 0x2d */
256*26ba0b50Schristos 	"TVWS Device Identification IE",		/* 0x2e */
257c74ad251Schristos 	"TVWS Device Location IE",			/* 0x2f */
258c74ad251Schristos 	"TVWS Channel Information Query IE",		/* 0x30 */
259c74ad251Schristos 	"TVWS Channel Information Source IE",		/* 0x31 */
260c74ad251Schristos 	"CTM IE",					/* 0x32 */
261c74ad251Schristos 	"Timestamp IE",					/* 0x33 */
262c74ad251Schristos 	"Timestamp Difference IE",			/* 0x34 */
263c74ad251Schristos 	"TMCTP Specification IE",			/* 0x35 */
264c74ad251Schristos 	"RCC PHY Operating Mode IE",			/* 0x36 */
265c74ad251Schristos 	"Reserved 0x37",				/* 0x37 */
266c74ad251Schristos 	"Reserved 0x38",				/* 0x38 */
267c74ad251Schristos 	"Reserved 0x39",				/* 0x39 */
268c74ad251Schristos 	"Reserved 0x3a",				/* 0x3a */
269c74ad251Schristos 	"Reserved 0x3b",				/* 0x3b */
270c74ad251Schristos 	"Reserved 0x3c",				/* 0x3c */
271c74ad251Schristos 	"Reserved 0x3d",				/* 0x3d */
272c74ad251Schristos 	"Reserved 0x3e",				/* 0x3e */
273c74ad251Schristos 	"Reserved 0x3f",				/* 0x3f */
274c74ad251Schristos 	"Reserved 0x40",				/* 0x40 */
275c74ad251Schristos 	"Reserved 0x41",				/* 0x41 */
276c74ad251Schristos 	"Reserved 0x42",				/* 0x42 */
277c74ad251Schristos 	"Reserved 0x43",				/* 0x43 */
278c74ad251Schristos 	"Reserved 0x44",				/* 0x44 */
279c74ad251Schristos 	"Reserved 0x45",				/* 0x45 */
280c74ad251Schristos 	"Reserved 0x46",				/* 0x46 */
281c74ad251Schristos 	"Reserved 0x47",				/* 0x47 */
282c74ad251Schristos 	"Reserved 0x48",				/* 0x48 */
283c74ad251Schristos 	"Reserved 0x49",				/* 0x49 */
284c74ad251Schristos 	"Reserved 0x4a",				/* 0x4a */
285c74ad251Schristos 	"Reserved 0x4b",				/* 0x4b */
286c74ad251Schristos 	"Reserved 0x4c",				/* 0x4c */
287c74ad251Schristos 	"Reserved 0x4d",				/* 0x4d */
288c74ad251Schristos 	"Reserved 0x4e",				/* 0x4e */
289c74ad251Schristos 	"Reserved 0x4f",				/* 0x4f */
290c74ad251Schristos 	"Reserved 0x50",				/* 0x50 */
291c74ad251Schristos 	"Reserved 0x51",				/* 0x51 */
292c74ad251Schristos 	"Reserved 0x52",				/* 0x52 */
293c74ad251Schristos 	"Reserved 0x53",				/* 0x53 */
294c74ad251Schristos 	"Reserved 0x54",				/* 0x54 */
295c74ad251Schristos 	"Reserved 0x55",				/* 0x55 */
296c74ad251Schristos 	"Reserved 0x56",				/* 0x56 */
297c74ad251Schristos 	"Reserved 0x57",				/* 0x57 */
298c74ad251Schristos 	"Reserved 0x58",				/* 0x58 */
299c74ad251Schristos 	"Reserved 0x59",				/* 0x59 */
300c74ad251Schristos 	"Reserved 0x5a",				/* 0x5a */
301c74ad251Schristos 	"Reserved 0x5b",				/* 0x5b */
302c74ad251Schristos 	"Reserved 0x5c",				/* 0x5c */
303c74ad251Schristos 	"Reserved 0x5d",				/* 0x5d */
304c74ad251Schristos 	"Reserved 0x5e",				/* 0x5e */
305c74ad251Schristos 	"Reserved 0x5f",				/* 0x5f */
306c74ad251Schristos 	"Reserved 0x60",				/* 0x60 */
307c74ad251Schristos 	"Reserved 0x61",				/* 0x61 */
308c74ad251Schristos 	"Reserved 0x62",				/* 0x62 */
309c74ad251Schristos 	"Reserved 0x63",				/* 0x63 */
310c74ad251Schristos 	"Reserved 0x64",				/* 0x64 */
311c74ad251Schristos 	"Reserved 0x65",				/* 0x65 */
312c74ad251Schristos 	"Reserved 0x66",				/* 0x66 */
313c74ad251Schristos 	"Reserved 0x67",				/* 0x67 */
314c74ad251Schristos 	"Reserved 0x68",				/* 0x68 */
315c74ad251Schristos 	"Reserved 0x69",				/* 0x69 */
316c74ad251Schristos 	"Reserved 0x6a",				/* 0x6a */
317c74ad251Schristos 	"Reserved 0x6b",				/* 0x6b */
318c74ad251Schristos 	"Reserved 0x6c",				/* 0x6c */
319c74ad251Schristos 	"Reserved 0x6d",				/* 0x6d */
320c74ad251Schristos 	"Reserved 0x6e",				/* 0x6e */
321c74ad251Schristos 	"Reserved 0x6f",				/* 0x6f */
322c74ad251Schristos 	"Reserved 0x70",				/* 0x70 */
323c74ad251Schristos 	"Reserved 0x71",				/* 0x71 */
324c74ad251Schristos 	"Reserved 0x72",				/* 0x72 */
325c74ad251Schristos 	"Reserved 0x73",				/* 0x73 */
326c74ad251Schristos 	"Reserved 0x74",				/* 0x74 */
327c74ad251Schristos 	"Reserved 0x75",				/* 0x75 */
328c74ad251Schristos 	"Reserved 0x76",				/* 0x76 */
329c74ad251Schristos 	"Reserved 0x77",				/* 0x77 */
330c74ad251Schristos 	"Reserved 0x78",				/* 0x78 */
331c74ad251Schristos 	"Reserved 0x79",				/* 0x79 */
332c74ad251Schristos 	"Reserved 0x7a",				/* 0x7a */
333c74ad251Schristos 	"Reserved 0x7b",				/* 0x7b */
334c74ad251Schristos 	"Reserved 0x7c",				/* 0x7c */
335c74ad251Schristos 	"Reserved 0x7d",				/* 0x7d */
336c74ad251Schristos 	"Reserved 0x7e",				/* 0x7e */
337c74ad251Schristos 	"Reserved 0x7f"					/* 0x7f */
338c74ad251Schristos };
339c74ad251Schristos 
340c74ad251Schristos /* Sub-ID for long format from Table 7-17 of 802.15.4-2015 */
341c74ad251Schristos static const char *p_mlme_long_names[] = {
342c74ad251Schristos 	"Reserved 0x00",			/* 0x00 */
343c74ad251Schristos 	"Reserved 0x01",			/* 0x01 */
344c74ad251Schristos 	"Reserved 0x02",			/* 0x02 */
345c74ad251Schristos 	"Reserved 0x03",			/* 0x03 */
346c74ad251Schristos 	"Reserved 0x04",			/* 0x04 */
347c74ad251Schristos 	"Reserved 0x05",			/* 0x05 */
348c74ad251Schristos 	"Reserved 0x06",			/* 0x06 */
349c74ad251Schristos 	"Reserved 0x07",			/* 0x07 */
350c74ad251Schristos 	"Vendor Specific MLME Nested IE",	/* 0x08 */
351c74ad251Schristos 	"Channel Hopping IE",			/* 0x09 */
352c74ad251Schristos 	"Reserved 0x0a",			/* 0x0a */
353c74ad251Schristos 	"Reserved 0x0b",			/* 0x0b */
354c74ad251Schristos 	"Reserved 0x0c",			/* 0x0c */
355c74ad251Schristos 	"Reserved 0x0d",			/* 0x0d */
356c74ad251Schristos 	"Reserved 0x0e",			/* 0x0e */
357c74ad251Schristos 	"Reserved 0x0f"				/* 0x0f */
358c74ad251Schristos };
359c74ad251Schristos 
360c74ad251Schristos /* MAC commands from Table 7-49 of 802.15.4-2015 */
361c74ad251Schristos static const char *mac_c_names[] = {
362c74ad251Schristos 	"Reserved 0x00",				/* 0x00 */
363c74ad251Schristos 	"Association Request command",			/* 0x01 */
364c74ad251Schristos 	"Association Response command",			/* 0x02 */
365c74ad251Schristos 	"Disassociation Notification command",		/* 0x03 */
366c74ad251Schristos 	"Data Request command",				/* 0x04 */
367c74ad251Schristos 	"PAN ID Conflict Notification command",		/* 0x05 */
368c74ad251Schristos 	"Orphan Notification command",			/* 0x06 */
369c74ad251Schristos 	"Beacon Request command",			/* 0x07 */
370c74ad251Schristos 	"Coordinator realignment command",		/* 0x08 */
371c74ad251Schristos 	"GTS request command",				/* 0x09 */
372c74ad251Schristos 	"TRLE Management Request command",		/* 0x0a */
373c74ad251Schristos 	"TRLE Management Response command",		/* 0x0b */
374c74ad251Schristos 	"Reserved 0x0c",				/* 0x0c */
375c74ad251Schristos 	"Reserved 0x0d",				/* 0x0d */
376c74ad251Schristos 	"Reserved 0x0e",				/* 0x0e */
377c74ad251Schristos 	"Reserved 0x0f",				/* 0x0f */
378c74ad251Schristos 	"Reserved 0x10",				/* 0x10 */
379c74ad251Schristos 	"Reserved 0x11",				/* 0x11 */
380c74ad251Schristos 	"Reserved 0x12",				/* 0x12 */
381c74ad251Schristos 	"DSME Association Request command",		/* 0x13 */
382c74ad251Schristos 	"DSME Association Response command",		/* 0x14 */
383c74ad251Schristos 	"DSME GTS Request command",			/* 0x15 */
384c74ad251Schristos 	"DSME GTS Response command",			/* 0x16 */
385c74ad251Schristos 	"DSME GTS Notify command",			/* 0x17 */
386c74ad251Schristos 	"DSME Information Request command",		/* 0x18 */
387c74ad251Schristos 	"DSME Information Response command",		/* 0x19 */
388c74ad251Schristos 	"DSME Beacon Allocation Notification command",	/* 0x1a */
389c74ad251Schristos 	"DSME Beacon Collision Notification command",	/* 0x1b */
390c74ad251Schristos 	"DSME Link Report command",			/* 0x1c */
391c74ad251Schristos 	"Reserved 0x1d",				/* 0x1d */
392c74ad251Schristos 	"Reserved 0x1e",				/* 0x1e */
393c74ad251Schristos 	"Reserved 0x1f",				/* 0x1f */
394c74ad251Schristos 	"RIT Data Request command",			/* 0x20 */
395c74ad251Schristos 	"DBS Request command",				/* 0x21 */
396c74ad251Schristos 	"DBS Response command",				/* 0x22 */
397c74ad251Schristos 	"RIT Data Response command",			/* 0x23 */
398c74ad251Schristos 	"Vendor Specific command",			/* 0x24 */
399c74ad251Schristos 	"Reserved 0x25",				/* 0x25 */
400c74ad251Schristos 	"Reserved 0x26",				/* 0x26 */
401c74ad251Schristos 	"Reserved 0x27",				/* 0x27 */
402c74ad251Schristos 	"Reserved 0x28",				/* 0x28 */
403c74ad251Schristos 	"Reserved 0x29",				/* 0x29 */
404c74ad251Schristos 	"Reserved 0x2a",				/* 0x2a */
405c74ad251Schristos 	"Reserved 0x2b",				/* 0x2b */
406c74ad251Schristos 	"Reserved 0x2c",				/* 0x2c */
407c74ad251Schristos 	"Reserved 0x2d",				/* 0x2d */
408c74ad251Schristos 	"Reserved 0x2e",				/* 0x2e */
409c74ad251Schristos 	"Reserved 0x2f"					/* 0x2f */
4109546e36dSchristos };
4119546e36dSchristos 
41272c96ff3Schristos /*
41372c96ff3Schristos  * Frame Control subfields.
41472c96ff3Schristos  */
41572c96ff3Schristos #define FC_FRAME_TYPE(fc)              ((fc) & 0x7)
41672c96ff3Schristos #define FC_FRAME_VERSION(fc)           (((fc) >> 12) & 0x3)
4179546e36dSchristos 
41872c96ff3Schristos #define FC_ADDRESSING_MODE_NONE         0x00
41972c96ff3Schristos #define FC_ADDRESSING_MODE_RESERVED     0x01
42072c96ff3Schristos #define FC_ADDRESSING_MODE_SHORT        0x02
42172c96ff3Schristos #define FC_ADDRESSING_MODE_LONG         0x03
4229546e36dSchristos 
423c74ad251Schristos /*
424*26ba0b50Schristos  * IEEE 802.15.4 CRC 16 function. This is using the CCITT polynomial of 0x1021,
425c74ad251Schristos  * but the initial value is 0, and the bits are reversed for both in and out.
426c74ad251Schristos  * See section 7.2.10 of 802.15.4-2015 for more information.
427c74ad251Schristos  */
428c74ad251Schristos static uint16_t
429c74ad251Schristos ieee802_15_4_crc16(netdissect_options *ndo, const u_char *p,
430c74ad251Schristos 		   u_int data_len)
4319546e36dSchristos {
432c74ad251Schristos 	uint16_t crc;
433c74ad251Schristos 	u_char x, y;
4349546e36dSchristos 
435c74ad251Schristos 	crc = 0x0000; /* Note, initial value is 0x0000 not 0xffff. */
436c74ad251Schristos 
437c74ad251Schristos 	while (data_len != 0){
438c74ad251Schristos 		y = GET_U_1(p);
439c74ad251Schristos 		p++;
440c74ad251Schristos 		/* Reverse bits on input */
441c74ad251Schristos 		y = (((y & 0xaa) >> 1) | ((y & 0x55) << 1));
442c74ad251Schristos 		y = (((y & 0xcc) >> 2) | ((y & 0x33) << 2));
443c74ad251Schristos 		y = (((y & 0xf0) >> 4) | ((y & 0x0f) << 4));
444c74ad251Schristos 		/* Update CRC */
445c74ad251Schristos 		x = crc >> 8 ^ y;
446c74ad251Schristos 		x ^= x >> 4;
447c74ad251Schristos 		crc = ((uint16_t)(crc << 8)) ^
448c74ad251Schristos 			((uint16_t)(x << 12)) ^
449c74ad251Schristos 			((uint16_t)(x << 5)) ^
450c74ad251Schristos 			((uint16_t)x);
451c74ad251Schristos 		data_len--;
452c74ad251Schristos 	}
453c74ad251Schristos 	/* Reverse bits on output */
454c74ad251Schristos 	crc = (((crc & 0xaaaa) >> 1) | ((crc & 0x5555) << 1));
455c74ad251Schristos 	crc = (((crc & 0xcccc) >> 2) | ((crc & 0x3333) << 2));
456c74ad251Schristos 	crc = (((crc & 0xf0f0) >> 4) | ((crc & 0x0f0f) << 4));
457c74ad251Schristos 	crc = (((crc & 0xff00) >> 8) | ((crc & 0x00ff) << 8));
458c74ad251Schristos 	return crc;
459c74ad251Schristos }
460c74ad251Schristos 
461c74ad251Schristos /*
462c74ad251Schristos  * Reverses the bits of the 32-bit word.
463c74ad251Schristos  */
464c74ad251Schristos static uint32_t
465c74ad251Schristos ieee802_15_4_reverse32(uint32_t x)
466c74ad251Schristos {
467c74ad251Schristos 	x = ((x & 0x55555555) <<  1) | ((x >>  1) & 0x55555555);
468c74ad251Schristos 	x = ((x & 0x33333333) <<  2) | ((x >>  2) & 0x33333333);
469c74ad251Schristos 	x = ((x & 0x0F0F0F0F) <<  4) | ((x >>  4) & 0x0F0F0F0F);
470c74ad251Schristos 	x = (x << 24) | ((x & 0xFF00) << 8) |
471c74ad251Schristos 		((x >> 8) & 0xFF00) | (x >> 24);
472c74ad251Schristos 	return x;
473c74ad251Schristos }
474c74ad251Schristos 
475c74ad251Schristos /*
476*26ba0b50Schristos  * IEEE 802.15.4 CRC 32 function. This is using the ANSI X3.66-1979 polynomial of
477c74ad251Schristos  * 0x04C11DB7, but the initial value is 0, and the bits are reversed for both
478c74ad251Schristos  * in and out. See section 7.2.10 of 802.15.4-2015 for more information.
479c74ad251Schristos  */
480c74ad251Schristos static uint32_t
481c74ad251Schristos ieee802_15_4_crc32(netdissect_options *ndo, const u_char *p,
482c74ad251Schristos 		   u_int data_len)
483c74ad251Schristos {
484c74ad251Schristos 	uint32_t crc, byte;
485c74ad251Schristos 	int b;
486c74ad251Schristos 
487c74ad251Schristos 	crc = 0x00000000; /* Note, initial value is 0x00000000 not 0xffffffff */
488c74ad251Schristos 
489c74ad251Schristos 	while (data_len != 0){
490c74ad251Schristos 		byte = GET_U_1(p);
491c74ad251Schristos 		p++;
492c74ad251Schristos 		/* Reverse bits on input */
493c74ad251Schristos 		byte = ieee802_15_4_reverse32(byte);
494c74ad251Schristos 		/* Update CRC */
495c74ad251Schristos 		for(b = 0; b <= 7; b++) {
496c74ad251Schristos 		  if ((int) (crc ^ byte) < 0)
497c74ad251Schristos 		    crc = (crc << 1) ^ 0x04C11DB7;
498c74ad251Schristos 		  else
499c74ad251Schristos 		    crc = crc << 1;
500c74ad251Schristos 		  byte = byte << 1;
501c74ad251Schristos 		}
502c74ad251Schristos 		data_len--;
503c74ad251Schristos 	}
504c74ad251Schristos 	/* Reverse bits on output */
505c74ad251Schristos 	crc = ieee802_15_4_reverse32(crc);
506c74ad251Schristos 	return crc;
507c74ad251Schristos }
508c74ad251Schristos 
509c74ad251Schristos /*
510c74ad251Schristos  * Find out the address length based on the address type. See table 7-3 of
511c74ad251Schristos  * 802.15.4-2015. Returns the address length.
512c74ad251Schristos  */
513c74ad251Schristos static int
514c74ad251Schristos ieee802_15_4_addr_len(uint16_t addr_type)
515c74ad251Schristos {
516c74ad251Schristos 	switch (addr_type) {
517c74ad251Schristos 	case FC_ADDRESSING_MODE_NONE: /* None. */
518c74ad251Schristos 		return 0;
519c74ad251Schristos 		break;
520c74ad251Schristos 	case FC_ADDRESSING_MODE_RESERVED: /* Reserved, there used to be 8-bit
521c74ad251Schristos 					   * address type in one amendment, but
522c74ad251Schristos 					   * that and the feature using it was
523c74ad251Schristos 					   * removed during 802.15.4-2015
524c74ad251Schristos 					   * maintenance process. */
525c74ad251Schristos 		return -1;
526c74ad251Schristos 		break;
527c74ad251Schristos 	case FC_ADDRESSING_MODE_SHORT: /* Short. */
528c74ad251Schristos 		return 2;
529c74ad251Schristos 		break;
530c74ad251Schristos 	case FC_ADDRESSING_MODE_LONG: /* Extended. */
531c74ad251Schristos 		return 8;
532c74ad251Schristos 		break;
533c74ad251Schristos 	}
534c74ad251Schristos 	return 0;
535c74ad251Schristos }
536c74ad251Schristos 
537c74ad251Schristos /*
538c74ad251Schristos  * Print out the ieee 802.15.4 address.
539c74ad251Schristos  */
540c74ad251Schristos static void
541c74ad251Schristos ieee802_15_4_print_addr(netdissect_options *ndo, const u_char *p,
542c74ad251Schristos 			int dst_addr_len)
543c74ad251Schristos {
544c74ad251Schristos 	switch (dst_addr_len) {
545c74ad251Schristos 	case 0:
546c74ad251Schristos 		ND_PRINT("none");
547c74ad251Schristos 		break;
548c74ad251Schristos 	case 2:
549c74ad251Schristos 		ND_PRINT("%04x", GET_LE_U_2(p));
550c74ad251Schristos 		break;
551c74ad251Schristos 	case 8:
552c74ad251Schristos 		ND_PRINT("%s", GET_LE64ADDR_STRING(p));
553c74ad251Schristos 		break;
554c74ad251Schristos 	}
555c74ad251Schristos }
556c74ad251Schristos 
557c74ad251Schristos /*
558c74ad251Schristos  * Beacon frame superframe specification structure. Used in the old Beacon
559c74ad251Schristos  * frames, and in the DSME PAN Descriptor IE. See section 7.3.1.3 of the
560c74ad251Schristos  * 802.15.4-2015.
561c74ad251Schristos  */
562c74ad251Schristos static void
563c74ad251Schristos ieee802_15_4_print_superframe_specification(netdissect_options *ndo,
564c74ad251Schristos 					    uint16_t ss)
565c74ad251Schristos {
566c74ad251Schristos 	if (ndo->ndo_vflag < 1) {
567c74ad251Schristos 		return;
568c74ad251Schristos 	}
569c74ad251Schristos 	ND_PRINT("\n\tBeacon order = %d, Superframe order = %d, ",
570c74ad251Schristos 		 (ss & 0xf), ((ss >> 4) & 0xf));
571c74ad251Schristos 	ND_PRINT("Final CAP Slot = %d",
572c74ad251Schristos 		 ((ss >> 8) & 0xf));
573c74ad251Schristos 	if (CHECK_BIT(ss, 12)) { ND_PRINT(", BLE enabled"); }
574c74ad251Schristos 	if (CHECK_BIT(ss, 14)) { ND_PRINT(", PAN Coordinator"); }
575c74ad251Schristos 	if (CHECK_BIT(ss, 15)) { ND_PRINT(", Association Permit"); }
576c74ad251Schristos }
577c74ad251Schristos 
578c74ad251Schristos /*
579c74ad251Schristos  * Beacon frame gts info structure. Used in the old Beacon frames, and
580c74ad251Schristos  * in the DSME PAN Descriptor IE. See section 7.3.1.4 of 802.15.4-2015.
581c74ad251Schristos  *
582c74ad251Schristos  * Returns number of byts consumed from the packet or -1 in case of error.
583c74ad251Schristos  */
584c74ad251Schristos static int
585c74ad251Schristos ieee802_15_4_print_gts_info(netdissect_options *ndo,
586c74ad251Schristos 			    const u_char *p,
587c74ad251Schristos 			    u_int data_len)
588c74ad251Schristos {
589c74ad251Schristos 	uint8_t gts_spec, gts_cnt;
590c74ad251Schristos 	u_int len;
591c74ad251Schristos 	int i;
592c74ad251Schristos 
593c74ad251Schristos 	gts_spec = GET_U_1(p);
594c74ad251Schristos 	gts_cnt = gts_spec & 0x7;
595c74ad251Schristos 
596c74ad251Schristos 	if (gts_cnt == 0) {
597c74ad251Schristos 		if (ndo->ndo_vflag > 0) {
598c74ad251Schristos 			ND_PRINT("\n\tGTS Descriptor Count = %d, ", gts_cnt);
599c74ad251Schristos 		}
600c74ad251Schristos 		return 1;
601c74ad251Schristos 	}
602c74ad251Schristos 	len = 1 + 1 + gts_cnt * 3;
603c74ad251Schristos 
604c74ad251Schristos 	if (data_len < len) {
605c74ad251Schristos 		ND_PRINT(" [ERROR: Truncated GTS Info List]");
606c74ad251Schristos 		return -1;
607c74ad251Schristos 	}
608c74ad251Schristos 	if (ndo->ndo_vflag < 2) {
609c74ad251Schristos 		return len;
610c74ad251Schristos 	}
611c74ad251Schristos 	ND_PRINT("GTS Descriptor Count = %d, ", gts_cnt);
612c74ad251Schristos 	ND_PRINT("GTS Directions Mask = %02x, [ ",
613c74ad251Schristos 		 GET_U_1(p + 1) & 0x7f);
614c74ad251Schristos 
615c74ad251Schristos 	for(i = 0; i < gts_cnt; i++) {
616c74ad251Schristos 		ND_PRINT("[ ");
617c74ad251Schristos 		ieee802_15_4_print_addr(ndo, p + 2 + i * 3, 2);
618c74ad251Schristos 		ND_PRINT(", Start slot = %d, Length = %d ] ",
619c74ad251Schristos 			 GET_U_1(p + 2 + i * 3 + 1) & 0x0f,
620c74ad251Schristos 			 (GET_U_1(p + 2 + i * 3 + 1) >> 4) & 0x0f);
621c74ad251Schristos 	}
622c74ad251Schristos 	ND_PRINT("]");
623c74ad251Schristos 	return len;
624c74ad251Schristos }
625c74ad251Schristos 
626c74ad251Schristos /*
627c74ad251Schristos  * Beacon frame pending address structure. Used in the old Beacon frames, and
628c74ad251Schristos  * in the DSME PAN Descriptor IE. See section 7.3.1.5 of 802.15.4-2015.
629c74ad251Schristos  *
630c74ad251Schristos  * Returns number of byts consumed from the packet or -1 in case of error.
631c74ad251Schristos  */
632c74ad251Schristos static int16_t
633c74ad251Schristos ieee802_15_4_print_pending_addresses(netdissect_options *ndo,
634c74ad251Schristos 				     const u_char *p,
635c74ad251Schristos 				     u_int data_len)
636c74ad251Schristos {
637c74ad251Schristos 	uint8_t pas, s_cnt, e_cnt, len, i;
638c74ad251Schristos 
639c74ad251Schristos 	pas = GET_U_1(p);
640c74ad251Schristos 	s_cnt = pas & 0x7;
641c74ad251Schristos 	e_cnt = (pas >> 4) & 0x7;
642c74ad251Schristos 	len = 1 + s_cnt * 2 + e_cnt * 8;
643c74ad251Schristos 	if (ndo->ndo_vflag > 0) {
644c74ad251Schristos 		ND_PRINT("\n\tPending address list, "
645c74ad251Schristos 			 "# short addresses = %d, # extended addresses = %d",
646c74ad251Schristos 			 s_cnt, e_cnt);
647c74ad251Schristos 	}
648c74ad251Schristos 	if (data_len < len) {
649c74ad251Schristos 		ND_PRINT(" [ERROR: Pending address list truncated]");
650c74ad251Schristos 		return -1;
651c74ad251Schristos 	}
652c74ad251Schristos 	if (ndo->ndo_vflag < 2) {
653c74ad251Schristos 		return len;
654c74ad251Schristos 	}
655c74ad251Schristos 	if (s_cnt != 0) {
656c74ad251Schristos 		ND_PRINT(", Short address list = [ ");
657c74ad251Schristos 		for(i = 0; i < s_cnt; i++) {
658c74ad251Schristos 			ieee802_15_4_print_addr(ndo, p + 1 + i * 2, 2);
659c74ad251Schristos 			ND_PRINT(" ");
660c74ad251Schristos 		}
661c74ad251Schristos 		ND_PRINT("]");
662c74ad251Schristos 	}
663c74ad251Schristos 	if (e_cnt != 0) {
664c74ad251Schristos 		ND_PRINT(", Extended address list = [ ");
665c74ad251Schristos 		for(i = 0; i < e_cnt; i++) {
666c74ad251Schristos 			ieee802_15_4_print_addr(ndo, p + 1 + s_cnt * 2 +
667c74ad251Schristos 						i * 8, 8);
668c74ad251Schristos 			ND_PRINT(" ");
669c74ad251Schristos 		}
670c74ad251Schristos 		ND_PRINT("]");
671c74ad251Schristos 	}
672c74ad251Schristos 	return len;
673c74ad251Schristos }
674c74ad251Schristos 
675c74ad251Schristos /*
676c74ad251Schristos  * Print header ie content.
677c74ad251Schristos  */
678c74ad251Schristos static void
679c74ad251Schristos ieee802_15_4_print_header_ie(netdissect_options *ndo,
680c74ad251Schristos 			     const u_char *p,
681c74ad251Schristos 			     uint16_t ie_len,
682c74ad251Schristos 			     int element_id)
683c74ad251Schristos {
684c74ad251Schristos 	int i;
685c74ad251Schristos 
686c74ad251Schristos 	switch (element_id) {
687c74ad251Schristos 	case 0x00: /* Vendor Specific Header IE */
688c74ad251Schristos 		if (ie_len < 3) {
689c74ad251Schristos 			ND_PRINT("[ERROR: Vendor OUI missing]");
690c74ad251Schristos 		} else {
691c74ad251Schristos 			ND_PRINT("OUI = 0x%02x%02x%02x, ", GET_U_1(p),
692c74ad251Schristos 				 GET_U_1(p + 1), GET_U_1(p + 2));
693c74ad251Schristos 			ND_PRINT("Data = ");
694c74ad251Schristos 			for(i = 3; i < ie_len; i++) {
695c74ad251Schristos 				ND_PRINT("%02x ", GET_U_1(p + i));
696c74ad251Schristos 			}
697c74ad251Schristos 		}
698c74ad251Schristos 		break;
699c74ad251Schristos 	case 0x1a: /* LE CSL IE */
700c74ad251Schristos 		if (ie_len < 4) {
701c74ad251Schristos 			ND_PRINT("[ERROR: Truncated CSL IE]");
702c74ad251Schristos 		} else {
703c74ad251Schristos 			ND_PRINT("CSL Phase = %d, CSL Period = %d",
704c74ad251Schristos 				 GET_LE_U_2(p), GET_LE_U_2(p + 2));
705c74ad251Schristos 			if (ie_len >= 6) {
706c74ad251Schristos 				ND_PRINT(", Rendezvous time = %d",
707c74ad251Schristos 					 GET_LE_U_2(p + 4));
708c74ad251Schristos 			}
709c74ad251Schristos 			if (ie_len != 4 && ie_len != 6) {
710c74ad251Schristos 				ND_PRINT(" [ERROR: CSL IE length wrong]");
711c74ad251Schristos 			}
712c74ad251Schristos 		}
713c74ad251Schristos 		break;
714c74ad251Schristos 	case 0x1b: /* LE RIT IE */
715c74ad251Schristos 		if (ie_len < 4) {
716c74ad251Schristos 			ND_PRINT("[ERROR: Truncated RIT IE]");
717c74ad251Schristos 		} else {
718c74ad251Schristos 			ND_PRINT("Time to First Listen = %d, # of Repeat Listen = %d, Repeat Listen Interval = %d",
719c74ad251Schristos 				 GET_U_1(p),
720c74ad251Schristos 				 GET_U_1(p + 1),
721c74ad251Schristos 				 GET_LE_U_2(p + 2));
722c74ad251Schristos 		}
723c74ad251Schristos 		break;
724c74ad251Schristos 	case 0x1c: /* DSME PAN Descriptor IE */
725c74ad251Schristos 		/*FALLTHROUGH*/
726c74ad251Schristos 	case 0x21: /* Extended DSME PAN descriptor IE */
727c74ad251Schristos 		if (ie_len < 2) {
728c74ad251Schristos 			ND_PRINT("[ERROR: Truncated DSME PAN IE]");
729c74ad251Schristos 		} else {
730c74ad251Schristos 			uint16_t ss, ptr, ulen;
731c74ad251Schristos 			int16_t len;
732c74ad251Schristos 			int hopping_present;
733c74ad251Schristos 
734c74ad251Schristos 			hopping_present = 0;
735c74ad251Schristos 
736c74ad251Schristos 			ss = GET_LE_U_2(p);
737c74ad251Schristos 			ieee802_15_4_print_superframe_specification(ndo, ss);
738c74ad251Schristos 			if (ie_len < 3) {
739c74ad251Schristos 				ND_PRINT("[ERROR: Truncated before pending addresses field]");
740c74ad251Schristos 				break;
741c74ad251Schristos 			}
742c74ad251Schristos 			ptr = 2;
743c74ad251Schristos 			len = ieee802_15_4_print_pending_addresses(ndo,
744c74ad251Schristos 								   p + ptr,
745c74ad251Schristos 								   ie_len -
746c74ad251Schristos 								   ptr);
747c74ad251Schristos 			if (len < 0) {
748c74ad251Schristos 				break;
749c74ad251Schristos 			}
750c74ad251Schristos 			ptr += len;
751c74ad251Schristos 
752c74ad251Schristos 			if (element_id == 0x21) {
753c74ad251Schristos 				/* Extended version. */
754c74ad251Schristos 				if (ie_len < ptr + 2) {
755c74ad251Schristos 					ND_PRINT("[ERROR: Truncated before DSME Superframe Specification]");
756c74ad251Schristos 					break;
757c74ad251Schristos 				}
758c74ad251Schristos 				ss = GET_LE_U_2(p + ptr);
759c74ad251Schristos 				ptr += 2;
760c74ad251Schristos 				ND_PRINT("Multi-superframe Order = %d", ss & 0xff);
761c74ad251Schristos 				ND_PRINT(", %s", ((ss & 0x100) ?
762c74ad251Schristos 						  "Channel hopping mode" :
763c74ad251Schristos 						  "Channel adaptation mode"));
764c74ad251Schristos 				if (ss & 0x400) {
765c74ad251Schristos 					ND_PRINT(", CAP reduction enabled");
766c74ad251Schristos 				}
767c74ad251Schristos 				if (ss & 0x800) {
768c74ad251Schristos 					ND_PRINT(", Deferred beacon enabled");
769c74ad251Schristos 				}
770c74ad251Schristos 				if (ss & 0x1000) {
771c74ad251Schristos 					ND_PRINT(", Hopping Sequence Present");
772c74ad251Schristos 					hopping_present = 1;
773c74ad251Schristos 				}
774c74ad251Schristos 			} else {
775c74ad251Schristos 				if (ie_len < ptr + 1) {
776c74ad251Schristos 					ND_PRINT("[ERROR: Truncated before DSME Superframe Specification]");
777c74ad251Schristos 					break;
778c74ad251Schristos 				}
779c74ad251Schristos 				ss = GET_U_1(p + ptr);
780c74ad251Schristos 				ptr++;
781c74ad251Schristos 				ND_PRINT("Multi-superframe Order = %d",
782c74ad251Schristos 					 ss & 0x0f);
783c74ad251Schristos 				ND_PRINT(", %s", ((ss & 0x10) ?
784c74ad251Schristos 						  "Channel hopping mode" :
785c74ad251Schristos 						  "Channel adaptation mode"));
786c74ad251Schristos 				if (ss & 0x40) {
787c74ad251Schristos 					ND_PRINT(", CAP reduction enabled");
788c74ad251Schristos 				}
789c74ad251Schristos 				if (ss & 0x80) {
790c74ad251Schristos 					ND_PRINT(", Deferred beacon enabled");
791c74ad251Schristos 				}
792c74ad251Schristos 			}
793c74ad251Schristos 			if (ie_len < ptr + 8) {
794c74ad251Schristos 				ND_PRINT(" [ERROR: Truncated before Time synchronization specification]");
795c74ad251Schristos 				break;
796c74ad251Schristos 			}
797c74ad251Schristos 			ND_PRINT("Beacon timestamp = %" PRIu64 ", offset = %d",
798c74ad251Schristos 				 GET_LE_U_6(p + ptr),
799c74ad251Schristos 				 GET_LE_U_2(p + ptr + 6));
800c74ad251Schristos 			ptr += 8;
801c74ad251Schristos 			if (ie_len < ptr + 4) {
802c74ad251Schristos 				ND_PRINT(" [ERROR: Truncated before Beacon Bitmap]");
803c74ad251Schristos 				break;
804c74ad251Schristos 			}
805c74ad251Schristos 
806c74ad251Schristos 			ulen = GET_LE_U_2(p + ptr + 2);
807c74ad251Schristos 			ND_PRINT("SD Index = %d, Bitmap len = %d, ",
808c74ad251Schristos 				 GET_LE_U_2(p + ptr), ulen);
809c74ad251Schristos 			ptr += 4;
810c74ad251Schristos 			if (ie_len < ptr + ulen) {
811c74ad251Schristos 				ND_PRINT(" [ERROR: Truncated in SD bitmap]");
812c74ad251Schristos 				break;
813c74ad251Schristos 			}
814c74ad251Schristos 			ND_PRINT(" SD Bitmap = ");
815c74ad251Schristos 			for(i = 0; i < ulen; i++) {
816c74ad251Schristos 				ND_PRINT("%02x ", GET_U_1(p + ptr + i));
817c74ad251Schristos 			}
818c74ad251Schristos 			ptr += ulen;
819c74ad251Schristos 
820c74ad251Schristos 			if (ie_len < ptr + 5) {
821c74ad251Schristos 				ND_PRINT(" [ERROR: Truncated before Channel hopping specification]");
822c74ad251Schristos 				break;
823c74ad251Schristos 			}
824c74ad251Schristos 
825c74ad251Schristos 			ulen = GET_LE_U_2(p + ptr + 4);
826c74ad251Schristos 			ND_PRINT("Hopping Seq ID = %d, PAN Coordinator BSN = %d, "
827c74ad251Schristos 				 "Channel offset = %d, Bitmap length = %d, ",
828c74ad251Schristos 				 GET_U_1(p + ptr),
829c74ad251Schristos 				 GET_U_1(p + ptr + 1),
830c74ad251Schristos 				 GET_LE_U_2(p + ptr + 2),
831c74ad251Schristos 				 ulen);
832c74ad251Schristos 			ptr += 5;
833c74ad251Schristos 			if (ie_len < ptr + ulen) {
834c74ad251Schristos 				ND_PRINT(" [ERROR: Truncated in Channel offset bitmap]");
835c74ad251Schristos 				break;
836c74ad251Schristos 			}
837c74ad251Schristos 			ND_PRINT(" Channel offset bitmap = ");
838c74ad251Schristos 			for(i = 0; i < ulen; i++) {
839c74ad251Schristos 				ND_PRINT("%02x ", GET_U_1(p + ptr + i));
840c74ad251Schristos 			}
841c74ad251Schristos 			ptr += ulen;
842c74ad251Schristos 			if (hopping_present) {
843c74ad251Schristos 				if (ie_len < ptr + 1) {
844c74ad251Schristos 					ND_PRINT(" [ERROR: Truncated in Hopping Sequence length]");
845c74ad251Schristos 					break;
846c74ad251Schristos 				}
847c74ad251Schristos 				ulen = GET_U_1(p + ptr);
848c74ad251Schristos 				ptr++;
849c74ad251Schristos 				ND_PRINT("Hopping Seq length = %d [ ", ulen);
850c74ad251Schristos 
851c74ad251Schristos 				/* The specification is not clear how the
852c74ad251Schristos 				   hopping sequence is encoded, I assume two
853c74ad251Schristos 				   octet unsigned integers for each channel. */
854c74ad251Schristos 
855c74ad251Schristos 				if (ie_len < ptr + ulen * 2) {
856c74ad251Schristos 					ND_PRINT(" [ERROR: Truncated in Channel offset bitmap]");
857c74ad251Schristos 					break;
858c74ad251Schristos 				}
859c74ad251Schristos 				for(i = 0; i < ulen; i++) {
860c74ad251Schristos 					ND_PRINT("%02x ",
861c74ad251Schristos 						 GET_LE_U_2(p + ptr + i * 2));
862c74ad251Schristos 				}
863c74ad251Schristos 				ND_PRINT("]");
864c74ad251Schristos 				ptr += ulen * 2;
865c74ad251Schristos 			}
866c74ad251Schristos 		}
867c74ad251Schristos 		break;
868c74ad251Schristos 	case 0x1d: /* Rendezvous Tome IE */
869c74ad251Schristos 		if (ie_len != 4) {
870c74ad251Schristos 			ND_PRINT("[ERROR: Length != 2]");
871c74ad251Schristos 		} else {
872c74ad251Schristos 			uint16_t r_time, w_u_interval;
873c74ad251Schristos 			r_time = GET_LE_U_2(p);
874c74ad251Schristos 			w_u_interval = GET_LE_U_2(p + 2);
875c74ad251Schristos 
876c74ad251Schristos 			ND_PRINT("Rendezvous time = %d, Wake-up Interval = %d",
877c74ad251Schristos 				 r_time, w_u_interval);
878c74ad251Schristos 		}
879c74ad251Schristos 		break;
880c74ad251Schristos 	case 0x1e: /* Time correction IE */
881c74ad251Schristos 		if (ie_len != 2) {
882c74ad251Schristos 			ND_PRINT("[ERROR: Length != 2]");
883c74ad251Schristos 		} else {
884c74ad251Schristos 			uint16_t val;
885c74ad251Schristos 			int16_t timecorr;
886c74ad251Schristos 
887c74ad251Schristos 			val = GET_LE_U_2(p);
888c74ad251Schristos 			if (val & 0x8000) { ND_PRINT("Negative "); }
889c74ad251Schristos 			val &= 0xfff;
890c74ad251Schristos 			val <<= 4;
891c74ad251Schristos 			timecorr = val;
892c74ad251Schristos 			timecorr >>= 4;
893c74ad251Schristos 
894c74ad251Schristos 			ND_PRINT("Ack time correction = %d, ", timecorr);
895c74ad251Schristos 		}
896c74ad251Schristos 		break;
897c74ad251Schristos 	case 0x22: /* Fragment Sequence Content Description IE */
898c74ad251Schristos 		/* XXX Not implemented */
899c74ad251Schristos 	case 0x23: /* Simplified Superframe Specification IE */
900c74ad251Schristos 		/* XXX Not implemented */
901c74ad251Schristos 	case 0x24: /* Simplified GTS Specification IE */
902c74ad251Schristos 		/* XXX Not implemented */
903c74ad251Schristos 	case 0x25: /* LECIM Capabilities IE */
904c74ad251Schristos 		/* XXX Not implemented */
905c74ad251Schristos 	case 0x26: /* TRLE Descriptor IE */
906c74ad251Schristos 		/* XXX Not implemented */
907c74ad251Schristos 	case 0x27: /* RCC Capabilities IE */
908c74ad251Schristos 		/* XXX Not implemented */
909c74ad251Schristos 	case 0x28: /* RCCN Descriptor IE */
910c74ad251Schristos 		/* XXX Not implemented */
911c74ad251Schristos 	case 0x29: /* Global Time IE */
912c74ad251Schristos 		/* XXX Not implemented */
913c74ad251Schristos 	case 0x2b: /* DA IE */
914c74ad251Schristos 		/* XXX Not implemented */
915c74ad251Schristos 	default:
916c74ad251Schristos 		ND_PRINT("IE Data = ");
917c74ad251Schristos 		for(i = 0; i < ie_len; i++) {
918c74ad251Schristos 			ND_PRINT("%02x ", GET_U_1(p + i));
919c74ad251Schristos 		}
920c74ad251Schristos 		break;
921c74ad251Schristos 	}
922c74ad251Schristos }
923c74ad251Schristos 
924c74ad251Schristos /*
925c74ad251Schristos  * Parse and print Header IE list. See 7.4.2 of 802.15.4-2015 for
926c74ad251Schristos  * more information.
927c74ad251Schristos  *
928c74ad251Schristos  * Returns number of byts consumed from the packet or -1 in case of error.
929c74ad251Schristos  */
930c74ad251Schristos static int
931c74ad251Schristos ieee802_15_4_print_header_ie_list(netdissect_options *ndo,
932c74ad251Schristos 				  const u_char *p,
933c74ad251Schristos 				  u_int caplen,
934c74ad251Schristos 				  int *payload_ie_present)
935c74ad251Schristos {
936c74ad251Schristos 	int len, ie, element_id, i;
937c74ad251Schristos 	uint16_t ie_len;
938c74ad251Schristos 
939c74ad251Schristos 	*payload_ie_present = 0;
940c74ad251Schristos 	len = 0;
941c74ad251Schristos 	do {
942c74ad251Schristos 		if (caplen < 2) {
943c74ad251Schristos 			ND_PRINT("[ERROR: Truncated header IE]");
944c74ad251Schristos 			return -1;
945c74ad251Schristos 		}
946c74ad251Schristos 		/* Extract IE Header */
947c74ad251Schristos 		ie = GET_LE_U_2(p);
948c74ad251Schristos 		if (CHECK_BIT(ie, 15)) {
949c74ad251Schristos 			ND_PRINT("[ERROR: Header IE with type 1] ");
950c74ad251Schristos 		}
951c74ad251Schristos 		/* Get length and Element ID */
952c74ad251Schristos 		ie_len = ie & 0x7f;
953c74ad251Schristos 		element_id = (ie >> 7) & 0xff;
954c74ad251Schristos 		if (element_id > 127) {
955c74ad251Schristos 			ND_PRINT("Reserved Element ID %02x, length = %d ",
956c74ad251Schristos 				 element_id, ie_len);
957c74ad251Schristos 		} else {
958c74ad251Schristos 			if (ie_len == 0) {
959c74ad251Schristos 				ND_PRINT("\n\t%s [", h_ie_names[element_id]);
960c74ad251Schristos 			} else {
961c74ad251Schristos 				ND_PRINT("\n\t%s [ length = %d, ",
962c74ad251Schristos 					 h_ie_names[element_id], ie_len);
963c74ad251Schristos 			}
964c74ad251Schristos 		}
965c74ad251Schristos 		if (caplen < 2U + ie_len) {
966c74ad251Schristos 			ND_PRINT("[ERROR: Truncated IE data]");
967c74ad251Schristos 			return -1;
968c74ad251Schristos 		}
969c74ad251Schristos 		/* Skip header */
970c74ad251Schristos 		p += 2;
971c74ad251Schristos 
972c74ad251Schristos 		/* Parse and print content. */
973c74ad251Schristos 		if (ndo->ndo_vflag > 3 && ie_len != 0) {
974c74ad251Schristos 			ieee802_15_4_print_header_ie(ndo, p,
975c74ad251Schristos 						     ie_len, element_id);
976c74ad251Schristos 		} else {
977c74ad251Schristos 			if (ie_len != 0) {
978c74ad251Schristos 				ND_PRINT("IE Data = ");
979c74ad251Schristos 				for(i = 0; i < ie_len; i++) {
980c74ad251Schristos 					ND_PRINT("%02x ", GET_U_1(p + i));
981c74ad251Schristos 				}
982c74ad251Schristos 			}
983c74ad251Schristos 		}
984c74ad251Schristos 		ND_PRINT("] ");
985c74ad251Schristos 		len += 2 + ie_len;
986c74ad251Schristos 		p += ie_len;
987c74ad251Schristos 		caplen -= 2 + ie_len;
988c74ad251Schristos 		if (element_id == 0x7e) {
989c74ad251Schristos 			*payload_ie_present = 1;
990c74ad251Schristos 			break;
991c74ad251Schristos 		}
992c74ad251Schristos 		if (element_id == 0x7f) {
993c74ad251Schristos 			break;
994c74ad251Schristos 		}
995c74ad251Schristos 	} while (caplen != 0);
996c74ad251Schristos 	return len;
997c74ad251Schristos }
998c74ad251Schristos 
999c74ad251Schristos /*
1000c74ad251Schristos  * Print MLME ie content.
1001c74ad251Schristos  */
1002c74ad251Schristos static void
1003c74ad251Schristos ieee802_15_4_print_mlme_ie(netdissect_options *ndo,
1004c74ad251Schristos 			   const u_char *p,
1005c74ad251Schristos 			   uint16_t sub_ie_len,
1006c74ad251Schristos 			   int sub_id)
1007c74ad251Schristos {
1008c74ad251Schristos 	int i, j;
1009c74ad251Schristos 	uint16_t len;
1010c74ad251Schristos 
1011c74ad251Schristos 	/* Note, as there is no overlap with the long and short
1012c74ad251Schristos 	   MLME sub IDs, we can just use one switch here. */
1013c74ad251Schristos 	switch (sub_id) {
1014c74ad251Schristos 	case 0x08: /* Vendor Specific Nested IE */
1015c74ad251Schristos 		if (sub_ie_len < 3) {
1016c74ad251Schristos 			ND_PRINT("[ERROR: Vendor OUI missing]");
1017c74ad251Schristos 		} else {
1018c74ad251Schristos 			ND_PRINT("OUI = 0x%02x%02x%02x, ",
1019c74ad251Schristos 				 GET_U_1(p),
1020c74ad251Schristos 				 GET_U_1(p + 1),
1021c74ad251Schristos 				 GET_U_1(p + 2));
1022c74ad251Schristos 			ND_PRINT("Data = ");
1023c74ad251Schristos 			for(i = 3; i < sub_ie_len; i++) {
1024c74ad251Schristos 				ND_PRINT("%02x ", GET_U_1(p + i));
1025c74ad251Schristos 			}
1026c74ad251Schristos 		}
1027c74ad251Schristos 		break;
1028c74ad251Schristos 	case 0x09: /* Channel Hopping IE */
1029c74ad251Schristos 		if (sub_ie_len < 1) {
1030c74ad251Schristos 			ND_PRINT("[ERROR: Hopping sequence ID missing]");
1031c74ad251Schristos 		} else if (sub_ie_len == 1) {
1032c74ad251Schristos 			ND_PRINT("Hopping Sequence ID = %d", GET_U_1(p));
1033c74ad251Schristos 			p++;
1034c74ad251Schristos 			sub_ie_len--;
1035c74ad251Schristos 		} else {
1036c74ad251Schristos 			uint16_t channel_page, number_of_channels;
1037c74ad251Schristos 
1038c74ad251Schristos 			ND_PRINT("Hopping Sequence ID = %d", GET_U_1(p));
1039c74ad251Schristos 			p++;
1040c74ad251Schristos 			sub_ie_len--;
1041c74ad251Schristos 			if (sub_ie_len < 7) {
1042c74ad251Schristos 				ND_PRINT("[ERROR: IE truncated]");
1043c74ad251Schristos 				break;
1044c74ad251Schristos 			}
1045c74ad251Schristos 			channel_page = GET_U_1(p);
1046c74ad251Schristos 			number_of_channels = GET_LE_U_2(p + 1);
1047c74ad251Schristos 			ND_PRINT("Channel Page = %d, Number of Channels = %d, ",
1048c74ad251Schristos 				 channel_page, number_of_channels);
1049c74ad251Schristos 			ND_PRINT("Phy Configuration = 0x%08x, ",
1050c74ad251Schristos 				 GET_LE_U_4(p + 3));
1051c74ad251Schristos 			p += 7;
1052c74ad251Schristos 			sub_ie_len -= 7;
1053c74ad251Schristos 			if (channel_page == 9 || channel_page == 10) {
1054c74ad251Schristos 				len = (number_of_channels + 7) / 8;
1055c74ad251Schristos 				if (sub_ie_len < len) {
1056c74ad251Schristos 					ND_PRINT("[ERROR: IE truncated]");
1057c74ad251Schristos 					break;
1058c74ad251Schristos 				}
1059c74ad251Schristos 				ND_PRINT("Extended bitmap = 0x");
1060c74ad251Schristos 				for(i = 0; i < len; i++) {
1061c74ad251Schristos 					ND_PRINT("%02x", GET_U_1(p + i));
1062c74ad251Schristos 				}
1063c74ad251Schristos 				ND_PRINT(", ");
1064c74ad251Schristos 				p += len;
1065c74ad251Schristos 				sub_ie_len -= len;
1066c74ad251Schristos 			}
1067c74ad251Schristos 			if (sub_ie_len < 2) {
1068c74ad251Schristos 				ND_PRINT("[ERROR: IE truncated]");
1069c74ad251Schristos 				break;
1070c74ad251Schristos 			}
1071c74ad251Schristos 			len = GET_LE_U_2(p);
1072c74ad251Schristos 			p += 2;
1073c74ad251Schristos 			sub_ie_len -= 2;
1074c74ad251Schristos 			ND_PRINT("Hopping Seq length = %d [ ", len);
1075c74ad251Schristos 
1076c74ad251Schristos 			if (sub_ie_len < len * 2) {
1077c74ad251Schristos 				ND_PRINT(" [ERROR: IE truncated]");
1078c74ad251Schristos 				break;
1079c74ad251Schristos 			}
1080c74ad251Schristos 			for(i = 0; i < len; i++) {
1081c74ad251Schristos 				ND_PRINT("%02x ", GET_LE_U_2(p + i * 2));
1082c74ad251Schristos 			}
1083c74ad251Schristos 			ND_PRINT("]");
1084c74ad251Schristos 			p += len * 2;
1085c74ad251Schristos 			sub_ie_len -= len * 2;
1086c74ad251Schristos 			if (sub_ie_len < 2) {
1087c74ad251Schristos 				ND_PRINT("[ERROR: IE truncated]");
1088c74ad251Schristos 				break;
1089c74ad251Schristos 			}
1090c74ad251Schristos 			ND_PRINT("Current hop = %d", GET_LE_U_2(p));
1091c74ad251Schristos 		}
1092c74ad251Schristos 
1093c74ad251Schristos 		break;
1094c74ad251Schristos 	case 0x1a: /* TSCH Synchronization IE. */
1095c74ad251Schristos 		if (sub_ie_len < 6) {
1096c74ad251Schristos 			ND_PRINT("[ERROR: Length != 6]");
1097c74ad251Schristos 		}
1098c74ad251Schristos 		ND_PRINT("ASN = %010" PRIx64 ", Join Metric = %d ",
1099c74ad251Schristos 			 GET_LE_U_5(p), GET_U_1(p + 5));
1100c74ad251Schristos 		break;
1101c74ad251Schristos 	case 0x1b: /* TSCH Slotframe and Link IE. */
1102c74ad251Schristos 		{
1103c74ad251Schristos 			int sf_num, off, links, opts;
1104c74ad251Schristos 
1105c74ad251Schristos 			if (sub_ie_len < 1) {
1106c74ad251Schristos 				ND_PRINT("[ERROR: Truncated IE]");
1107c74ad251Schristos 				break;
1108c74ad251Schristos 			}
1109c74ad251Schristos 			sf_num = GET_U_1(p);
1110c74ad251Schristos 			ND_PRINT("Slotframes = %d ", sf_num);
1111c74ad251Schristos 			off = 1;
1112c74ad251Schristos 			for(i = 0; i < sf_num; i++) {
1113c74ad251Schristos 				if (sub_ie_len < off + 4) {
1114c74ad251Schristos 					ND_PRINT("[ERROR: Truncated IE before slotframes]");
1115c74ad251Schristos 					break;
1116c74ad251Schristos 				}
1117c74ad251Schristos 				links = GET_U_1(p + off + 3);
1118c74ad251Schristos 				ND_PRINT("\n\t\t\t[ Handle %d, size = %d, links = %d ",
1119c74ad251Schristos 					 GET_U_1(p + off),
1120c74ad251Schristos 					 GET_LE_U_2(p + off + 1),
1121c74ad251Schristos 					 links);
1122c74ad251Schristos 				off += 4;
1123c74ad251Schristos 				for(j = 0; j < links; j++) {
1124c74ad251Schristos 					if (sub_ie_len < off + 5) {
1125c74ad251Schristos 						ND_PRINT("[ERROR: Truncated IE links]");
1126c74ad251Schristos 						break;
1127c74ad251Schristos 					}
1128c74ad251Schristos 					opts = GET_U_1(p + off + 4);
1129c74ad251Schristos 					ND_PRINT("\n\t\t\t\t[ Timeslot =  %d, Offset = %d, Options = ",
1130c74ad251Schristos 						 GET_LE_U_2(p + off),
1131c74ad251Schristos 						 GET_LE_U_2(p + off + 2));
1132c74ad251Schristos 					if (opts & 0x1) { ND_PRINT("TX "); }
1133c74ad251Schristos 					if (opts & 0x2) { ND_PRINT("RX "); }
1134c74ad251Schristos 					if (opts & 0x4) { ND_PRINT("Shared "); }
1135c74ad251Schristos 					if (opts & 0x8) {
1136c74ad251Schristos 						ND_PRINT("Timekeeping ");
1137c74ad251Schristos 					}
1138c74ad251Schristos 					if (opts & 0x10) {
1139c74ad251Schristos 						ND_PRINT("Priority ");
1140c74ad251Schristos 					}
1141c74ad251Schristos 					off += 5;
1142c74ad251Schristos 					ND_PRINT("] ");
1143c74ad251Schristos 				}
1144c74ad251Schristos 				ND_PRINT("] ");
1145c74ad251Schristos 			}
1146c74ad251Schristos 		}
1147c74ad251Schristos 		break;
1148c74ad251Schristos 	case 0x1c: /* TSCH Timeslot IE. */
1149c74ad251Schristos 		if (sub_ie_len == 1) {
1150c74ad251Schristos 			ND_PRINT("Time slot ID = %d ", GET_U_1(p));
1151c74ad251Schristos 		} else if (sub_ie_len == 25) {
1152c74ad251Schristos 			ND_PRINT("Time slot ID = %d, CCA Offset = %d, CCA = %d, TX Offset = %d, RX Offset = %d, RX Ack Delay = %d, TX Ack Delay = %d, RX Wait = %d, Ack Wait = %d, RX TX = %d, Max Ack = %d, Max TX = %d, Time slot Length = %d ",
1153c74ad251Schristos 				 GET_U_1(p),
1154c74ad251Schristos 				 GET_LE_U_2(p + 1),
1155c74ad251Schristos 				 GET_LE_U_2(p + 3),
1156c74ad251Schristos 				 GET_LE_U_2(p + 5),
1157c74ad251Schristos 				 GET_LE_U_2(p + 7),
1158c74ad251Schristos 				 GET_LE_U_2(p + 9),
1159c74ad251Schristos 				 GET_LE_U_2(p + 11),
1160c74ad251Schristos 				 GET_LE_U_2(p + 13),
1161c74ad251Schristos 				 GET_LE_U_2(p + 15),
1162c74ad251Schristos 				 GET_LE_U_2(p + 17),
1163c74ad251Schristos 				 GET_LE_U_2(p + 19),
1164c74ad251Schristos 				 GET_LE_U_2(p + 21),
1165c74ad251Schristos 				 GET_LE_U_2(p + 23));
1166c74ad251Schristos 		} else if (sub_ie_len == 27) {
1167c74ad251Schristos 			ND_PRINT("Time slot ID = %d, CCA Offset = %d, CCA = %d, TX Offset = %d, RX Offset = %d, RX Ack Delay = %d, TX Ack Delay = %d, RX Wait = %d, Ack Wait = %d, RX TX = %d, Max Ack = %d, Max TX = %d, Time slot Length = %d ",
1168c74ad251Schristos 				 GET_U_1(p),
1169c74ad251Schristos 				 GET_LE_U_2(p + 1),
1170c74ad251Schristos 				 GET_LE_U_2(p + 3),
1171c74ad251Schristos 				 GET_LE_U_2(p + 5),
1172c74ad251Schristos 				 GET_LE_U_2(p + 7),
1173c74ad251Schristos 				 GET_LE_U_2(p + 9),
1174c74ad251Schristos 				 GET_LE_U_2(p + 11),
1175c74ad251Schristos 				 GET_LE_U_2(p + 13),
1176c74ad251Schristos 				 GET_LE_U_2(p + 15),
1177c74ad251Schristos 				 GET_LE_U_2(p + 17),
1178c74ad251Schristos 				 GET_LE_U_2(p + 19),
1179c74ad251Schristos 				 GET_LE_U_3(p + 21),
1180c74ad251Schristos 				 GET_LE_U_3(p + 24));
1181c74ad251Schristos 		} else {
1182c74ad251Schristos 			ND_PRINT("[ERROR: Length not 1, 25, or 27]");
1183c74ad251Schristos 			ND_PRINT("\n\t\t\tIE Data = ");
1184c74ad251Schristos 			for(i = 0; i < sub_ie_len; i++) {
1185c74ad251Schristos 				ND_PRINT("%02x ", GET_U_1(p + i));
1186c74ad251Schristos 			}
1187c74ad251Schristos 		}
1188c74ad251Schristos 		break;
1189c74ad251Schristos 	case 0x1d: /* Hopping timing IE */
1190c74ad251Schristos 		/* XXX Not implemented */
1191c74ad251Schristos 	case 0x1e: /* Enhanced Beacon Filter IE */
1192c74ad251Schristos 		/* XXX Not implemented */
1193c74ad251Schristos 	case 0x1f: /* MAC Metrics IE */
1194c74ad251Schristos 		/* XXX Not implemented */
1195c74ad251Schristos 	case 0x20: /* All MAC Metrics IE */
1196c74ad251Schristos 		/* XXX Not implemented */
1197c74ad251Schristos 	case 0x21: /* Coexistence Specification IE */
1198c74ad251Schristos 		/* XXX Not implemented */
1199c74ad251Schristos 	case 0x22: /* SUN Device Capabilities IE */
1200c74ad251Schristos 		/* XXX Not implemented */
1201c74ad251Schristos 	case 0x23: /* SUN FSK Generic PHY IE */
1202c74ad251Schristos 		/* XXX Not implemented */
1203c74ad251Schristos 	case 0x24: /* Mode Switch Parameter IE */
1204c74ad251Schristos 		/* XXX Not implemented */
1205c74ad251Schristos 	case 0x25: /* PHY Parameter Change IE */
1206c74ad251Schristos 		/* XXX Not implemented */
1207c74ad251Schristos 	case 0x26: /* O-QPSK PHY Mode IE */
1208c74ad251Schristos 		/* XXX Not implemented */
1209c74ad251Schristos 	case 0x27: /* PCA Allocation IE */
1210c74ad251Schristos 		/* XXX Not implemented */
1211c74ad251Schristos 	case 0x28: /* LECIM DSSS Operating Mode IE */
1212c74ad251Schristos 		/* XXX Not implemented */
1213c74ad251Schristos 	case 0x29: /* LECIM FSK Operating Mode IE */
1214c74ad251Schristos 		/* XXX Not implemented */
1215c74ad251Schristos 	case 0x2b: /* TVWS PHY Operating Mode Description IE */
1216c74ad251Schristos 		/* XXX Not implemented */
1217c74ad251Schristos 	case 0x2c: /* TVWS Device Capabilities IE */
1218c74ad251Schristos 		/* XXX Not implemented */
1219c74ad251Schristos 	case 0x2d: /* TVWS Device Category IE */
1220c74ad251Schristos 		/* XXX Not implemented */
1221c74ad251Schristos 	case 0x2e: /* TVWS Device Identification IE */
1222c74ad251Schristos 		/* XXX Not implemented */
1223c74ad251Schristos 	case 0x2f: /* TVWS Device Location IE */
1224c74ad251Schristos 		/* XXX Not implemented */
1225c74ad251Schristos 	case 0x30: /* TVWS Channel Information Query IE */
1226c74ad251Schristos 		/* XXX Not implemented */
1227c74ad251Schristos 	case 0x31: /* TVWS Channel Information Source IE */
1228c74ad251Schristos 		/* XXX Not implemented */
1229c74ad251Schristos 	case 0x32: /* CTM IE */
1230c74ad251Schristos 		/* XXX Not implemented */
1231c74ad251Schristos 	case 0x33: /* Timestamp IE */
1232c74ad251Schristos 		/* XXX Not implemented */
1233c74ad251Schristos 	case 0x34: /* Timestamp Difference IE */
1234c74ad251Schristos 		/* XXX Not implemented */
1235c74ad251Schristos 	case 0x35: /* TMCTP Specification IE */
1236c74ad251Schristos 		/* XXX Not implemented */
1237c74ad251Schristos 	case 0x36: /* TCC PHY Operating Mode IE */
1238c74ad251Schristos 		/* XXX Not implemented */
1239c74ad251Schristos 	default:
1240c74ad251Schristos 		ND_PRINT("IE Data = ");
1241c74ad251Schristos 		for(i = 0; i < sub_ie_len; i++) {
1242c74ad251Schristos 			ND_PRINT("%02x ", GET_U_1(p + i));
1243c74ad251Schristos 		}
1244c74ad251Schristos 		break;
1245c74ad251Schristos 	}
1246c74ad251Schristos }
1247c74ad251Schristos 
1248c74ad251Schristos /*
1249c74ad251Schristos  * MLME IE list parsing and printing. See 7.4.3.2 of 802.15.4-2015
1250c74ad251Schristos  * for more information.
1251c74ad251Schristos  */
1252c74ad251Schristos static void
1253c74ad251Schristos ieee802_15_4_print_mlme_ie_list(netdissect_options *ndo,
1254c74ad251Schristos 				const u_char *p,
1255c74ad251Schristos 				uint16_t ie_len)
1256c74ad251Schristos {
1257c74ad251Schristos 	int ie, sub_id, i, type;
1258c74ad251Schristos 	uint16_t sub_ie_len;
1259c74ad251Schristos 
1260c74ad251Schristos 	do {
1261c74ad251Schristos 		if (ie_len < 2) {
1262c74ad251Schristos 			ND_PRINT("[ERROR: Truncated MLME IE]");
1263c74ad251Schristos 			return;
1264c74ad251Schristos 		}
1265c74ad251Schristos 		/* Extract IE header */
1266c74ad251Schristos 		ie = GET_LE_U_2(p);
1267c74ad251Schristos 		type = CHECK_BIT(ie, 15);
1268c74ad251Schristos 		if (type) {
1269c74ad251Schristos 			/* Long type */
1270c74ad251Schristos 			sub_ie_len = ie & 0x3ff;
1271c74ad251Schristos 			sub_id = (ie >> 11) & 0x0f;
1272c74ad251Schristos 		} else {
1273c74ad251Schristos 			sub_ie_len = ie & 0xff;
1274c74ad251Schristos 			sub_id = (ie >> 8) & 0x7f;
1275c74ad251Schristos 		}
1276c74ad251Schristos 
1277c74ad251Schristos 		/* Skip the IE header */
1278c74ad251Schristos 		p += 2;
1279c74ad251Schristos 
1280c74ad251Schristos 		if (type == 0) {
1281c74ad251Schristos 			ND_PRINT("\n\t\t%s [ length = %d, ",
1282c74ad251Schristos 				 p_mlme_short_names[sub_id], sub_ie_len);
1283c74ad251Schristos 		} else {
1284c74ad251Schristos 			ND_PRINT("\n\t\t%s [ length = %d, ",
1285c74ad251Schristos 				 p_mlme_long_names[sub_id], sub_ie_len);
1286c74ad251Schristos 		}
1287c74ad251Schristos 
1288c74ad251Schristos 		if (ie_len < 2 + sub_ie_len) {
1289c74ad251Schristos 			ND_PRINT("[ERROR: Truncated IE data]");
1290c74ad251Schristos 			return;
1291c74ad251Schristos 		}
1292c74ad251Schristos 		if (sub_ie_len != 0) {
1293c74ad251Schristos 			if (ndo->ndo_vflag > 3) {
1294c74ad251Schristos 				ieee802_15_4_print_mlme_ie(ndo, p, sub_ie_len, sub_id);
1295c74ad251Schristos 			} else if (ndo->ndo_vflag > 2) {
1296c74ad251Schristos 				ND_PRINT("IE Data = ");
1297c74ad251Schristos 				for(i = 0; i < sub_ie_len; i++) {
1298c74ad251Schristos 					ND_PRINT("%02x ", GET_U_1(p + i));
1299c74ad251Schristos 				}
1300c74ad251Schristos 			}
1301c74ad251Schristos 		}
1302c74ad251Schristos 		ND_PRINT("] ");
1303c74ad251Schristos 		p += sub_ie_len;
1304c74ad251Schristos 		ie_len -= 2 + sub_ie_len;
1305*26ba0b50Schristos 	} while (ie_len != 0);
1306c74ad251Schristos }
1307c74ad251Schristos 
1308c74ad251Schristos /*
1309*26ba0b50Schristos  * Multiplexed IE (802.15.9) parsing and printing.
1310c74ad251Schristos  *
1311c74ad251Schristos  * Returns number of bytes consumed from packet or -1 in case of error.
1312c74ad251Schristos  */
1313c74ad251Schristos static void
1314c74ad251Schristos ieee802_15_4_print_mpx_ie(netdissect_options *ndo,
1315c74ad251Schristos 			  const u_char *p,
1316c74ad251Schristos 			  uint16_t ie_len)
1317c74ad251Schristos {
1318c74ad251Schristos 	int transfer_type, tid;
1319c74ad251Schristos 	int fragment_number, data_start;
1320c74ad251Schristos 	int i;
1321c74ad251Schristos 
1322c74ad251Schristos 	data_start = 0;
1323c74ad251Schristos 	if (ie_len < 1) {
1324c74ad251Schristos 		ND_PRINT("[ERROR: Transaction control byte missing]");
1325c74ad251Schristos 		return;
1326c74ad251Schristos 	}
1327c74ad251Schristos 
1328c74ad251Schristos 	transfer_type = GET_U_1(p) & 0x7;
1329c74ad251Schristos 	tid = GET_U_1(p) >> 3;
1330c74ad251Schristos 	switch (transfer_type) {
1331c74ad251Schristos 	case 0x00: /* Full upper layer frame. */
1332c74ad251Schristos 	case 0x01: /* Full upper layer frame with small Multiplex ID. */
1333c74ad251Schristos 		ND_PRINT("Type = Full upper layer fragment%s, ",
1334c74ad251Schristos 			 (transfer_type == 0x01 ?
1335c74ad251Schristos 			  " with small Multiplex ID" : ""));
1336c74ad251Schristos 		if (transfer_type == 0x00) {
1337c74ad251Schristos 			if (ie_len < 3) {
1338c74ad251Schristos 				ND_PRINT("[ERROR: Multiplex ID missing]");
1339c74ad251Schristos 				return;
1340c74ad251Schristos 			}
1341c74ad251Schristos 			data_start = 3;
1342c74ad251Schristos 			ND_PRINT("tid = 0x%02x, Multiplex ID = 0x%04x, ",
1343c74ad251Schristos 				 tid, GET_LE_U_2(p + 1));
1344c74ad251Schristos 		} else {
1345c74ad251Schristos 			data_start = 1;
1346c74ad251Schristos 			ND_PRINT("Multiplex ID = 0x%04x, ", tid);
1347c74ad251Schristos 		}
1348c74ad251Schristos 		break;
1349c74ad251Schristos 	case 0x02: /* First, or middle, Fragments */
1350c74ad251Schristos 	case 0x04: /* Last fragment */
1351c74ad251Schristos 		if (ie_len < 2) {
1352c74ad251Schristos 			ND_PRINT("[ERROR: fragment number missing]");
1353c74ad251Schristos 			return;
1354c74ad251Schristos 		}
1355c74ad251Schristos 
1356c74ad251Schristos 		fragment_number = GET_U_1(p + 1);
1357c74ad251Schristos 		ND_PRINT("Type = %s, tid = 0x%02x, fragment = 0x%02x, ",
1358c74ad251Schristos 			 (transfer_type == 0x02 ?
1359c74ad251Schristos 			  (fragment_number == 0 ?
1360c74ad251Schristos 			   "First fragment" : "Middle fragment") :
1361c74ad251Schristos 			  "Last fragment"), tid,
1362c74ad251Schristos 			 fragment_number);
1363c74ad251Schristos 		data_start = 2;
1364c74ad251Schristos 		if (fragment_number == 0) {
1365c74ad251Schristos 			int total_size, multiplex_id;
1366c74ad251Schristos 
1367c74ad251Schristos 			if (ie_len < 6) {
1368c74ad251Schristos 				ND_PRINT("[ERROR: Total upper layer size or multiplex ID missing]");
1369c74ad251Schristos 				return;
1370c74ad251Schristos 			}
1371c74ad251Schristos 			total_size = GET_LE_U_2(p + 2);
1372c74ad251Schristos 			multiplex_id = GET_LE_U_2(p + 4);
1373c74ad251Schristos 			ND_PRINT("Total upper layer size = 0x%04x, Multiplex ID = 0x%04x, ",
1374c74ad251Schristos 				 total_size, multiplex_id);
1375c74ad251Schristos 			data_start = 6;
1376c74ad251Schristos 		}
1377c74ad251Schristos 		break;
1378c74ad251Schristos 	case 0x06: /* Abort code */
1379c74ad251Schristos 		if (ie_len == 1) {
1380c74ad251Schristos 			ND_PRINT("Type = Abort, tid = 0x%02x, no max size given",
1381c74ad251Schristos 				 tid);
1382c74ad251Schristos 		} else if (ie_len == 3) {
1383c74ad251Schristos 			ND_PRINT("Type = Abort, tid = 0x%02x, max size = 0x%04x",
1384c74ad251Schristos 				 tid, GET_LE_U_2(p + 1));
1385c74ad251Schristos 		} else {
1386c74ad251Schristos 			ND_PRINT("Type = Abort, tid = 0x%02x, invalid length = %d (not 1 or 3)",
1387c74ad251Schristos 				 tid, ie_len);
1388c74ad251Schristos 			ND_PRINT("Abort data = ");
1389c74ad251Schristos 			for(i = 1; i < ie_len; i++) {
1390c74ad251Schristos 				ND_PRINT("%02x ", GET_U_1(p + i));
1391c74ad251Schristos 			}
1392c74ad251Schristos 		}
1393c74ad251Schristos 		return;
1394c74ad251Schristos 		/* NOTREACHED */
1395c74ad251Schristos 		break;
1396c74ad251Schristos 	case 0x03: /* Reserved */
1397c74ad251Schristos 	case 0x05: /* Reserved */
1398c74ad251Schristos 	case 0x07: /* Reserved */
1399c74ad251Schristos 		ND_PRINT("Type = %d (Reserved), tid = 0x%02x, ",
1400c74ad251Schristos 			 transfer_type, tid);
1401c74ad251Schristos 		data_start = 1;
1402c74ad251Schristos 		break;
1403c74ad251Schristos 	}
1404c74ad251Schristos 
1405c74ad251Schristos 	ND_PRINT("Upper layer data = ");
1406c74ad251Schristos 	for(i = data_start; i < ie_len; i++) {
1407c74ad251Schristos 		ND_PRINT("%02x ", GET_U_1(p + i));
1408c74ad251Schristos 	}
1409c74ad251Schristos }
1410c74ad251Schristos 
1411c74ad251Schristos /*
1412c74ad251Schristos  * Payload IE list parsing and printing. See 7.4.3 of 802.15.4-2015
1413c74ad251Schristos  * for more information.
1414c74ad251Schristos  *
1415c74ad251Schristos  * Returns number of byts consumed from the packet or -1 in case of error.
1416c74ad251Schristos  */
1417c74ad251Schristos static int
1418c74ad251Schristos ieee802_15_4_print_payload_ie_list(netdissect_options *ndo,
1419c74ad251Schristos 				   const u_char *p,
1420c74ad251Schristos 				   u_int caplen)
1421c74ad251Schristos {
1422c74ad251Schristos 	int len, ie, group_id, i;
1423c74ad251Schristos 	uint16_t ie_len;
1424c74ad251Schristos 
1425c74ad251Schristos 	len = 0;
1426c74ad251Schristos 	do {
1427c74ad251Schristos 		if (caplen < 2) {
1428c74ad251Schristos 			ND_PRINT("[ERROR: Truncated header IE]");
1429c74ad251Schristos 			return -1;
1430c74ad251Schristos 		}
1431c74ad251Schristos 		/* Extract IE header */
1432c74ad251Schristos 		ie = GET_LE_U_2(p);
1433c74ad251Schristos 		if ((CHECK_BIT(ie, 15)) == 0) {
1434c74ad251Schristos 			ND_PRINT("[ERROR: Payload IE with type 0] ");
1435c74ad251Schristos 		}
1436c74ad251Schristos 		ie_len = ie & 0x3ff;
1437c74ad251Schristos 		group_id = (ie >> 11) & 0x0f;
1438c74ad251Schristos 
1439c74ad251Schristos 		/* Skip the IE header */
1440c74ad251Schristos 		p += 2;
1441c74ad251Schristos 		if (ie_len == 0) {
1442c74ad251Schristos 			ND_PRINT("\n\t%s [", p_ie_names[group_id]);
1443c74ad251Schristos 		} else {
1444c74ad251Schristos 			ND_PRINT("\n\t%s [ length = %d, ",
1445c74ad251Schristos 				 p_ie_names[group_id], ie_len);
1446c74ad251Schristos 		}
1447c74ad251Schristos 		if (caplen < 2U + ie_len) {
1448c74ad251Schristos 			ND_PRINT("[ERROR: Truncated IE data]");
1449c74ad251Schristos 			return -1;
1450c74ad251Schristos 		}
1451c74ad251Schristos 		if (ndo->ndo_vflag > 3 && ie_len != 0) {
1452c74ad251Schristos 			switch (group_id) {
1453c74ad251Schristos 			case 0x1: /* MLME IE */
1454c74ad251Schristos 				ieee802_15_4_print_mlme_ie_list(ndo, p, ie_len);
1455c74ad251Schristos 				break;
1456c74ad251Schristos 			case 0x2: /* Vendor Specific Nested IE */
1457c74ad251Schristos 				if (ie_len < 3) {
1458c74ad251Schristos 					ND_PRINT("[ERROR: Vendor OUI missing]");
1459c74ad251Schristos 				} else {
1460c74ad251Schristos 					ND_PRINT("OUI = 0x%02x%02x%02x, ",
1461c74ad251Schristos 						 GET_U_1(p),
1462c74ad251Schristos 						 GET_U_1(p + 1),
1463c74ad251Schristos 						 GET_U_1(p + 2));
1464c74ad251Schristos 					ND_PRINT("Data = ");
1465c74ad251Schristos 					for(i = 3; i < ie_len; i++) {
1466c74ad251Schristos 						ND_PRINT("%02x ",
1467c74ad251Schristos 							 GET_U_1(p + i));
1468c74ad251Schristos 					}
1469c74ad251Schristos 				}
1470c74ad251Schristos 				break;
1471c74ad251Schristos 			case 0x3: /* Multiplexed IE (802.15.9) */
1472c74ad251Schristos 				ieee802_15_4_print_mpx_ie(ndo, p, ie_len);
1473c74ad251Schristos 				break;
1474c74ad251Schristos 			case 0x5: /* IETF IE */
1475c74ad251Schristos 				if (ie_len < 1) {
1476c74ad251Schristos 					ND_PRINT("[ERROR: Subtype ID missing]");
1477c74ad251Schristos 				} else {
1478c74ad251Schristos 					ND_PRINT("Subtype ID = 0x%02x, Subtype content = ",
1479c74ad251Schristos 						 GET_U_1(p));
1480c74ad251Schristos 					for(i = 1; i < ie_len; i++) {
1481c74ad251Schristos 						ND_PRINT("%02x ",
1482c74ad251Schristos 							 GET_U_1(p + i));
1483c74ad251Schristos 					}
1484c74ad251Schristos 				}
1485c74ad251Schristos 				break;
1486c74ad251Schristos 			default:
1487c74ad251Schristos 				ND_PRINT("IE Data = ");
1488c74ad251Schristos 				for(i = 0; i < ie_len; i++) {
1489c74ad251Schristos 					ND_PRINT("%02x ", GET_U_1(p + i));
1490c74ad251Schristos 				}
1491c74ad251Schristos 				break;
1492c74ad251Schristos 			}
1493c74ad251Schristos 		} else {
1494c74ad251Schristos 			if (ie_len != 0) {
1495c74ad251Schristos 				ND_PRINT("IE Data = ");
1496c74ad251Schristos 				for(i = 0; i < ie_len; i++) {
1497c74ad251Schristos 					ND_PRINT("%02x ", GET_U_1(p + i));
1498c74ad251Schristos 				}
1499c74ad251Schristos 			}
1500c74ad251Schristos 		}
1501c74ad251Schristos 		ND_PRINT("]\n\t");
1502c74ad251Schristos 		len += 2 + ie_len;
1503c74ad251Schristos 		p += ie_len;
1504c74ad251Schristos 		caplen -= 2 + ie_len;
1505c74ad251Schristos 		if (group_id == 0xf) {
1506c74ad251Schristos 			break;
1507c74ad251Schristos 		}
1508*26ba0b50Schristos 	} while (caplen != 0);
1509c74ad251Schristos 	return len;
1510c74ad251Schristos }
1511c74ad251Schristos 
1512c74ad251Schristos /*
1513c74ad251Schristos  * Parse and print auxiliary security header.
1514c74ad251Schristos  *
1515c74ad251Schristos  * Returns number of byts consumed from the packet or -1 in case of error.
1516c74ad251Schristos  */
1517c74ad251Schristos static int
1518c74ad251Schristos ieee802_15_4_print_aux_sec_header(netdissect_options *ndo,
1519c74ad251Schristos 				  const u_char *p,
1520c74ad251Schristos 				  u_int caplen,
1521c74ad251Schristos 				  int *security_level)
1522c74ad251Schristos {
1523c74ad251Schristos 	int sc, key_id_mode, len;
1524c74ad251Schristos 
1525c74ad251Schristos 	if (caplen < 1) {
1526c74ad251Schristos 		ND_PRINT("[ERROR: Truncated before Aux Security Header]");
1527c74ad251Schristos 		return -1;
1528c74ad251Schristos 	}
1529c74ad251Schristos 	sc = GET_U_1(p);
1530c74ad251Schristos 	len = 1;
1531c74ad251Schristos 	*security_level = sc & 0x7;
1532c74ad251Schristos 	key_id_mode = (sc >> 3) & 0x3;
1533c74ad251Schristos 
1534c74ad251Schristos 	caplen -= 1;
1535c74ad251Schristos 	p += 1;
1536c74ad251Schristos 
1537c74ad251Schristos 	if (ndo->ndo_vflag > 0) {
1538c74ad251Schristos 		ND_PRINT("\n\tSecurity Level %d, Key Id Mode %d, ",
1539c74ad251Schristos 			 *security_level, key_id_mode);
1540c74ad251Schristos 	}
1541c74ad251Schristos 	if ((CHECK_BIT(sc, 5)) == 0) {
1542c74ad251Schristos 		if (caplen < 4) {
1543c74ad251Schristos 			ND_PRINT("[ERROR: Truncated before Frame Counter]");
1544c74ad251Schristos 			return -1;
1545c74ad251Schristos 		}
1546c74ad251Schristos 		if (ndo->ndo_vflag > 1) {
1547c74ad251Schristos 			ND_PRINT("Frame Counter 0x%08x ",
1548c74ad251Schristos 				 GET_LE_U_4(p));
1549c74ad251Schristos 		}
1550c74ad251Schristos 		p += 4;
1551c74ad251Schristos 		caplen -= 4;
1552c74ad251Schristos 		len += 4;
1553c74ad251Schristos 	}
1554c74ad251Schristos 	switch (key_id_mode) {
1555c74ad251Schristos 	case 0x00: /* Implicit. */
1556c74ad251Schristos 		if (ndo->ndo_vflag > 1) {
1557c74ad251Schristos 			ND_PRINT("Implicit");
1558c74ad251Schristos 		}
1559c74ad251Schristos 		return len;
1560c74ad251Schristos 		break;
1561c74ad251Schristos 	case 0x01: /* Key Index, nothing to print here. */
1562c74ad251Schristos 		break;
1563c74ad251Schristos 	case 0x02: /* PAN and Short address Key Source, and Key Index. */
1564c74ad251Schristos 		if (caplen < 4) {
1565c74ad251Schristos 			ND_PRINT("[ERROR: Truncated before Key Source]");
1566c74ad251Schristos 			return -1;
1567c74ad251Schristos 		}
1568c74ad251Schristos 		if (ndo->ndo_vflag > 1) {
1569c74ad251Schristos 			ND_PRINT("KeySource 0x%04x:%0x4x, ",
1570c74ad251Schristos 				 GET_LE_U_2(p), GET_LE_U_2(p + 2));
1571c74ad251Schristos 		}
1572c74ad251Schristos 		p += 4;
1573c74ad251Schristos 		caplen -= 4;
1574c74ad251Schristos 		len += 4;
1575c74ad251Schristos 		break;
1576c74ad251Schristos 	case 0x03: /* Extended address and Key Index. */
1577c74ad251Schristos 		if (caplen < 8) {
1578c74ad251Schristos 			ND_PRINT("[ERROR: Truncated before Key Source]");
1579c74ad251Schristos 			return -1;
1580c74ad251Schristos 		}
1581c74ad251Schristos 		if (ndo->ndo_vflag > 1) {
1582c74ad251Schristos 			ND_PRINT("KeySource %s, ", GET_LE64ADDR_STRING(p));
1583c74ad251Schristos 		}
1584c74ad251Schristos 		p += 4;
1585c74ad251Schristos 		caplen -= 4;
1586c74ad251Schristos 		len += 4;
1587c74ad251Schristos 		break;
1588c74ad251Schristos 	}
1589c74ad251Schristos 	if (caplen < 1) {
1590c74ad251Schristos 		ND_PRINT("[ERROR: Truncated before Key Index]");
1591c74ad251Schristos 		return -1;
1592c74ad251Schristos 	}
1593c74ad251Schristos 	if (ndo->ndo_vflag > 1) {
1594c74ad251Schristos 		ND_PRINT("KeyIndex 0x%02x, ", GET_U_1(p));
1595c74ad251Schristos 	}
1596c74ad251Schristos 	caplen -= 1;
1597c74ad251Schristos 	p += 1;
1598c74ad251Schristos 	len += 1;
1599c74ad251Schristos 	return len;
1600c74ad251Schristos }
1601c74ad251Schristos 
1602c74ad251Schristos /*
1603c74ad251Schristos  * Print command data.
1604c74ad251Schristos  *
1605c74ad251Schristos  * Returns number of byts consumed from the packet or -1 in case of error.
1606c74ad251Schristos  */
1607c74ad251Schristos static int
1608c74ad251Schristos ieee802_15_4_print_command_data(netdissect_options *ndo,
1609c74ad251Schristos 				uint8_t command_id,
1610c74ad251Schristos 				const u_char *p,
1611c74ad251Schristos 				u_int caplen)
1612c74ad251Schristos {
1613c74ad251Schristos 	u_int i;
1614c74ad251Schristos 
1615c74ad251Schristos 	switch (command_id) {
1616c74ad251Schristos 	case 0x01: /* Association Request */
1617c74ad251Schristos 		if (caplen != 1) {
1618c74ad251Schristos 			ND_PRINT("Invalid Association request command length");
1619c74ad251Schristos 			return -1;
1620c74ad251Schristos 		} else {
1621c74ad251Schristos 			uint8_t cap_info;
1622c74ad251Schristos 			cap_info = GET_U_1(p);
1623c74ad251Schristos 			ND_PRINT("%s%s%s%s%s%s",
1624c74ad251Schristos 				 ((cap_info & 0x02) ?
1625c74ad251Schristos 				  "FFD, " : "RFD, "),
1626c74ad251Schristos 				 ((cap_info & 0x04) ?
1627c74ad251Schristos 				  "AC powered, " : ""),
1628c74ad251Schristos 				 ((cap_info & 0x08) ?
1629c74ad251Schristos 				  "Receiver on when idle, " : ""),
1630c74ad251Schristos 				 ((cap_info & 0x10) ?
1631c74ad251Schristos 				  "Fast association, " : ""),
1632c74ad251Schristos 				 ((cap_info & 0x40) ?
1633c74ad251Schristos 				  "Security supported, " : ""),
1634c74ad251Schristos 				 ((cap_info & 0x80) ?
1635c74ad251Schristos 				  "Allocate address, " : ""));
16369546e36dSchristos 			return caplen;
16379546e36dSchristos 		}
1638c74ad251Schristos 		break;
1639c74ad251Schristos 	case 0x02: /* Association Response */
1640c74ad251Schristos 		if (caplen != 3) {
1641c74ad251Schristos 			ND_PRINT("Invalid Association response command length");
1642c74ad251Schristos 			return -1;
1643c74ad251Schristos 		} else {
1644c74ad251Schristos 			ND_PRINT("Short address = ");
1645c74ad251Schristos 			ieee802_15_4_print_addr(ndo, p, 2);
1646c74ad251Schristos 			switch (GET_U_1(p + 2)) {
1647c74ad251Schristos 			case 0x00:
1648c74ad251Schristos 				ND_PRINT(", Association successful");
1649c74ad251Schristos 				break;
1650c74ad251Schristos 			case 0x01:
1651c74ad251Schristos 				ND_PRINT(", PAN at capacity");
1652c74ad251Schristos 				break;
1653c74ad251Schristos 			case 0x02:
1654c74ad251Schristos 				ND_PRINT(", PAN access denied");
1655c74ad251Schristos 				break;
1656c74ad251Schristos 			case 0x03:
1657c74ad251Schristos 				ND_PRINT(", Hooping sequence offset duplication");
1658c74ad251Schristos 				break;
1659c74ad251Schristos 			case 0x80:
1660c74ad251Schristos 				ND_PRINT(", Fast association successful");
1661c74ad251Schristos 				break;
1662c74ad251Schristos 			default:
1663c74ad251Schristos 				ND_PRINT(", Status = 0x%02x",
1664c74ad251Schristos 					 GET_U_1(p + 2));
1665c74ad251Schristos 				break;
1666c74ad251Schristos 			}
1667c74ad251Schristos 			return caplen;
1668c74ad251Schristos 		}
1669c74ad251Schristos 		break;
1670*26ba0b50Schristos 	case 0x03: /* Disassociation Notification command */
1671c74ad251Schristos 		if (caplen != 1) {
1672c74ad251Schristos 			ND_PRINT("Invalid Disassociation Notification command length");
1673c74ad251Schristos 			return -1;
1674c74ad251Schristos 		} else {
1675c74ad251Schristos 			switch (GET_U_1(p)) {
1676c74ad251Schristos 			case 0x00:
1677c74ad251Schristos 				ND_PRINT("Reserved");
1678c74ad251Schristos 				break;
1679c74ad251Schristos 			case 0x01:
1680c74ad251Schristos 				ND_PRINT("Reason = The coordinator wishes the device to leave PAN");
1681c74ad251Schristos 				break;
1682c74ad251Schristos 			case 0x02:
1683c74ad251Schristos 				ND_PRINT("Reason = The device wishes to leave the PAN");
1684c74ad251Schristos 				break;
1685c74ad251Schristos 			default:
1686c74ad251Schristos 				ND_PRINT("Reason = 0x%02x", GET_U_1(p + 2));
1687c74ad251Schristos 				break;
1688c74ad251Schristos 			}
1689c74ad251Schristos 			return caplen;
1690c74ad251Schristos 		}
16919546e36dSchristos 
1692c74ad251Schristos 		/* Following ones do not have any data. */
1693c74ad251Schristos 	case 0x04: /* Data Request command */
1694c74ad251Schristos 	case 0x05: /* PAN ID Conflict Notification command */
1695c74ad251Schristos 	case 0x06: /* Orphan Notification command */
1696c74ad251Schristos 	case 0x07: /* Beacon Request command */
1697c74ad251Schristos 		/* Should not have any data. */
1698c74ad251Schristos 		return 0;
1699c74ad251Schristos 	case 0x08: /* Coordinator Realignment command */
1700c74ad251Schristos 		if (caplen < 7 || caplen > 8) {
1701c74ad251Schristos 			ND_PRINT("Invalid Coordinator Realignment command length");
1702c74ad251Schristos 			return -1;
1703c74ad251Schristos 		} else {
1704c74ad251Schristos 			uint16_t channel, page;
17059546e36dSchristos 
1706c74ad251Schristos 			ND_PRINT("Pan ID = 0x%04x, Coordinator short address = ",
1707c74ad251Schristos 				 GET_LE_U_2(p));
1708c74ad251Schristos 			ieee802_15_4_print_addr(ndo, p + 2, 2);
1709c74ad251Schristos 			channel = GET_U_1(p + 4);
1710c74ad251Schristos 
1711c74ad251Schristos 			if (caplen == 8) {
1712c74ad251Schristos 				page = GET_U_1(p + 7);
1713c74ad251Schristos 			} else {
1714c74ad251Schristos 				page = 0x80;
1715c74ad251Schristos 			}
1716c74ad251Schristos 			if (CHECK_BIT(page, 7)) {
1717c74ad251Schristos 				/* No page present, instead we have msb of
1718c74ad251Schristos 				   channel in the page. */
1719c74ad251Schristos 				channel |= (page & 0x7f) << 8;
1720c74ad251Schristos 				ND_PRINT(", Channel Number = %d", channel);
1721c74ad251Schristos 			} else {
1722c74ad251Schristos 				ND_PRINT(", Channel Number = %d, page = %d",
1723c74ad251Schristos 					 channel, page);
1724c74ad251Schristos 			}
1725c74ad251Schristos 			ND_PRINT(", Short address = ");
1726c74ad251Schristos 			ieee802_15_4_print_addr(ndo, p + 5, 2);
1727c74ad251Schristos 			return caplen;
1728c74ad251Schristos 		}
1729c74ad251Schristos 		break;
1730c74ad251Schristos 	case 0x09: /* GTS Request command */
1731c74ad251Schristos 		if (caplen != 1) {
1732c74ad251Schristos 			ND_PRINT("Invalid GTS Request command length");
1733c74ad251Schristos 			return -1;
1734c74ad251Schristos 		} else {
1735c74ad251Schristos 			uint8_t gts;
1736c74ad251Schristos 
1737c74ad251Schristos 			gts = GET_U_1(p);
1738c74ad251Schristos 			ND_PRINT("GTS Length = %d, %s, %s",
1739c74ad251Schristos 				 gts & 0xf,
1740c74ad251Schristos 				 (CHECK_BIT(gts, 4) ?
1741c74ad251Schristos 				  "Receive-only GTS" : "Transmit-only GTS"),
1742c74ad251Schristos 				 (CHECK_BIT(gts, 5) ?
1743c74ad251Schristos 				  "GTS allocation" : "GTS deallocations"));
1744c74ad251Schristos 			return caplen;
1745c74ad251Schristos 		}
1746c74ad251Schristos 		break;
1747c74ad251Schristos 	case 0x13: /* DSME Association Request command */
1748c74ad251Schristos 		/* XXX Not implemented */
1749c74ad251Schristos 	case 0x14: /* DSME Association Response command */
1750c74ad251Schristos 		/* XXX Not implemented */
1751c74ad251Schristos 	case 0x15: /* DSME GTS Request command */
1752c74ad251Schristos 		/* XXX Not implemented */
1753c74ad251Schristos 	case 0x16: /* DSME GTS Response command */
1754c74ad251Schristos 		/* XXX Not implemented */
1755c74ad251Schristos 	case 0x17: /* DSME GTS Notify command */
1756c74ad251Schristos 		/* XXX Not implemented */
1757c74ad251Schristos 	case 0x18: /* DSME Information Request command */
1758c74ad251Schristos 		/* XXX Not implemented */
1759c74ad251Schristos 	case 0x19: /* DSME Information Response command */
1760c74ad251Schristos 		/* XXX Not implemented */
1761c74ad251Schristos 	case 0x1a: /* DSME Beacon Allocation Notification command */
1762c74ad251Schristos 		/* XXX Not implemented */
1763c74ad251Schristos 	case 0x1b: /* DSME Beacon Collision Notification command */
1764c74ad251Schristos 		/* XXX Not implemented */
1765c74ad251Schristos 	case 0x1c: /* DSME Link Report command */
1766c74ad251Schristos 		/* XXX Not implemented */
1767c74ad251Schristos 	case 0x20: /* RIT Data Request command */
1768c74ad251Schristos 		/* XXX Not implemented */
1769c74ad251Schristos 	case 0x21: /* DBS Request command */
1770c74ad251Schristos 		/* XXX Not implemented */
1771c74ad251Schristos 	case 0x22: /* DBS Response command */
1772c74ad251Schristos 		/* XXX Not implemented */
1773c74ad251Schristos 	case 0x23: /* RIT Data Response command */
1774c74ad251Schristos 		/* XXX Not implemented */
1775c74ad251Schristos 	case 0x24: /* Vendor Specific command */
1776c74ad251Schristos 		/* XXX Not implemented */
1777c74ad251Schristos 	case 0x0a: /* TRLE Management Request command */
1778c74ad251Schristos 		/* XXX Not implemented */
1779c74ad251Schristos 	case 0x0b: /* TRLE Management Response command */
1780c74ad251Schristos 		/* XXX Not implemented */
1781c74ad251Schristos 	default:
1782c74ad251Schristos 		ND_PRINT("Command Data = ");
1783c74ad251Schristos 		for(i = 0; i < caplen; i++) {
1784c74ad251Schristos 			ND_PRINT("%02x ", GET_U_1(p + i));
1785c74ad251Schristos 		}
1786c74ad251Schristos 		break;
1787c74ad251Schristos 	}
1788c74ad251Schristos 	return 0;
1789c74ad251Schristos }
1790c74ad251Schristos 
1791c74ad251Schristos /*
1792c74ad251Schristos  * Parse and print frames following standard format.
1793c74ad251Schristos  *
1794c74ad251Schristos  * Returns FALSE in case of error.
1795c74ad251Schristos  */
1796c74ad251Schristos static u_int
1797c74ad251Schristos ieee802_15_4_std_frames(netdissect_options *ndo,
1798c74ad251Schristos 			const u_char *p, u_int caplen,
1799c74ad251Schristos 			uint16_t fc)
1800c74ad251Schristos {
1801c74ad251Schristos 	int len, frame_version, pan_id_comp;
1802c74ad251Schristos 	int frame_type;
1803c74ad251Schristos 	int src_pan, dst_pan, src_addr_len, dst_addr_len;
1804c74ad251Schristos 	int security_level;
1805c74ad251Schristos 	u_int miclen = 0;
1806c74ad251Schristos 	int payload_ie_present;
1807c74ad251Schristos 	uint8_t seq;
1808c74ad251Schristos 	uint32_t fcs, crc_check;
1809c74ad251Schristos 	const u_char *mic_start = NULL;
1810c74ad251Schristos 
1811c74ad251Schristos 	payload_ie_present = 0;
1812c74ad251Schristos 
1813c74ad251Schristos 	crc_check = 0;
1814c74ad251Schristos 	/* Assume 2 octet FCS, the FCS length depends on the PHY, and we do not
1815c74ad251Schristos 	   know about that. */
1816c74ad251Schristos 	if (caplen < 4) {
1817c74ad251Schristos 		/* Cannot have FCS, assume no FCS. */
1818c74ad251Schristos 		fcs = 0;
1819c74ad251Schristos 	} else {
1820c74ad251Schristos 		/* Test for 4 octet FCS. */
1821c74ad251Schristos 		fcs = GET_LE_U_4(p + caplen - 4);
1822c74ad251Schristos 		crc_check = ieee802_15_4_crc32(ndo, p, caplen - 4);
1823c74ad251Schristos 		if (crc_check == fcs) {
1824c74ad251Schristos 			/* Remove FCS */
1825c74ad251Schristos 			caplen -= 4;
1826c74ad251Schristos 		} else {
1827c74ad251Schristos 			/* Test for 2 octet FCS. */
1828c74ad251Schristos 			fcs = GET_LE_U_2(p + caplen - 2);
1829c74ad251Schristos 			crc_check = ieee802_15_4_crc16(ndo, p, caplen - 2);
1830c74ad251Schristos 			if (crc_check == fcs) {
1831c74ad251Schristos 				/* Remove FCS */
1832c74ad251Schristos 				caplen -= 2;
1833c74ad251Schristos 			} else {
1834c74ad251Schristos 				/* Wrong FCS, FCS might not be included in the
1835c74ad251Schristos 				   captured frame, do not remove it. */
1836c74ad251Schristos 			}
1837c74ad251Schristos 		}
1838c74ad251Schristos 	}
1839c74ad251Schristos 
1840c74ad251Schristos 	/* Frame version. */
1841c74ad251Schristos 	frame_version = FC_FRAME_VERSION(fc);
1842c74ad251Schristos 	frame_type = FC_FRAME_TYPE(fc);
1843c74ad251Schristos 	ND_PRINT("v%d ", frame_version);
1844c74ad251Schristos 
1845c74ad251Schristos 	if (ndo->ndo_vflag > 2) {
1846c74ad251Schristos 		if (CHECK_BIT(fc, 3)) { ND_PRINT("Security Enabled, "); }
1847c74ad251Schristos 		if (CHECK_BIT(fc, 4)) { ND_PRINT("Frame Pending, "); }
1848c74ad251Schristos 		if (CHECK_BIT(fc, 5)) { ND_PRINT("AR, "); }
1849c74ad251Schristos 		if (CHECK_BIT(fc, 6)) { ND_PRINT("PAN ID Compression, "); }
1850c74ad251Schristos 		if (CHECK_BIT(fc, 8)) { ND_PRINT("Sequence Number Suppression, "); }
1851c74ad251Schristos 		if (CHECK_BIT(fc, 9)) { ND_PRINT("IE present, "); }
1852c74ad251Schristos 	}
1853c74ad251Schristos 
1854c74ad251Schristos 	/* Check for the sequence number suppression. */
1855c74ad251Schristos 	if (CHECK_BIT(fc, 8)) {
1856c74ad251Schristos 		/* Sequence number is suppressed. */
1857c74ad251Schristos 		if (frame_version < 2) {
1858c74ad251Schristos 			/* Sequence number can only be suppressed for frame
1859c74ad251Schristos 			   version 2 or higher, this is invalid frame. */
1860c74ad251Schristos 			ND_PRINT("[ERROR: Sequence number suppressed on frames where version < 2]");
1861c74ad251Schristos 		}
1862c74ad251Schristos 		if (ndo->ndo_vflag)
1863c74ad251Schristos 			ND_PRINT("seq suppressed ");
1864c74ad251Schristos 		if (caplen < 2) {
1865c74ad251Schristos 			nd_print_trunc(ndo);
1866c74ad251Schristos 			return 0;
1867c74ad251Schristos 		}
1868c74ad251Schristos 		p += 2;
1869c74ad251Schristos 		caplen -= 2;
1870c74ad251Schristos 	} else {
1871c74ad251Schristos 		seq = GET_U_1(p + 2);
1872c74ad251Schristos 		if (ndo->ndo_vflag)
1873c74ad251Schristos 			ND_PRINT("seq %02x ", seq);
1874c74ad251Schristos 		if (caplen < 3) {
1875c74ad251Schristos 			nd_print_trunc(ndo);
1876c74ad251Schristos 			return 0;
1877c74ad251Schristos 		}
18789546e36dSchristos 		p += 3;
18799546e36dSchristos 		caplen -= 3;
1880c74ad251Schristos 	}
18819546e36dSchristos 
1882c74ad251Schristos 	/* See which parts of addresses we have. */
1883c74ad251Schristos 	dst_addr_len = ieee802_15_4_addr_len((fc >> 10) & 0x3);
1884c74ad251Schristos 	src_addr_len = ieee802_15_4_addr_len((fc >> 14) & 0x3);
1885c74ad251Schristos 	if (src_addr_len < 0) {
1886c74ad251Schristos 		ND_PRINT("[ERROR: Invalid src address mode]");
18879546e36dSchristos 		return 0;
1888c74ad251Schristos 	}
1889c74ad251Schristos 	if (dst_addr_len < 0) {
1890c74ad251Schristos 		ND_PRINT("[ERROR: Invalid dst address mode]");
1891c74ad251Schristos 		return 0;
1892c74ad251Schristos 	}
1893c74ad251Schristos 	src_pan = 0;
1894c74ad251Schristos 	dst_pan = 0;
1895c74ad251Schristos 	pan_id_comp = CHECK_BIT(fc, 6);
1896c74ad251Schristos 
1897c74ad251Schristos 	/* The PAN ID Compression rules are complicated. */
1898c74ad251Schristos 
1899c74ad251Schristos 	/* First check old versions, where the rules are simple. */
1900c74ad251Schristos 	if (frame_version < 2) {
1901c74ad251Schristos 		if (pan_id_comp) {
1902c74ad251Schristos 			src_pan = 0;
1903c74ad251Schristos 			dst_pan = 1;
1904c74ad251Schristos 			if (dst_addr_len <= 0 || src_addr_len <= 0) {
1905c74ad251Schristos 				/* Invalid frame, PAN ID Compression must be 0
1906c74ad251Schristos 				   if only one address in the frame. */
1907c74ad251Schristos 				ND_PRINT("[ERROR: PAN ID Compression != 0, and only one address with frame version < 2]");
1908c74ad251Schristos 			}
1909c74ad251Schristos 		} else {
1910c74ad251Schristos 			src_pan = 1;
1911c74ad251Schristos 			dst_pan = 1;
1912c74ad251Schristos 		}
1913c74ad251Schristos 		if (dst_addr_len <= 0) {
1914c74ad251Schristos 			dst_pan = 0;
1915c74ad251Schristos 		}
1916c74ad251Schristos 		if (src_addr_len <= 0) {
1917c74ad251Schristos 			src_pan = 0;
1918c74ad251Schristos 		}
1919c74ad251Schristos 	} else {
1920c74ad251Schristos 		/* Frame version 2 rules are more complicated, and they depend
1921c74ad251Schristos 		   on the address modes of the frame, generic rules are same,
1922c74ad251Schristos 		   but then there are some special cases. */
1923c74ad251Schristos 		if (pan_id_comp) {
1924c74ad251Schristos 			src_pan = 0;
1925c74ad251Schristos 			dst_pan = 1;
1926c74ad251Schristos 		} else {
1927c74ad251Schristos 			src_pan = 1;
1928c74ad251Schristos 			dst_pan = 1;
1929c74ad251Schristos 		}
1930c74ad251Schristos 		if (dst_addr_len <= 0) {
1931c74ad251Schristos 			dst_pan = 0;
1932c74ad251Schristos 		}
1933c74ad251Schristos 		if (src_addr_len <= 0) {
1934c74ad251Schristos 			src_pan = 0;
1935c74ad251Schristos 		}
1936c74ad251Schristos 		if (pan_id_comp) {
1937c74ad251Schristos 			if (src_addr_len == 0 &&
1938c74ad251Schristos 			    dst_addr_len == 0) {
1939c74ad251Schristos 				/* Both addresses are missing, but PAN ID
1940c74ad251Schristos 				   compression set, special case we have
1941c74ad251Schristos 				   destination PAN but no addresses. */
1942c74ad251Schristos 				dst_pan = 1;
1943c74ad251Schristos 			} else if ((src_addr_len == 0 &&
1944c74ad251Schristos 				    dst_addr_len > 0) ||
1945c74ad251Schristos 				   (src_addr_len > 0 &&
1946c74ad251Schristos 				    dst_addr_len == 0)) {
1947c74ad251Schristos 				/* Only one address present, and PAN ID
1948c74ad251Schristos 				   compression is set, we do not have PAN id at
1949c74ad251Schristos 				   all. */
1950c74ad251Schristos 				dst_pan = 0;
1951c74ad251Schristos 				src_pan = 0;
1952c74ad251Schristos 			} else if (src_addr_len == 8 &&
1953c74ad251Schristos 				   dst_addr_len == 8) {
1954c74ad251Schristos 				/* Both addresses are Extended, and PAN ID
1955c74ad251Schristos 				   compression set, we do not have PAN ID at
1956c74ad251Schristos 				   all. */
1957c74ad251Schristos 				dst_pan = 0;
1958c74ad251Schristos 				src_pan = 0;
1959c74ad251Schristos 			}
1960c74ad251Schristos 		} else {
1961c74ad251Schristos 			/* Special cases where PAN ID Compression is not set. */
1962c74ad251Schristos 			if (src_addr_len == 8 &&
1963c74ad251Schristos 			    dst_addr_len == 8) {
1964c74ad251Schristos 				/* Both addresses are Extended, and PAN ID
1965c74ad251Schristos 				   compression not set, we do have only one PAN
1966c74ad251Schristos 				   ID (destination). */
1967c74ad251Schristos 				dst_pan = 1;
1968c74ad251Schristos 				src_pan = 0;
1969c74ad251Schristos 			}
1970c74ad251Schristos #ifdef BROKEN_6TISCH_PAN_ID_COMPRESSION
1971c74ad251Schristos 			if (src_addr_len == 8 &&
1972c74ad251Schristos 			    dst_addr_len == 2) {
1973c74ad251Schristos 				/* Special case for the broken 6tisch
1974c74ad251Schristos 				   implementations. */
1975c74ad251Schristos 				src_pan = 0;
1976c74ad251Schristos 			}
1977c74ad251Schristos #endif /* BROKEN_6TISCH_PAN_ID_COMPRESSION */
1978c74ad251Schristos 		}
1979c74ad251Schristos 	}
1980c74ad251Schristos 
1981c74ad251Schristos 	/* Print dst PAN and address. */
1982c74ad251Schristos 	if (dst_pan) {
1983c74ad251Schristos 		if (caplen < 2) {
1984c74ad251Schristos 			ND_PRINT("[ERROR: Truncated before dst_pan]");
1985c74ad251Schristos 			return 0;
1986c74ad251Schristos 		}
1987c74ad251Schristos 		ND_PRINT("%04x:", GET_LE_U_2(p));
1988c74ad251Schristos 		p += 2;
1989c74ad251Schristos 		caplen -= 2;
1990c74ad251Schristos 	} else {
1991c74ad251Schristos 		ND_PRINT("-:");
1992c74ad251Schristos 	}
1993c74ad251Schristos 	if (caplen < (u_int) dst_addr_len) {
1994c74ad251Schristos 		ND_PRINT("[ERROR: Truncated before dst_addr]");
1995c74ad251Schristos 		return 0;
1996c74ad251Schristos 	}
1997c74ad251Schristos 	ieee802_15_4_print_addr(ndo, p, dst_addr_len);
1998c74ad251Schristos 	p += dst_addr_len;
1999c74ad251Schristos 	caplen -= dst_addr_len;
2000c74ad251Schristos 
2001c74ad251Schristos 	ND_PRINT(" < ");
2002c74ad251Schristos 
2003c74ad251Schristos 	/* Print src PAN and address. */
2004c74ad251Schristos 	if (src_pan) {
2005c74ad251Schristos 		if (caplen < 2) {
2006c74ad251Schristos 			ND_PRINT("[ERROR: Truncated before dst_pan]");
2007c74ad251Schristos 			return 0;
2008c74ad251Schristos 		}
2009c74ad251Schristos 		ND_PRINT("%04x:", GET_LE_U_2(p));
2010c74ad251Schristos 		p += 2;
2011c74ad251Schristos 		caplen -= 2;
2012c74ad251Schristos 	} else {
2013c74ad251Schristos 		ND_PRINT("-:");
2014c74ad251Schristos 	}
2015c74ad251Schristos 	if (caplen < (u_int) src_addr_len) {
2016c74ad251Schristos 		ND_PRINT("[ERROR: Truncated before dst_addr]");
2017c74ad251Schristos 		return 0;
2018c74ad251Schristos 	}
2019c74ad251Schristos 	ieee802_15_4_print_addr(ndo, p, src_addr_len);
2020c74ad251Schristos 	ND_PRINT(" ");
2021c74ad251Schristos 	p += src_addr_len;
2022c74ad251Schristos 	caplen -= src_addr_len;
2023c74ad251Schristos 	if (CHECK_BIT(fc, 3)) {
202472c96ff3Schristos 		/*
2025c74ad251Schristos 		 * XXX - if frame_version is 0, this is the 2003
2026c74ad251Schristos 		 * spec, and you don't have the auxiliary security
2027c74ad251Schristos 		 * header, you have a frame counter and key index
2028c74ad251Schristos 		 * for the AES-CTR and AES-CCM security suites but
2029c74ad251Schristos 		 * not for the AES-CBC-MAC security suite.
203072c96ff3Schristos 		 */
2031c74ad251Schristos 		len = ieee802_15_4_print_aux_sec_header(ndo, p, caplen,
2032c74ad251Schristos 							&security_level);
2033c74ad251Schristos 		if (len < 0) {
2034c74ad251Schristos 			return 0;
203572c96ff3Schristos 		}
2036c74ad251Schristos 		ND_TCHECK_LEN(p, len);
2037c74ad251Schristos 		p += len;
2038c74ad251Schristos 		caplen -= len;
2039c74ad251Schristos 	} else {
2040c74ad251Schristos 		security_level = 0;
20419546e36dSchristos 	}
2042c74ad251Schristos 
2043c74ad251Schristos 	switch (security_level) {
2044*26ba0b50Schristos 	case 0: /*FALLTHROUGH */
2045c74ad251Schristos 	case 4:
2046c74ad251Schristos 		miclen = 0;
20479546e36dSchristos 		break;
2048*26ba0b50Schristos 	case 1: /*FALLTHROUGH */
2049c74ad251Schristos 	case 5:
2050c74ad251Schristos 		miclen = 4;
2051c74ad251Schristos 		break;
2052*26ba0b50Schristos 	case 2: /*FALLTHROUGH */
2053c74ad251Schristos 	case 6:
2054c74ad251Schristos 		miclen = 8;
2055c74ad251Schristos 		break;
2056*26ba0b50Schristos 	case 3: /*FALLTHROUGH */
2057c74ad251Schristos 	case 7:
2058c74ad251Schristos 		miclen = 16;
2059c74ad251Schristos 		break;
2060c74ad251Schristos 	}
2061c74ad251Schristos 
2062c74ad251Schristos 	/* Remove MIC */
2063c74ad251Schristos 	if (miclen != 0) {
2064c74ad251Schristos 		if (caplen < miclen) {
2065c74ad251Schristos 			ND_PRINT("[ERROR: Truncated before MIC]");
2066c74ad251Schristos 			return 0;
2067c74ad251Schristos 		}
2068c74ad251Schristos 		caplen -= miclen;
2069c74ad251Schristos 		mic_start = p + caplen;
2070c74ad251Schristos 	}
2071c74ad251Schristos 
2072c74ad251Schristos 	/* Parse Information elements if present */
2073c74ad251Schristos 	if (CHECK_BIT(fc, 9)) {
2074c74ad251Schristos 		/* Yes we have those. */
2075c74ad251Schristos 		len = ieee802_15_4_print_header_ie_list(ndo, p, caplen,
2076c74ad251Schristos 							&payload_ie_present);
2077c74ad251Schristos 		if (len < 0) {
2078c74ad251Schristos 			return 0;
2079c74ad251Schristos 		}
2080c74ad251Schristos 		p += len;
2081c74ad251Schristos 		caplen -= len;
2082c74ad251Schristos 	}
2083c74ad251Schristos 
2084c74ad251Schristos 	if (payload_ie_present) {
2085c74ad251Schristos 		if (security_level >= 4) {
2086c74ad251Schristos 			ND_PRINT("Payload IEs present, but encrypted, cannot print ");
2087c74ad251Schristos 		} else {
2088c74ad251Schristos 			len = ieee802_15_4_print_payload_ie_list(ndo, p, caplen);
2089c74ad251Schristos 			if (len < 0) {
2090c74ad251Schristos 				return 0;
2091c74ad251Schristos 			}
2092c74ad251Schristos 			p += len;
2093c74ad251Schristos 			caplen -= len;
2094c74ad251Schristos 		}
2095c74ad251Schristos 	}
2096c74ad251Schristos 
2097c74ad251Schristos 	/* Print MIC */
2098c74ad251Schristos 	if (ndo->ndo_vflag > 2 && miclen != 0) {
2099c74ad251Schristos 		ND_PRINT("\n\tMIC ");
2100c74ad251Schristos 
2101c74ad251Schristos 		for (u_int micoffset = 0; micoffset < miclen; micoffset++) {
2102c74ad251Schristos 			ND_PRINT("%02x", GET_U_1(mic_start + micoffset));
2103c74ad251Schristos 		}
2104c74ad251Schristos 		ND_PRINT(" ");
2105c74ad251Schristos 	}
2106c74ad251Schristos 
2107c74ad251Schristos 	/* Print FCS */
2108c74ad251Schristos 	if (ndo->ndo_vflag > 2) {
2109c74ad251Schristos 		if (crc_check == fcs) {
2110c74ad251Schristos 			ND_PRINT("FCS %x ", fcs);
2111c74ad251Schristos 		} else {
2112c74ad251Schristos 			ND_PRINT("wrong FCS %x vs %x (assume no FCS stored) ",
2113c74ad251Schristos 				 fcs, crc_check);
2114c74ad251Schristos 		}
2115c74ad251Schristos 	}
2116c74ad251Schristos 
2117c74ad251Schristos 	/* Payload print */
2118c74ad251Schristos 	switch (frame_type) {
2119c74ad251Schristos 	case 0x00: /* Beacon */
2120c74ad251Schristos 		if (frame_version < 2) {
2121c74ad251Schristos 			if (caplen < 2) {
2122c74ad251Schristos 				ND_PRINT("[ERROR: Truncated before beacon information]");
2123c74ad251Schristos 				break;
2124c74ad251Schristos 			} else {
2125c74ad251Schristos 				uint16_t ss;
2126c74ad251Schristos 
2127c74ad251Schristos 				ss = GET_LE_U_2(p);
2128c74ad251Schristos 				ieee802_15_4_print_superframe_specification(ndo, ss);
2129c74ad251Schristos 				p += 2;
2130c74ad251Schristos 				caplen -= 2;
2131c74ad251Schristos 
2132c74ad251Schristos 				/* GTS */
2133c74ad251Schristos 				if (caplen < 1) {
2134c74ad251Schristos 					ND_PRINT("[ERROR: Truncated before GTS info]");
2135c74ad251Schristos 					break;
2136c74ad251Schristos 				}
2137c74ad251Schristos 
2138c74ad251Schristos 				len = ieee802_15_4_print_gts_info(ndo, p, caplen);
2139c74ad251Schristos 				if (len < 0) {
2140c74ad251Schristos 					break;
2141c74ad251Schristos 				}
2142c74ad251Schristos 
2143c74ad251Schristos 				p += len;
2144c74ad251Schristos 				caplen -= len;
2145c74ad251Schristos 
2146c74ad251Schristos 				/* Pending Addresses */
2147c74ad251Schristos 				if (caplen < 1) {
2148c74ad251Schristos 					ND_PRINT("[ERROR: Truncated before pending addresses]");
2149c74ad251Schristos 					break;
2150c74ad251Schristos 				}
2151c74ad251Schristos 				len = ieee802_15_4_print_pending_addresses(ndo, p, caplen);
2152c74ad251Schristos 				if (len < 0) {
2153c74ad251Schristos 					break;
2154c74ad251Schristos 				}
2155c74ad251Schristos 				ND_TCHECK_LEN(p, len);
2156c74ad251Schristos 				p += len;
2157c74ad251Schristos 				caplen -= len;
2158c74ad251Schristos 			}
2159c74ad251Schristos 		}
2160c74ad251Schristos 		if (!ndo->ndo_suppress_default_print)
2161c74ad251Schristos 			ND_DEFAULTPRINT(p, caplen);
2162c74ad251Schristos 
2163c74ad251Schristos 		break;
2164c74ad251Schristos 	case 0x01: /* Data */
2165c74ad251Schristos 	case 0x02: /* Acknowledgement */
2166c74ad251Schristos 		if (!ndo->ndo_suppress_default_print)
2167c74ad251Schristos 			ND_DEFAULTPRINT(p, caplen);
2168c74ad251Schristos 		break;
2169c74ad251Schristos 	case 0x03: /* MAC Command */
2170c74ad251Schristos 		if (caplen < 1) {
2171c74ad251Schristos 			ND_PRINT("[ERROR: Truncated before Command ID]");
2172c74ad251Schristos 		} else {
2173c74ad251Schristos 			uint8_t command_id;
2174c74ad251Schristos 
2175c74ad251Schristos 			command_id = GET_U_1(p);
2176c74ad251Schristos 			if (command_id >= 0x30) {
2177c74ad251Schristos 				ND_PRINT("Command ID = Reserved 0x%02x ",
2178c74ad251Schristos 					 command_id);
2179c74ad251Schristos 			} else {
2180c74ad251Schristos 				ND_PRINT("Command ID = %s ",
2181c74ad251Schristos 					 mac_c_names[command_id]);
2182c74ad251Schristos 			}
2183c74ad251Schristos 			p++;
2184c74ad251Schristos 			caplen--;
2185c74ad251Schristos 			if (caplen != 0) {
2186c74ad251Schristos 				len = ieee802_15_4_print_command_data(ndo, command_id, p, caplen);
2187c74ad251Schristos 				if (len >= 0) {
2188c74ad251Schristos 					p += len;
2189c74ad251Schristos 					caplen -= len;
2190c74ad251Schristos 				}
2191c74ad251Schristos 			}
2192c74ad251Schristos 		}
2193c74ad251Schristos 		if (!ndo->ndo_suppress_default_print)
2194c74ad251Schristos 			ND_DEFAULTPRINT(p, caplen);
2195c74ad251Schristos 		break;
2196c74ad251Schristos 	}
2197c74ad251Schristos 	return 1;
2198c74ad251Schristos }
2199c74ad251Schristos 
220072c96ff3Schristos /*
2201c74ad251Schristos  * Print and parse Multipurpose frames.
2202c74ad251Schristos  *
2203c74ad251Schristos  * Returns FALSE in case of error.
220472c96ff3Schristos  */
2205c74ad251Schristos static u_int
2206c74ad251Schristos ieee802_15_4_mp_frame(netdissect_options *ndo,
2207c74ad251Schristos 		      const u_char *p, u_int caplen,
2208c74ad251Schristos 		      uint16_t fc)
2209c74ad251Schristos {
2210c74ad251Schristos 	int len, frame_version, pan_id_present;
2211c74ad251Schristos 	int src_addr_len, dst_addr_len;
2212c74ad251Schristos 	int security_level;
2213c74ad251Schristos 	u_int miclen = 0;
2214c74ad251Schristos 	int ie_present, payload_ie_present, security_enabled;
2215c74ad251Schristos 	uint8_t seq;
2216c74ad251Schristos 	uint32_t fcs, crc_check;
2217c74ad251Schristos 	const u_char *mic_start = NULL;
2218c74ad251Schristos 
2219c74ad251Schristos 	pan_id_present = 0;
2220c74ad251Schristos 	ie_present = 0;
2221c74ad251Schristos 	payload_ie_present = 0;
2222c74ad251Schristos 	security_enabled = 0;
2223c74ad251Schristos 	crc_check = 0;
2224c74ad251Schristos 
2225c74ad251Schristos 	/* Assume 2 octet FCS, the FCS length depends on the PHY, and we do not
2226c74ad251Schristos 	   know about that. */
2227c74ad251Schristos 	if (caplen < 3) {
2228c74ad251Schristos 		/* Cannot have FCS, assume no FCS. */
2229c74ad251Schristos 		fcs = 0;
2230c74ad251Schristos 	} else {
2231c74ad251Schristos 		if (caplen > 4) {
2232c74ad251Schristos 			/* Test for 4 octet FCS. */
2233c74ad251Schristos 			fcs = GET_LE_U_4(p + caplen - 4);
2234c74ad251Schristos 			crc_check = ieee802_15_4_crc32(ndo, p, caplen - 4);
2235c74ad251Schristos 			if (crc_check == fcs) {
2236c74ad251Schristos 				/* Remove FCS */
2237c74ad251Schristos 				caplen -= 4;
2238c74ad251Schristos 			} else {
2239c74ad251Schristos 				fcs = GET_LE_U_2(p + caplen - 2);
2240c74ad251Schristos 				crc_check = ieee802_15_4_crc16(ndo, p, caplen - 2);
2241c74ad251Schristos 				if (crc_check == fcs) {
2242c74ad251Schristos 					/* Remove FCS */
2243c74ad251Schristos 					caplen -= 2;
224472c96ff3Schristos 				}
2245c74ad251Schristos 			}
2246c74ad251Schristos 		} else {
2247c74ad251Schristos 			fcs = GET_LE_U_2(p + caplen - 2);
2248c74ad251Schristos 			crc_check = ieee802_15_4_crc16(ndo, p, caplen - 2);
2249c74ad251Schristos 			if (crc_check == fcs) {
2250c74ad251Schristos 				/* Remove FCS */
2251c74ad251Schristos 				caplen -= 2;
2252c74ad251Schristos 			}
2253c74ad251Schristos 		}
2254c74ad251Schristos 	}
2255c74ad251Schristos 
2256c74ad251Schristos 	if (CHECK_BIT(fc, 3)) {
2257c74ad251Schristos 		/* Long Frame Control */
2258c74ad251Schristos 
2259c74ad251Schristos 		/* Frame version. */
2260c74ad251Schristos 		frame_version = FC_FRAME_VERSION(fc);
2261c74ad251Schristos 		ND_PRINT("v%d ", frame_version);
2262c74ad251Schristos 
2263c74ad251Schristos 		pan_id_present = CHECK_BIT(fc, 8);
2264c74ad251Schristos 		ie_present = CHECK_BIT(fc, 15);
2265c74ad251Schristos 		security_enabled = CHECK_BIT(fc, 9);
2266c74ad251Schristos 
2267c74ad251Schristos 		if (ndo->ndo_vflag > 2) {
2268c74ad251Schristos 			if (security_enabled) { ND_PRINT("Security Enabled, "); }
2269c74ad251Schristos 			if (CHECK_BIT(fc, 11)) { ND_PRINT("Frame Pending, "); }
2270c74ad251Schristos 			if (CHECK_BIT(fc, 14)) { ND_PRINT("AR, "); }
2271c74ad251Schristos 			if (pan_id_present) { ND_PRINT("PAN ID Present, "); }
2272c74ad251Schristos 			if (CHECK_BIT(fc, 10)) {
2273c74ad251Schristos 				ND_PRINT("Sequence Number Suppression, ");
2274c74ad251Schristos 			}
2275c74ad251Schristos 			if (ie_present) { ND_PRINT("IE present, "); }
2276c74ad251Schristos 		}
2277c74ad251Schristos 
2278c74ad251Schristos 		/* Check for the sequence number suppression. */
2279c74ad251Schristos 		if (CHECK_BIT(fc, 10)) {
2280c74ad251Schristos 			/* Sequence number is suppressed, but long version. */
2281c74ad251Schristos 			if (caplen < 2) {
2282c74ad251Schristos 				nd_print_trunc(ndo);
2283c74ad251Schristos 				return 0;
2284c74ad251Schristos 			}
22859546e36dSchristos 			p += 2;
228672c96ff3Schristos 			caplen -= 2;
2287c74ad251Schristos 		} else {
2288c74ad251Schristos 			seq = GET_U_1(p + 2);
228972c96ff3Schristos 			if (ndo->ndo_vflag)
2290c74ad251Schristos 				ND_PRINT("seq %02x ", seq);
2291c74ad251Schristos 			if (caplen < 3) {
2292c74ad251Schristos 				nd_print_trunc(ndo);
2293c74ad251Schristos 				return 0;
2294c74ad251Schristos 			}
2295c74ad251Schristos 			p += 3;
2296c74ad251Schristos 			caplen -= 3;
2297c74ad251Schristos 		}
2298c74ad251Schristos 	} else {
2299c74ad251Schristos 		/* Short format of header, but with seq no */
2300c74ad251Schristos 		seq = GET_U_1(p + 1);
2301c74ad251Schristos 		p += 2;
2302c74ad251Schristos 		caplen -= 2;
2303c74ad251Schristos 		if (ndo->ndo_vflag)
2304c74ad251Schristos 			ND_PRINT("seq %02x ", seq);
2305c74ad251Schristos 	}
2306c74ad251Schristos 
2307c74ad251Schristos 	/* See which parts of addresses we have. */
2308c74ad251Schristos 	dst_addr_len = ieee802_15_4_addr_len((fc >> 4) & 0x3);
2309c74ad251Schristos 	src_addr_len = ieee802_15_4_addr_len((fc >> 6) & 0x3);
2310c74ad251Schristos 	if (src_addr_len < 0) {
2311c74ad251Schristos 		ND_PRINT("[ERROR: Invalid src address mode]");
2312c74ad251Schristos 		return 0;
2313c74ad251Schristos 	}
2314c74ad251Schristos 	if (dst_addr_len < 0) {
2315c74ad251Schristos 		ND_PRINT("[ERROR: Invalid dst address mode]");
2316c74ad251Schristos 		return 0;
2317c74ad251Schristos 	}
2318c74ad251Schristos 
2319c74ad251Schristos 	/* Print dst PAN and address. */
2320c74ad251Schristos 	if (pan_id_present) {
2321c74ad251Schristos 		if (caplen < 2) {
2322c74ad251Schristos 			ND_PRINT("[ERROR: Truncated before dst_pan]");
2323c74ad251Schristos 			return 0;
2324c74ad251Schristos 		}
2325c74ad251Schristos 		ND_PRINT("%04x:", GET_LE_U_2(p));
2326c74ad251Schristos 		p += 2;
2327c74ad251Schristos 		caplen -= 2;
2328c74ad251Schristos 	} else {
2329c74ad251Schristos 		ND_PRINT("-:");
2330c74ad251Schristos 	}
2331c74ad251Schristos 	if (caplen < (u_int) dst_addr_len) {
2332c74ad251Schristos 		ND_PRINT("[ERROR: Truncated before dst_addr]");
2333c74ad251Schristos 		return 0;
2334c74ad251Schristos 	}
2335c74ad251Schristos 	ieee802_15_4_print_addr(ndo, p, dst_addr_len);
2336c74ad251Schristos 	p += dst_addr_len;
2337c74ad251Schristos 	caplen -= dst_addr_len;
2338c74ad251Schristos 
2339c74ad251Schristos 	ND_PRINT(" < ");
2340c74ad251Schristos 
2341c74ad251Schristos 	/* Print src PAN and address. */
2342c74ad251Schristos 	ND_PRINT(" -:");
2343c74ad251Schristos 	if (caplen < (u_int) src_addr_len) {
2344c74ad251Schristos 		ND_PRINT("[ERROR: Truncated before dst_addr]");
2345c74ad251Schristos 		return 0;
2346c74ad251Schristos 	}
2347c74ad251Schristos 	ieee802_15_4_print_addr(ndo, p, src_addr_len);
2348c74ad251Schristos 	ND_PRINT(" ");
2349c74ad251Schristos 	p += src_addr_len;
2350c74ad251Schristos 	caplen -= src_addr_len;
2351c74ad251Schristos 
2352c74ad251Schristos 	if (security_enabled) {
2353c74ad251Schristos 		len = ieee802_15_4_print_aux_sec_header(ndo, p, caplen,
2354c74ad251Schristos 							&security_level);
2355c74ad251Schristos 		if (len < 0) {
2356c74ad251Schristos 			return 0;
2357c74ad251Schristos 		}
2358c74ad251Schristos 		ND_TCHECK_LEN(p, len);
2359c74ad251Schristos 		p += len;
2360c74ad251Schristos 		caplen -= len;
2361c74ad251Schristos 	} else {
2362c74ad251Schristos 		security_level = 0;
2363c74ad251Schristos 	}
2364c74ad251Schristos 
2365c74ad251Schristos 	switch (security_level) {
2366*26ba0b50Schristos 	case 0: /*FALLTHROUGH */
2367c74ad251Schristos 	case 4:
2368c74ad251Schristos 		miclen = 0;
23699546e36dSchristos 		break;
2370*26ba0b50Schristos 	case 1: /*FALLTHROUGH */
2371c74ad251Schristos 	case 5:
2372c74ad251Schristos 		miclen = 4;
2373c74ad251Schristos 		break;
2374*26ba0b50Schristos 	case 2: /*FALLTHROUGH */
2375c74ad251Schristos 	case 6:
2376c74ad251Schristos 		miclen = 8;
2377c74ad251Schristos 		break;
2378*26ba0b50Schristos 	case 3: /*FALLTHROUGH */
2379c74ad251Schristos 	case 7:
2380c74ad251Schristos 		miclen = 16;
2381c74ad251Schristos 		break;
2382c74ad251Schristos 	}
2383c74ad251Schristos 
2384c74ad251Schristos 	/* Remove MIC */
2385c74ad251Schristos 	if (miclen != 0) {
2386c74ad251Schristos 		if (caplen < miclen) {
2387c74ad251Schristos 			ND_PRINT("[ERROR: Truncated before MIC]");
2388c74ad251Schristos 			return 0;
2389c74ad251Schristos 		}
2390c74ad251Schristos 		caplen -= miclen;
2391c74ad251Schristos 		mic_start = p + caplen;
2392c74ad251Schristos 	}
2393c74ad251Schristos 
2394c74ad251Schristos 	/* Parse Information elements if present */
2395c74ad251Schristos 	if (ie_present) {
2396c74ad251Schristos 		/* Yes we have those. */
2397c74ad251Schristos 		len = ieee802_15_4_print_header_ie_list(ndo, p, caplen,
2398c74ad251Schristos 							&payload_ie_present);
2399c74ad251Schristos 		if (len < 0) {
2400c74ad251Schristos 			return 0;
2401c74ad251Schristos 		}
2402c74ad251Schristos 		p += len;
2403c74ad251Schristos 		caplen -= len;
2404c74ad251Schristos 	}
2405c74ad251Schristos 
2406c74ad251Schristos 	if (payload_ie_present) {
2407c74ad251Schristos 		if (security_level >= 4) {
2408c74ad251Schristos 			ND_PRINT("Payload IEs present, but encrypted, cannot print ");
2409c74ad251Schristos 		} else {
2410c74ad251Schristos 			len = ieee802_15_4_print_payload_ie_list(ndo, p,
2411c74ad251Schristos 								 caplen);
2412c74ad251Schristos 			if (len < 0) {
2413c74ad251Schristos 				return 0;
2414c74ad251Schristos 			}
2415c74ad251Schristos 			p += len;
2416c74ad251Schristos 			caplen -= len;
2417c74ad251Schristos 		}
2418c74ad251Schristos 	}
2419c74ad251Schristos 
2420c74ad251Schristos 	/* Print MIC */
2421c74ad251Schristos 	if (ndo->ndo_vflag > 2 && miclen != 0) {
2422c74ad251Schristos 		ND_PRINT("\n\tMIC ");
2423c74ad251Schristos 
2424c74ad251Schristos 		for (u_int micoffset = 0; micoffset < miclen; micoffset++) {
2425c74ad251Schristos 			ND_PRINT("%02x", GET_U_1(mic_start + micoffset));
2426c74ad251Schristos 		}
2427c74ad251Schristos 		ND_PRINT(" ");
2428c74ad251Schristos 	}
2429c74ad251Schristos 
2430c74ad251Schristos 
2431c74ad251Schristos 	/* Print FCS */
2432c74ad251Schristos 	if (ndo->ndo_vflag > 2) {
2433c74ad251Schristos 		if (crc_check == fcs) {
2434c74ad251Schristos 			ND_PRINT("FCS %x ", fcs);
2435c74ad251Schristos 		} else {
2436c74ad251Schristos 			ND_PRINT("wrong FCS %x vs %x (assume no FCS stored) ",
2437c74ad251Schristos 				 fcs, crc_check);
2438c74ad251Schristos 		}
24399546e36dSchristos 	}
24409546e36dSchristos 
2441c47fd378Schristos 	if (!ndo->ndo_suppress_default_print)
2442c47fd378Schristos 		ND_DEFAULTPRINT(p, caplen);
24439546e36dSchristos 
2444c74ad251Schristos 	return 1;
2445c74ad251Schristos }
2446c74ad251Schristos 
2447c74ad251Schristos /*
2448c74ad251Schristos  * Print frag frame.
2449c74ad251Schristos  *
2450c74ad251Schristos  * Returns FALSE in case of error.
2451c74ad251Schristos  */
2452c74ad251Schristos static u_int
2453c74ad251Schristos ieee802_15_4_frag_frame(netdissect_options *ndo _U_,
2454c74ad251Schristos 			const u_char *p _U_,
2455c74ad251Schristos 			u_int caplen _U_,
2456c74ad251Schristos 			uint16_t fc _U_)
2457c74ad251Schristos {
2458c74ad251Schristos 	/* Not implement yet, might be bit hard to implement, as the
2459c74ad251Schristos 	 * information to set up the fragment is coming in the previous frame
2460c74ad251Schristos 	 * in the Fragment Sequence Context Description IE, thus we need to
2461c74ad251Schristos 	 * store information from there, so we can use it here. */
2462c74ad251Schristos 	return 0;
2463c74ad251Schristos }
2464c74ad251Schristos 
2465c74ad251Schristos /*
2466c74ad251Schristos  * Internal call to dissector taking packet + len instead of pcap_pkthdr.
2467c74ad251Schristos  *
2468c74ad251Schristos  * Returns FALSE in case of error.
2469c74ad251Schristos  */
2470c74ad251Schristos u_int
2471c74ad251Schristos ieee802_15_4_print(netdissect_options *ndo,
2472c74ad251Schristos 		   const u_char *p, u_int caplen)
2473c74ad251Schristos {
2474c74ad251Schristos 	int frame_type;
2475c74ad251Schristos 	uint16_t fc;
2476c74ad251Schristos 
2477c74ad251Schristos 	ndo->ndo_protocol = "802.15.4";
2478c74ad251Schristos 
2479c74ad251Schristos 	if (caplen < 2) {
2480c74ad251Schristos 		nd_print_trunc(ndo);
2481c74ad251Schristos 		return caplen;
2482c74ad251Schristos 	}
2483c74ad251Schristos 
2484c74ad251Schristos 	fc = GET_LE_U_2(p);
2485c74ad251Schristos 
2486c74ad251Schristos 	/* First we need to check the frame type to know how to parse the rest
2487c74ad251Schristos 	   of the FC. Frame type is the first 3 bit of the frame control field.
2488c74ad251Schristos 	*/
2489c74ad251Schristos 
2490c74ad251Schristos 	frame_type = FC_FRAME_TYPE(fc);
2491c74ad251Schristos 	ND_PRINT("IEEE 802.15.4 %s packet ", ftypes[frame_type]);
2492c74ad251Schristos 
2493c74ad251Schristos 	switch (frame_type) {
2494c74ad251Schristos 	case 0x00: /* Beacon */
2495c74ad251Schristos 	case 0x01: /* Data */
2496c74ad251Schristos 	case 0x02: /* Acknowledgement */
2497c74ad251Schristos 	case 0x03: /* MAC Command */
2498c74ad251Schristos 		return ieee802_15_4_std_frames(ndo, p, caplen, fc);
2499c74ad251Schristos 		break;
2500c74ad251Schristos 	case 0x04: /* Reserved */
2501c74ad251Schristos 		return 0;
2502c74ad251Schristos 		break;
2503c74ad251Schristos 	case 0x05: /* Multipurpose */
2504c74ad251Schristos 		return ieee802_15_4_mp_frame(ndo, p, caplen, fc);
2505c74ad251Schristos 		break;
2506c74ad251Schristos 	case 0x06: /* Fragment or Frak */
2507c74ad251Schristos 		return ieee802_15_4_frag_frame(ndo, p, caplen, fc);
2508c74ad251Schristos 		break;
2509c74ad251Schristos 	case 0x07: /* Extended */
2510c74ad251Schristos 		return 0;
2511c74ad251Schristos 		break;
2512c74ad251Schristos 	}
2513c74ad251Schristos 	return 0;
2514c74ad251Schristos }
2515c74ad251Schristos 
2516c74ad251Schristos /*
2517c74ad251Schristos  * Main function to print packets.
2518c74ad251Schristos  */
2519c74ad251Schristos 
2520c74ad251Schristos void
2521c74ad251Schristos ieee802_15_4_if_print(netdissect_options *ndo,
2522c74ad251Schristos                       const struct pcap_pkthdr *h, const u_char *p)
2523c74ad251Schristos {
2524c74ad251Schristos 	u_int caplen = h->caplen;
2525c74ad251Schristos 	ndo->ndo_protocol = "802.15.4";
2526c74ad251Schristos 	ndo->ndo_ll_hdr_len += ieee802_15_4_print(ndo, p, caplen);
2527c74ad251Schristos }
2528c74ad251Schristos 
2529c74ad251Schristos /* For DLT_IEEE802_15_4_TAP */
2530c74ad251Schristos /* https://github.com/jkcko/ieee802.15.4-tap */
2531c74ad251Schristos void
2532c74ad251Schristos ieee802_15_4_tap_if_print(netdissect_options *ndo,
2533c74ad251Schristos                           const struct pcap_pkthdr *h, const u_char *p)
2534c74ad251Schristos {
2535c74ad251Schristos 	uint8_t version;
2536c74ad251Schristos 	uint16_t length;
2537c74ad251Schristos 
2538c74ad251Schristos 	ndo->ndo_protocol = "802.15.4_tap";
2539c74ad251Schristos 	if (h->caplen < 4) {
2540c74ad251Schristos 		nd_print_trunc(ndo);
2541c74ad251Schristos 		ndo->ndo_ll_hdr_len += h->caplen;
2542c74ad251Schristos 		return;
2543c74ad251Schristos 	}
2544c74ad251Schristos 
2545c74ad251Schristos 	version = GET_U_1(p);
2546c74ad251Schristos 	length = GET_LE_U_2(p + 2);
2547c74ad251Schristos 	if (version != 0 || length < 4) {
2548c74ad251Schristos 		nd_print_invalid(ndo);
2549c74ad251Schristos 		return;
2550c74ad251Schristos 	}
2551c74ad251Schristos 
2552c74ad251Schristos 	if (h->caplen < length) {
2553c74ad251Schristos 		nd_print_trunc(ndo);
2554c74ad251Schristos 		ndo->ndo_ll_hdr_len += h->caplen;
2555c74ad251Schristos 		return;
2556c74ad251Schristos 	}
2557c74ad251Schristos 
2558c74ad251Schristos 	ndo->ndo_ll_hdr_len += ieee802_15_4_print(ndo, p+length, h->caplen-length) + length;
25599546e36dSchristos }
2560