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