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