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