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