]> The Tcpdump Group git mirrors - tcpdump/commitdiff
Updated 802.15.4 code
authorTero Kivinen <[email protected]>
Sat, 17 Nov 2018 21:35:46 +0000 (04:35 +0700)
committerTero Kivinen <[email protected]>
Sat, 17 Nov 2018 21:35:46 +0000 (04:35 +0700)
1  2 
Makefile.in
extract.h
netdissect.h
print-802_15_4.c
print-udp.c
print-zep.c
tests/802_15_4-data.out
tests/802_15_4-oobr-1.out
tests/802_15_4-oobr-2.out
tests/802_15_4_beacon.out
udp.h

diff --cc Makefile.in
index cddb8225f558b072429461dac0e54b969f8f4cc2,419dfd67cc49d34ea59c30483ef9b735962ec38d..e50242733a6f8d5f933af62419bb0d0a87e4f5be
@@@ -230,10 -231,8 +231,9 @@@ LIBNETDISSECT_SRC=
        print-vxlan.c \
        print-vxlan-gpe.c \
        print-wb.c \
 +      print-zep.c \
        print-zephyr.c \
        print-zeromq.c \
-       netdissect.c \
        signature.c \
        strtoaddr.c \
        util-print.c
diff --cc extract.h
index 38b08daa7a22ab451ed8889ed631e0491e97bbd7,ab0ac958e1ae4f1575c7747385c2b006f05abfb8..945032400576b47f125c1657110d7b2a24b43fc7
+++ b/extract.h
@@@ -202,41 -483,38 +483,64 @@@ EXTRACT_IPV4_TO_NETWORK_ORDER(const voi
                    ((uint32_t)(*((const uint8_t *)(p) + 2)) << 16) | \
                    ((uint32_t)(*((const uint8_t *)(p) + 1)) << 8) | \
                    ((uint32_t)(*((const uint8_t *)(p) + 0)) << 0)))
- #define EXTRACT_LE_24BITS(p) \
+ #define EXTRACT_LE_S_4(p) \
+       ((int32_t)(((uint32_t)(*((const uint8_t *)(p) + 3)) << 24) | \
+                  ((uint32_t)(*((const uint8_t *)(p) + 2)) << 16) | \
+                  ((uint32_t)(*((const uint8_t *)(p) + 1)) << 8) | \
+                  ((uint32_t)(*((const uint8_t *)(p) + 0)) << 0)))
 -#define EXTRACT_LE_U_3(p) \
 -      ((uint32_t)(((uint32_t)(*((const uint8_t *)(p) + 2)) << 16) | \
 -                  ((uint32_t)(*((const uint8_t *)(p) + 1)) << 8) | \
 -                  ((uint32_t)(*((const uint8_t *)(p) + 0)) << 0)))
 -#define EXTRACT_LE_S_3(p) \
 -      ((int32_t)(((uint32_t)(*((const uint8_t *)(p) + 2)) << 16) | \
 -                 ((uint32_t)(*((const uint8_t *)(p) + 1)) << 8) | \
 -                 ((uint32_t)(*((const uint8_t *)(p) + 0)) << 0)))
+ #define EXTRACT_LE_U_8(p) \
+       ((uint64_t)(((uint64_t)(*((const uint8_t *)(p) + 7)) << 56) | \
+                   ((uint64_t)(*((const uint8_t *)(p) + 6)) << 48) | \
+                   ((uint64_t)(*((const uint8_t *)(p) + 5)) << 40) | \
+                   ((uint64_t)(*((const uint8_t *)(p) + 4)) << 32) | \
+                   ((uint64_t)(*((const uint8_t *)(p) + 3)) << 24) | \
+                   ((uint64_t)(*((const uint8_t *)(p) + 2)) << 16) | \
+                   ((uint64_t)(*((const uint8_t *)(p) + 1)) << 8) | \
+                   ((uint64_t)(*((const uint8_t *)(p) + 0)) << 0)))
+ #define EXTRACT_LE_S_8(p) \
+       ((int64_t)(((uint64_t)(*((const uint8_t *)(p) + 7)) << 56) | \
+                  ((uint64_t)(*((const uint8_t *)(p) + 6)) << 48) | \
+                  ((uint64_t)(*((const uint8_t *)(p) + 5)) << 40) | \
+                  ((uint64_t)(*((const uint8_t *)(p) + 4)) << 32) | \
+                  ((uint64_t)(*((const uint8_t *)(p) + 3)) << 24) | \
+                  ((uint64_t)(*((const uint8_t *)(p) + 2)) << 16) | \
+                  ((uint64_t)(*((const uint8_t *)(p) + 1)) << 8) | \
+                  ((uint64_t)(*((const uint8_t *)(p) + 0)) << 0)))
++/*
++ * Non-power-of-2 sizes.
++ */
++
++#define EXTRACT_LE_U_3(p) \
 +      ((uint32_t)(((uint32_t)(*((const uint8_t *)(p) + 2)) << 16) | \
 +                  ((uint32_t)(*((const uint8_t *)(p) + 1)) << 8) | \
 +                  ((uint32_t)(*((const uint8_t *)(p) + 0)) << 0)))
- #define EXTRACT_LE_40BITS(p) \
++#define EXTRACT_LE_S_3(p) \
++      ((int32_t)(((uint32_t)(*((const uint8_t *)(p) + 2)) << 16) | \
++                 ((uint32_t)(*((const uint8_t *)(p) + 1)) << 8) | \
++                 ((uint32_t)(*((const uint8_t *)(p) + 0)) << 0)))
++#define EXTRACT_LE_U_5(p) \
 +      ((uint64_t)(((uint64_t)(*((const uint8_t *)(p) + 4)) << 32) |   \
 +                  ((uint64_t)(*((const uint8_t *)(p) + 3)) << 24) |   \
 +                  ((uint64_t)(*((const uint8_t *)(p) + 2)) << 16) |   \
 +                  ((uint64_t)(*((const uint8_t *)(p) + 1)) << 8) |    \
 +                  ((uint64_t)(*((const uint8_t *)(p) + 0)) << 0)))
- #define EXTRACT_LE_48BITS(p) \
++#define EXTRACT_LE_U_6(p) \
 +      ((uint64_t)(((uint64_t)(*((const uint8_t *)(p) + 5)) << 40) |   \
 +                  ((uint64_t)(*((const uint8_t *)(p) + 4)) << 32) |   \
 +                  ((uint64_t)(*((const uint8_t *)(p) + 3)) << 24) |   \
 +                  ((uint64_t)(*((const uint8_t *)(p) + 2)) << 16) |   \
 +                  ((uint64_t)(*((const uint8_t *)(p) + 1)) << 8) |    \
 +                  ((uint64_t)(*((const uint8_t *)(p) + 0)) << 0)))
- #define EXTRACT_LE_56BITS(p) \
++#define EXTRACT_LE_U_7(p) \
 +      ((uint64_t)(((uint64_t)(*((const uint8_t *)(p) + 6)) << 48) |   \
 +                  ((uint64_t)(*((const uint8_t *)(p) + 5)) << 40) |   \
 +                  ((uint64_t)(*((const uint8_t *)(p) + 4)) << 32) |   \
 +                  ((uint64_t)(*((const uint8_t *)(p) + 3)) << 24) |   \
 +                  ((uint64_t)(*((const uint8_t *)(p) + 2)) << 16) |   \
 +                  ((uint64_t)(*((const uint8_t *)(p) + 1)) << 8) |    \
 +                  ((uint64_t)(*((const uint8_t *)(p) + 0)) << 0)))
- #define EXTRACT_LE_64BITS(p) \
-       ((uint64_t)(((uint64_t)(*((const uint8_t *)(p) + 7)) << 56) | \
-                   ((uint64_t)(*((const uint8_t *)(p) + 6)) << 48) | \
-                   ((uint64_t)(*((const uint8_t *)(p) + 5)) << 40) | \
-                   ((uint64_t)(*((const uint8_t *)(p) + 4)) << 32) | \
-                   ((uint64_t)(*((const uint8_t *)(p) + 3)) << 24) | \
-                   ((uint64_t)(*((const uint8_t *)(p) + 2)) << 16) | \
-                   ((uint64_t)(*((const uint8_t *)(p) + 1)) << 8) | \
-                   ((uint64_t)(*((const uint8_t *)(p) + 0)) << 0)))
 +
  /*
   * Macros to check the presence of the values in question.
   */
diff --cc netdissect.h
index 88ff923cd15638ce51166e6b376df302a55f13c4,0bacbfc7c1bb15cb1a3c88a80b281858f380aa01..6b3592cbc383f674044077755be1591916becc14
@@@ -520,7 -538,7 +538,8 @@@ extern void hsrp_print(netdissect_optio
  extern void http_print(netdissect_options *, const u_char *, u_int);
  extern void icmp6_print(netdissect_options *, const u_char *, u_int, const u_char *, int);
  extern void icmp_print(netdissect_options *, const u_char *, u_int, const u_char *, int);
 +extern u_int ieee802_15_4_print(netdissect_options *ndo, const u_char *p, u_int caplen);
+ extern u_int ieee802_11_radio_print(netdissect_options *, const u_char *, u_int, u_int);
  extern void igmp_print(netdissect_options *, const u_char *, u_int);
  extern void igrp_print(netdissect_options *, const u_char *, u_int);
  extern void ip6_print(netdissect_options *, const u_char *, u_int);
@@@ -621,11 -639,10 +640,11 @@@ extern void vrrp_print(netdissect_optio
  extern void vtp_print(netdissect_options *, const u_char *, u_int);
  extern void vxlan_gpe_print(netdissect_options *ndo, const u_char *bp, u_int len);
  extern void vxlan_print(netdissect_options *, const u_char *, u_int);
- extern void wb_print(netdissect_options *, const void *, u_int);
+ extern void wb_print(netdissect_options *, const u_char *, u_int);
 +extern void zep_print(netdissect_options *, const u_char *, u_int);
  extern void zephyr_print(netdissect_options *, const u_char *, int);
  extern void zmtp1_print(netdissect_options *, const u_char *, u_int);
- extern void zmtp1_print_datagram(netdissect_options *, const u_char *, const u_int);
+ extern void zmtp1_datagram_print(netdissect_options *, const u_char *, const u_int);
  
  /* checksum routines */
  extern void init_checksum(void);
index 3a3c59911fded5114965f8cf8440ca5c7195d476,f9f05d2f3f5d20055042f2b5bc142b2d5dca34e4..79535ce1087f1df258994cb2a77fc9c84c5e28a0
  /* \summary: IEEE 802.15.4 printer */
  
  #ifdef HAVE_CONFIG_H
- #include "config.h"
+ #include <config.h>
  #endif
  
 -#include "netdissect-stdinc.h"
 +#include <netdissect-stdinc.h>
  
  #include "netdissect.h"
  #include "addrtoname.h"
  
  #include "extract.h"
  
 +#define CHECK_BIT(num,bit) (((num) >> (bit)) & 0x1)
 +
 +#define BROKEN_6TISCH_PAN_ID_COMPRESSION 0
 +
 +/* Frame types from Table 7-1 of 802.15.4-2015 */
  static const char *ftypes[] = {
-   "Beacon",                   /* 0 */
-   "Data",                     /* 1 */
-   "ACK",                      /* 2 */
-   "Command",                  /* 3 */
-   "Reserved",                 /* 4 */
-   "Multipurpose",             /* 5 */
-   "Fragment",                 /* 6 */
-   "Extended"                  /* 7 */
+       "Beacon",                       /* 0 */
 -      "Data",                         /* 1 */
++      "Data",                         /* 1 */
+       "ACK",                          /* 2 */
+       "Command",                      /* 3 */
 -      "Reserved (0x4)",               /* 4 */
 -      "Reserved (0x5)",               /* 5 */
 -      "Reserved (0x6)",               /* 6 */
 -      "Reserved (0x7)",               /* 7 */
++      "Reserved",                     /* 4 */
++      "Multipurpose",                 /* 5 */
++      "Fragment",                     /* 6 */
++      "Extended"                      /* 7 */
 +};
 +
 +/* Element IDs for Header IEs from Table 7-7 of 802.15.4-2015 */
 +static const char *h_ie_names[] = {
-   "Vendor Specific Header IE",                        /* 0x00 */
-   "Reserved 0x01",                            /* 0x01 */
-   "Reserved 0x02",                            /* 0x02 */
-   "Reserved 0x03",                            /* 0x03 */
-   "Reserved 0x04",                            /* 0x04 */
-   "Reserved 0x05",                            /* 0x05 */
-   "Reserved 0x06",                            /* 0x06 */
-   "Reserved 0x07",                            /* 0x07 */
-   "Reserved 0x08",                            /* 0x08 */
-   "Reserved 0x09",                            /* 0x09 */
-   "Reserved 0x0a",                            /* 0x0a */
-   "Reserved 0x0b",                            /* 0x0b */
-   "Reserved 0x0c",                            /* 0x0c */
-   "Reserved 0x0d",                            /* 0x0d */
-   "Reserved 0x0e",                            /* 0x0e */
-   "Reserved 0x0f",                            /* 0x0f */
-   "Reserved 0x10",                            /* 0x10 */
-   "Reserved 0x11",                            /* 0x11 */
-   "Reserved 0x12",                            /* 0x12 */
-   "Reserved 0x13",                            /* 0x13 */
-   "Reserved 0x14",                            /* 0x14 */
-   "Reserved 0x15",                            /* 0x15 */
-   "Reserved 0x16",                            /* 0x16 */
-   "Reserved 0x17",                            /* 0x17 */
-   "Reserved 0x18",                            /* 0x18 */
-   "Reserved 0x19",                            /* 0x19 */
-   "LE CSL IE",                                        /* 0x1a */
-   "LE RIT IE",                                        /* 0x1b */
-   "DSME PAN descriptor IE",                   /* 0x1c */
-   "Rendezvous Time IE",                               /* 0x1d */
-   "Time Correction IE",                               /* 0x1e */
-   "Reserved 0x1f",                            /* 0x1f */
-   "Reserved 0x20",                            /* 0x20 */
-   "Extended DSME PAN descriptor IE",          /* 0x21 */
-   "Fragment Sequence Context Description IE",   /* 0x22 */
-   "Simplified Superframe Specification IE",   /* 0x23 */
-   "Simplified GTS Specification IE",          /* 0x24 */
-   "LECIM Capabilities IE",                    /* 0x25 */
-   "TRLE Descriptor IE",                       /* 0x26 */
-   "RCC Capabilities IE",                      /* 0x27 */
-   "RCCN Descriptor IE",                       /* 0x28 */
-   "Global Time IE",                           /* 0x29 */
-   "Omnibus Header IE",                                /* 0x2a */
-   "DA IE",                                    /* 0x2b */
-   "Reserved 0x2c",                            /* 0x2c */
-   "Reserved 0x2d",                            /* 0x2d */
-   "Reserved 0x2e",                            /* 0x2e */
-   "Reserved 0x2f",                            /* 0x2f */
-   "Reserved 0x30",                            /* 0x30 */
-   "Reserved 0x31",                            /* 0x31 */
-   "Reserved 0x32",                            /* 0x32 */
-   "Reserved 0x33",                            /* 0x33 */
-   "Reserved 0x34",                            /* 0x34 */
-   "Reserved 0x35",                            /* 0x35 */
-   "Reserved 0x36",                            /* 0x36 */
-   "Reserved 0x37",                            /* 0x37 */
-   "Reserved 0x38",                            /* 0x38 */
-   "Reserved 0x39",                            /* 0x39 */
-   "Reserved 0x3a",                            /* 0x3a */
-   "Reserved 0x3b",                            /* 0x3b */
-   "Reserved 0x3c",                            /* 0x3c */
-   "Reserved 0x3d",                            /* 0x3d */
-   "Reserved 0x3e",                            /* 0x3e */
-   "Reserved 0x3f",                            /* 0x3f */
-   "Reserved 0x40",                            /* 0x40 */
-   "Reserved 0x41",                            /* 0x41 */
-   "Reserved 0x42",                            /* 0x42 */
-   "Reserved 0x43",                            /* 0x43 */
-   "Reserved 0x44",                            /* 0x44 */
-   "Reserved 0x45",                            /* 0x45 */
-   "Reserved 0x46",                            /* 0x46 */
-   "Reserved 0x47",                            /* 0x47 */
-   "Reserved 0x48",                            /* 0x48 */
-   "Reserved 0x49",                            /* 0x49 */
-   "Reserved 0x4a",                            /* 0x4a */
-   "Reserved 0x4b",                            /* 0x4b */
-   "Reserved 0x4c",                            /* 0x4c */
-   "Reserved 0x4d",                            /* 0x4d */
-   "Reserved 0x4e",                            /* 0x4e */
-   "Reserved 0x4f",                            /* 0x4f */
-   "Reserved 0x50",                            /* 0x50 */
-   "Reserved 0x51",                            /* 0x51 */
-   "Reserved 0x52",                            /* 0x52 */
-   "Reserved 0x53",                            /* 0x53 */
-   "Reserved 0x54",                            /* 0x54 */
-   "Reserved 0x55",                            /* 0x55 */
-   "Reserved 0x56",                            /* 0x56 */
-   "Reserved 0x57",                            /* 0x57 */
-   "Reserved 0x58",                            /* 0x58 */
-   "Reserved 0x59",                            /* 0x59 */
-   "Reserved 0x5a",                            /* 0x5a */
-   "Reserved 0x5b",                            /* 0x5b */
-   "Reserved 0x5c",                            /* 0x5c */
-   "Reserved 0x5d",                            /* 0x5d */
-   "Reserved 0x5e",                            /* 0x5e */
-   "Reserved 0x5f",                            /* 0x5f */
-   "Reserved 0x60",                            /* 0x60 */
-   "Reserved 0x61",                            /* 0x61 */
-   "Reserved 0x62",                            /* 0x62 */
-   "Reserved 0x63",                            /* 0x63 */
-   "Reserved 0x64",                            /* 0x64 */
-   "Reserved 0x65",                            /* 0x65 */
-   "Reserved 0x66",                            /* 0x66 */
-   "Reserved 0x67",                            /* 0x67 */
-   "Reserved 0x68",                            /* 0x68 */
-   "Reserved 0x69",                            /* 0x69 */
-   "Reserved 0x6a",                            /* 0x6a */
-   "Reserved 0x6b",                            /* 0x6b */
-   "Reserved 0x6c",                            /* 0x6c */
-   "Reserved 0x6d",                            /* 0x6d */
-   "Reserved 0x6e",                            /* 0x6e */
-   "Reserved 0x6f",                            /* 0x6f */
-   "Reserved 0x70",                            /* 0x70 */
-   "Reserved 0x71",                            /* 0x71 */
-   "Reserved 0x72",                            /* 0x72 */
-   "Reserved 0x73",                            /* 0x73 */
-   "Reserved 0x74",                            /* 0x74 */
-   "Reserved 0x75",                            /* 0x75 */
-   "Reserved 0x76",                            /* 0x76 */
-   "Reserved 0x77",                            /* 0x77 */
-   "Reserved 0x78",                            /* 0x78 */
-   "Reserved 0x79",                            /* 0x79 */
-   "Reserved 0x7a",                            /* 0x7a */
-   "Reserved 0x7b",                            /* 0x7b */
-   "Reserved 0x7c",                            /* 0x7c */
-   "Reserved 0x7d",                            /* 0x7d */
-   "Header Termination 1 IE",                  /* 0x7e */
-   "Header Termination 2 IE"                   /* 0x7f */
++      "Vendor Specific Header IE",                    /* 0x00 */
++      "Reserved 0x01",                                /* 0x01 */
++      "Reserved 0x02",                                /* 0x02 */
++      "Reserved 0x03",                                /* 0x03 */
++      "Reserved 0x04",                                /* 0x04 */
++      "Reserved 0x05",                                /* 0x05 */
++      "Reserved 0x06",                                /* 0x06 */
++      "Reserved 0x07",                                /* 0x07 */
++      "Reserved 0x08",                                /* 0x08 */
++      "Reserved 0x09",                                /* 0x09 */
++      "Reserved 0x0a",                                /* 0x0a */
++      "Reserved 0x0b",                                /* 0x0b */
++      "Reserved 0x0c",                                /* 0x0c */
++      "Reserved 0x0d",                                /* 0x0d */
++      "Reserved 0x0e",                                /* 0x0e */
++      "Reserved 0x0f",                                /* 0x0f */
++      "Reserved 0x10",                                /* 0x10 */
++      "Reserved 0x11",                                /* 0x11 */
++      "Reserved 0x12",                                /* 0x12 */
++      "Reserved 0x13",                                /* 0x13 */
++      "Reserved 0x14",                                /* 0x14 */
++      "Reserved 0x15",                                /* 0x15 */
++      "Reserved 0x16",                                /* 0x16 */
++      "Reserved 0x17",                                /* 0x17 */
++      "Reserved 0x18",                                /* 0x18 */
++      "Reserved 0x19",                                /* 0x19 */
++      "LE CSL IE",                                    /* 0x1a */
++      "LE RIT IE",                                    /* 0x1b */
++      "DSME PAN descriptor IE",                       /* 0x1c */
++      "Rendezvous Time IE",                           /* 0x1d */
++      "Time Correction IE",                           /* 0x1e */
++      "Reserved 0x1f",                                /* 0x1f */
++      "Reserved 0x20",                                /* 0x20 */
++      "Extended DSME PAN descriptor IE",              /* 0x21 */
++      "Fragment Sequence Context Description IE",     /* 0x22 */
++      "Simplified Superframe Specification IE",       /* 0x23 */
++      "Simplified GTS Specification IE",              /* 0x24 */
++      "LECIM Capabilities IE",                        /* 0x25 */
++      "TRLE Descriptor IE",                           /* 0x26 */
++      "RCC Capabilities IE",                          /* 0x27 */
++      "RCCN Descriptor IE",                           /* 0x28 */
++      "Global Time IE",                               /* 0x29 */
++      "Omnibus Header IE",                            /* 0x2a */
++      "DA IE",                                        /* 0x2b */
++      "Reserved 0x2c",                                /* 0x2c */
++      "Reserved 0x2d",                                /* 0x2d */
++      "Reserved 0x2e",                                /* 0x2e */
++      "Reserved 0x2f",                                /* 0x2f */
++      "Reserved 0x30",                                /* 0x30 */
++      "Reserved 0x31",                                /* 0x31 */
++      "Reserved 0x32",                                /* 0x32 */
++      "Reserved 0x33",                                /* 0x33 */
++      "Reserved 0x34",                                /* 0x34 */
++      "Reserved 0x35",                                /* 0x35 */
++      "Reserved 0x36",                                /* 0x36 */
++      "Reserved 0x37",                                /* 0x37 */
++      "Reserved 0x38",                                /* 0x38 */
++      "Reserved 0x39",                                /* 0x39 */
++      "Reserved 0x3a",                                /* 0x3a */
++      "Reserved 0x3b",                                /* 0x3b */
++      "Reserved 0x3c",                                /* 0x3c */
++      "Reserved 0x3d",                                /* 0x3d */
++      "Reserved 0x3e",                                /* 0x3e */
++      "Reserved 0x3f",                                /* 0x3f */
++      "Reserved 0x40",                                /* 0x40 */
++      "Reserved 0x41",                                /* 0x41 */
++      "Reserved 0x42",                                /* 0x42 */
++      "Reserved 0x43",                                /* 0x43 */
++      "Reserved 0x44",                                /* 0x44 */
++      "Reserved 0x45",                                /* 0x45 */
++      "Reserved 0x46",                                /* 0x46 */
++      "Reserved 0x47",                                /* 0x47 */
++      "Reserved 0x48",                                /* 0x48 */
++      "Reserved 0x49",                                /* 0x49 */
++      "Reserved 0x4a",                                /* 0x4a */
++      "Reserved 0x4b",                                /* 0x4b */
++      "Reserved 0x4c",                                /* 0x4c */
++      "Reserved 0x4d",                                /* 0x4d */
++      "Reserved 0x4e",                                /* 0x4e */
++      "Reserved 0x4f",                                /* 0x4f */
++      "Reserved 0x50",                                /* 0x50 */
++      "Reserved 0x51",                                /* 0x51 */
++      "Reserved 0x52",                                /* 0x52 */
++      "Reserved 0x53",                                /* 0x53 */
++      "Reserved 0x54",                                /* 0x54 */
++      "Reserved 0x55",                                /* 0x55 */
++      "Reserved 0x56",                                /* 0x56 */
++      "Reserved 0x57",                                /* 0x57 */
++      "Reserved 0x58",                                /* 0x58 */
++      "Reserved 0x59",                                /* 0x59 */
++      "Reserved 0x5a",                                /* 0x5a */
++      "Reserved 0x5b",                                /* 0x5b */
++      "Reserved 0x5c",                                /* 0x5c */
++      "Reserved 0x5d",                                /* 0x5d */
++      "Reserved 0x5e",                                /* 0x5e */
++      "Reserved 0x5f",                                /* 0x5f */
++      "Reserved 0x60",                                /* 0x60 */
++      "Reserved 0x61",                                /* 0x61 */
++      "Reserved 0x62",                                /* 0x62 */
++      "Reserved 0x63",                                /* 0x63 */
++      "Reserved 0x64",                                /* 0x64 */
++      "Reserved 0x65",                                /* 0x65 */
++      "Reserved 0x66",                                /* 0x66 */
++      "Reserved 0x67",                                /* 0x67 */
++      "Reserved 0x68",                                /* 0x68 */
++      "Reserved 0x69",                                /* 0x69 */
++      "Reserved 0x6a",                                /* 0x6a */
++      "Reserved 0x6b",                                /* 0x6b */
++      "Reserved 0x6c",                                /* 0x6c */
++      "Reserved 0x6d",                                /* 0x6d */
++      "Reserved 0x6e",                                /* 0x6e */
++      "Reserved 0x6f",                                /* 0x6f */
++      "Reserved 0x70",                                /* 0x70 */
++      "Reserved 0x71",                                /* 0x71 */
++      "Reserved 0x72",                                /* 0x72 */
++      "Reserved 0x73",                                /* 0x73 */
++      "Reserved 0x74",                                /* 0x74 */
++      "Reserved 0x75",                                /* 0x75 */
++      "Reserved 0x76",                                /* 0x76 */
++      "Reserved 0x77",                                /* 0x77 */
++      "Reserved 0x78",                                /* 0x78 */
++      "Reserved 0x79",                                /* 0x79 */
++      "Reserved 0x7a",                                /* 0x7a */
++      "Reserved 0x7b",                                /* 0x7b */
++      "Reserved 0x7c",                                /* 0x7c */
++      "Reserved 0x7d",                                /* 0x7d */
++      "Header Termination 1 IE",                      /* 0x7e */
++      "Header Termination 2 IE"                       /* 0x7f */
 +};
 +
 +/* Payload IE Group IDs from Table 7-15 of 802.15.4-2015 */
 +static const char *p_ie_names[] = {
-   "ESDU IE",                  /* 0x00 */
-   "MLME IE",                  /* 0x01 */
-   "Vendor Specific Nested IE",        /* 0x02 */
-   "Multiplexed IE (802.15.9)",        /* 0x03 */
-   "Omnibus Payload Group IE", /* 0x04 */
-   "IETF IE",                  /* 0x05 */
-   "Reserved 0x06",            /* 0x06 */
-   "Reserved 0x07",            /* 0x07 */
-   "Reserved 0x08",            /* 0x08 */
-   "Reserved 0x09",            /* 0x09 */
-   "Reserved 0x0a",            /* 0x0a */
-   "Reserved 0x0b",            /* 0x0b */
-   "Reserved 0x0c",            /* 0x0c */
-   "Reserved 0x0d",            /* 0x0d */
-   "Reserved 0x0e",            /* 0x0e */
-   "List termination"          /* 0x0f */
++      "ESDU IE",                      /* 0x00 */
++      "MLME IE",                      /* 0x01 */
++      "Vendor Specific Nested IE",    /* 0x02 */
++      "Multiplexed IE (802.15.9)",    /* 0x03 */
++      "Omnibus Payload Group IE",     /* 0x04 */
++      "IETF IE",                      /* 0x05 */
++      "Reserved 0x06",                /* 0x06 */
++      "Reserved 0x07",                /* 0x07 */
++      "Reserved 0x08",                /* 0x08 */
++      "Reserved 0x09",                /* 0x09 */
++      "Reserved 0x0a",                /* 0x0a */
++      "Reserved 0x0b",                /* 0x0b */
++      "Reserved 0x0c",                /* 0x0c */
++      "Reserved 0x0d",                /* 0x0d */
++      "Reserved 0x0e",                /* 0x0e */
++      "List termination"              /* 0x0f */
 +};
 +
 +/* Sub-ID for short format from Table 7-16 of 802.15.4-2015 */
 +static const char *p_mlme_short_names[] = {
-   "Reserved for long format 0x0",             /* 0x00 */
-   "Reserved for long format 0x1",             /* 0x01 */
-   "Reserved for long format 0x2",             /* 0x02 */
-   "Reserved for long format 0x3",             /* 0x03 */
-   "Reserved for long format 0x4",             /* 0x04 */
-   "Reserved for long format 0x5",             /* 0x05 */
-   "Reserved for long format 0x6",             /* 0x06 */
-   "Reserved for long format 0x7",             /* 0x07 */
-   "Reserved for long format 0x8",             /* 0x08 */
-   "Reserved for long format 0x9",             /* 0x09 */
-   "Reserved for long format 0xa",             /* 0x0a */
-   "Reserved for long format 0xb",             /* 0x0b */
-   "Reserved for long format 0xc",             /* 0x0c */
-   "Reserved for long format 0xd",             /* 0x0d */
-   "Reserved for long format 0xe",             /* 0x0e */
-   "Reserved for long format 0xf",             /* 0x0f */
-   "Reserved 0x10",                            /* 0x10 */
-   "Reserved 0x11",                            /* 0x11 */
-   "Reserved 0x12",                            /* 0x12 */
-   "Reserved 0x13",                            /* 0x13 */
-   "Reserved 0x14",                            /* 0x14 */
-   "Reserved 0x15",                            /* 0x15 */
-   "Reserved 0x16",                            /* 0x16 */
-   "Reserved 0x17",                            /* 0x17 */
-   "Reserved 0x18",                            /* 0x18 */
-   "Reserved 0x19",                            /* 0x19 */
-   "TSCH Synchronization IE",                  /* 0x1a */
-   "TSCH Slotframe and Link IE",                       /* 0x1b */
-   "TSCH Timeslot IE",                         /* 0x1c */
-   "Hopping timing IE",                                /* 0x1d */
-   "Enhanced Beacon Filter IE",                        /* 0x1e */
-   "MAC Metrics IE",                           /* 0x1f */
-   "All MAC Metrics IE",                               /* 0x20 */
-   "Coexistence Specification IE",             /* 0x21 */
-   "SUN Device Capabilities IE",                       /* 0x22 */
-   "SUN FSK Generic PHY IE",                   /* 0x23 */
-   "Mode Switch Parameter IE",                         /* 0x24 */
-   "PHY Parameter Change IE",                  /* 0x25 */
-   "O-QPSK PHY Mode IE",                       /* 0x26 */
-   "PCA Allocation IE",                                /* 0x27 */
-   "LECIM DSSS Operating Mode IE",             /* 0x28 */
-   "LECIM FSK Operating Mode IE",              /* 0x29 */
-   "Reserved 0x2a",                            /* 0x2a */
-   "TVWS PHY Operating Mode Description IE",   /* 0x2b */
-   "TVWS Device Capabilities IE",              /* 0x2c */
-   "TVWS Device Category IE",                  /* 0x2d */
-   "TVWS Device Identiication IE",             /* 0x2e */
-   "TVWS Device Location IE",                  /* 0x2f */
-   "TVWS Channel Information Query IE",                /* 0x30 */
-   "TVWS Channel Information Source IE",               /* 0x31 */
-   "CTM IE",                                   /* 0x32 */
-   "Timestamp IE",                             /* 0x33 */
-   "Timestamp Difference IE",                  /* 0x34 */
-   "TMCTP Sepcification IE",                   /* 0x35 */
-   "RCC PHY Operating Mode IE",                        /* 0x36 */
-   "Reserved 0x37",                            /* 0x37 */
-   "Reserved 0x38",                            /* 0x38 */
-   "Reserved 0x39",                            /* 0x39 */
-   "Reserved 0x3a",                            /* 0x3a */
-   "Reserved 0x3b",                            /* 0x3b */
-   "Reserved 0x3c",                            /* 0x3c */
-   "Reserved 0x3d",                            /* 0x3d */
-   "Reserved 0x3e",                            /* 0x3e */
-   "Reserved 0x3f",                            /* 0x3f */
-   "Reserved 0x40",                            /* 0x40 */
-   "Reserved 0x41",                            /* 0x41 */
-   "Reserved 0x42",                            /* 0x42 */
-   "Reserved 0x43",                            /* 0x43 */
-   "Reserved 0x44",                            /* 0x44 */
-   "Reserved 0x45",                            /* 0x45 */
-   "Reserved 0x46",                            /* 0x46 */
-   "Reserved 0x47",                            /* 0x47 */
-   "Reserved 0x48",                            /* 0x48 */
-   "Reserved 0x49",                            /* 0x49 */
-   "Reserved 0x4a",                            /* 0x4a */
-   "Reserved 0x4b",                            /* 0x4b */
-   "Reserved 0x4c",                            /* 0x4c */
-   "Reserved 0x4d",                            /* 0x4d */
-   "Reserved 0x4e",                            /* 0x4e */
-   "Reserved 0x4f",                            /* 0x4f */
-   "Reserved 0x50",                            /* 0x50 */
-   "Reserved 0x51",                            /* 0x51 */
-   "Reserved 0x52",                            /* 0x52 */
-   "Reserved 0x53",                            /* 0x53 */
-   "Reserved 0x54",                            /* 0x54 */
-   "Reserved 0x55",                            /* 0x55 */
-   "Reserved 0x56",                            /* 0x56 */
-   "Reserved 0x57",                            /* 0x57 */
-   "Reserved 0x58",                            /* 0x58 */
-   "Reserved 0x59",                            /* 0x59 */
-   "Reserved 0x5a",                            /* 0x5a */
-   "Reserved 0x5b",                            /* 0x5b */
-   "Reserved 0x5c",                            /* 0x5c */
-   "Reserved 0x5d",                            /* 0x5d */
-   "Reserved 0x5e",                            /* 0x5e */
-   "Reserved 0x5f",                            /* 0x5f */
-   "Reserved 0x60",                            /* 0x60 */
-   "Reserved 0x61",                            /* 0x61 */
-   "Reserved 0x62",                            /* 0x62 */
-   "Reserved 0x63",                            /* 0x63 */
-   "Reserved 0x64",                            /* 0x64 */
-   "Reserved 0x65",                            /* 0x65 */
-   "Reserved 0x66",                            /* 0x66 */
-   "Reserved 0x67",                            /* 0x67 */
-   "Reserved 0x68",                            /* 0x68 */
-   "Reserved 0x69",                            /* 0x69 */
-   "Reserved 0x6a",                            /* 0x6a */
-   "Reserved 0x6b",                            /* 0x6b */
-   "Reserved 0x6c",                            /* 0x6c */
-   "Reserved 0x6d",                            /* 0x6d */
-   "Reserved 0x6e",                            /* 0x6e */
-   "Reserved 0x6f",                            /* 0x6f */
-   "Reserved 0x70",                            /* 0x70 */
-   "Reserved 0x71",                            /* 0x71 */
-   "Reserved 0x72",                            /* 0x72 */
-   "Reserved 0x73",                            /* 0x73 */
-   "Reserved 0x74",                            /* 0x74 */
-   "Reserved 0x75",                            /* 0x75 */
-   "Reserved 0x76",                            /* 0x76 */
-   "Reserved 0x77",                            /* 0x77 */
-   "Reserved 0x78",                            /* 0x78 */
-   "Reserved 0x79",                            /* 0x79 */
-   "Reserved 0x7a",                            /* 0x7a */
-   "Reserved 0x7b",                            /* 0x7b */
-   "Reserved 0x7c",                            /* 0x7c */
-   "Reserved 0x7d",                            /* 0x7d */
-   "Reserved 0x7e",                            /* 0x7e */
-   "Reserved 0x7f"                             /* 0x7f */
++      "Reserved for long format 0x0",                 /* 0x00 */
++      "Reserved for long format 0x1",                 /* 0x01 */
++      "Reserved for long format 0x2",                 /* 0x02 */
++      "Reserved for long format 0x3",                 /* 0x03 */
++      "Reserved for long format 0x4",                 /* 0x04 */
++      "Reserved for long format 0x5",                 /* 0x05 */
++      "Reserved for long format 0x6",                 /* 0x06 */
++      "Reserved for long format 0x7",                 /* 0x07 */
++      "Reserved for long format 0x8",                 /* 0x08 */
++      "Reserved for long format 0x9",                 /* 0x09 */
++      "Reserved for long format 0xa",                 /* 0x0a */
++      "Reserved for long format 0xb",                 /* 0x0b */
++      "Reserved for long format 0xc",                 /* 0x0c */
++      "Reserved for long format 0xd",                 /* 0x0d */
++      "Reserved for long format 0xe",                 /* 0x0e */
++      "Reserved for long format 0xf",                 /* 0x0f */
++      "Reserved 0x10",                                /* 0x10 */
++      "Reserved 0x11",                                /* 0x11 */
++      "Reserved 0x12",                                /* 0x12 */
++      "Reserved 0x13",                                /* 0x13 */
++      "Reserved 0x14",                                /* 0x14 */
++      "Reserved 0x15",                                /* 0x15 */
++      "Reserved 0x16",                                /* 0x16 */
++      "Reserved 0x17",                                /* 0x17 */
++      "Reserved 0x18",                                /* 0x18 */
++      "Reserved 0x19",                                /* 0x19 */
++      "TSCH Synchronization IE",                      /* 0x1a */
++      "TSCH Slotframe and Link IE",                   /* 0x1b */
++      "TSCH Timeslot IE",                             /* 0x1c */
++      "Hopping timing IE",                            /* 0x1d */
++      "Enhanced Beacon Filter IE",                    /* 0x1e */
++      "MAC Metrics IE",                               /* 0x1f */
++      "All MAC Metrics IE",                           /* 0x20 */
++      "Coexistence Specification IE",                 /* 0x21 */
++      "SUN Device Capabilities IE",                   /* 0x22 */
++      "SUN FSK Generic PHY IE",                       /* 0x23 */
++      "Mode Switch Parameter IE",                     /* 0x24 */
++      "PHY Parameter Change IE",                      /* 0x25 */
++      "O-QPSK PHY Mode IE",                           /* 0x26 */
++      "PCA Allocation IE",                            /* 0x27 */
++      "LECIM DSSS Operating Mode IE",                 /* 0x28 */
++      "LECIM FSK Operating Mode IE",                  /* 0x29 */
++      "Reserved 0x2a",                                /* 0x2a */
++      "TVWS PHY Operating Mode Description IE",       /* 0x2b */
++      "TVWS Device Capabilities IE",                  /* 0x2c */
++      "TVWS Device Category IE",                      /* 0x2d */
++      "TVWS Device Identiication IE",                 /* 0x2e */
++      "TVWS Device Location IE",                      /* 0x2f */
++      "TVWS Channel Information Query IE",            /* 0x30 */
++      "TVWS Channel Information Source IE",           /* 0x31 */
++      "CTM IE",                                       /* 0x32 */
++      "Timestamp IE",                                 /* 0x33 */
++      "Timestamp Difference IE",                      /* 0x34 */
++      "TMCTP Sepcification IE",                       /* 0x35 */
++      "RCC PHY Operating Mode IE",                    /* 0x36 */
++      "Reserved 0x37",                                /* 0x37 */
++      "Reserved 0x38",                                /* 0x38 */
++      "Reserved 0x39",                                /* 0x39 */
++      "Reserved 0x3a",                                /* 0x3a */
++      "Reserved 0x3b",                                /* 0x3b */
++      "Reserved 0x3c",                                /* 0x3c */
++      "Reserved 0x3d",                                /* 0x3d */
++      "Reserved 0x3e",                                /* 0x3e */
++      "Reserved 0x3f",                                /* 0x3f */
++      "Reserved 0x40",                                /* 0x40 */
++      "Reserved 0x41",                                /* 0x41 */
++      "Reserved 0x42",                                /* 0x42 */
++      "Reserved 0x43",                                /* 0x43 */
++      "Reserved 0x44",                                /* 0x44 */
++      "Reserved 0x45",                                /* 0x45 */
++      "Reserved 0x46",                                /* 0x46 */
++      "Reserved 0x47",                                /* 0x47 */
++      "Reserved 0x48",                                /* 0x48 */
++      "Reserved 0x49",                                /* 0x49 */
++      "Reserved 0x4a",                                /* 0x4a */
++      "Reserved 0x4b",                                /* 0x4b */
++      "Reserved 0x4c",                                /* 0x4c */
++      "Reserved 0x4d",                                /* 0x4d */
++      "Reserved 0x4e",                                /* 0x4e */
++      "Reserved 0x4f",                                /* 0x4f */
++      "Reserved 0x50",                                /* 0x50 */
++      "Reserved 0x51",                                /* 0x51 */
++      "Reserved 0x52",                                /* 0x52 */
++      "Reserved 0x53",                                /* 0x53 */
++      "Reserved 0x54",                                /* 0x54 */
++      "Reserved 0x55",                                /* 0x55 */
++      "Reserved 0x56",                                /* 0x56 */
++      "Reserved 0x57",                                /* 0x57 */
++      "Reserved 0x58",                                /* 0x58 */
++      "Reserved 0x59",                                /* 0x59 */
++      "Reserved 0x5a",                                /* 0x5a */
++      "Reserved 0x5b",                                /* 0x5b */
++      "Reserved 0x5c",                                /* 0x5c */
++      "Reserved 0x5d",                                /* 0x5d */
++      "Reserved 0x5e",                                /* 0x5e */
++      "Reserved 0x5f",                                /* 0x5f */
++      "Reserved 0x60",                                /* 0x60 */
++      "Reserved 0x61",                                /* 0x61 */
++      "Reserved 0x62",                                /* 0x62 */
++      "Reserved 0x63",                                /* 0x63 */
++      "Reserved 0x64",                                /* 0x64 */
++      "Reserved 0x65",                                /* 0x65 */
++      "Reserved 0x66",                                /* 0x66 */
++      "Reserved 0x67",                                /* 0x67 */
++      "Reserved 0x68",                                /* 0x68 */
++      "Reserved 0x69",                                /* 0x69 */
++      "Reserved 0x6a",                                /* 0x6a */
++      "Reserved 0x6b",                                /* 0x6b */
++      "Reserved 0x6c",                                /* 0x6c */
++      "Reserved 0x6d",                                /* 0x6d */
++      "Reserved 0x6e",                                /* 0x6e */
++      "Reserved 0x6f",                                /* 0x6f */
++      "Reserved 0x70",                                /* 0x70 */
++      "Reserved 0x71",                                /* 0x71 */
++      "Reserved 0x72",                                /* 0x72 */
++      "Reserved 0x73",                                /* 0x73 */
++      "Reserved 0x74",                                /* 0x74 */
++      "Reserved 0x75",                                /* 0x75 */
++      "Reserved 0x76",                                /* 0x76 */
++      "Reserved 0x77",                                /* 0x77 */
++      "Reserved 0x78",                                /* 0x78 */
++      "Reserved 0x79",                                /* 0x79 */
++      "Reserved 0x7a",                                /* 0x7a */
++      "Reserved 0x7b",                                /* 0x7b */
++      "Reserved 0x7c",                                /* 0x7c */
++      "Reserved 0x7d",                                /* 0x7d */
++      "Reserved 0x7e",                                /* 0x7e */
++      "Reserved 0x7f"                                 /* 0x7f */
 +};
 +
 +/* Sub-ID for long format from Table 7-17 of 802.15.4-2015 */
 +static const char *p_mlme_long_names[] = {
-   "Reserved 0x00",                    /* 0x00 */
-   "Reserved 0x01",                    /* 0x01 */
-   "Reserved 0x02",                    /* 0x02 */
-   "Reserved 0x03",                    /* 0x03 */
-   "Reserved 0x04",                    /* 0x04 */
-   "Reserved 0x05",                    /* 0x05 */
-   "Reserved 0x06",                    /* 0x06 */
-   "Reserved 0x07",                    /* 0x07 */
-   "Vendor Specific MLME Nested IE",   /* 0x08 */
-   "Channel Hopping IE",                       /* 0x09 */
-   "Reserved 0x0a",                    /* 0x0a */
-   "Reserved 0x0b",                    /* 0x0b */
-   "Reserved 0x0c",                    /* 0x0c */
-   "Reserved 0x0d",                    /* 0x0d */
-   "Reserved 0x0e",                    /* 0x0e */
-   "Reserved 0x0f"                     /* 0x0f */
++      "Reserved 0x00",                        /* 0x00 */
++      "Reserved 0x01",                        /* 0x01 */
++      "Reserved 0x02",                        /* 0x02 */
++      "Reserved 0x03",                        /* 0x03 */
++      "Reserved 0x04",                        /* 0x04 */
++      "Reserved 0x05",                        /* 0x05 */
++      "Reserved 0x06",                        /* 0x06 */
++      "Reserved 0x07",                        /* 0x07 */
++      "Vendor Specific MLME Nested IE",       /* 0x08 */
++      "Channel Hopping IE",                   /* 0x09 */
++      "Reserved 0x0a",                        /* 0x0a */
++      "Reserved 0x0b",                        /* 0x0b */
++      "Reserved 0x0c",                        /* 0x0c */
++      "Reserved 0x0d",                        /* 0x0d */
++      "Reserved 0x0e",                        /* 0x0e */
++      "Reserved 0x0f"                         /* 0x0f */
 +};
 +
 +/* MAC commands from Table 7-49 of 802.15.4-2015 */
 +static const char *mac_c_names[] = {
-   "Reserved 0x00",                            /* 0x00 */
-   "Association Request command",              /* 0x01 */
-   "Association Response command",             /* 0x02 */
-   "Disassociation Notification command",      /* 0x03 */
-   "Data Request command",                     /* 0x04 */
-   "PAN ID Conflict Notification command",     /* 0x05 */
-   "Orphan Notification command",              /* 0x06 */
-   "Beacon Request command",                   /* 0x07 */
-   "Coordinator realignment command",          /* 0x08 */
-   "GTS request command",                      /* 0x09 */
-   "TRLE Management Request command",          /* 0x0a */
-   "TRLE Management Response command",         /* 0x0b */
-   "Reserved 0x0c",                            /* 0x0c */
-   "Reserved 0x0d",                            /* 0x0d */
-   "Reserved 0x0e",                            /* 0x0e */
-   "Reserved 0x0f",                            /* 0x0f */
-   "Reserved 0x10",                            /* 0x10 */
-   "Reserved 0x11",                            /* 0x11 */
-   "Reserved 0x12",                            /* 0x12 */
-   "DSME Association Request command",         /* 0x13 */
-   "DSME Association Response command",                /* 0x14 */
-   "DSME GTS Request command",                 /* 0x15 */
-   "DSME GTS Response command",                        /* 0x16 */
-   "DSME GTS Notify command",                  /* 0x17 */
-   "DSME Information Request command",         /* 0x18 */
-   "DSME Information Response command",                /* 0x19 */
-   "DSME Beacon Allocation Notification command",/* 0x1a */
-   "DSME Beacon Collision Notification command",       /* 0x1b */
-   "DSME Link Report command",                 /* 0x1c */
-   "Reserved 0x1d",                            /* 0x1d */
-   "Reserved 0x1e",                            /* 0x1e */
-   "Reserved 0x1f",                            /* 0x1f */
-   "RIT Data Request command",                 /* 0x20 */
-   "DBS Request command",                      /* 0x21 */
-   "DBS Response command",                             /* 0x22 */
-   "RIT Data Response command",                        /* 0x23 */
-   "Vendor Specific command",                  /* 0x24 */
-   "Reserved 0x25",                            /* 0x25 */
-   "Reserved 0x26",                            /* 0x26 */
-   "Reserved 0x27",                            /* 0x27 */
-   "Reserved 0x28",                            /* 0x28 */
-   "Reserved 0x29",                            /* 0x29 */
-   "Reserved 0x2a",                            /* 0x2a */
-   "Reserved 0x2b",                            /* 0x2b */
-   "Reserved 0x2c",                            /* 0x2c */
-   "Reserved 0x2d",                            /* 0x2d */
-   "Reserved 0x2e",                            /* 0x2e */
-   "Reserved 0x2f"                             /* 0x2f */
++      "Reserved 0x00",                                /* 0x00 */
++      "Association Request command",                  /* 0x01 */
++      "Association Response command",                 /* 0x02 */
++      "Disassociation Notification command",          /* 0x03 */
++      "Data Request command",                         /* 0x04 */
++      "PAN ID Conflict Notification command",         /* 0x05 */
++      "Orphan Notification command",                  /* 0x06 */
++      "Beacon Request command",                       /* 0x07 */
++      "Coordinator realignment command",              /* 0x08 */
++      "GTS request command",                          /* 0x09 */
++      "TRLE Management Request command",              /* 0x0a */
++      "TRLE Management Response command",             /* 0x0b */
++      "Reserved 0x0c",                                /* 0x0c */
++      "Reserved 0x0d",                                /* 0x0d */
++      "Reserved 0x0e",                                /* 0x0e */
++      "Reserved 0x0f",                                /* 0x0f */
++      "Reserved 0x10",                                /* 0x10 */
++      "Reserved 0x11",                                /* 0x11 */
++      "Reserved 0x12",                                /* 0x12 */
++      "DSME Association Request command",             /* 0x13 */
++      "DSME Association Response command",            /* 0x14 */
++      "DSME GTS Request command",                     /* 0x15 */
++      "DSME GTS Response command",                    /* 0x16 */
++      "DSME GTS Notify command",                      /* 0x17 */
++      "DSME Information Request command",             /* 0x18 */
++      "DSME Information Response command",            /* 0x19 */
++      "DSME Beacon Allocation Notification command",  /* 0x1a */
++      "DSME Beacon Collision Notification command",   /* 0x1b */
++      "DSME Link Report command",                     /* 0x1c */
++      "Reserved 0x1d",                                /* 0x1d */
++      "Reserved 0x1e",                                /* 0x1e */
++      "Reserved 0x1f",                                /* 0x1f */
++      "RIT Data Request command",                     /* 0x20 */
++      "DBS Request command",                          /* 0x21 */
++      "DBS Response command",                         /* 0x22 */
++      "RIT Data Response command",                    /* 0x23 */
++      "Vendor Specific command",                      /* 0x24 */
++      "Reserved 0x25",                                /* 0x25 */
++      "Reserved 0x26",                                /* 0x26 */
++      "Reserved 0x27",                                /* 0x27 */
++      "Reserved 0x28",                                /* 0x28 */
++      "Reserved 0x29",                                /* 0x29 */
++      "Reserved 0x2a",                                /* 0x2a */
++      "Reserved 0x2b",                                /* 0x2b */
++      "Reserved 0x2c",                                /* 0x2c */
++      "Reserved 0x2d",                                /* 0x2d */
++      "Reserved 0x2e",                                /* 0x2e */
++      "Reserved 0x2f"                         /* 0x2f */
  };
  
 -#define FC_FRAME_TYPE(fc)             ((fc) & 0x7)
 -#define FC_SECURITY_ENABLED           0x0008
 -#define FC_FRAME_PENDING              0x0010
 -#define FC_ACK_REQUEST                        0x0020
 -#define FC_PAN_ID_COMPRESSION         0x0040
 -#define FC_DEST_ADDRESSING_MODE(fc)   (((fc) >> 10) & 0x3)
 -#define FC_FRAME_VERSION(fc)          (((fc) >> 12) & 0x3)
 -#define FC_SRC_ADDRESSING_MODE(fc)    (((fc) >> 14) & 0x3)
+ /*
+  * Frame Control subfields.
+  */
 -#define FC_ADDRESSING_MODE_NONE               0x00
 -#define FC_ADDRESSING_MODE_RESERVED   0x01
 -#define FC_ADDRESSING_MODE_SHORT      0x02
 -#define FC_ADDRESSING_MODE_LONG               0x03
++#define FC_FRAME_TYPE(fc)              ((fc) & 0x7)
++#define FC_FRAME_VERSION(fc)           (((fc) >> 12) & 0x3)
++#define FC_ADDRESSING_MODE_NONE         0x00
++#define FC_ADDRESSING_MODE_RESERVED     0x01
++#define FC_ADDRESSING_MODE_SHORT        0x02
++#define FC_ADDRESSING_MODE_LONG         0x03
  
 -static u_int
 -ieee802_15_4_print(netdissect_options *ndo,
 -                   const u_char *p, u_int caplen)
 +/*
 + * IEEE 802.15.4 CRC 16 function. This is using CCITT polynomical of 0x1021,
 + * but the initial value is 0, and the bits are reversed for both in and out.
 + * See secton 7.2.10 of 802.15.4-2015 for more information.
 + */
 +static uint16_t
 +ieee802_15_4_crc16(const u_char *p,
 +                 uint16_t data_len)
  {
-   uint16_t crc;
-   u_char x, y;
 -      u_int hdrlen;
 -      uint16_t fc;
 -      uint8_t seq;
 -      uint16_t panid = 0;
++      uint16_t crc;
++      u_char x, y;
++      
++      crc = 0x0000; /* Note, initial value is 0x0000 not 0xffff. */
++      
++      while (data_len--){
++              y = *p++;
++              /* Reverse bits on input */
++              y = (((y & 0xaa) >> 1) | ((y & 0x55) << 1));
++              y = (((y & 0xcc) >> 2) | ((y & 0x33) << 2));
++              y = (((y & 0xf0) >> 4) | ((y & 0x0f) << 4));
++              /* Update CRC */
++              x = crc >> 8 ^ y;
++              x ^= x >> 4;
++              crc = (crc << 8) ^
++                      ((unsigned short)(x << 12)) ^
++                      ((unsigned short)(x <<5)) ^
++                      ((unsigned short)x);
++      }
++      /* Reverse bits on output */
++      crc = (((crc & 0xaaaa) >> 1) | ((crc & 0x5555) << 1));
++      crc = (((crc & 0xcccc) >> 2) | ((crc & 0x3333) << 2));
++      crc = (((crc & 0xf0f0) >> 4) | ((crc & 0x0f0f) << 4));
++      crc = (((crc & 0xff00) >> 8) | ((crc & 0x00ff) << 8));
++      return crc;
++}
  
-   crc = 0x0000; /* Note, initial value is 0x0000 not 0xffff. */
 -      ndo->ndo_protocol = "802.15.4";
 -      if (caplen < 3) {
 -              nd_print_trunc(ndo);
 -              return caplen;
++/*
++ * Reverses the bits of the 32-bit word.
++ */
++static uint32_t
++ieee802_15_4_reverse32(uint32_t x)
++{
++      x = ((x & 0x55555555) <<  1) | ((x >>  1) & 0x55555555);
++      x = ((x & 0x33333333) <<  2) | ((x >>  2) & 0x33333333);
++      x = ((x & 0x0F0F0F0F) <<  4) | ((x >>  4) & 0x0F0F0F0F);
++      x = (x << 24) | ((x & 0xFF00) << 8) |
++              ((x >> 8) & 0xFF00) | (x >> 24);
++      return x;
++}
 +
-   while (data_len--){
-     y = *p++;
-     /* Reverse bits on input */
-     y = (((y & 0xaa) >> 1) | ((y & 0x55) << 1));
-     y = (((y & 0xcc) >> 2) | ((y & 0x33) << 2));
-     y = (((y & 0xf0) >> 4) | ((y & 0x0f) << 4));
-     /* Update CRC */
-     x = crc >> 8 ^ y;
-     x ^= x >> 4;
-     crc = (crc << 8) ^
-       ((unsigned short)(x << 12)) ^
-       ((unsigned short)(x <<5)) ^
-       ((unsigned short)x);
-   }
-   /* Reverse bits on output */
-   crc = (((crc & 0xaaaa) >> 1) | ((crc & 0x5555) << 1));
-   crc = (((crc & 0xcccc) >> 2) | ((crc & 0x3333) << 2));
-   crc = (((crc & 0xf0f0) >> 4) | ((crc & 0x0f0f) << 4));
-   crc = (((crc & 0xff00) >> 8) | ((crc & 0x00ff) << 8));
-   return crc;
++/*
++ * IEEE 802.15.4 CRC 32 function. This is using ANSI X3.66-1979 polynomical of
++ * 0x04C11DB7, but the initial value is 0, and the bits are reversed for both
++ * in and out. See secton 7.2.10 of 802.15.4-2015 for more information.
++ */
++static uint32_t
++ieee802_15_4_crc32(const u_char *p,
++                 uint16_t data_len)
++{
++      uint32_t crc, mask, byte;
++      u_char x, y;
++      int b;
++      
++      crc = 0x00000000; /* Note, initial value is 0x00000000 not 0xffffffff */
++      
++      while (data_len--){
++              byte = *p++;
++              /* Reverse bits on input */
++              byte = ieee802_15_4_reverse32(byte);
++              /* Update CRC */
++              for(b = 0; b <= 7; b++) {
++                if ((int) (crc ^ byte) < 0)
++                  crc = (crc << 1) ^ 0x04C11DB7;
++                else
++                  crc = crc << 1;
++                byte = byte << 1;
++              }
+       }
 -      hdrlen = 3;
++      /* Reverse bits on output */
++      crc = ieee802_15_4_reverse32(crc);
++      return crc;
 +}
  
 -      fc = EXTRACT_LE_U_2(p);
 -      seq = EXTRACT_U_1(p + 2);
 -
 -      p += 3;
 -      caplen -= 3;
 -
 -      ND_PRINT("IEEE 802.15.4 %s packet ", ftypes[FC_FRAME_TYPE(fc)]);
 -      if (ndo->ndo_vflag)
 -              ND_PRINT("seq %02x ", seq);
 -
 -      /*
 -       * Destination address and PAN ID, if present.
 -       */
 -      switch (FC_DEST_ADDRESSING_MODE(fc)) {
 -      case FC_ADDRESSING_MODE_NONE:
 -              if (fc & FC_PAN_ID_COMPRESSION) {
 -                      /*
 -                       * PAN ID compression; this requires that both
 -                       * the source and destination addresses be present,
 -                       * but the destination address is missing.
 -                       */
 -                      nd_print_trunc(ndo);
 -                      return hdrlen;
 +/*
 + * Find out the address length based on the address type. See table 7-3 of
 + * 802.15.4-2015. Returns the address length.
 + */
 +static int
 +ieee802_15_4_addr_len(uint16_t addr_type)
 +{
-   switch (addr_type) {
-   case 0x00: /* None. */
-     return 0;
-     break;
-   case 0x01: /* Reserved, there used to be 8-bit address type in one
-             * amendment, but that and the feature using it was removed
-             * during 802.15.4-2015 maintenance process. */
-     return -1;
-     break;
-   case 0x02: /* Short. */
-     return 2;
-     break;
-   case 0x03: /* Extended. */
-     return 8;
-     break;
-   }
-   return 0;
++      switch (addr_type) {
++      case FC_ADDRESSING_MODE_NONE: /* None. */
++              return 0;
++              break;
++      case FC_ADDRESSING_MODE_RESERVED: /* Reserved, there used to be 8-bit
++                                         * address type in one amendment, but
++                                         * that and the feature using it was
++                                         * removed during 802.15.4-2015
++                                         * maintenance process. */
++              return -1;
++              break;
++      case FC_ADDRESSING_MODE_SHORT: /* Short. */
++              return 2;
++              break;
++      case FC_ADDRESSING_MODE_LONG: /* Extended. */
++              return 8;
++              break;
++      }
++      return 0;
 +}
 +
 +/*
 + * Print out the ieee 802.15.4 address.
 + */
 +static void
 +ieee802_15_4_print_addr(netdissect_options *ndo, const u_char *p,
 +                      int dst_addr_len)
 +{
-   switch (dst_addr_len) {
-   case 0:
-     ND_PRINT((ndo, "none"));
-     break;
-   case 2:
-     ND_PRINT((ndo, "%04x", EXTRACT_LE_16BITS(p)));
-     break;
-   case 8:
-     ND_PRINT((ndo, "%s", le64addr_string(ndo, p)));
-     break;
-   }
-   return;
++      switch (dst_addr_len) {
++      case 0:
++              ND_PRINT("none");
++              break;
++      case 2:
++              ND_PRINT("%04x", EXTRACT_LE_U_2(p));
++              break;
++      case 8:
++              ND_PRINT("%s", le64addr_string(ndo, p));
++              break;
++      }
++      return;
 +}
 +
 +/*
 + * Beacon frame superframe specification structure. Used in the old Beacon
 + * frames, and in the DSME PAN Descriptor IE. See section 7.3.1.3 of the
 + * 802.15.4-2015.
 + */
 +static void
 +ieee802_15_4_print_superframe_specification(netdissect_options *ndo,
 +                                          uint16_t ss)
 +{
-   if (ndo->ndo_vflag < 1) {
-     return;
-   }
-   ND_PRINT((ndo, "\n\tBeacon order = %d, Superframe order = %d, ",
-           (ss & 0xf), ((ss >> 4) & 0xf)));
-   ND_PRINT((ndo, "Final CAP Slot = %d",
-           ((ss >> 8) & 0xf)));
-   if (CHECK_BIT(ss, 12)) { ND_PRINT((ndo, ", BLE enabled")); }
-   if (CHECK_BIT(ss, 14)) { ND_PRINT((ndo, ", PAN Coordinator")); }
-   if (CHECK_BIT(ss, 15)) { ND_PRINT((ndo, ", Assocation Permit")); }
++      if (ndo->ndo_vflag < 1) {
++              return;
++      }
++      ND_PRINT("\n\tBeacon order = %d, Superframe order = %d, ",
++               (ss & 0xf), ((ss >> 4) & 0xf));
++      ND_PRINT("Final CAP Slot = %d",
++               ((ss >> 8) & 0xf));
++      if (CHECK_BIT(ss, 12)) { ND_PRINT(", BLE enabled"); }
++      if (CHECK_BIT(ss, 14)) { ND_PRINT(", PAN Coordinator"); }
++      if (CHECK_BIT(ss, 15)) { ND_PRINT(", Assocation Permit"); }
 +}
 +
 +/*
 + * Beacon frame gts info structure. Used in the old Beacon frames, and
 + * in the DSME PAN Descriptor IE. See section 7.3.1.4 of 802.15.4-2015.
 + *
 + * Returns number of byts consumed from the packet or -1 in case of error.
 + */
 +static int
 +ieee802_15_4_print_gts_info(netdissect_options *ndo,
 +                          const u_char *p,
 +                          uint16_t data_len)
 +{
-   uint8_t gts_spec, gts_cnt;
-   int len, i;
-   gts_spec = EXTRACT_LE_8BITS(p);
-   gts_cnt = gts_spec & 0x7;
-   if (gts_cnt == 0) {
-     if (ndo->ndo_vflag > 0) {
-       ND_PRINT((ndo, "\n\tGTS Descriptor Count = %d, ", gts_cnt));
-     }
-     return 1;
-   }
-   len = 1 + 1 + gts_cnt * 3;
-   if (data_len < len) {
-     ND_PRINT((ndo, " [ERROR: Truncated GTS Info List]"));
-     return -1;
-   }
-   if (ndo->ndo_vflag < 2) {
-     return len;
-   }
-   ND_PRINT((ndo, "GTS Descriptor Count = %d, ", gts_cnt));
-   ND_PRINT((ndo, "GTS Directions Mask = %02x, [ ",
-           EXTRACT_LE_8BITS(p + 1) & 0x7f));
-   for(i = 0; i < gts_cnt; i++) {
-     ND_PRINT((ndo, "[ "));
-     ieee802_15_4_print_addr(ndo, p + 2 + i * 3, 2);
-     ND_PRINT((ndo, ", Start slot = %d, Length = %d ] ",
-             EXTRACT_LE_8BITS(p + 2 + i * 3 + 1) & 0x0f,
-             (EXTRACT_LE_8BITS(p + 2 + i * 3 + 1) >> 4) & 0x0f));
-   }
-   ND_PRINT((ndo, "]"));
-   return len;
++      uint8_t gts_spec, gts_cnt;
++      int len, i;
++      
++      gts_spec = EXTRACT_U_1(p);
++      gts_cnt = gts_spec & 0x7;
++      
++      if (gts_cnt == 0) {
++              if (ndo->ndo_vflag > 0) {
++                      ND_PRINT("\n\tGTS Descriptor Count = %d, ", gts_cnt);
++              }
++              return 1;
++      }
++      len = 1 + 1 + gts_cnt * 3;
++      
++      if (data_len < len) {
++              ND_PRINT(" [ERROR: Truncated GTS Info List]");
++              return -1;
++      }
++      if (ndo->ndo_vflag < 2) {
++              return len;
++      }
++      ND_PRINT("GTS Descriptor Count = %d, ", gts_cnt);
++      ND_PRINT("GTS Directions Mask = %02x, [ ",
++               EXTRACT_U_1(p + 1) & 0x7f);
++      
++      for(i = 0; i < gts_cnt; i++) {
++              ND_PRINT("[ ");
++              ieee802_15_4_print_addr(ndo, p + 2 + i * 3, 2);
++              ND_PRINT(", Start slot = %d, Length = %d ] ",
++                       EXTRACT_U_1(p + 2 + i * 3 + 1) & 0x0f,
++                       (EXTRACT_U_1(p + 2 + i * 3 + 1) >> 4) & 0x0f);
++      }
++      ND_PRINT("]");
++      return len;
 +}
 +
 +/*
 + * Beacon frame pending address structure. Used in the old Beacon frames, and
 + * in the DSME PAN Descriptor IE. See section 7.3.1.5 of 802.15.4-2015.
 + *
 + * Returns number of byts consumed from the packet or -1 in case of error.
 + */
 +static int
 +ieee802_15_4_print_pending_addresses(netdissect_options *ndo,
 +                                   const u_char *p,
 +                                   uint16_t data_len)
 +{
-   uint8_t pas, s_cnt, e_cnt, len, i;
-   pas = EXTRACT_LE_8BITS(p);
-   s_cnt = pas & 0x7;
-   e_cnt = (pas >> 4) & 0x7;
-   len = 1 + s_cnt * 2 + e_cnt * 8;
-   if (ndo->ndo_vflag > 0) {
-     ND_PRINT((ndo, "\n\tPending address list, "
-             "# short addresses = %d, # extended addresses = %d",
-             s_cnt, e_cnt));
-   }
-   if (data_len < len) {
-     ND_PRINT((ndo, " [ERROR: Pending address list truncated]"));
-     return -1;
-   }
-   if (ndo->ndo_vflag < 2) {
-     return len;
-   }
-   if (s_cnt != 0) {
-     ND_PRINT((ndo, ", Short address list = [ "));
-     for(i = 0; i < s_cnt; i++) {
-       ieee802_15_4_print_addr(ndo, p + 1 + i * 2, 2);
-       ND_PRINT((ndo, " "));
-     }
-     ND_PRINT((ndo, "]"));
-   }
-   if (s_cnt != 0) {
-     ND_PRINT((ndo, ", Extended address list = [ "));
-     for(i = 0; i < e_cnt; i++) {
-       ieee802_15_4_print_addr(ndo, p + 1 + s_cnt * 2 +
-                             e_cnt * 8, 8);
-       ND_PRINT((ndo, " "));
-     }
-     ND_PRINT((ndo, "]"));
-   }
-   return len;
++      uint8_t pas, s_cnt, e_cnt, len, i;
++      
++      pas = EXTRACT_U_1(p);
++      s_cnt = pas & 0x7;
++      e_cnt = (pas >> 4) & 0x7;
++      len = 1 + s_cnt * 2 + e_cnt * 8;
++      if (ndo->ndo_vflag > 0) {
++              ND_PRINT("\n\tPending address list, "
++                       "# short addresses = %d, # extended addresses = %d",
++                       s_cnt, e_cnt);
++      }
++      if (data_len < len) {
++              ND_PRINT(" [ERROR: Pending address list truncated]");
++              return -1;
++      }
++      if (ndo->ndo_vflag < 2) {
++              return len;
++      }
++      if (s_cnt != 0) {
++              ND_PRINT(", Short address list = [ ");
++              for(i = 0; i < s_cnt; i++) {
++                      ieee802_15_4_print_addr(ndo, p + 1 + i * 2, 2);
++                      ND_PRINT(" ");
++              }
++              ND_PRINT("]");
++      }
++      if (s_cnt != 0) {
++              ND_PRINT(", Extended address list = [ ");
++              for(i = 0; i < e_cnt; i++) {
++                      ieee802_15_4_print_addr(ndo, p + 1 + s_cnt * 2 +
++                                              e_cnt * 8, 8);
++                      ND_PRINT(" ");
++              }
++              ND_PRINT("]");
++      }
++      return len;
 +}
 +
 +/*
 + * Print header ie content.
 + */
 +static void
 +ieee802_15_4_print_header_ie(netdissect_options *ndo,
 +                           const u_char *p,
 +                           uint16_t ie_len,
 +                           int element_id)
 +{
-   int i;
-   switch (element_id) {
-   case 0x00: /* Vendor Specific Header IE */
-     if (ie_len < 3) {
-       ND_PRINT((ndo, "[ERROR: Vendor OUI missing]"));
-     } else {
-       ND_PRINT((ndo, "OUI = 0x%02x%02x%02x, ", EXTRACT_LE_8BITS(p),
-               EXTRACT_LE_8BITS(p + 1), EXTRACT_LE_8BITS(p + 2)));
-       ND_PRINT((ndo, "Data = "));
-       for(i = 3; i < ie_len; i++) {
-       ND_PRINT((ndo, "%02x ", EXTRACT_LE_8BITS(p + i)));
-       }
-     }
-     break;
-   case 0x1a: /* LE CSL IE */
-     if (ie_len < 4) {
-       ND_PRINT((ndo, "[ERROR: Truncated CSL IE]"));
-     } else {
-       ND_PRINT((ndo, "CSL Phase = %d, CSL Period = %d",
-               EXTRACT_LE_16BITS(p), EXTRACT_LE_16BITS(p + 2)));
-       if (ie_len >= 6) {
-       ND_PRINT((ndo, ", Rendezvous time = %d", EXTRACT_LE_16BITS(p + 4)));
-       }
-       if (ie_len != 4 && ie_len != 6) {
-       ND_PRINT((ndo, " [ERROR: CSL IE length wrong]"));
-       }
-     }
-     break;
-   case 0x1b: /* LE RIT IE */
-     if (ie_len < 4) {
-       ND_PRINT((ndo, "[ERROR: Truncated RIT IE]"));
-     } else {
-       ND_PRINT((ndo, "Time to First Listen = %d, # of Repeat Listen = %d, Repeat Listen Interval = %d",
-               EXTRACT_LE_8BITS(p),
-               EXTRACT_LE_8BITS(p + 1),
-               EXTRACT_LE_16BITS(p + 2)));
-     }
-     break;
-   case 0x1c: /* DSME PAN Descriptor IE */
-     /*FALLTHROUGH*/
-   case 0x21: /* Extended DSME PAN descriptior IE */
-     if (ie_len < 2) {
-       ND_PRINT((ndo, "[ERROR: Truncated DSME PAN IE]"));
-     } else {
-       uint16_t ss, ptr;
-       int len, hopping_present;
-     
-       hopping_present = 0;
-     
-       ss = EXTRACT_LE_16BITS(p);
-       ieee802_15_4_print_superframe_specification(ndo, ss);
-       if (ie_len < 3) {
-       ND_PRINT((ndo, "[ERROR: Truncated before pending addresses field]"));
-       break;
-       }
-       ptr = 2;
-       len = ieee802_15_4_print_pending_addresses(ndo, p + ptr, ie_len - ptr);
-       if (len < 0) {
-       break;
-       }
-       ptr += len;
-     
-       if (element_id == 0x21) {
-       /* Extended version. */
-       if (ie_len < ptr + 2) {
-         ND_PRINT((ndo, "[ERROR: Truncated before DSME Superframe Specification]"));
-         break;
-       }
-       ss = EXTRACT_LE_16BITS(p + ptr);
-       ptr += 2;
-       ND_PRINT((ndo, "Multi-superframe Order = %d", ss & 0xff));
-       ND_PRINT((ndo, ", %s", ((ss & 0x100) ? "Channel hopping mode" :
-                               "Channel adaptation mode")));
-       if (ss & 0x400) { ND_PRINT((ndo, ", CAP reduction enabled")); }
-       if (ss & 0x800) { ND_PRINT((ndo, ", Deferred beacon enabled")); }
-       if (ss & 0x1000) {
-         ND_PRINT((ndo, ", Hopping Sequence Present"));
-         hopping_present = 1;
-       }
-       } else {
-       if (ie_len < ptr + 1) {
-         ND_PRINT((ndo, "[ERROR: Truncated before DSME Superframe Specification]"));
-         break;
-       }
-       ss = EXTRACT_LE_8BITS(p + ptr);
-       ptr++;
-       ND_PRINT((ndo, "Multi-superframe Order = %d", ss & 0x0f));
-       ND_PRINT((ndo, ", %s", ((ss & 0x10) ? "Channel hopping mode" :
-                               "Channel adaptation mode")));
-       if (ss & 0x40) { ND_PRINT((ndo, ", CAP reduction enabled")); }
-       if (ss & 0x80) { ND_PRINT((ndo, ", Deferred beacon enabled")); }
-       }
-       if (ie_len < ptr + 8) {
-       ND_PRINT((ndo, " [ERROR: Truncated before Time syncronization specification]"));
-       break;
-       }
-       ND_PRINT((ndo, "Beacon timestamp = %" PRIu64 ", offset = %d",
-               EXTRACT_LE_48BITS(p + ptr),
-               EXTRACT_LE_16BITS(p + ptr + 6)));
-       ptr += 8;
-       if (ie_len < ptr + 4) {
-       ND_PRINT((ndo, " [ERROR: Truncated before Beacon Bitmap]"));
-       break;
-       }
-     
-       len = EXTRACT_LE_16BITS(p + ptr + 2);
-       ND_PRINT((ndo, "SD Index = %d, Bitmap len = %d, ",
-               EXTRACT_LE_16BITS(p + ptr), len));
-       ptr += 4;
-       if (ie_len < ptr + len) {
-       ND_PRINT((ndo, " [ERROR: Truncated in SD bitmap]"));
-       break;
-       }
-       ND_PRINT((ndo, " SD Bitmap = "));
-       for(i = 0; i < len; i++) {
-       ND_PRINT((ndo, "%02x ", EXTRACT_LE_8BITS(p + ptr + i)));
-       }
-       ptr += len;
-     
-       if (ie_len < ptr + 5) {
-       ND_PRINT((ndo, " [ERROR: Truncated before Channel hopping specification]"));
-       break;
-       }
-     
-       len = EXTRACT_LE_16BITS(p + ptr + 4);
-       ND_PRINT((ndo, "Hopping Seq ID = %d, PAN Coordinator BSN = %d, "
-               "Channel offset = %d, Bitmap length = %d, ",
-               EXTRACT_LE_8BITS(p + ptr),
-               EXTRACT_LE_8BITS(p + ptr + 1),
-               EXTRACT_LE_16BITS(p + ptr + 2),
-               len));
-       ptr += 5;
-       if (ie_len < ptr + len) {
-       ND_PRINT((ndo, " [ERROR: Truncated in Channel offset bitmap]"));
-       break;
-       }
-       ND_PRINT((ndo, " Channel offset bitmap = "));
-       for(i = 0; i < len; i++) {
-       ND_PRINT((ndo, "%02x ",
-                 EXTRACT_LE_8BITS(p + ptr + i)));
-       }
-       ptr += len;
-       if (hopping_present) {
-       if (ie_len < ptr + 1) {
-         ND_PRINT((ndo, " [ERROR: Truncated in Hopping Sequence length]"));
-         break;
-       }
-       len = EXTRACT_LE_8BITS(p + ptr);
-       ptr++;
-       ND_PRINT((ndo, "Hopping Seq length = %d [ ", len));
-       /* The specification is not clear how the
-          hopping sequence is encoded, I assume two octet
-          unsigned integers for each channel. */
-       if (ie_len < ptr + len * 2) {
-         ND_PRINT((ndo, " [ERROR: Truncated in Channel offset bitmap]"));
-         break;
-       }
-       for(i = 0; i < len; i++) {
-         ND_PRINT((ndo, "%02x ", EXTRACT_LE_16BITS(p + ptr + i * 2)));
++      int i;
++      
++      switch (element_id) {
++      case 0x00: /* Vendor Specific Header IE */
++              if (ie_len < 3) {
++                      ND_PRINT("[ERROR: Vendor OUI missing]");
++              } else {
++                      ND_PRINT("OUI = 0x%02x%02x%02x, ", EXTRACT_U_1(p),
++                               EXTRACT_U_1(p + 1), EXTRACT_U_1(p + 2));
++                      ND_PRINT("Data = ");
++                      for(i = 3; i < ie_len; i++) {
++                              ND_PRINT("%02x ", EXTRACT_U_1(p + i));
++                      }
+               }
 -              if (ndo->ndo_vflag)
 -                      ND_PRINT("none ");
+               break;
 -      case FC_ADDRESSING_MODE_RESERVED:
 -              if (ndo->ndo_vflag)
 -                      ND_PRINT("reserved destination addressing mode");
 -              return hdrlen;
 -      case FC_ADDRESSING_MODE_SHORT:
++      case 0x1a: /* LE CSL IE */
++              if (ie_len < 4) {
++                      ND_PRINT("[ERROR: Truncated CSL IE]");
++              } else {
++                      ND_PRINT("CSL Phase = %d, CSL Period = %d",
++                               EXTRACT_LE_U_2(p), EXTRACT_LE_U_2(p + 2));
++                      if (ie_len >= 6) {
++                              ND_PRINT(", Rendezvous time = %d",
++                                       EXTRACT_LE_U_2(p + 4));
++                      }
++                      if (ie_len != 4 && ie_len != 6) {
++                              ND_PRINT(" [ERROR: CSL IE length wrong]");
++                      }
++              }
++              break;
++      case 0x1b: /* LE RIT IE */
++              if (ie_len < 4) {
++                      ND_PRINT("[ERROR: Truncated RIT IE]");
++              } else {
++                      ND_PRINT("Time to First Listen = %d, # of Repeat Listen = %d, Repeat Listen Interval = %d",
++                               EXTRACT_U_1(p),
++                               EXTRACT_U_1(p + 1),
++                               EXTRACT_LE_U_2(p + 2));
++              }
++              break;
++      case 0x1c: /* DSME PAN Descriptor IE */
++              /*FALLTHROUGH*/
++      case 0x21: /* Extended DSME PAN descriptior IE */
++              if (ie_len < 2) {
++                      ND_PRINT("[ERROR: Truncated DSME PAN IE]");
++              } else {
++                      uint16_t ss, ptr;
++                      int len, hopping_present;
++                      
++                      hopping_present = 0;
++                      
++                      ss = EXTRACT_LE_U_2(p);
++                      ieee802_15_4_print_superframe_specification(ndo, ss);
++                      if (ie_len < 3) {
++                              ND_PRINT("[ERROR: Truncated before pending addresses field]");
++                              break;
++                      }
++                      ptr = 2;
++                      len = ieee802_15_4_print_pending_addresses(ndo,
++                                                                 p + ptr,
++                                                                 ie_len -
++                                                                 ptr);
++                      if (len < 0) {
++                              break;
++                      }
++                      ptr += len;
++                      
++                      if (element_id == 0x21) {
++                              /* Extended version. */
++                              if (ie_len < ptr + 2) {
++                                      ND_PRINT("[ERROR: Truncated before DSME Superframe Specification]");
++                                      break;
++                              }
++                              ss = EXTRACT_LE_U_2(p + ptr);
++                              ptr += 2;
++                              ND_PRINT("Multi-superframe Order = %d", ss & 0xff);
++                              ND_PRINT(", %s", ((ss & 0x100) ?
++                                                "Channel hopping mode" :
++                                                "Channel adaptation mode"));
++                              if (ss & 0x400) {
++                                      ND_PRINT(", CAP reduction enabled");
++                              }
++                              if (ss & 0x800) {
++                                      ND_PRINT(", Deferred beacon enabled");
++                              }
++                              if (ss & 0x1000) {
++                                      ND_PRINT(", Hopping Sequence Present");
++                                      hopping_present = 1;
++                              }
++                      } else {
++                              if (ie_len < ptr + 1) {
++                                      ND_PRINT("[ERROR: Truncated before DSME Superframe Specification]");
++                                      break;
++                              }
++                              ss = EXTRACT_U_1(p + ptr);
++                              ptr++;
++                              ND_PRINT("Multi-superframe Order = %d",
++                                       ss & 0x0f);
++                              ND_PRINT(", %s", ((ss & 0x10) ?
++                                                "Channel hopping mode" :
++                                                "Channel adaptation mode"));
++                              if (ss & 0x40) {
++                                      ND_PRINT(", CAP reduction enabled");
++                              }
++                              if (ss & 0x80) {
++                                      ND_PRINT(", Deferred beacon enabled");
++                              }
++                      }
++                      if (ie_len < ptr + 8) {
++                              ND_PRINT(" [ERROR: Truncated before Time syncronization specification]");
++                              break;
++                      }
++                      ND_PRINT("Beacon timestamp = %" PRIu64 ", offset = %d",
++                               EXTRACT_LE_U_6(p + ptr),
++                               EXTRACT_LE_U_2(p + ptr + 6));
++                      ptr += 8;
++                      if (ie_len < ptr + 4) {
++                              ND_PRINT(" [ERROR: Truncated before Beacon Bitmap]");
++                              break;
++                      }
++                      
++                      len = EXTRACT_LE_U_2(p + ptr + 2);
++                      ND_PRINT("SD Index = %d, Bitmap len = %d, ",
++                               EXTRACT_LE_U_2(p + ptr), len);
++                      ptr += 4;
++                      if (ie_len < ptr + len) {
++                              ND_PRINT(" [ERROR: Truncated in SD bitmap]");
++                              break;
++                      }
++                      ND_PRINT(" SD Bitmap = ");
++                      for(i = 0; i < len; i++) {
++                              ND_PRINT("%02x ", EXTRACT_U_1(p + ptr + i));
++                      }
++                      ptr += len;
++                      
++                      if (ie_len < ptr + 5) {
++                              ND_PRINT(" [ERROR: Truncated before Channel hopping specification]");
++                              break;
++                      }
++                      
++                      len = EXTRACT_LE_U_2(p + ptr + 4);
++                      ND_PRINT("Hopping Seq ID = %d, PAN Coordinator BSN = %d, "
++                               "Channel offset = %d, Bitmap length = %d, ",
++                               EXTRACT_U_1(p + ptr),
++                               EXTRACT_U_1(p + ptr + 1),
++                               EXTRACT_LE_U_2(p + ptr + 2),
++                               len);
++                      ptr += 5;
++                      if (ie_len < ptr + len) {
++                              ND_PRINT(" [ERROR: Truncated in Channel offset bitmap]");
++                              break;
++                      }
++                      ND_PRINT(" Channel offset bitmap = ");
++                      for(i = 0; i < len; i++) {
++                              ND_PRINT("%02x ", EXTRACT_U_1(p + ptr + i));
++                      }
++                      ptr += len;
++                      if (hopping_present) {
++                              if (ie_len < ptr + 1) {
++                                      ND_PRINT(" [ERROR: Truncated in Hopping Sequence length]");
++                                      break;
++                              }
++                              len = EXTRACT_U_1(p + ptr);
++                              ptr++;
++                              ND_PRINT("Hopping Seq length = %d [ ", len);
++                              
++                              /* The specification is not clear how the
++                                 hopping sequence is encoded, I assume two
++                                 octet unsigned integers for each channel. */
++                              
++                              if (ie_len < ptr + len * 2) {
++                                      ND_PRINT(" [ERROR: Truncated in Channel offset bitmap]");
++                                      break;
++                              }
++                              for(i = 0; i < len; i++) {
++                                      ND_PRINT("%02x ", EXTRACT_LE_U_2(p + ptr + i * 2));
++                              }
++                              ND_PRINT("]");
++                              ptr += len * 2;
++                      }
++              }
++              break;
++      case 0x1d: /* Rendezvous Tome IE */
++              if (ie_len != 4) {
++                      ND_PRINT("[ERROR: Length != 2]");
++              } else {
++                      uint16_t r_time, w_u_interval;
++                      r_time = EXTRACT_LE_U_2(p);
++                      w_u_interval = EXTRACT_LE_U_2(p + 2);
++                      
++                      ND_PRINT("Rendezvous time = %d, Wake-up Interval = %d",
++                               r_time, w_u_interval);
++              }
++              break;
++      case 0x1e: /* Time correction IE */
++              if (ie_len != 2) {
++                      ND_PRINT("[ERROR: Length != 2]");
++              } else {
++                      uint16_t val;
++                      int16_t timecorr;
++                      
++                      val = EXTRACT_LE_U_2(p);
++                      if (val & 0x8000) { ND_PRINT("Negative "); }
++                      val &= 0xfff;
++                      val <<= 4;
++                      timecorr = val;
++                      timecorr >>= 4;
++                      
++                      ND_PRINT("Ack time correction = %d, ", timecorr);
++              }
++              break;
++      case 0x22: /* Frament Sequence Content Description IE */
++              /* XXX Not implemented */
++      case 0x23: /* Simplified Superframe Specification IE */
++              /* XXX Not implemented */
++      case 0x24: /* Simplified GTS Specification IE */
++              /* XXX Not implemented */
++      case 0x25: /* LECIM Capabilities IE */
++              /* XXX Not implemented */
++      case 0x26: /* TRLE Descriptor IE */
++              /* XXX Not implemented */
++      case 0x27: /* RCC Capabilities IE */
++              /* XXX Not implemented */
++      case 0x28: /* RCCN Descriptor IE */
++              /* XXX Not implemented */
++      case 0x29: /* Global Time IE */
++              /* XXX Not implemented */
++      case 0x2b: /* DA IE */
++              /* XXX Not implemented */
++      default:
++              ND_PRINT("IE Data = ");
++              for(i = 0; i < ie_len; i++) {
++                      ND_PRINT("%02x ", EXTRACT_U_1(p + i));
++              }
++              break;
 +      }
-       ND_PRINT((ndo, "]"));
-       ptr += len * 2;
-       }
-     }
-     break;
-   case 0x1d: /* Rendezvous Tome IE */
-     if (ie_len != 4) {
-       ND_PRINT((ndo, "[ERROR: Length != 2]"));
-     } else {
-       uint16_t r_time, w_u_interval;
-       r_time = EXTRACT_LE_16BITS(p);
-       w_u_interval = EXTRACT_LE_16BITS(p + 2);
-     
-       ND_PRINT((ndo, "Rendezvous time = %d, Wake-up Interval = %d",
-               r_time, w_u_interval));
-     }
-     break;
-   case 0x1e: /* Time correction IE */
-     if (ie_len != 2) {
-       ND_PRINT((ndo, "[ERROR: Length != 2]"));
-     } else {
-       uint16_t val;
-       int16_t timecorr;
-       val = EXTRACT_LE_16BITS(p);
-       if (val & 0x8000) { ND_PRINT((ndo, "Negative ")); }
-       val &= 0xfff;
-       val <<= 4;
-       timecorr = val;
-       timecorr >>= 4;
-     
-       ND_PRINT((ndo, "Ack time correction = %d, ", timecorr));
-     }
-     break;
-   case 0x22: /* Frament Sequence Content Description IE */
-     /* XXX Not implemented */
-   case 0x23: /* Simplified Superframe Specification IE */
-     /* XXX Not implemented */
-   case 0x24: /* Simplified GTS Specification IE */
-     /* XXX Not implemented */
-   case 0x25: /* LECIM Capabilities IE */
-     /* XXX Not implemented */
-   case 0x26: /* TRLE Descriptor IE */
-     /* XXX Not implemented */
-   case 0x27: /* RCC Capabilities IE */
-     /* XXX Not implemented */
-   case 0x28: /* RCCN Descriptor IE */
-     /* XXX Not implemented */
-   case 0x29: /* Global Time IE */
-     /* XXX Not implemented */
-   case 0x2b: /* DA IE */
-     /* XXX Not implemented */
-   default:
-     ND_PRINT((ndo, "IE Data = "));
-     for(i = 0; i < ie_len; i++) {
-       ND_PRINT((ndo, "%02x ", EXTRACT_LE_8BITS(p + i)));
-     }
-     break;
-   }
 +}
 +
 +/*
 + * Parse and print Header IE list. See 7.4.2 of 802.15.4-2015 for
 + * more information.
 + *
 + * Returns number of byts consumed from the packet or -1 in case of error.
 + */
 +static int
 +ieee802_15_4_print_header_ie_list(netdissect_options *ndo,
 +                                const u_char *p,
 +                                uint16_t caplen,
 +                                int *payload_ie_present)
 +{
-   int len, ie, ie_len, element_id, i;
-   *payload_ie_present = 0;
-   len = 0;
-   do {
-     if (caplen < 2) {
-       ND_PRINT((ndo, "[ERROR: Truncated header IE]"));
-       return -1;
-     }
-     /* Extract IE Header */
-     ie = EXTRACT_LE_16BITS(p);
-     if (CHECK_BIT(ie, 15)) {
-       ND_PRINT((ndo, "[ERROR: Header IE with type 1] "));
-     }
-     /* Get length and Element ID */
-     ie_len = ie & 0x7f;
-     element_id = (ie >> 7) & 0xff;
-     if (element_id > 127) {
-       ND_PRINT((ndo, "Reserved Element ID %02x, length = %d ",
-               element_id, ie_len));
-     } else {
-       if (ie_len == 0) {
-       ND_PRINT((ndo, "\n\t%s [",
-                 h_ie_names[element_id]));
-       } else {
-       ND_PRINT((ndo, "\n\t%s [ length = %d, ",
-                 h_ie_names[element_id], ie_len));
-       }
-     }
-     if (caplen < ie_len) {
-       ND_PRINT((ndo, "[ERROR: Truncated IE data]"));
-       return -1;
-     }
-     /* Skip header */
-     p += 2;
-   
-     /* Parse and print content. */
-     if (ndo->ndo_vflag > 3 && ie_len != 0) {
-       ieee802_15_4_print_header_ie(ndo, p, ie_len, element_id);
-     } else {
-       if (ie_len != 0) {
-       ND_PRINT((ndo, "IE Data = "));
-       for(i = 0; i < ie_len; i++) {
-         ND_PRINT((ndo, "%02x ", EXTRACT_LE_8BITS(p + i)));
-       }
-       }
-     }
-     ND_PRINT((ndo, "] "));
-     len += 2 + ie_len;
-     p += ie_len;
-     caplen -= 2 + ie_len;
-     if (element_id == 0x7e) {
-       *payload_ie_present = 1;
-       break;
-     }
-     if (element_id == 0x7f) {
-       break;
-     }
-   } while (caplen > 0);
-   return len;
++      int len, ie, ie_len, element_id, i;
++      
++      *payload_ie_present = 0;
++      len = 0;
++      do {
+               if (caplen < 2) {
 -                      nd_print_trunc(ndo);
 -                      return hdrlen;
++                      ND_PRINT("[ERROR: Truncated header IE]");
++                      return -1;
++              }
++              /* Extract IE Header */
++              ie = EXTRACT_LE_U_2(p);
++              if (CHECK_BIT(ie, 15)) {
++                      ND_PRINT("[ERROR: Header IE with type 1] ");
++              }
++              /* Get length and Element ID */
++              ie_len = ie & 0x7f;
++              element_id = (ie >> 7) & 0xff;
++              if (element_id > 127) {
++                      ND_PRINT("Reserved Element ID %02x, length = %d ",
++                               element_id, ie_len);
++              } else {
++                      if (ie_len == 0) {
++                              ND_PRINT("\n\t%s [", h_ie_names[element_id]);
++                      } else {
++                              ND_PRINT("\n\t%s [ length = %d, ",
++                                       h_ie_names[element_id], ie_len);
++                      }
++              }
++              if (caplen < ie_len) {
++                      ND_PRINT("[ERROR: Truncated IE data]");
++                      return -1;
+               }
 -              panid = EXTRACT_LE_U_2(p);
++              /* Skip header */
+               p += 2;
 -              caplen -= 2;
 -              hdrlen += 2;
 -              if (caplen < 2) {
 -                      nd_print_trunc(ndo);
 -                      return hdrlen;
++              
++              /* Parse and print content. */
++              if (ndo->ndo_vflag > 3 && ie_len != 0) {
++                      ieee802_15_4_print_header_ie(ndo, p,
++                                                   ie_len, element_id);
++              } else {
++                      if (ie_len != 0) {
++                              ND_PRINT("IE Data = ");
++                              for(i = 0; i < ie_len; i++) {
++                                      ND_PRINT("%02x ", EXTRACT_U_1(p + i));
++                              }
++                      }
+               }
 -              if (ndo->ndo_vflag)
 -                      ND_PRINT("%04x:%04x ", panid, EXTRACT_LE_U_2(p));
++              ND_PRINT("] ");
++              len += 2 + ie_len;
++              p += ie_len;
++              caplen -= 2 + ie_len;
++              if (element_id == 0x7e) {
++                      *payload_ie_present = 1;
++                      break;
++              }
++              if (element_id == 0x7f) {
++                      break;
++              }
++      } while (caplen > 0);
++      return len;
 +}
 +
 +/*
 + * Print MLME ie content.
 + */
 +static void
 +ieee802_15_4_print_mlme_ie(netdissect_options *ndo,
 +                         const u_char *p,
 +                         uint16_t sub_ie_len,
 +                         int sub_id)
 +{
-   int i, j, len;
-   /* Note, as there is no overlap with the long and short
-      MLME sub IDs, we can just use one switch here. */
-   switch (sub_id) {
-   case 0x08: /* Vendor Specific Nested IE */
-     if (sub_ie_len < 3) {
-       ND_PRINT((ndo, "[ERROR: Vendor OUI missing]"));
-     } else {
-       ND_PRINT((ndo, "OUI = 0x%02x%02x%02x, ",
-               EXTRACT_LE_8BITS(p),
-               EXTRACT_LE_8BITS(p + 1),
-               EXTRACT_LE_8BITS(p + 2)));
-       ND_PRINT((ndo, "Data = "));
-       for(i = 3; i < sub_ie_len; i++) {
-       ND_PRINT((ndo, "%02x ", EXTRACT_LE_8BITS(p + i)));
-       }
-     }
-     break;
-   case 0x09: /* Channel Hopping IE */
-     if (sub_ie_len < 1) {
-       ND_PRINT((ndo, "[ERROR: Hopping sequence ID missing]"));
-     } else if (sub_ie_len == 1) {
-       ND_PRINT((ndo, "Hopping Sequence ID = %d", EXTRACT_LE_8BITS(p)));
-       p++;
-       sub_ie_len--;
-     } else {
-       int channel_page, number_of_channels;
-     
-       ND_PRINT((ndo, "Hopping Sequence ID = %d", EXTRACT_LE_8BITS(p)));
-       p++;
-       sub_ie_len--;
-       if (sub_ie_len < 7) {
-       ND_PRINT((ndo, "[ERROR: IE truncated]"));
-       break;
-       }
-       channel_page = EXTRACT_LE_8BITS(p);
-       number_of_channels = EXTRACT_LE_16BITS(p + 1);
-       ND_PRINT((ndo, "Channel Page = %d, Number of Channels = %d, ",
-               channel_page, number_of_channels));
-       ND_PRINT((ndo, "Phy Configuration = 0x%08x, ",
-               EXTRACT_LE_32BITS(p + 3)));
-       p += 7;
-       sub_ie_len -= 7;
-       if (channel_page == 9 || channel_page == 10) {
-       len = (number_of_channels + 7) / 8;
-       if (sub_ie_len < len) {
-         ND_PRINT((ndo, "[ERROR: IE truncated]"));
-         break;
-       }
-       ND_PRINT((ndo, "Extended bitmap = 0x"));
-       for(i = 0; i < len; i++) {
-         ND_PRINT((ndo, "%02x", EXTRACT_LE_8BITS(p + i)));
-       }
-       ND_PRINT((ndo, ", "));
-       p += len;
-       sub_ie_len -= len;
-       }
-       if (sub_ie_len < 2) {
-       ND_PRINT((ndo, "[ERROR: IE truncated]"));
-       break;
-       }
-       len = EXTRACT_LE_16BITS(p);
-       p += 2;
-       sub_ie_len -= 2;
-       ND_PRINT((ndo, "Hopping Seq length = %d [ ", len));
-     
-       if (sub_ie_len < len * 2) {
-       ND_PRINT((ndo, " [ERROR: IE truncated]"));
-       break;
-       }
-       for(i = 0; i < len; i++) {
-       ND_PRINT((ndo, "%02x ", EXTRACT_LE_16BITS(p + i * 2)));
-       }
-       ND_PRINT((ndo, "]"));
-       p += len * 2;
-       sub_ie_len -= len * 2;
-       if (sub_ie_len < 2) {
-       ND_PRINT((ndo, "[ERROR: IE truncated]"));
-       break;
-       }
-       ND_PRINT((ndo, "Current hop = %d", EXTRACT_LE_16BITS(p)));
-     }
-   
-     break;
-   case 0x1a: /* TSCH Syncronization IE. */
-     if (sub_ie_len < 6) {
-       ND_PRINT((ndo, "[ERROR: Length != 6]"));
-     }
-     ND_PRINT((ndo, "ASN = %02x%02x%02x%02x%02x, Join Metric = %d ",
-             EXTRACT_LE_8BITS(p + 4), EXTRACT_LE_8BITS(p + 3),
-             EXTRACT_LE_8BITS(p + 2), EXTRACT_LE_8BITS(p + 1),
-             EXTRACT_LE_8BITS(p + 0), EXTRACT_LE_8BITS(p + 5)));
-     break;
-   case 0x1b: /* TSCH Slotframe and Link IE. */
-     {
-       int sf_num, off, links, opts;
-     
-       if (sub_ie_len < 1) {
-       ND_PRINT((ndo, "[ERROR: Truncated IE]"));
-       break;
-       }
-       sf_num = EXTRACT_LE_8BITS(p);
-       ND_PRINT((ndo, "Slotframes = %d ", sf_num));
-       off = 1;
-       for(i = 0; i < sf_num; i++) {
-       if (sub_ie_len < off + 4) {
-         ND_PRINT((ndo, "[ERROR: Truncated IE before slotframes]"));
-         break;
-       }
-       links = EXTRACT_LE_8BITS(p + off + 3);
-       ND_PRINT((ndo, "\n\t\t\t[ Handle %d, size = %d, links = %d ",
-                 EXTRACT_LE_8BITS(p + off),
-                 EXTRACT_LE_16BITS(p + off + 1),
-                 links));
-       off += 4;
-       for(j = 0; j < links; j++) {
-         if (sub_ie_len < off + 5) {
-           ND_PRINT((ndo, "[ERROR: Truncated IE links]"));
-           break;
-         }
-         opts = EXTRACT_LE_8BITS(p + off + 4);
-         ND_PRINT((ndo, "\n\t\t\t\t[ Timeslot =  %d, Offset = %d, Options = ",
-                   EXTRACT_LE_16BITS(p + off),
-                   EXTRACT_LE_16BITS(p + off + 2)));
-         if (opts & 0x1) { ND_PRINT((ndo, "TX ")); }
-         if (opts & 0x2) { ND_PRINT((ndo, "RX ")); }
-         if (opts & 0x4) { ND_PRINT((ndo, "Shared ")); }
-         if (opts & 0x8) { ND_PRINT((ndo, "Timekeeping ")); }
-         if (opts & 0x10) { ND_PRINT((ndo, "Priority ")); }
-         off += 5;
-         ND_PRINT((ndo, "] "));
++      int i, j, len;
++      
++      /* Note, as there is no overlap with the long and short
++         MLME sub IDs, we can just use one switch here. */
++      switch (sub_id) {
++      case 0x08: /* Vendor Specific Nested IE */
++              if (sub_ie_len < 3) {
++                      ND_PRINT("[ERROR: Vendor OUI missing]");
++              } else {
++                      ND_PRINT("OUI = 0x%02x%02x%02x, ",
++                               EXTRACT_U_1(p),
++                               EXTRACT_U_1(p + 1),
++                               EXTRACT_U_1(p + 2));
++                      ND_PRINT("Data = ");
++                      for(i = 3; i < sub_ie_len; i++) {
++                              ND_PRINT("%02x ", EXTRACT_U_1(p + i));
++                      }
++              }
++              break;
++      case 0x09: /* Channel Hopping IE */
++              if (sub_ie_len < 1) {
++                      ND_PRINT("[ERROR: Hopping sequence ID missing]");
++              } else if (sub_ie_len == 1) {
++                      ND_PRINT("Hopping Sequence ID = %d", EXTRACT_U_1(p));
++                      p++;
++                      sub_ie_len--;
++              } else {
++                      int channel_page, number_of_channels;
++                      
++                      ND_PRINT("Hopping Sequence ID = %d", EXTRACT_U_1(p));
++                      p++;
++                      sub_ie_len--;
++                      if (sub_ie_len < 7) {
++                              ND_PRINT("[ERROR: IE truncated]");
++                              break;
++                      }
++                      channel_page = EXTRACT_U_1(p);
++                      number_of_channels = EXTRACT_LE_U_2(p + 1);
++                      ND_PRINT("Channel Page = %d, Number of Channels = %d, ",
++                               channel_page, number_of_channels);
++                      ND_PRINT("Phy Configuration = 0x%08x, ",
++                               EXTRACT_LE_U_4(p + 3));
++                      p += 7;
++                      sub_ie_len -= 7;
++                      if (channel_page == 9 || channel_page == 10) {
++                              len = (number_of_channels + 7) / 8;
++                              if (sub_ie_len < len) {
++                                      ND_PRINT("[ERROR: IE truncated]");
++                                      break;
++                              }
++                              ND_PRINT("Extended bitmap = 0x");
++                              for(i = 0; i < len; i++) {
++                                      ND_PRINT("%02x", EXTRACT_U_1(p + i));
++                              }
++                              ND_PRINT(", ");
++                              p += len;
++                              sub_ie_len -= len;
++                      }
++                      if (sub_ie_len < 2) {
++                              ND_PRINT("[ERROR: IE truncated]");
++                              break;
++                      }
++                      len = EXTRACT_LE_U_2(p);
++                      p += 2;
++                      sub_ie_len -= 2;
++                      ND_PRINT("Hopping Seq length = %d [ ", len);
++                      
++                      if (sub_ie_len < len * 2) {
++                              ND_PRINT(" [ERROR: IE truncated]");
++                              break;
++                      }
++                      for(i = 0; i < len; i++) {
++                              ND_PRINT("%02x ", EXTRACT_LE_U_2(p + i * 2));
++                      }
++                      ND_PRINT("]");
++                      p += len * 2;
++                      sub_ie_len -= len * 2;
++                      if (sub_ie_len < 2) {
++                              ND_PRINT("[ERROR: IE truncated]");
++                              break;
++                      }
++                      ND_PRINT("Current hop = %d", EXTRACT_LE_U_2(p));
++              }
++              
++              break;
++      case 0x1a: /* TSCH Syncronization IE. */
++              if (sub_ie_len < 6) {
++                      ND_PRINT("[ERROR: Length != 6]");
++              }
++              ND_PRINT("ASN = %010" PRIx64 ", Join Metric = %d ",
++                       EXTRACT_LE_U_5(p), EXTRACT_U_1(p + 5));
++              break;
++      case 0x1b: /* TSCH Slotframe and Link IE. */
++              {
++                      int sf_num, off, links, opts;
++                      
++                      if (sub_ie_len < 1) {
++                              ND_PRINT("[ERROR: Truncated IE]");
++                              break;
++                      }
++                      sf_num = EXTRACT_U_1(p);
++                      ND_PRINT("Slotframes = %d ", sf_num);
++                      off = 1;
++                      for(i = 0; i < sf_num; i++) {
++                              if (sub_ie_len < off + 4) {
++                                      ND_PRINT("[ERROR: Truncated IE before slotframes]");
++                                      break;
++                              }
++                              links = EXTRACT_U_1(p + off + 3);
++                              ND_PRINT("\n\t\t\t[ Handle %d, size = %d, links = %d ",
++                                       EXTRACT_U_1(p + off),
++                                       EXTRACT_LE_U_2(p + off + 1),
++                                       links);
++                              off += 4;
++                              for(j = 0; j < links; j++) {
++                                      if (sub_ie_len < off + 5) {
++                                              ND_PRINT("[ERROR: Truncated IE links]");
++                                              break;
++                                      }
++                                      opts = EXTRACT_U_1(p + off + 4);
++                                      ND_PRINT("\n\t\t\t\t[ Timeslot =  %d, Offset = %d, Options = ",
++                                               EXTRACT_LE_U_2(p + off),
++                                               EXTRACT_LE_U_2(p + off + 2));
++                                      if (opts & 0x1) { ND_PRINT("TX "); }
++                                      if (opts & 0x2) { ND_PRINT("RX "); }
++                                      if (opts & 0x4) { ND_PRINT("Shared "); }
++                                      if (opts & 0x8) {
++                                              ND_PRINT("Timekeeping ");
++                                      }
++                                      if (opts & 0x10) {
++                                              ND_PRINT("Priority ");
++                                      }
++                                      off += 5;
++                                      ND_PRINT("] ");
++                              }
++                              ND_PRINT("] ");
++                      }
++              }
++              break;
++      case 0x1c: /* TSCH Timeslot IE. */
++              if (sub_ie_len == 1) {
++                      ND_PRINT("Time slot ID = %d ", EXTRACT_U_1(p));
++              } else if (sub_ie_len == 25) {
++                      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 ",
++                               EXTRACT_U_1(p),
++                               EXTRACT_LE_U_2(p + 1),
++                               EXTRACT_LE_U_2(p + 3),
++                               EXTRACT_LE_U_2(p + 5),
++                               EXTRACT_LE_U_2(p + 7),
++                               EXTRACT_LE_U_2(p + 9),
++                               EXTRACT_LE_U_2(p + 11),
++                               EXTRACT_LE_U_2(p + 13),
++                               EXTRACT_LE_U_2(p + 15),
++                               EXTRACT_LE_U_2(p + 17),
++                               EXTRACT_LE_U_2(p + 19),
++                               EXTRACT_LE_U_2(p + 21),
++                               EXTRACT_LE_U_2(p + 23));
++              } else if (sub_ie_len == 27) {
++                      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 ",
++                               EXTRACT_U_1(p),
++                               EXTRACT_LE_U_2(p + 1),
++                               EXTRACT_LE_U_2(p + 3),
++                               EXTRACT_LE_U_2(p + 5),
++                               EXTRACT_LE_U_2(p + 7),
++                               EXTRACT_LE_U_2(p + 9),
++                               EXTRACT_LE_U_2(p + 11),
++                               EXTRACT_LE_U_2(p + 13),
++                               EXTRACT_LE_U_2(p + 15),
++                               EXTRACT_LE_U_2(p + 17),
++                               EXTRACT_LE_U_2(p + 19),
++                               EXTRACT_LE_U_3(p + 21),
++                               EXTRACT_LE_U_3(p + 24));
++              } else {
++                      ND_PRINT("[ERROR: Length not 1, 25, or 27]");
++                      ND_PRINT("\n\t\t\tIE Data = ");
++                      for(i = 0; i < sub_ie_len; i++) {
++                              ND_PRINT("%02x ", EXTRACT_U_1(p + i));
++                      }
++              }
++              break;
++      case 0x1d: /* Hopping timing IE */
++              /* XXX Not implemented */
++      case 0x1e: /* Enhanced Beacon Filter IE */
++              /* XXX Not implemented */
++      case 0x1f: /* MAC Metrics IE */
++              /* XXX Not implemented */
++      case 0x20: /* All MAC Metrics IE */
++              /* XXX Not implemented */
++      case 0x21: /* Coexistence Specification IE */
++              /* XXX Not implemented */
++      case 0x22: /* SUN Device Capabilities IE */
++              /* XXX Not implemented */
++      case 0x23: /* SUN FSK Generic PHY IE */
++              /* XXX Not implemented */
++      case 0x24: /* Mode Switch Parameter IE */
++              /* XXX Not implemented */
++      case 0x25: /* PHY Parameter Change IE */
++              /* XXX Not implemented */
++      case 0x26: /* O-QPSK PHY Mode IE */
++              /* XXX Not implemented */
++      case 0x27: /* PCA Allocation IE */
++              /* XXX Not implemented */
++      case 0x28: /* LECIM DSSS Operating Mode IE */
++              /* XXX Not implemented */
++      case 0x29: /* LECIM FSK Operating Mode IE */
++              /* XXX Not implemented */
++      case 0x2b: /* TVWS PHY Operating Mode Description IE */
++              /* XXX Not implemented */
++      case 0x2c: /* TVWS Device Capabilities IE */
++              /* XXX Not implemented */
++      case 0x2d: /* TVWS Device Catagory IE */
++              /* XXX Not implemented */
++      case 0x2e: /* TVWS Device Identification IE */
++              /* XXX Not implemented */
++      case 0x2f: /* TVWS Device Location IE */
++              /* XXX Not implemented */
++      case 0x30: /* TVWS Channel Information Query IE */
++              /* XXX Not implemented */
++      case 0x31: /* TVWS Channel Information Source IE */
++              /* XXX Not implemented */
++      case 0x32: /* CTM IE */
++              /* XXX Not implemented */
++      case 0x33: /* Timestamp IE */
++              /* XXX Not implemented */
++      case 0x34: /* Timestamp Difference IE */
++              /* XXX Not implemented */
++      case 0x35: /* TMCTP Specification IE */
++              /* XXX Not implemented */
++      case 0x36: /* TCC PHY Operating Mode IE */
++              /* XXX Not implemented */
++      default:
++              ND_PRINT("IE Data = ");
++              for(i = 0; i < sub_ie_len; i++) {
++                      ND_PRINT("%02x ", EXTRACT_U_1(p + i));
++              }
++              break;
 +      }
-       ND_PRINT((ndo, "] "));
-       }
-     }
-     break;
-   case 0x1c: /* TSCH Timeslot IE. */
-     if (sub_ie_len == 1) {
-       ND_PRINT((ndo, "Time slot ID = %d ", EXTRACT_LE_8BITS(p)));
-     } else if (sub_ie_len == 25) {
-       ND_PRINT((ndo, "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 ",
-               EXTRACT_LE_8BITS(p),
-               EXTRACT_LE_16BITS(p + 1),
-               EXTRACT_LE_16BITS(p + 3),
-               EXTRACT_LE_16BITS(p + 5),
-               EXTRACT_LE_16BITS(p + 7),
-               EXTRACT_LE_16BITS(p + 9),
-               EXTRACT_LE_16BITS(p + 11),
-               EXTRACT_LE_16BITS(p + 13),
-               EXTRACT_LE_16BITS(p + 15),
-               EXTRACT_LE_16BITS(p + 17),
-               EXTRACT_LE_16BITS(p + 19),
-               EXTRACT_LE_16BITS(p + 21),
-               EXTRACT_LE_16BITS(p + 23)));
-     } else if (sub_ie_len == 27) {
-       ND_PRINT((ndo, "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 ",
-               EXTRACT_LE_8BITS(p),
-               EXTRACT_LE_16BITS(p + 1),
-               EXTRACT_LE_16BITS(p + 3),
-               EXTRACT_LE_16BITS(p + 5),
-               EXTRACT_LE_16BITS(p + 7),
-               EXTRACT_LE_16BITS(p + 9),
-               EXTRACT_LE_16BITS(p + 11),
-               EXTRACT_LE_16BITS(p + 13),
-               EXTRACT_LE_16BITS(p + 15),
-               EXTRACT_LE_16BITS(p + 17),
-               EXTRACT_LE_16BITS(p + 19),
-               EXTRACT_LE_24BITS(p + 21),
-               EXTRACT_LE_24BITS(p + 24)));
-     } else {
-       ND_PRINT((ndo, "[ERROR: Length not 1, 25, or 27]"));
-       ND_PRINT((ndo, "\n\t\t\tIE Data = "));
-       for(i = 0; i < sub_ie_len; i++) {
-       ND_PRINT((ndo, "%02x ", EXTRACT_LE_8BITS(p + i)));
-       }
-     }
-     break;
-   case 0x1d: /* Hopping timing IE */
-     /* XXX Not implemented */
-   case 0x1e: /* Enhanced Beacon Filter IE */
-     /* XXX Not implemented */
-   case 0x1f: /* MAC Metrics IE */
-     /* XXX Not implemented */
-   case 0x20: /* All MAC Metrics IE */
-     /* XXX Not implemented */
-   case 0x21: /* Coexistence Specification IE */
-     /* XXX Not implemented */
-   case 0x22: /* SUN Device Capabilities IE */
-     /* XXX Not implemented */
-   case 0x23: /* SUN FSK Generic PHY IE */
-     /* XXX Not implemented */
-   case 0x24: /* Mode Switch Parameter IE */
-     /* XXX Not implemented */
-   case 0x25: /* PHY Parameter Change IE */
-     /* XXX Not implemented */
-   case 0x26: /* O-QPSK PHY Mode IE */
-     /* XXX Not implemented */
-   case 0x27: /* PCA Allocation IE */
-     /* XXX Not implemented */
-   case 0x28: /* LECIM DSSS Operating Mode IE */
-     /* XXX Not implemented */
-   case 0x29: /* LECIM FSK Operating Mode IE */
-     /* XXX Not implemented */
-   case 0x2b: /* TVWS PHY Operating Mode Description IE */
-     /* XXX Not implemented */
-   case 0x2c: /* TVWS Device Capabilities IE */
-     /* XXX Not implemented */
-   case 0x2d: /* TVWS Device Catagory IE */
-     /* XXX Not implemented */
-   case 0x2e: /* TVWS Device Identification IE */
-     /* XXX Not implemented */
-   case 0x2f: /* TVWS Device Location IE */
-     /* XXX Not implemented */
-   case 0x30: /* TVWS Channel Information Query IE */
-     /* XXX Not implemented */
-   case 0x31: /* TVWS Channel Information Source IE */
-     /* XXX Not implemented */
-   case 0x32: /* CTM IE */
-     /* XXX Not implemented */
-   case 0x33: /* Timestamp IE */
-     /* XXX Not implemented */
-   case 0x34: /* Timestamp Difference IE */
-     /* XXX Not implemented */
-   case 0x35: /* TMCTP Specification IE */
-     /* XXX Not implemented */
-   case 0x36: /* TCC PHY Operating Mode IE */
-     /* XXX Not implemented */
-   default:
-     ND_PRINT((ndo, "IE Data = "));
-     for(i = 0; i < sub_ie_len; i++) {
-       ND_PRINT((ndo, "%02x ", EXTRACT_LE_8BITS(p + i)));
-     }
-     break;
-   }
 +}
 +
 +/*
 + * MLME IE list parsing and printing. See 7.4.3.2 of 802.15.4-2015
 + * for more information.
 + */
 +static void
 +ieee802_15_4_print_mlme_ie_list(netdissect_options *ndo,
 +                              const u_char *p,
 +                              uint16_t ie_len)
 +{
-   int ie, sub_ie_len, sub_id, i, type;
++      int ie, sub_ie_len, sub_id, i, type;
++      
++      do {
++              if (ie_len < 2) {
++                      ND_PRINT("[ERROR: Truncated MLME IE]");
++                      return;
++              }
++              /* Extract IE header */
++              ie = EXTRACT_LE_U_2(p);
++              type = CHECK_BIT(ie, 15);
++              if (type) {
++                      /* Long type */
++                      sub_ie_len = ie & 0x3ff;
++                      sub_id = (ie >> 11) & 0x0f;
++              } else {
++                      sub_ie_len = ie & 0xff;
++                      sub_id = (ie >> 8) & 0x7f;
++              }
++              
++              /* Skip the IE header */
+               p += 2;
 -              caplen -= 2;
 -              hdrlen += 2;
++              
++              if (type == 0) {
++                      ND_PRINT("\n\t\t%s [ length = %d, ",
++                               p_mlme_short_names[sub_id], sub_ie_len);
++              } else {
++                      ND_PRINT("\n\t\t%s [ length = %d, ",
++                               p_mlme_long_names[sub_id], sub_ie_len);
++              }
++              
++              if (ie_len < sub_ie_len) {
++                      ND_PRINT("[ERROR: Truncated IE data]");
++                      return;
++              }
++              if (sub_ie_len != 0) {
++                      if (ndo->ndo_vflag > 3) {
++                              ieee802_15_4_print_mlme_ie(ndo, p, sub_ie_len, sub_id);
++                      } else if (ndo->ndo_vflag > 2) {
++                              ND_PRINT("IE Data = ");
++                              for(i = 0; i < sub_ie_len; i++) {
++                                      ND_PRINT("%02x ", EXTRACT_U_1(p + i));
++                              }
++                      }
++              }
++              ND_PRINT("] ");
++              p += sub_ie_len;
++              ie_len -= 2 + sub_ie_len;
++      } while (ie_len > 0);
++      return;
++}
++
++/*
++ * Multiplexd IE (802.15.9) parsing and printing.
++ *
++ * Returns number of bytes consumed from packet or -1 in case of error.
++ */
++static void
++ieee802_15_4_print_mpx_ie(netdissect_options *ndo,
++                        const u_char *p,
++                        uint16_t ie_len)
++{
++      int transfer_type, tid;
++      int fragment_number, data_start;
++      int i;
++
++      if (ie_len < 1) {
++              ND_PRINT("[ERROR: Transaction control byte missing]");
++              return;
++      }
++              
++      transfer_type = EXTRACT_U_1(p) & 0x7;
++      tid = EXTRACT_U_1(p) >> 3;
++      switch (transfer_type) {
++      case 0x00: /* Full upper layer frame. */
++      case 0x01: /* Full upper layer frame with small Multiplex ID. */
++              ND_PRINT("Type = Full upper layer fragment%s, ",
++                       (transfer_type == 0x01 ?
++                        " with small Multiplex ID" : ""));
++              if (transfer_type == 0x00) {
++                      if (ie_len < 3) {
++                              ND_PRINT("[ERROR: Multiplex ID missing]");
++                              return;
++                      } 
++                      data_start = 3;
++                      ND_PRINT("tid = 0x%02x, Multiplex ID = 0x%04x, ",
++                               tid, EXTRACT_LE_U_2(p + 1));
++              } else {
++                      data_start = 1;
++                      ND_PRINT("Multiplex ID = 0x%04x, ", tid);
++              }
++              break;
++      case 0x02: /* First, or middle, Fragments */
++      case 0x04: /* Last fragment */
++              if (ie_len < 2) {
++                      ND_PRINT("[ERROR: fragment number missing]");
++                      return;
++              }
++              
++              fragment_number = EXTRACT_U_1(p + 1);
++              ND_PRINT("Type = %s, tid = 0x%02x, fragment = 0x%02x, ",
++                       (transfer_type == 0x02 ?
++                        (fragment_number == 0 ?
++                         "First fragment" : "Middle fragment") :
++                        "Last fragment"), tid,
++                       fragment_number);
++              data_start = 2;
++              if (fragment_number == 0) {
++                      int total_size, multiplex_id;
++                      
++                      if (ie_len < 6) {
++                              ND_PRINT("[ERROR: Total upper layer size or multiplex ID missing]");
++                              return;
++                      }
++                      total_size = EXTRACT_LE_U_2(p + 2);
++                      multiplex_id = EXTRACT_LE_U_2(p + 4);
++                      ND_PRINT("Total upper layer size = 0x%04x, Multiplex ID = 0x%04x, ",
++                               total_size, multiplex_id);
++                      data_start = 6;
++              }
++              break;
++      case 0x06: /* Abort code */
++              if (ie_len == 1) {
++                      ND_PRINT("Type = Abort, tid = 0x%02x, no max size given",
++                               tid);
++              } else if (ie_len == 3) {
++                      ND_PRINT("Type = Abort, tid = 0x%02x, max size = 0x%04x",
++                               tid, EXTRACT_LE_U_2(p + 1));
++              } else {
++                      ND_PRINT("Type = Abort, tid = 0x%02x, invalid length = %d (not 1 or 3)",
++                               tid, ie_len);
++                      ND_PRINT("Abort data = ");
++                      for(i = 1; i < ie_len; i++) {
++                              ND_PRINT("%02x ", EXTRACT_U_1(p + i));
++                      }
++              }
++              return;
++              /* NOTREACHED */
++              break;
++      case 0x03: /* Reserved */
++      case 0x05: /* Reserved */
++      case 0x07: /* Reserved */
++              ND_PRINT("Type = %d (Reserved), tid = 0x%02x, ",
++                       transfer_type, tid);
++              data_start = 1;
+               break;
 -      case FC_ADDRESSING_MODE_LONG:
++      }
 +
-   do {
-     if (ie_len < 2) {
-       ND_PRINT((ndo, "[ERROR: Truncated MLME IE]"));
-       return;
-     }
-     /* Extract IE header */
-     ie = EXTRACT_LE_16BITS(p);
-     type = CHECK_BIT(ie, 15);
-     if (type) {
-       /* Long type */
-       sub_ie_len = ie & 0x3ff;
-       sub_id = (ie >> 11) & 0x0f;
-     } else {
-       sub_ie_len = ie & 0xff;
-       sub_id = (ie >> 8) & 0x7f;
-     }
-   
-     /* Skip the IE header */
-     p += 2;
-   
-     if (type == 0) {
-       ND_PRINT((ndo, "\n\t\t%s [ length = %d, ",
-               p_mlme_short_names[sub_id], sub_ie_len));
-     } else {
-       ND_PRINT((ndo, "\n\t\t%s [ length = %d, ",
-               p_mlme_long_names[sub_id], sub_ie_len));
-     }
-   
-     if (ie_len < sub_ie_len) {
-       ND_PRINT((ndo, "[ERROR: Truncated IE data]"));
-       return;
-     }
-     if (sub_ie_len != 0) {
-       if (ndo->ndo_vflag > 3) {
-       ieee802_15_4_print_mlme_ie(ndo, p, sub_ie_len, sub_id);
-       } else if (ndo->ndo_vflag > 2) {
-       ND_PRINT((ndo, "IE Data = "));
-       for(i = 0; i < sub_ie_len; i++) {
-         ND_PRINT((ndo, "%02x ", EXTRACT_LE_8BITS(p + i)));
++      ND_PRINT("Upper layer data = ");
++      for(i = data_start; i < ie_len; i++) {
++              ND_PRINT("%02x ", EXTRACT_U_1(p + i));
 +      }
-       }
-     }
-     ND_PRINT((ndo, "] "));
-     p += sub_ie_len;
-     ie_len -= 2 + sub_ie_len;
-   } while (ie_len > 0);
-   return;
 +}
 +
 +/*
 + * Payload IE list parsing and printing. See 7.4.3 of 802.15.4-2015
 + * for more information.
 + *
 + * Returns number of byts consumed from the packet or -1 in case of error.
 + */
 +static int
 +ieee802_15_4_print_payload_ie_list(netdissect_options *ndo,
 +                                 const u_char *p,
 +                                 uint16_t caplen)
 +{
-   int len, ie, ie_len, group_id, i;
-   len = 0;
-   do {
-     if (caplen < 2) {
-       ND_PRINT((ndo, "[ERROR: Truncated header IE]"));
-       return -1;
-     }
-     /* Extract IE header */
-     ie = EXTRACT_LE_16BITS(p);
-     if ((CHECK_BIT(ie, 15)) == 0) {
-       ND_PRINT((ndo, "[ERROR: Payload IE with type 0] "));
-     }
-     ie_len = ie & 0x3ff;
-     group_id = (ie >> 11) & 0x0f;
-     /* Skip the IE header */
-     p += 2;
-     if (ie_len == 0) {
-       ND_PRINT((ndo, "\n\t%s [", p_ie_names[group_id]));
-     } else {
-       ND_PRINT((ndo, "\n\t%s [ length = %d, ",
-               p_ie_names[group_id], ie_len));
-     }
-     if (caplen < ie_len) {
-       ND_PRINT((ndo, "[ERROR: Truncated IE data]"));
-       return -1;
-     }
-     if (ndo->ndo_vflag > 3 && ie_len != 0) {
-       switch (group_id) {
-       case 0x1: /* MLME IE */
-       ieee802_15_4_print_mlme_ie_list(ndo, p, ie_len);
-       break;
-       case 0x2: /* Vendor Specific Nested IE */
-       if (ie_len < 3) {
-         ND_PRINT((ndo, "[ERROR: Vendor OUI missing]"));
-       } else {
-         ND_PRINT((ndo, "OUI = 0x%02x%02x%02x, ",
-                   EXTRACT_LE_8BITS(p),
-                   EXTRACT_LE_8BITS(p + 1),
-                   EXTRACT_LE_8BITS(p + 2)));
-         ND_PRINT((ndo, "Data = "));
-         for(i = 3; i < ie_len; i++) {
-           ND_PRINT((ndo, "%02x ", EXTRACT_LE_8BITS(p + i)));
-         }
-       }
-       break;
-       case 0x3: /* Multiplexed IE (802.15.9) */
-       if (ie_len < 1) {
-         ND_PRINT((ndo, "[ERROR: Transaction control byte missing]"));
-       } else {
-         int transfer_type, tid, fragment_number, data_start;
-         transfer_type = EXTRACT_LE_8BITS(p) & 0x7;
-         tid = EXTRACT_LE_8BITS(p) >> 3;
-         switch (transfer_type) {
-         case 0x00: /* Full upper layer frame. */
-         case 0x01: /* Full upper layer frame with small Multiplex ID. */
-           data_start = 1;
-           ND_PRINT((ndo, "Type = Full upper layer fragment%s, ",
-                     (transfer_type == 0x01 ?
-                      " with small Multiplex ID" : "")));
-           if (transfer_type == 0x00) {
-             if (ie_len < 3) {
-               ND_PRINT((ndo, "[ERROR: Multiplex ID missing]"));
-             } else {
-               data_start = 3;
-               ND_PRINT((ndo, "tid = 0x%02x, Multiplex ID = 0x%04x, ",
-                         tid, EXTRACT_LE_16BITS(p + 1)));
-             }
-           } else {
-             ND_PRINT((ndo, "Multiplex ID = 0x%04x, ", tid));
-           }
-           ND_PRINT((ndo, "Upper layer data = "));
-           for(i = data_start; i < ie_len; i++) {
-             ND_PRINT((ndo, "%02x ", EXTRACT_LE_8BITS(p + i)));
-           }
-           break;
-         case 0x02: /* First, or middle, Fragments */
-         case 0x04: /* Last fragment */
-           if (ie_len < 2) {
-             ND_PRINT((ndo, "[ERROR: fragment number missing]"));
-           } else {
-             fragment_number = EXTRACT_LE_8BITS(p + 1);
-             ND_PRINT((ndo, "Type = %s, tid = 0x%02x, fragment = 0x%02x, ",
-                       (transfer_type == 0x02 ?
-                        (fragment_number == 0 ?
-                         "First fragment" : "Middle fragment") :
-                        "Last fragment"), tid,
-                       fragment_number));
-             data_start = 2;
-             if (fragment_number == 0) {
-               if (ie_len < 6) {
-                 ND_PRINT((ndo, "[ERROR: Total upper layer size or multiplex ID missing]"));
++      int len, ie, ie_len, group_id, i;
++      
++      len = 0;
++      do {
+               if (caplen < 2) {
 -                      nd_print_trunc(ndo);
 -                      return hdrlen;
++                      ND_PRINT("[ERROR: Truncated header IE]");
++                      return -1;
+               }
 -              panid = EXTRACT_LE_U_2(p);
++              /* Extract IE header */
++              ie = EXTRACT_LE_U_2(p);
++              if ((CHECK_BIT(ie, 15)) == 0) {
++                      ND_PRINT("[ERROR: Payload IE with type 0] ");
++              }
++              ie_len = ie & 0x3ff;
++              group_id = (ie >> 11) & 0x0f;
++              
++              /* Skip the IE header */
+               p += 2;
 -              caplen -= 2;
 -              hdrlen += 2;
++              if (ie_len == 0) {
++                      ND_PRINT("\n\t%s [", p_ie_names[group_id]);
 +              } else {
-                 int total_size, multiplex_id;
-                 total_size = EXTRACT_LE_16BITS(p + 2);
-                 multiplex_id = EXTRACT_LE_16BITS(p + 4);
-                 ND_PRINT((ndo, "Total upper layer size = 0x%04x, Multiplex ID = 0x%04x, ",
-                           total_size, multiplex_id));
-               }
-               data_start = 6;
-             }
-             ND_PRINT((ndo, "Upper layer data = "));
-             for(i = data_start; i < ie_len; i++) {
-               ND_PRINT((ndo, "%02x ", EXTRACT_LE_8BITS(p + i)));
-             }
-           }
-           break;
-         case 0x06: /* Abort code */
-           if (ie_len == 1) {
-             ND_PRINT((ndo, "Type = Abort, tid = 0x%02x, no max size given",
-                       tid));
-           } else if (ie_len == 3) {
-             ND_PRINT((ndo, "Type = Abort, tid = 0x%02x, max size = 0x%04x",
-                       tid, EXTRACT_LE_16BITS(p + 1)));
-           } else {
-             ND_PRINT((ndo, "Type = Abort, tid = 0x%02x, invalid length = %d (not 1 or 3)",
-                       tid, ie_len));
-             ND_PRINT((ndo, "Abort data = "));
-             for(i = 1; i < ie_len; i++) {
-               ND_PRINT((ndo, "%02x ", EXTRACT_LE_8BITS(p + i)));
-             }
-           }
-           break;
-         case 0x03: /* Reserved */
-         case 0x05: /* Reserved */
-         case 0x07: /* Reserved */
-           ND_PRINT((ndo, "Type = %d (Reserved), tid = 0x%02x, ",
-                     transfer_type, tid));
-           ND_PRINT((ndo, "Upper layer data = "));
-           for(i = 1; i < ie_len; i++) {
-             ND_PRINT((ndo, "%02x ", EXTRACT_LE_8BITS(p + i)));
-           }
-           break;
-         }
-       }
-       break;
-       case 0x5: /* IETF IE */
-       if (ie_len < 1) {
-         ND_PRINT((ndo, "[ERROR: Subtype ID missing]"));
-       } else {        
-         ND_PRINT((ndo, "Subtype ID = 0x%02x, Subtype content = ",
-                   EXTRACT_LE_8BITS(p)));
-         for(i = 1; i < ie_len; i++) {
-           ND_PRINT((ndo, "%02x ", EXTRACT_LE_8BITS(p + i)));
-         }
-       }
-       break;
-       default:
-       ND_PRINT((ndo, "IE Data = "));
-       for(i = 0; i < ie_len; i++) {
-         ND_PRINT((ndo, "%02x ", EXTRACT_LE_8BITS(p + i)));
-       }
-       break;
-       }
-     } else {
-       if (ie_len != 0) {
-       ND_PRINT((ndo, "IE Data = "));
-       for(i = 0; i < ie_len; i++) {
-         ND_PRINT((ndo, "%02x ", EXTRACT_LE_8BITS(p + i)));
-       }
-       }
-     }
-     ND_PRINT((ndo, "]\n\t"));
-     len += 2 + ie_len;
-     p += ie_len;
-     caplen -= 2 + ie_len;
-     if (group_id == 0xf) {
-       break;
-     }
-   } while (caplen > 0);
-   return len;
++                      ND_PRINT("\n\t%s [ length = %d, ",
++                               p_ie_names[group_id], ie_len);
++              }
++              if (caplen < ie_len) {
++                      ND_PRINT("[ERROR: Truncated IE data]");
++                      return -1;
++              }
++              if (ndo->ndo_vflag > 3 && ie_len != 0) {
++                      switch (group_id) {
++                      case 0x1: /* MLME IE */
++                              ieee802_15_4_print_mlme_ie_list(ndo, p, ie_len);
++                              break;
++                      case 0x2: /* Vendor Specific Nested IE */
++                              if (ie_len < 3) {
++                                      ND_PRINT("[ERROR: Vendor OUI missing]");
++                              } else {
++                                      ND_PRINT("OUI = 0x%02x%02x%02x, ",
++                                               EXTRACT_U_1(p),
++                                               EXTRACT_U_1(p + 1),
++                                               EXTRACT_U_1(p + 2));
++                                      ND_PRINT("Data = ");
++                                      for(i = 3; i < ie_len; i++) {
++                                              ND_PRINT("%02x ",
++                                                       EXTRACT_U_1(p + i));
++                                      }
++                              }
++                              break;
++                      case 0x3: /* Multiplexed IE (802.15.9) */
++                              ieee802_15_4_print_mpx_ie(ndo, p, ie_len);
++                              break;
++                      case 0x5: /* IETF IE */
++                              if (ie_len < 1) {
++                                      ND_PRINT("[ERROR: Subtype ID missing]");
++                              } else {        
++                                      ND_PRINT("Subtype ID = 0x%02x, Subtype content = ",
++                                               EXTRACT_U_1(p));
++                                      for(i = 1; i < ie_len; i++) {
++                                              ND_PRINT("%02x ", EXTRACT_U_1(p + i));
++                                      }
++                              }
++                              break;
++                      default:
++                              ND_PRINT("IE Data = ");
++                              for(i = 0; i < ie_len; i++) {
++                                      ND_PRINT("%02x ", EXTRACT_U_1(p + i));
++                              }
++                              break;
++                      }
++              } else {
++                      if (ie_len != 0) {
++                              ND_PRINT("IE Data = ");
++                              for(i = 0; i < ie_len; i++) {
++                                      ND_PRINT("%02x ", EXTRACT_U_1(p + i));
++                              }
++                      }
++              }
++              ND_PRINT("]\n\t");
++              len += 2 + ie_len;
++              p += ie_len;
++              caplen -= 2 + ie_len;
++              if (group_id == 0xf) {
++                      break;
++              }
++      } while (caplen > 0);
++      return len;
 +}
 +
 +/*
 + * Parse and print auxiliary security header.
 + *
 + * Returns number of byts consumed from the packet or -1 in case of error.
 + */
 +static int
 +ieee802_15_4_print_aux_sec_header(netdissect_options *ndo,
 +                                const u_char *p,
 +                                uint16_t caplen,
 +                                int *security_level)
 +{
-   int sc, key_id_mode, len;
-   if (caplen < 1) {
-     ND_PRINT((ndo, "[ERROR: Truncated before Aux Security Header]"));
-     return -1;
-   }
-   sc = EXTRACT_LE_8BITS(p);
-   len = 1;
-   *security_level = sc & 0x7;
-   key_id_mode = (sc >> 3) & 0x3;
-   caplen -= 1;
-   p += 1;
-   if (ndo->ndo_vflag > 0) {
-     ND_PRINT((ndo, "\n\tSecurity Level %d, Key Id Mode %d, ",
-             *security_level, key_id_mode));
-   }
-   if ((CHECK_BIT(sc, 5)) == 0) {
-     if (caplen < 4) {
-       ND_PRINT((ndo, "[ERROR: Truncated before Frame Counter]"));
-       return -1;
-     }
-     len += 4;
-     caplen -= 4;
-     p += 4;
-     if (ndo->ndo_vflag > 1) {
-       ND_PRINT((ndo, "Frame Counter 0x%08x ",
-               EXTRACT_LE_32BITS(p + 1)));
-     }
-   }
-   switch (key_id_mode) {
-   case 0x00: /* Implicit. */
-     if (ndo->ndo_vflag > 1) {
-       ND_PRINT((ndo, "Implicit"));
-     }
-     return len;
-     break;
-   case 0x01: /* Key Index, nothing to print here. */
-     break;
-   case 0x02: /* PAN and Short address Key Source, and Key Index. */
-     if (caplen < 4) {
-       ND_PRINT((ndo, "[ERROR: Truncated before Key Source]"));
-       return -1;
-     }
-     if (ndo->ndo_vflag > 1) {
-       ND_PRINT((ndo, "KeySource 0x%04x:%0x4x, ",
-               EXTRACT_LE_16BITS(p), EXTRACT_LE_16BITS(p + 2)));
-     }
-     p += 4;
-     caplen -= 4;
-     len += 4;
-     break;
-   case 0x03: /* Extended address and Key Index. */
-     if (caplen < 8) {
-       ND_PRINT((ndo, "[ERROR: Truncated before Key Source]"));
-       return -1;
-     }
-     if (ndo->ndo_vflag > 1) {
-       ND_PRINT((ndo, "KeySource %s, ", le64addr_string(ndo, p)));
-     }
-     p += 4;
-     caplen -= 4;
-     len += 4;
-     break;
-   }
-   if (caplen < 1) {
-     ND_PRINT((ndo, "[ERROR: Truncated before Key Index]"));
-     return -1;
-   }
-   if (ndo->ndo_vflag > 1) {
-     ND_PRINT((ndo, "KeyIndex 0x%02x, ", EXTRACT_LE_8BITS(p)));
-   }
-   caplen -= 1;
-   p += 1;
-   len += 1;
-   return len;
++      int sc, key_id_mode, len;
++      
++      if (caplen < 1) {
++              ND_PRINT("[ERROR: Truncated before Aux Security Header]");
++              return -1;
++      }
++      sc = EXTRACT_U_1(p);
++      len = 1;
++      *security_level = sc & 0x7;
++      key_id_mode = (sc >> 3) & 0x3;
++      
++      caplen -= 1;
++      p += 1;
++      
++      if (ndo->ndo_vflag > 0) {
++              ND_PRINT("\n\tSecurity Level %d, Key Id Mode %d, ",
++                       *security_level, key_id_mode);
++      }
++      if ((CHECK_BIT(sc, 5)) == 0) {
++              if (caplen < 4) {
++                      ND_PRINT("[ERROR: Truncated before Frame Counter]");
++                      return -1;
++              }
++              len += 4;
++              caplen -= 4;
++              p += 4;
++              if (ndo->ndo_vflag > 1) {
++                      ND_PRINT("Frame Counter 0x%08x ",
++                               EXTRACT_LE_U_4(p + 1));
++              }
++      }
++      switch (key_id_mode) {
++      case 0x00: /* Implicit. */
++              if (ndo->ndo_vflag > 1) {
++                      ND_PRINT("Implicit");
++              }
++              return len;
++              break;
++      case 0x01: /* Key Index, nothing to print here. */
++              break;
++      case 0x02: /* PAN and Short address Key Source, and Key Index. */
++              if (caplen < 4) {
++                      ND_PRINT("[ERROR: Truncated before Key Source]");
++                      return -1;
++              }
++              if (ndo->ndo_vflag > 1) {
++                      ND_PRINT("KeySource 0x%04x:%0x4x, ",
++                               EXTRACT_LE_U_2(p), EXTRACT_LE_U_2(p + 2));
++              }
++              p += 4;
++              caplen -= 4;
++              len += 4;
++              break;
++      case 0x03: /* Extended address and Key Index. */
+               if (caplen < 8) {
 -                      nd_print_trunc(ndo);
 -                      return hdrlen;
++                      ND_PRINT("[ERROR: Truncated before Key Source]");
++                      return -1;
+               }
 -              if (ndo->ndo_vflag)
 -                      ND_PRINT("%04x:%s ", panid, le64addr_string(ndo, p));
 -              p += 8;
 -              caplen -= 8;
 -              hdrlen += 8;
++              if (ndo->ndo_vflag > 1) {
++                      ND_PRINT("KeySource %s, ", le64addr_string(ndo, p));
++              }
++              p += 4;
++              caplen -= 4;
++              len += 4;
+               break;
+       }
 -      if (ndo->ndo_vflag)
 -              ND_PRINT("< ");
++      if (caplen < 1) {
++              ND_PRINT("[ERROR: Truncated before Key Index]");
++              return -1;
++      }
++      if (ndo->ndo_vflag > 1) {
++              ND_PRINT("KeyIndex 0x%02x, ", EXTRACT_U_1(p));
++      }
++      caplen -= 1;
++      p += 1;
++      len += 1;
++      return len;
 +}
  
 -      /*
 -       * Source address and PAN ID, if present.
 -       */
 -      switch (FC_SRC_ADDRESSING_MODE(fc)) {
 -      case FC_ADDRESSING_MODE_NONE:
 -              if (ndo->ndo_vflag)
 -                      ND_PRINT("none ");
 +/*
 + * Print command data.
 + *
 + * Returns number of byts consumed from the packet or -1 in case of error.
 + */
 +static int
 +ieee802_15_4_print_command_data(netdissect_options *ndo,
 +                              uint8_t command_id,
 +                              const u_char *p,
 +                              u_int caplen)
 +{
-   u_int i;
-   switch (command_id) {
-   case 0x01: /* Assocation Request */
-     if (caplen != 1) {
-       ND_PRINT((ndo, "Invalid Assocation request command length"));
-       return -1;
-     } else {
-       uint8_t cap_info;
-       cap_info = EXTRACT_LE_8BITS(p);
-       ND_PRINT((ndo, "%s%s%s%s%s%s",
-               ((cap_info & 0x02) ? "FFD, " : "RFD, "),
-               ((cap_info & 0x04) ? "AC powered, " : ""),
-               ((cap_info & 0x08) ? "Receiver on when idle, " : ""),
-               ((cap_info & 0x10) ? "Fast association, " : ""),
-               ((cap_info & 0x40) ? "Security supported, " : ""),
-               ((cap_info & 0x80) ? "Allocate address, " : "")));
-       return caplen;
-     }
-     break;
-   case 0x02: /* Assocation Response */
-     if (caplen != 3) {
-       ND_PRINT((ndo, "Invalid Assocation response command length"));
-       return -1;
-     } else {
-       ND_PRINT((ndo, "Short address = "));
-       ieee802_15_4_print_addr(ndo, p, 2);
-       switch (EXTRACT_LE_8BITS(p + 2)) {
-       case 0x00:
-       ND_PRINT((ndo, ", Association successful"));
-       break;
-       case 0x01:
-       ND_PRINT((ndo, ", PAN at capacity"));
-       break;
-       case 0x02:
-       ND_PRINT((ndo, ", PAN access denied"));
-       break;
-       case 0x03:
-       ND_PRINT((ndo, ", Hooping sequence offset duplication"));
-       break;
-       case 0x80:
-       ND_PRINT((ndo, ", Fast association successful"));
-       break;
-       default:
-       ND_PRINT((ndo, ", Status = 0x%02x", EXTRACT_LE_8BITS(p + 2)));
-       break;
-       }
-       return caplen;
-     }
-     break;
-   case 0x03: /* Diassociation Notification command */
-     if (caplen != 1) {
-       ND_PRINT((ndo, "Invalid Disassociation Notification command length"));
-       return -1;
-     } else {
-       switch (EXTRACT_LE_8BITS(p)) {
-       case 0x00:
-       ND_PRINT((ndo, "Reserved"));
-       break;
-       case 0x01:
-       ND_PRINT((ndo, "Reason = The coordinator wishes the device to leave PAN"));
-       break;
-       case 0x02:
-       ND_PRINT((ndo, "Reason = The device wishes to leave the PAN"));
-       break;
-       default:
-       ND_PRINT((ndo, "Reason = 0x%02x", EXTRACT_LE_8BITS(p + 2)));
-       break;
-       }
-       return caplen;
-     }
++      u_int i;
 +      
-     /* Following ones do not have any data. */
-   case 0x04: /* Data Request command */
-   case 0x05: /* PAN ID Conflict Notification command */
-   case 0x06: /* Orphan Notification command */
-   case 0x07: /* Beacon Request command */
-     /* Should not have any data. */
-     return 0;
-   case 0x08: /* Coordinator Realignment command */
-     if (caplen < 7 || caplen > 8) {
-       ND_PRINT((ndo, "Invalid Coordinator Realignment command length"));
-       return -1;
-     } else {
-       uint16_t channel, page;
-       ND_PRINT((ndo, "Pan ID = 0x%04x, Coordinator short address = ",
-               EXTRACT_LE_16BITS(p)));
-       ieee802_15_4_print_addr(ndo, p + 2, 2);
-       channel = EXTRACT_LE_8BITS(p + 4);
-       if (caplen == 8) {
-       page = EXTRACT_LE_8BITS(p + 7);
-       } else {
-       page = 0x80;
-       }
-       if (CHECK_BIT(page, 7)) {
-       /* No page present, instead we have msb of
-          channel in the page. */
-       channel |= (page & 0x7f) << 8;
-       ND_PRINT((ndo, ", Channel Number = %d", channel));
-       } else {
-       ND_PRINT((ndo, ", Channel Number = %d, page = %d",
-                 channel, page));
-       }
-       ND_PRINT((ndo, ", Short address = "));
-       ieee802_15_4_print_addr(ndo, p + 5, 2);
-       return caplen;
-     }
-     break;
-   case 0x09: /* GTS Request command */
-     if (caplen != 1) {
-       ND_PRINT((ndo, "Invalid GTS Request command length"));
-       return -1;
-     } else {
-       uint8_t gts;
-       gts = EXTRACT_LE_8BITS(p);
-       ND_PRINT((ndo, "GTS Length = %d, %s, %s",
-               gts & 0xf,
-               (CHECK_BIT(gts, 4) ? "Receive-only GTS" : "Transmit-only GTS"),
-               (CHECK_BIT(gts, 5) ? "GTS allocation" : "GTS deallocations")));
-       return caplen;
-     }
-     break;
-   case 0x13: /* DSME Association Request command */
-     /* XXX Not implemented */
-   case 0x14: /* DSME Association Response command */
-     /* XXX Not implemented */
-   case 0x15: /* DSME GTS Request command */
-     /* XXX Not implemented */
-   case 0x16: /* DSME GTS Response command */
-     /* XXX Not implemented */
-   case 0x17: /* DSME GTS GTS Notify command */
-     /* XXX Not implemented */
-   case 0x18: /* DSME Information Request command */
-     /* XXX Not implemented */
-   case 0x19: /* DSME Information Response command */
-     /* XXX Not implemented */
-   case 0x1a: /* DSME Beacon Allocation Notification command */
-     /* XXX Not implemented */
-   case 0x1b: /* DSME Beacon Collision Notification command */
-     /* XXX Not implemented */
-   case 0x1c: /* DSME Link Report command */
-     /* XXX Not implemented */
-   case 0x20: /* RIT Data Request command */
-     /* XXX Not implemented */
-   case 0x21: /* DBS Request command */
-     /* XXX Not implemented */
-   case 0x22: /* DBS Response command */
-     /* XXX Not implemented */
-   case 0x23: /* RIT Data Response command */
-     /* XXX Not implemented */
-   case 0x24: /* Vendor Specific command */
-     /* XXX Not implemented */
-   case 0x0a: /* TRLE Management Request command */
-     /* XXX Not implemented */
-   case 0x0b: /* TRLE Management Response command */
-     /* XXX Not implemented */
-   default:
-     ND_PRINT((ndo, "Command Data = "));
-     for(i = 0; i < caplen; i++) {
-       ND_PRINT((ndo, "%02x ", EXTRACT_LE_8BITS(p + i)));
-     }
-     break;
-   }
-   return 0;
++      switch (command_id) {
++      case 0x01: /* Assocation Request */
++              if (caplen != 1) {
++                      ND_PRINT("Invalid Assocation request command length");
++                      return -1;
++              } else {
++                      uint8_t cap_info;
++                      cap_info = EXTRACT_U_1(p);
++                      ND_PRINT("%s%s%s%s%s%s",
++                               ((cap_info & 0x02) ?
++                                "FFD, " : "RFD, "),
++                               ((cap_info & 0x04) ?
++                                "AC powered, " : ""),
++                               ((cap_info & 0x08) ?
++                                "Receiver on when idle, " : ""),
++                               ((cap_info & 0x10) ?
++                                "Fast association, " : ""),
++                               ((cap_info & 0x40) ?
++                                "Security supported, " : ""),
++                               ((cap_info & 0x80) ?
++                                "Allocate address, " : ""));
++                      return caplen;
++              }
+               break;
 -      case FC_ADDRESSING_MODE_RESERVED:
++      case 0x02: /* Assocation Response */
++              if (caplen != 3) {
++                      ND_PRINT("Invalid Assocation response command length");
++                      return -1;
++              } else {
++                      ND_PRINT("Short address = ");
++                      ieee802_15_4_print_addr(ndo, p, 2);
++                      switch (EXTRACT_U_1(p + 2)) {
++                      case 0x00:
++                              ND_PRINT(", Association successful");
++                              break;
++                      case 0x01:
++                              ND_PRINT(", PAN at capacity");
++                              break;
++                      case 0x02:
++                              ND_PRINT(", PAN access denied");
++                              break;
++                      case 0x03:
++                              ND_PRINT(", Hooping sequence offset duplication");
++                              break;
++                      case 0x80:
++                              ND_PRINT(", Fast association successful");
++                              break;
++                      default:
++                              ND_PRINT(", Status = 0x%02x",
++                                       EXTRACT_U_1(p + 2));
++                              break;
++                      }
++                      return caplen;
++              }
++              break;
++      case 0x03: /* Diassociation Notification command */
++              if (caplen != 1) {
++                      ND_PRINT("Invalid Disassociation Notification command length");
++                      return -1;
++              } else {
++                      switch (EXTRACT_U_1(p)) {
++                      case 0x00:
++                              ND_PRINT("Reserved");
++                              break;
++                      case 0x01:
++                              ND_PRINT("Reason = The coordinator wishes the device to leave PAN");
++                              break;
++                      case 0x02:
++                              ND_PRINT("Reason = The device wishes to leave the PAN");
++                              break;
++                      default:
++                              ND_PRINT("Reason = 0x%02x", EXTRACT_U_1(p + 2));
++                              break;
++                      }
++                      return caplen;
++              }
++              
++              /* Following ones do not have any data. */
++      case 0x04: /* Data Request command */
++      case 0x05: /* PAN ID Conflict Notification command */
++      case 0x06: /* Orphan Notification command */
++      case 0x07: /* Beacon Request command */
++              /* Should not have any data. */
++              return 0;
++      case 0x08: /* Coordinator Realignment command */
++              if (caplen < 7 || caplen > 8) {
++                      ND_PRINT("Invalid Coordinator Realignment command length");
++                      return -1;
++              } else {
++                      uint16_t channel, page;
++                      
++                      ND_PRINT("Pan ID = 0x%04x, Coordinator short address = ",
++                               EXTRACT_LE_U_2(p));
++                      ieee802_15_4_print_addr(ndo, p + 2, 2);
++                      channel = EXTRACT_U_1(p + 4);
++                      
++                      if (caplen == 8) {
++                              page = EXTRACT_U_1(p + 7);
++                      } else {
++                              page = 0x80;
++                      }
++                      if (CHECK_BIT(page, 7)) {
++                              /* No page present, instead we have msb of
++                                 channel in the page. */
++                              channel |= (page & 0x7f) << 8;
++                              ND_PRINT(", Channel Number = %d", channel);
++                      } else {
++                              ND_PRINT(", Channel Number = %d, page = %d",
++                                       channel, page);
++                      }
++                      ND_PRINT(", Short address = ");
++                      ieee802_15_4_print_addr(ndo, p + 5, 2);
++                      return caplen;
++              }
++              break;
++      case 0x09: /* GTS Request command */
++              if (caplen != 1) {
++                      ND_PRINT("Invalid GTS Request command length");
++                      return -1;
++              } else {
++                      uint8_t gts;
++                      
++                      gts = EXTRACT_U_1(p);
++                      ND_PRINT("GTS Length = %d, %s, %s",
++                               gts & 0xf,
++                               (CHECK_BIT(gts, 4) ?
++                                "Receive-only GTS" : "Transmit-only GTS"),
++                               (CHECK_BIT(gts, 5) ?
++                                "GTS allocation" : "GTS deallocations"));
++                      return caplen;
++              }
++              break;
++      case 0x13: /* DSME Association Request command */
++              /* XXX Not implemented */
++      case 0x14: /* DSME Association Response command */
++              /* XXX Not implemented */
++      case 0x15: /* DSME GTS Request command */
++              /* XXX Not implemented */
++      case 0x16: /* DSME GTS Response command */
++              /* XXX Not implemented */
++      case 0x17: /* DSME GTS GTS Notify command */
++              /* XXX Not implemented */
++      case 0x18: /* DSME Information Request command */
++              /* XXX Not implemented */
++      case 0x19: /* DSME Information Response command */
++              /* XXX Not implemented */
++      case 0x1a: /* DSME Beacon Allocation Notification command */
++              /* XXX Not implemented */
++      case 0x1b: /* DSME Beacon Collision Notification command */
++              /* XXX Not implemented */
++      case 0x1c: /* DSME Link Report command */
++              /* XXX Not implemented */
++      case 0x20: /* RIT Data Request command */
++              /* XXX Not implemented */
++      case 0x21: /* DBS Request command */
++              /* XXX Not implemented */
++      case 0x22: /* DBS Response command */
++              /* XXX Not implemented */
++      case 0x23: /* RIT Data Response command */
++              /* XXX Not implemented */
++      case 0x24: /* Vendor Specific command */
++              /* XXX Not implemented */
++      case 0x0a: /* TRLE Management Request command */
++              /* XXX Not implemented */
++      case 0x0b: /* TRLE Management Response command */
++              /* XXX Not implemented */
++      default:
++              ND_PRINT("Command Data = ");
++              for(i = 0; i < caplen; i++) {
++                      ND_PRINT("%02x ", EXTRACT_U_1(p + i));
++              }
++              break;
++      }
++      return 0;
 +}
 +
 +/*
 + * Parse and print frames folloing standard format.
 + *
 + * Returns FALSE in case of error.
 + */
 +static u_int
 +ieee802_15_4_std_frames(netdissect_options *ndo,
 +                      const u_char *p, u_int caplen,
 +                      uint16_t fc)
 +{
-   int len, frame_version, pan_id_comp;
-   int frame_type;
-   int src_pan, dst_pan, src_addr_len, dst_addr_len;
-   int security_level, miclen = 0;
-   int payload_ie_present;
-   uint8_t seq, fcs_len;
-   uint32_t fcs, crc_check;
-   const u_char *mic_start = NULL;
-   payload_ie_present = 0;
-   /* Assume 2 octet FCS, the FCS length depends on the PHY, and we do not
-      know about that. */
-   if (caplen < 2) {
-     /* Cannot have FCS, assume fcs_len of 0. */
-     fcs_len = 0;
-     fcs = 0;
-   } else {
-     fcs_len = 2;
-     fcs = EXTRACT_LE_16BITS(p + caplen - 2);
-     crc_check = ieee802_15_4_crc16(p, caplen - 2);
-     if (crc_check != fcs) {
-       /* Wrong fcs, might not contain fcs, do not remove it. */
-     } else {
-       /* Remove FCS */
-       caplen -= fcs_len;
-     }
-   }
-   /* Frame version. */
-   frame_version = (fc >> 12) & 0x03;
-   frame_type = fc & 0x7;
-   ND_PRINT((ndo, "v%d ", frame_version));
-   if (ndo->ndo_vflag > 2) {
-     if (CHECK_BIT(fc, 3)) { ND_PRINT((ndo, "Security Enabled, ")); }
-     if (CHECK_BIT(fc, 4)) { ND_PRINT((ndo, "Frame Pending, ")); }
-     if (CHECK_BIT(fc, 5)) { ND_PRINT((ndo, "AR, ")); }
-     if (CHECK_BIT(fc, 6)) { ND_PRINT((ndo, "PAN ID Compression, ")); }
-     if (CHECK_BIT(fc, 8)) { ND_PRINT((ndo, "Sequence Number Suppression, ")); }
-     if (CHECK_BIT(fc, 9)) { ND_PRINT((ndo, "IE present, ")); }
-   }
-   /* Check for the sequence number supression. */
-   if (CHECK_BIT(fc, 8)) {
-     /* Sequence number is suppressed. */
-     if (frame_version < 2) {
-       /* Sequence number can only be supressed for frame
-        version 2 or higher, this is invalid frame. */
-       ND_PRINT((ndo, "[ERROR: Sequence number suppressed on frames where version < 2]"));
-     }
-     if (ndo->ndo_vflag)
-       ND_PRINT((ndo,"seq suppressed "));
-     p += 2;
-     caplen -= 2;
-   } else {
-     seq = EXTRACT_LE_8BITS(p + 2);
-     p += 3;
-     caplen -= 3;
-     if (ndo->ndo_vflag)
-       ND_PRINT((ndo,"seq %02x ", seq));
-   }
-   /* See which parts of addresses we have. */
-   dst_addr_len = ieee802_15_4_addr_len((fc >> 10) & 0x3);
-   src_addr_len = ieee802_15_4_addr_len((fc >> 14) & 0x3);
-   if (src_addr_len < 0) {
-     ND_PRINT((ndo,"[ERROR: Invalid src address mode]"));
-     return 0;
-   }
-   if (dst_addr_len < 0) {
-     ND_PRINT((ndo,"[ERROR: Invalid dst address mode]"));
-     return 0;
-   }
-   src_pan = 0;
-   dst_pan = 0;
-   pan_id_comp = CHECK_BIT(fc, 6);
-   /* The PAN ID Compression rules are complicated. */
-   /* First check old versions, where the rules are simple. */
-   if (frame_version < 2) {
-     if (pan_id_comp) {
-       src_pan = 0;
-       dst_pan = 1;
-       if (dst_addr_len <= 0 || src_addr_len <= 0) {
-       /* Invalid frame, PAN ID Compression must be 0
-          if only one address in the frame. */
-       ND_PRINT((ndo,"[ERROR: PAN ID Compression != 0, and only one address with frame version < 2]"));
-       }
-     } else {
-       src_pan = 1;
-       dst_pan = 1;
-     }
-     if (dst_addr_len <= 0) {
-       dst_pan = 0;
-     }
-     if (src_addr_len <= 0) {
-       src_pan = 0;
-     }
-   } else {
-     /* Frame version 2 rules are more complicated, and they depend
-        on the address modes of the frame, generic rules are same,
-        but then there are some special cases. */
-     if (pan_id_comp) {
-       src_pan = 0;
-       dst_pan = 1;
-     } else {
-       src_pan = 1;
-       dst_pan = 1;
-     }
-     if (dst_addr_len <= 0) {
-       dst_pan = 0;
-     }
-     if (src_addr_len <= 0) {
-       src_pan = 0;
-     }
-     if (pan_id_comp) {
-       if (src_addr_len == 0 &&
-         dst_addr_len == 0) {
-       /* Both addresses are missing, but PAN ID
-          compression set, special case we have
-          destination PAN but no addresses. */
-       dst_pan = 1;
-       } else if ((src_addr_len == 0 &&
-                 dst_addr_len > 0) ||
-                (src_addr_len > 0 &&
-                 dst_addr_len == 0)) {
-       /* Only one address present, and PAN ID
-          compression is set, we do not have PAN id at
-          all. */
-       dst_pan = 0;
++      int len, frame_version, pan_id_comp;
++      int frame_type;
++      int src_pan, dst_pan, src_addr_len, dst_addr_len;
++      int security_level, miclen = 0;
++      int payload_ie_present;
++      uint8_t seq;
++      uint32_t fcs, crc_check;
++      const u_char *mic_start = NULL;
++      
++      payload_ie_present = 0;
++      
++      /* Assume 2 octet FCS, the FCS length depends on the PHY, and we do not
++         know about that. */
++      if (caplen < 4) {
++              /* Cannot have FCS, assume no FCS. */
++              fcs = 0;
++      } else {
++              /* Test for 4 octet FCS. */
++              fcs = EXTRACT_LE_U_4(p + caplen - 4);
++              crc_check = ieee802_15_4_crc32(p, caplen - 4);
++              if (crc_check == fcs) {
++                      /* Remove FCS */
++                      caplen -= 4;
++              } else {
++                      /* Test for 2 octet FCS. */
++                      fcs = EXTRACT_LE_U_2(p + caplen - 2);
++                      crc_check = ieee802_15_4_crc16(p, caplen - 2);
++                      if (crc_check == fcs) {
++                              /* Remove FCS */
++                              caplen -= 2;
++                      } else {
++                              /* Wrong FCS, FCS might not be included in the
++                                 captured frame, do not remove it. */
++                      }
++              }
++      }
++      
++      /* Frame version. */
++      frame_version = FC_FRAME_VERSION(fc);
++      frame_type = FC_FRAME_TYPE(fc);
++      ND_PRINT("v%d ", frame_version);
++      
++      if (ndo->ndo_vflag > 2) {
++              if (CHECK_BIT(fc, 3)) { ND_PRINT("Security Enabled, "); }
++              if (CHECK_BIT(fc, 4)) { ND_PRINT("Frame Pending, "); }
++              if (CHECK_BIT(fc, 5)) { ND_PRINT("AR, "); }
++              if (CHECK_BIT(fc, 6)) { ND_PRINT("PAN ID Compression, "); }
++              if (CHECK_BIT(fc, 8)) { ND_PRINT("Sequence Number Suppression, "); }
++              if (CHECK_BIT(fc, 9)) { ND_PRINT("IE present, "); }
++      }
++      
++      /* Check for the sequence number supression. */
++      if (CHECK_BIT(fc, 8)) {
++              /* Sequence number is suppressed. */
++              if (frame_version < 2) {
++                      /* Sequence number can only be supressed for frame
++                         version 2 or higher, this is invalid frame. */
++                      ND_PRINT("[ERROR: Sequence number suppressed on frames where version < 2]");
++              }
++              if (ndo->ndo_vflag)
++                      ND_PRINT("seq suppressed ");
++              p += 2;
++              caplen -= 2;
++      } else {
++              seq = EXTRACT_U_1(p + 2);
++              p += 3;
++              caplen -= 3;
+               if (ndo->ndo_vflag)
 -                      ND_PRINT("reserved source addressing mode");
++                      ND_PRINT("seq %02x ", seq);
++      }
++      
++      /* See which parts of addresses we have. */
++      dst_addr_len = ieee802_15_4_addr_len((fc >> 10) & 0x3);
++      src_addr_len = ieee802_15_4_addr_len((fc >> 14) & 0x3);
++      if (src_addr_len < 0) {
++              ND_PRINT("[ERROR: Invalid src address mode]");
+               return 0;
 -      case FC_ADDRESSING_MODE_SHORT:
 -              if (!(fc & FC_PAN_ID_COMPRESSION)) {
 -                      /*
 -                       * The source PAN ID is not compressed out, so
 -                       * fetch it.  (Otherwise, we'll use the destination
 -                       * PAN ID, fetched above.)
 -                       */
 -                      if (caplen < 2) {
 -                              nd_print_trunc(ndo);
 -                              return hdrlen;
++      }
++      if (dst_addr_len < 0) {
++              ND_PRINT("[ERROR: Invalid dst address mode]");
++              return 0;
++      }
 +      src_pan = 0;
-       } else if (src_addr_len == 8 &&
-                dst_addr_len == 8) {
-       /* Both addresses are Extended, and PAN ID
-          compression set, we do not have PAN ID at
-          all. */
 +      dst_pan = 0;
-       src_pan = 0;
-       }
-     } else {
-       /* Special cases where PAN ID Compression is not set. */
-       if (src_addr_len == 8 &&
-         dst_addr_len == 8) {
-       /* Both addresses are Extended, and PAN ID
-          compression not set, we do have only one PAN
-          ID (destination). */
-       dst_pan = 1;
-       src_pan = 0;
-       }
++      pan_id_comp = CHECK_BIT(fc, 6);
++      
++      /* The PAN ID Compression rules are complicated. */
++      
++      /* First check old versions, where the rules are simple. */
++      if (frame_version < 2) {
++              if (pan_id_comp) {
++                      src_pan = 0;
++                      dst_pan = 1;
++                      if (dst_addr_len <= 0 || src_addr_len <= 0) {
++                              /* Invalid frame, PAN ID Compression must be 0
++                                 if only one address in the frame. */
++                              ND_PRINT("[ERROR: PAN ID Compression != 0, and only one address with frame version < 2]");
+                       }
 -                      panid = EXTRACT_LE_U_2(p);
 -                      p += 2;
 -                      caplen -= 2;
 -                      hdrlen += 2;
++              } else {
++                      src_pan = 1;
++                      dst_pan = 1;
++              }
++              if (dst_addr_len <= 0) {
++                      dst_pan = 0;
++              }
++              if (src_addr_len <= 0) {
++                      src_pan = 0;
++              }
++      } else {
++              /* Frame version 2 rules are more complicated, and they depend
++                 on the address modes of the frame, generic rules are same,
++                 but then there are some special cases. */
++              if (pan_id_comp) {
++                      src_pan = 0;
++                      dst_pan = 1;
++              } else {
++                      src_pan = 1;
++                      dst_pan = 1;
++              }
++              if (dst_addr_len <= 0) {
++                      dst_pan = 0;
++              }
++              if (src_addr_len <= 0) {
++                      src_pan = 0;
+               }
++              if (pan_id_comp) {
++                      if (src_addr_len == 0 &&
++                          dst_addr_len == 0) {
++                              /* Both addresses are missing, but PAN ID
++                                 compression set, special case we have
++                                 destination PAN but no addresses. */
++                              dst_pan = 1;
++                      } else if ((src_addr_len == 0 &&
++                                  dst_addr_len > 0) ||
++                                 (src_addr_len > 0 &&
++                                  dst_addr_len == 0)) {
++                              /* Only one address present, and PAN ID
++                                 compression is set, we do not have PAN id at
++                                 all. */
++                              dst_pan = 0;
++                              src_pan = 0;
++                      } else if (src_addr_len == 8 &&
++                                 dst_addr_len == 8) {
++                              /* Both addresses are Extended, and PAN ID
++                                 compression set, we do not have PAN ID at
++                                 all. */
++                              dst_pan = 0;
++                              src_pan = 0;
++                      }
++              } else {
++                      /* Special cases where PAN ID Compression is not set. */
++                      if (src_addr_len == 8 &&
++                          dst_addr_len == 8) {
++                              /* Both addresses are Extended, and PAN ID
++                                 compression not set, we do have only one PAN
++                                 ID (destination). */
++                              dst_pan = 1;
++                              src_pan = 0;
++                      }
 +#ifdef BROKEN_6TISCH_PAN_ID_COMPRESSION
-       if (src_addr_len == 8 &&
-         dst_addr_len == 2) {
-       /* Special case for the broken 6tisch
-          implementations. */
-       src_pan = 0;
-       }
++                      if (src_addr_len == 8 &&
++                          dst_addr_len == 2) {
++                              /* Special case for the broken 6tisch
++                                 implementations. */
++                              src_pan = 0;
++                      }
 +#endif /* BROKEN_6TISCH_PAN_ID_COMPRESSION */
-     }
-   }
-   /* Print dst PAN and address. */
-   if (dst_pan) {
-     if (caplen < 2) {
-       ND_PRINT((ndo, "[ERROR: Truncated before dst_pan]"));
-       return 0;
-     }
-     ND_PRINT((ndo, "%04x:", EXTRACT_LE_16BITS(p)));
-     p += 2;
-     caplen -= 2;
-   } else {
-     ND_PRINT((ndo, "-:"));
-   }
-   if (caplen < (u_int) dst_addr_len) {
-     ND_PRINT((ndo, "[ERROR: Truncated before dst_addr]"));
-     return 0;
-   }
-   ieee802_15_4_print_addr(ndo, p, dst_addr_len);
-   p += dst_addr_len;
-   caplen -= dst_addr_len;
-   ND_PRINT((ndo," < "));
-   /* Print src PAN and address. */
-   if (src_pan) {
-     if (caplen < 2) {
-       ND_PRINT((ndo, "[ERROR: Truncated before dst_pan]"));
-       return 0;
-     }
-     ND_PRINT((ndo, "%04x:", EXTRACT_LE_16BITS(p)));
-     p += 2;
-     caplen -= 2;
-   } else {
-     ND_PRINT((ndo, "-:"));
-   }
-   if (caplen < (u_int) src_addr_len) {
-     ND_PRINT((ndo, "[ERROR: Truncated before dst_addr]"));
-     return 0;
-   }
-   ieee802_15_4_print_addr(ndo, p, src_addr_len);
-   ND_PRINT((ndo, " "));
-   p += src_addr_len;
-   caplen -= src_addr_len;
-   if (CHECK_BIT(fc, 3)) {
-     len = ieee802_15_4_print_aux_sec_header(ndo, p, caplen, &security_level);
-     if (len < 0) {
-       return 0;
-     }
-     p += len;
-     caplen -= len;
-   } else {
-     security_level = 0;
-   }
-   switch (security_level) {
-   case 0: /*FALLTHOUGH */
-   case 4:
-     miclen = 0;
-     break;
-   case 1: /*FALLTHOUGH */
-   case 5:
-     miclen = 4;
-     break;
-   case 2: /*FALLTHOUGH */
-   case 6:
-     miclen = 8;
-     break;
-   case 3: /*FALLTHOUGH */
-   case 7:
-     miclen = 16;
-     break;
-   }
-   /* Remove MIC */
-   if (miclen > 0) {
-     if (caplen < (u_int) miclen) {
-       ND_PRINT((ndo, "[ERROR: Truncated before MIC]"));
-       return 0;
-     }
-     caplen -= miclen;
-     mic_start = p + caplen;
-   }
-   /* Parse Information elements if present */
-   if (CHECK_BIT(fc, 9)) {
-     /* Yes we have those. */
-     len = ieee802_15_4_print_header_ie_list(ndo, p, caplen,
-                                           &payload_ie_present);
-     if (len < 0) {
-       return 0;
-     }
-     p += len;
-     caplen -= len;
-   }
-   if (payload_ie_present) {
-     if (security_level >= 4) {
-       ND_PRINT((ndo, "Payload IEs present, but encrypted, cannot print "));
-     } else {
-       len = ieee802_15_4_print_payload_ie_list(ndo, p, caplen);
-       if (len < 0) {
-       return 0;
-       }
-       p += len;
-       caplen -= len;
-     }
-   }
-   /* Print MIC */
-   if (ndo->ndo_vflag > 2 && miclen != 0) {
-     ND_PRINT((ndo, "\n\tMIC "));
++              }
++      }
 +      
-     for(len = 0; len < miclen; len += 4) {
-       ND_PRINT((ndo, "%08x", EXTRACT_32BITS(mic_start + len)));
-     }
-     ND_PRINT((ndo, " "));
-   }
-   /* Print FCS */
-   if (ndo->ndo_vflag > 2) {
-     if (crc_check == fcs) {
-       ND_PRINT((ndo, "FCS %04x ", fcs));
-     } else {
-       ND_PRINT((ndo, "wrong FCS %04x vs %04x (assume no FCS stored) ",
-               fcs, crc_check));
-     }
-   }
-   /* Payload print */
-   switch (frame_type) {
-   case 0x00: /* Beacon */
-     if (frame_version < 2) {
-       if (caplen < 2) {
-       ND_PRINT((ndo, "[ERROR: Truncated before beacon information]"));
-       break;
-       } else {
-       uint16_t ss;
-                       
-       ss = EXTRACT_LE_16BITS(p);
-       ieee802_15_4_print_superframe_specification(ndo, ss);
-       p += 2;
-       caplen -= 2;
-       /* GTS */
-       if (caplen < 1) {
-         ND_PRINT((ndo, "[ERROR: Truncated before GTS info]"));
-         break;
++      /* Print dst PAN and address. */
++      if (dst_pan) {
+               if (caplen < 2) {
 -                      nd_print_trunc(ndo);
 -                      return hdrlen;
++                      ND_PRINT("[ERROR: Truncated before dst_pan]");
++                      return 0;
+               }
 -              if (ndo->ndo_vflag)
 -                      ND_PRINT("%04x:%04x ", panid, EXTRACT_LE_U_2(p));
++              ND_PRINT("%04x:", EXTRACT_LE_U_2(p));
++              p += 2;
++              caplen -= 2;
++      } else {
++              ND_PRINT("-:");
 +      }
-                               
-       len = ieee802_15_4_print_gts_info(ndo, p, caplen);
-       if (len < 0) {
-         break;
++      if (caplen < (u_int) dst_addr_len) {
++              ND_PRINT("[ERROR: Truncated before dst_addr]");
++              return 0;
 +      }
-       p += len;
-       caplen -= len;
-                       
-       /* Pending Addresses */
-       if (caplen < 1) {
-         ND_PRINT((ndo, "[ERROR: Truncated before pending addresses]"));
-         break;
++      ieee802_15_4_print_addr(ndo, p, dst_addr_len);
++      p += dst_addr_len;
++      caplen -= dst_addr_len;
++      
++      ND_PRINT(" < ");
++      
++      /* Print src PAN and address. */
++      if (src_pan) {
++              if (caplen < 2) {
++                      ND_PRINT("[ERROR: Truncated before dst_pan]");
++                      return 0;
++              }
++              ND_PRINT("%04x:", EXTRACT_LE_U_2(p));
+               p += 2;
+               caplen -= 2;
 -              hdrlen += 2;
 -              break;
 -      case FC_ADDRESSING_MODE_LONG:
 -              if (!(fc & FC_PAN_ID_COMPRESSION)) {
 -                      /*
 -                       * The source PAN ID is not compressed out, so
 -                       * fetch it.  (Otherwise, we'll use the destination
 -                       * PAN ID, fetched above.)
 -                       */
++      } else {
++              ND_PRINT("-:");
 +      }
-       len = ieee802_15_4_print_pending_addresses(ndo, p, caplen);
-       if (len < 0) {
-         break;
++      if (caplen < (u_int) src_addr_len) {
++              ND_PRINT("[ERROR: Truncated before dst_addr]");
++              return 0;
 +      }
-       p += len;
-       caplen -= len;
-       }
-     }
-     if (!ndo->ndo_suppress_default_print)
-       ND_DEFAULTPRINT(p, caplen);
-     break;
-   case 0x01: /* Data */
-   case 0x02: /* Acknowledgement */
-     if (!ndo->ndo_suppress_default_print)
-       ND_DEFAULTPRINT(p, caplen);
-     break;
-   case 0x03: /* MAC Command */
-     if (caplen < 1) {
-       ND_PRINT((ndo, "[ERROR: Truncated before Command ID]"));
-     } else {
-       uint8_t command_id;
-       command_id = EXTRACT_LE_8BITS(p);
-       if (command_id >= 0x30) {
-       ND_PRINT((ndo, "Command ID = Reserved 0x%02x ", command_id));
-       } else {
-       ND_PRINT((ndo, "Command ID = %s ", mac_c_names[command_id]));
-       }
-       p++;
-       caplen--;
-       if (caplen != 0) {
-       len = ieee802_15_4_print_command_data(ndo, command_id, p, caplen);
-       if (len >= 0) {
-         p += len;
-         caplen -= len;
++      ieee802_15_4_print_addr(ndo, p, src_addr_len);
++      ND_PRINT(" ");
++      p += src_addr_len;
++      caplen -= src_addr_len;
++      if (CHECK_BIT(fc, 3)) {
++              len = ieee802_15_4_print_aux_sec_header(ndo, p, caplen,
++                                                      &security_level);
++              if (len < 0) {
++                      return 0;
++              }
++              p += len;
++              caplen -= len;
++      } else {
++              security_level = 0;
++      }
++      
++      switch (security_level) {
++      case 0: /*FALLTHOUGH */
++      case 4:
++              miclen = 0;
++              break;
++      case 1: /*FALLTHOUGH */
++      case 5:
++              miclen = 4;
++              break;
++      case 2: /*FALLTHOUGH */
++      case 6:
++              miclen = 8;
++              break;
++      case 3: /*FALLTHOUGH */
++      case 7:
++              miclen = 16;
++              break;
++      }
++      
++      /* Remove MIC */
++      if (miclen > 0) {
++              if (caplen < (u_int) miclen) {
++                      ND_PRINT("[ERROR: Truncated before MIC]");
++                      return 0;
++              }
++              caplen -= miclen;
++              mic_start = p + caplen;
++      }
++      
++      /* Parse Information elements if present */
++      if (CHECK_BIT(fc, 9)) {
++              /* Yes we have those. */
++              len = ieee802_15_4_print_header_ie_list(ndo, p, caplen,
++                                                      &payload_ie_present);
++              if (len < 0) {
++                      return 0;
++              }
++              p += len;
++              caplen -= len;
++      }
++      
++      if (payload_ie_present) {
++              if (security_level >= 4) {
++                      ND_PRINT("Payload IEs present, but encrypted, cannot print ");
++              } else {
++                      len = ieee802_15_4_print_payload_ie_list(ndo, p, caplen);
++                      if (len < 0) {
++                              return 0;
++                      }
++                      p += len;
++                      caplen -= len;
++              }
++      }
++      
++      /* Print MIC */
++      if (ndo->ndo_vflag > 2 && miclen != 0) {
++              ND_PRINT("\n\tMIC ");
++              
++              for(len = 0; len < miclen; len++) {
++                      ND_PRINT("%02x", EXTRACT_U_1(mic_start + len));
++              }
++              ND_PRINT(" ");
++      }
++      
++      /* Print FCS */
++      if (ndo->ndo_vflag > 2) {
++              if (crc_check == fcs) {
++                      ND_PRINT("FCS %x ", fcs);
++              } else {
++                      ND_PRINT("wrong FCS %x vs %x (assume no FCS stored) ",
++                               fcs, crc_check);
++              }
 +      }
-       }
-     }
-     if (!ndo->ndo_suppress_default_print)
-       ND_DEFAULTPRINT(p, caplen);
-     break;
-   }
-   return 1;
++      
++      /* Payload print */
++      switch (frame_type) {
++      case 0x00: /* Beacon */
++              if (frame_version < 2) {
+                       if (caplen < 2) {
 -                              nd_print_trunc(ndo);
 -                              return hdrlen;
++                              ND_PRINT("[ERROR: Truncated before beacon information]");
++                              break;
++                      } else {
++                              uint16_t ss;
++                              
++                              ss = EXTRACT_LE_U_2(p);
++                              ieee802_15_4_print_superframe_specification(ndo, ss);
++                              p += 2;
++                              caplen -= 2;
++                              
++                              /* GTS */
++                              if (caplen < 1) {
++                                      ND_PRINT("[ERROR: Truncated before GTS info]");
++                                      break;
++                              }
++                              
++                              len = ieee802_15_4_print_gts_info(ndo, p, caplen);
++                              if (len < 0) {
++                                      break;
++                              }
++                              
++                              p += len;
++                              caplen -= len;
++                              
++                              /* Pending Addresses */
++                              if (caplen < 1) {
++                                      ND_PRINT("[ERROR: Truncated before pending addresses]");
++                                      break;
++                              }
++                              len = ieee802_15_4_print_pending_addresses(ndo, p, caplen);
++                              if (len < 0) {
++                                      break;
++                              }
++                              p += len;
++                              caplen -= len;
++                      }
++              }
++              if (!ndo->ndo_suppress_default_print)
++                      ND_DEFAULTPRINT(p, caplen);
++              
++              break;
++      case 0x01: /* Data */
++      case 0x02: /* Acknowledgement */
++              if (!ndo->ndo_suppress_default_print)
++                      ND_DEFAULTPRINT(p, caplen);
++              break;
++      case 0x03: /* MAC Command */
++              if (caplen < 1) {
++                      ND_PRINT("[ERROR: Truncated before Command ID]");
++              } else {
++                      uint8_t command_id;
++                      
++                      command_id = EXTRACT_U_1(p);
++                      if (command_id >= 0x30) {
++                              ND_PRINT("Command ID = Reserved 0x%02x ",
++                                       command_id);
++                      } else {
++                              ND_PRINT("Command ID = %s ",
++                                       mac_c_names[command_id]);
+                       }
 -                      panid = EXTRACT_LE_U_2(p);
++                      p++;
++                      caplen--;
++                      if (caplen != 0) {
++                              len = ieee802_15_4_print_command_data(ndo, command_id, p, caplen);
++                              if (len >= 0) {
++                                      p += len;
++                                      caplen -= len;
++                              }
++                      }
++              }
++              if (!ndo->ndo_suppress_default_print)
++                      ND_DEFAULTPRINT(p, caplen);
++              break;
++      }
++      return 1;
 +}
 +
 +/*
 + * Print and parse Multipurpose frames.
 + *
 + * Returns FALSE in case of error.
- */
++ */
 +static u_int
 +ieee802_15_4_mp_frame(netdissect_options *ndo,
 +                    const u_char *p, u_int caplen,
 +                    uint16_t fc)
 +{
-   int len, frame_version, pan_id_present;
-   int src_addr_len, dst_addr_len;
-   int security_level, miclen = 0;
-   int ie_present, payload_ie_present, security_enabled;
-   uint8_t seq, fcs_len;
-   uint32_t fcs, crc_check;
-   const u_char *mic_start = NULL;
-   pan_id_present = 0;
-   ie_present = 0;
-   payload_ie_present = 0;
-   security_enabled = 0;
-   /* Assume 2 octet FCS, the FCS length depends on the PHY, and we do not
-      know about that. */
-   if (caplen < 2) {
-     /* Cannot have FCS, assume fcs_len of 0. */
-     fcs_len = 0;
-     fcs = 0;
-   } else {
-     fcs_len = 2;
-     fcs = EXTRACT_LE_16BITS(p + caplen - 2);
-     crc_check = ieee802_15_4_crc16(p, caplen - 2);
-     if (crc_check != fcs) {
-       /* Wrong fcs, might not contain fcs, do not remove it. */
-     } else {
-       /* Remove FCS */
-       caplen -= fcs_len;
-     }
-   }
-   if (CHECK_BIT(fc, 3)) {
-     /* Long Frame Control */
-     /* Frame version. */
-     frame_version = (fc >> 12) & 0x03;
-     ND_PRINT((ndo, "v%d ", frame_version));
-     pan_id_present = CHECK_BIT(fc, 8);
-     ie_present = CHECK_BIT(fc, 15);
-     security_enabled = CHECK_BIT(fc, 9);
-     if (ndo->ndo_vflag > 2) {
-       if (security_enabled) { ND_PRINT((ndo, "Security Enabled, ")); }
-       if (CHECK_BIT(fc, 11)) { ND_PRINT((ndo, "Frame Pending, ")); }
-       if (CHECK_BIT(fc, 14)) { ND_PRINT((ndo, "AR, ")); }
-       if (pan_id_present) { ND_PRINT((ndo, "PAN ID Present, ")); }
-       if (CHECK_BIT(fc, 10)) {
-       ND_PRINT((ndo, "Sequence Number Suppression, "));
-       }
-       if (ie_present) { ND_PRINT((ndo, "IE present, ")); }
-     }
-     /* Check for the sequence number supression. */
-     if (CHECK_BIT(fc, 10)) {
-       /* Sequence number is suppressed, but long version. */
-       p += 2;
-       caplen -= 2;
-     } else {
-       seq = EXTRACT_LE_8BITS(p + 2);
-       p += 3;
-       caplen -= 3;
-       if (ndo->ndo_vflag)
-       ND_PRINT((ndo,"seq %02x ", seq));
-     }
-   } else {
-     /* Short format of header, but with seq no */
-     seq = EXTRACT_LE_8BITS(p + 1);
-     p += 2;
-     caplen -= 2;
-     if (ndo->ndo_vflag)
-       ND_PRINT((ndo,"seq %02x ", seq));
-   }
-   /* See which parts of addresses we have. */
-   dst_addr_len = ieee802_15_4_addr_len((fc >> 4) & 0x3);
-   src_addr_len = ieee802_15_4_addr_len((fc >> 6) & 0x3);
-   if (src_addr_len < 0) {
-     ND_PRINT((ndo,"[ERROR: Invalid src address mode]"));
-     return 0;
-   }
-   if (dst_addr_len < 0) {
-     ND_PRINT((ndo,"[ERROR: Invalid dst address mode]"));
-     return 0;
-   }
-   /* Print dst PAN and address. */
-   if (pan_id_present) {
-     if (caplen < 2) {
-       ND_PRINT((ndo, "[ERROR: Truncated before dst_pan]"));
-       return 0;
-     }
-     ND_PRINT((ndo, "%04x:", EXTRACT_LE_16BITS(p)));
-     p += 2;
-     caplen -= 2;
-   } else {
-     ND_PRINT((ndo, "-:"));
-   }
-   if (caplen < (u_int) dst_addr_len) {
-     ND_PRINT((ndo, "[ERROR: Truncated before dst_addr]"));
-     return 0;
-   }
-   ieee802_15_4_print_addr(ndo, p, dst_addr_len);
-   p += dst_addr_len;
-   caplen -= dst_addr_len;
-   ND_PRINT((ndo," < "));
-   /* Print src PAN and address. */
-   ND_PRINT((ndo, " -:"));
-   if (caplen < (u_int) src_addr_len) {
-     ND_PRINT((ndo, "[ERROR: Truncated before dst_addr]"));
-     return 0;
-   }
-   ieee802_15_4_print_addr(ndo, p, src_addr_len);
-   ND_PRINT((ndo, " "));
-   p += src_addr_len;
-   caplen -= src_addr_len;
-   if (security_enabled) {
-     len = ieee802_15_4_print_aux_sec_header(ndo, p, caplen, &security_level);
-     if (len < 0) {
-       return 0;
-     }
-     p += len;
-     caplen -= len;
-   } else {
-     security_level = 0;
-   }
-   switch (security_level) {
-   case 0: /*FALLTHOUGH */
-   case 4:
-     miclen = 0;
-     break;
-   case 1: /*FALLTHOUGH */
-   case 5:
-     miclen = 4;
-     break;
-   case 2: /*FALLTHOUGH */
-   case 6:
-     miclen = 8;
-     break;
-   case 3: /*FALLTHOUGH */
-   case 7:
-     miclen = 16;
-     break;
-   }
-   /* Remove MIC */
-   if (miclen > 0) {
-     if (caplen < (u_int) miclen) {
-       ND_PRINT((ndo, "[ERROR: Truncated before MIC]"));
-       return 0;
-     }
-     caplen -= miclen;
-     mic_start = p + caplen;
-   }
-   /* Parse Information elements if present */
-   if (ie_present) {
-     /* Yes we have those. */
-     len = ieee802_15_4_print_header_ie_list(ndo, p, caplen,
-                                           &payload_ie_present);
-     if (len < 0) {
-       return 0;
-     }
-     p += len;
-     caplen -= len;
-   }
-   if (payload_ie_present) {
-     if (security_level >= 4) {
-       ND_PRINT((ndo, "Payload IEs present, but encrypted, cannot print "));
-     } else {
-       len = ieee802_15_4_print_payload_ie_list(ndo, p, caplen);
-       if (len < 0) {
-       return 0;
-       }
-       p += len;
-       caplen -= len;
-     }
-   }
-   /* Print MIC */
-   if (ndo->ndo_vflag > 2 && miclen != 0) {
-     ND_PRINT((ndo, "\n\tMIC "));
++      int len, frame_version, pan_id_present;
++      int src_addr_len, dst_addr_len;
++      int security_level, miclen = 0;
++      int ie_present, payload_ie_present, security_enabled;
++      uint8_t seq;
++      uint32_t fcs, crc_check;
++      const u_char *mic_start = NULL;
 +      
-     for(len = 0; len < miclen; len += 4) {
-       ND_PRINT((ndo, "%08x", EXTRACT_32BITS(mic_start + len)));
-     }
-     ND_PRINT((ndo, " "));
-   }
-   /* Print FCS */
-   if (ndo->ndo_vflag > 2) {
-     if (crc_check == fcs) {
-       ND_PRINT((ndo, "FCS %04x ", fcs));
-     } else {
-       ND_PRINT((ndo, "wrong FCS %04x vs %04x (assume no FCS stored) ",
-               fcs, crc_check));
-     }
-   }
-   if (!ndo->ndo_suppress_default_print)
-     ND_DEFAULTPRINT(p, caplen);
-   return 1;
++      pan_id_present = 0;
++      ie_present = 0;
++      payload_ie_present = 0;
++      security_enabled = 0;
++      
++      /* Assume 2 octet FCS, the FCS length depends on the PHY, and we do not
++         know about that. */
++      if (caplen < 3) {
++              /* Cannot have FCS, assume no FCS. */
++              fcs = 0;
++      } else {
++              if (caplen > 4) {
++                      /* Test for 4 octet FCS. */
++                      fcs = EXTRACT_LE_U_4(p + caplen - 4);
++                      crc_check = ieee802_15_4_crc32(p, caplen - 4);
++                      if (crc_check == fcs) {
++                              /* Remove FCS */
++                              caplen -= 4;
++                      } else {
++                              fcs = EXTRACT_LE_U_2(p + caplen - 2);
++                              crc_check = ieee802_15_4_crc16(p, caplen - 2);
++                              if (crc_check == fcs) {
++                                      /* Remove FCS */
++                                      caplen -= 2;
++                              }
++                      }
++              } else {
++                      fcs = EXTRACT_LE_U_2(p + caplen - 2);
++                      crc_check = ieee802_15_4_crc16(p, caplen - 2);
++                      if (crc_check == fcs) {
++                              /* Remove FCS */
++                              caplen -= 2;
++                      }
++              }
++      }
++      
++      if (CHECK_BIT(fc, 3)) {
++              /* Long Frame Control */
++              
++              /* Frame version. */
++              frame_version = FC_FRAME_VERSION(fc);
++              ND_PRINT("v%d ", frame_version);
++              
++              pan_id_present = CHECK_BIT(fc, 8);
++              ie_present = CHECK_BIT(fc, 15);
++              security_enabled = CHECK_BIT(fc, 9);
++              
++              if (ndo->ndo_vflag > 2) {
++                      if (security_enabled) { ND_PRINT("Security Enabled, "); }
++                      if (CHECK_BIT(fc, 11)) { ND_PRINT("Frame Pending, "); }
++                      if (CHECK_BIT(fc, 14)) { ND_PRINT("AR, "); }
++                      if (pan_id_present) { ND_PRINT("PAN ID Present, "); }
++                      if (CHECK_BIT(fc, 10)) {
++                              ND_PRINT("Sequence Number Suppression, ");
++                      }
++                      if (ie_present) { ND_PRINT("IE present, "); }
++              }
++              
++              /* Check for the sequence number supression. */
++              if (CHECK_BIT(fc, 10)) {
++                      /* Sequence number is suppressed, but long version. */
+                       p += 2;
+                       caplen -= 2;
 -                      hdrlen += 2;
 -              }
 -              if (caplen < 8) {
 -                      nd_print_trunc(ndo);
 -                      return hdrlen;
++              } else {
++                      seq = EXTRACT_U_1(p + 2);
++                      p += 3;
++                      caplen -= 3;
++                      if (ndo->ndo_vflag)
++                              ND_PRINT("seq %02x ", seq);
+               }
++      } else {
++              /* Short format of header, but with seq no */
++              seq = EXTRACT_U_1(p + 1);
++              p += 2;
++              caplen -= 2;
+               if (ndo->ndo_vflag)
 -                      ND_PRINT("%04x:%s ", panid, le64addr_string(ndo, p));
 -              p += 8;
 -              caplen -= 8;
 -              hdrlen += 8;
++                      ND_PRINT("seq %02x ", seq);
++      }
++      
++      /* See which parts of addresses we have. */
++      dst_addr_len = ieee802_15_4_addr_len((fc >> 4) & 0x3);
++      src_addr_len = ieee802_15_4_addr_len((fc >> 6) & 0x3);
++      if (src_addr_len < 0) {
++              ND_PRINT("[ERROR: Invalid src address mode]");
++              return 0;
++      }
++      if (dst_addr_len < 0) {
++              ND_PRINT("[ERROR: Invalid dst address mode]");
++              return 0;
++      }
++      
++      /* Print dst PAN and address. */
++      if (pan_id_present) {
++              if (caplen < 2) {
++                      ND_PRINT("[ERROR: Truncated before dst_pan]");
++                      return 0;
++              }
++              ND_PRINT("%04x:", EXTRACT_LE_U_2(p));
++              p += 2;
++              caplen -= 2;
++      } else {
++              ND_PRINT("-:");
++      }
++      if (caplen < (u_int) dst_addr_len) {
++              ND_PRINT("[ERROR: Truncated before dst_addr]");
++              return 0;
++      }
++      ieee802_15_4_print_addr(ndo, p, dst_addr_len);
++      p += dst_addr_len;
++      caplen -= dst_addr_len;
++      
++      ND_PRINT(" < ");
++      
++      /* Print src PAN and address. */
++      ND_PRINT(" -:");
++      if (caplen < (u_int) src_addr_len) {
++              ND_PRINT("[ERROR: Truncated before dst_addr]");
++              return 0;
++      }
++      ieee802_15_4_print_addr(ndo, p, src_addr_len);
++      ND_PRINT(" ");
++      p += src_addr_len;
++      caplen -= src_addr_len;
++      
++      if (security_enabled) {
++              len = ieee802_15_4_print_aux_sec_header(ndo, p, caplen,
++                                                      &security_level);
++              if (len < 0) {
++                      return 0;
++              }
++              p += len;
++              caplen -= len;
++      } else {
++              security_level = 0;
++      }
++      
++      switch (security_level) {
++      case 0: /*FALLTHOUGH */
++      case 4:
++              miclen = 0;
++              break;
++      case 1: /*FALLTHOUGH */
++      case 5:
++              miclen = 4;
++              break;
++      case 2: /*FALLTHOUGH */
++      case 6:
++              miclen = 8;
++              break;
++      case 3: /*FALLTHOUGH */
++      case 7:
++              miclen = 16;
+               break;
+       }
 -
++      
++      /* Remove MIC */
++      if (miclen > 0) {
++              if (caplen < (u_int) miclen) {
++                      ND_PRINT("[ERROR: Truncated before MIC]");
++                      return 0;
++              }
++              caplen -= miclen;
++              mic_start = p + caplen;
++      }
++      
++      /* Parse Information elements if present */
++      if (ie_present) {
++              /* Yes we have those. */
++              len = ieee802_15_4_print_header_ie_list(ndo, p, caplen,
++                                                      &payload_ie_present);
++              if (len < 0) {
++                      return 0;
++              }
++              p += len;
++              caplen -= len;
++      }
++      
++      if (payload_ie_present) {
++              if (security_level >= 4) {
++                      ND_PRINT("Payload IEs present, but encrypted, cannot print ");
++              } else {
++                      len = ieee802_15_4_print_payload_ie_list(ndo, p, caplen);
++                      if (len < 0) {
++                              return 0;
++                      }
++                      p += len;
++                      caplen -= len;
++              }
++      }
++      
++      /* Print MIC */
++      if (ndo->ndo_vflag > 2 && miclen != 0) {
++              ND_PRINT("\n\tMIC ");
++              
++              for(len = 0; len < miclen; len++) {
++                      ND_PRINT("%02x", EXTRACT_U_1(mic_start + len));
++              }
++              ND_PRINT(" ");
++      }
++      
++      
++      /* Print FCS */
++      if (ndo->ndo_vflag > 2) {
++              if (crc_check == fcs) {
++                      ND_PRINT("FCS %x ", fcs);
++              } else {
++                      ND_PRINT("wrong FCS %x vs %x (assume no FCS stored) ",
++                               fcs, crc_check);
++              }
++      }
++      
+       if (!ndo->ndo_suppress_default_print)
+               ND_DEFAULTPRINT(p, caplen);
++      
++      return 1;
 +}
 +
 +/*
 + * Print frag frame.
 + *
 + * Returns FALSE in case of error.
 + */
 +static u_int
 +ieee802_15_4_frag_frame(netdissect_options *ndo _U_,
 +                      const u_char *p _U_,
 +                      u_int caplen _U_,
 +                      uint16_t fc _U_)
 +{
-   /* Not implement yet, might be bit hard to implement, as the
-    * information to set up the fragment is coming in the previous frame
-    * in the Fragment Sequence Context Description IE, thus we need to
-    * store information from there, so we can use it here. */
-   return 0;
++      /* Not implement yet, might be bit hard to implement, as the
++       * information to set up the fragment is coming in the previous frame
++       * in the Fragment Sequence Context Description IE, thus we need to
++       * store information from there, so we can use it here. */
++      return 0;
 +}
 +
 +/*
 + * Interal call to dissector taking packet + len instead of pcap_pkthdr.
 + *
 + * Returns FALSE in case of error.
 + */
 +u_int
 +ieee802_15_4_print(netdissect_options *ndo,
 +                 const u_char *p, u_int caplen)
 +{
-   int frame_type;
-   uint16_t fc;
-   if (caplen < 3) {
-     ND_PRINT((ndo, "[|802.15.4] %x", caplen));
-     return 0;
-   }
-   fc = EXTRACT_LE_16BITS(p);
-   /* First we need to check the frame type to know how to parse the rest
-      of the FC. Frame type is the first 3 bit of the frame control field.
-   */
-   frame_type = fc & 0x7;
-   ND_PRINT((ndo,"IEEE 802.15.4 %s packet ", ftypes[frame_type]));
++      int frame_type;
++      uint16_t fc;
++      
++      ndo->ndo_protocol ="802.15.4";
  
-   switch (frame_type) {
-   case 0x00: /* Beacon */
-   case 0x01: /* Data */
-   case 0x02: /* Acknowledgement */
-   case 0x03: /* MAC Command */
-     return ieee802_15_4_std_frames(ndo, p, caplen, fc);
-     break;
-   case 0x04: /* Reserved */
-     return 0;
-     break;
-   case 0x05: /* Multipurpose */
-     return ieee802_15_4_mp_frame(ndo, p, caplen, fc);
-     break;
-   case 0x06: /* Fragment or Frak */
-     return ieee802_15_4_frag_frame(ndo, p, caplen, fc);
-     break;
-   case 0x07: /* Extended */
-     return 0;
-     break;
-   }
-   return 0;
 -      return hdrlen;
++      if (caplen < 2) {
++              nd_print_trunc(ndo);
++              return caplen;
++      }
++      
++      fc = EXTRACT_LE_U_2(p);
++      
++      /* First we need to check the frame type to know how to parse the rest
++         of the FC. Frame type is the first 3 bit of the frame control field.
++      */
++      
++      frame_type = FC_FRAME_TYPE(fc);
++      ND_PRINT("IEEE 802.15.4 %s packet ", ftypes[frame_type]);
++      
++      switch (frame_type) {
++      case 0x00: /* Beacon */
++      case 0x01: /* Data */
++      case 0x02: /* Acknowledgement */
++      case 0x03: /* MAC Command */
++              return ieee802_15_4_std_frames(ndo, p, caplen, fc);
++              break;
++      case 0x04: /* Reserved */
++              return 0;
++              break;
++      case 0x05: /* Multipurpose */
++              return ieee802_15_4_mp_frame(ndo, p, caplen, fc);
++              break;
++      case 0x06: /* Fragment or Frak */
++              return ieee802_15_4_frag_frame(ndo, p, caplen, fc);
++              break;
++      case 0x07: /* Extended */
++              return 0;
++              break;
++      }
++      return 0;
  }
  
 -/* For DLT_IEEE802_15_4 and DLT_IEEE802_15_4_NOFCS */
 +/*
 + * Main function to print packets.
 + */
 +
  u_int
  ieee802_15_4_if_print(netdissect_options *ndo,
                        const struct pcap_pkthdr *h, const u_char *p)
  {
-   u_int caplen = h->caplen;
-   return ieee802_15_4_print(ndo, p, caplen);
 -      ndo->ndo_protocol = "802.15.4_if";
 -      return ieee802_15_4_print(ndo, p, h->caplen);
++      u_int caplen = h->caplen;
++      ndo->ndo_protocol ="802.15.4_if";
++      return ieee802_15_4_print(ndo, p, caplen);
  }
 +
++/*
++ * Local Variables:
++ * c-style: whitesmith
++ * c-basic-offset: 8
++ * End:
++ */
diff --cc print-udp.c
index b5a54accf088b8545ec91222ffa0c58e8ac85340,57e5b2bb5a8e5928b9374bb67cef976f14b9a58a..906dc0d2671581272688a5b365aca75bddfa3c50
@@@ -683,13 -700,11 +700,13 @@@ udp_print(netdissect_options *ndo, cons
                        lisp_print(ndo, (const u_char *)(up + 1), length);
                else if (IS_SRC_OR_DST_PORT(VXLAN_GPE_PORT))
                        vxlan_gpe_print(ndo, (const u_char *)(up + 1), length);
-               else if (ND_TTEST(((const struct LAP *)cp)->type) &&
-                   ((const struct LAP *)cp)->type == lapDDP &&
-                   (atalk_port(sport) || atalk_port(dport))) {
 +              else if (IS_SRC_OR_DST_PORT(ZEP_PORT))
 +                      zep_print(ndo, (const u_char *)(up + 1), length);
+               else if (ND_TTEST_1(((const struct LAP *)cp)->type) &&
+                        EXTRACT_U_1(((const struct LAP *)cp)->type) == lapDDP &&
+                        (atalk_port(sport) || atalk_port(dport))) {
                        if (ndo->ndo_vflag)
-                               ND_PRINT((ndo, "kip "));
+                               ND_PRINT("kip ");
                        llap_print(ndo, cp, length);
                } else {
                        if (ulen > length)
diff --cc print-zep.c
index 8954d7fd386fe535e271bc4babe82bf37e71a216,0000000000000000000000000000000000000000..ab98315055c75e014789cdc9466334d14cf8210a
mode 100644,000000..100644
--- /dev/null
@@@ -1,173 -1,0 +1,185 @@@
- #include "config.h"
 +/*
 + * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
 + *    The Regents of the University of California.  All rights reserved.
 + *
 + * Redistribution and use in source and binary forms, with or without
 + * modification, are permitted provided that: (1) source code distributions
 + * retain the above copyright notice and this paragraph in its entirety, (2)
 + * distributions including binary code include the above copyright notice and
 + * this paragraph in its entirety in the documentation or other materials
 + * provided with the distribution, and (3) all advertising materials mentioning
 + * features or use of this software display the following acknowledgement:
 + * ``This product includes software developed by the University of California,
 + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
 + * the University nor the names of its contributors may be used to endorse
 + * or promote products derived from this software without specific prior
 + * written permission.
 + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
 + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
 + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 + */
 +
 +
 +#ifdef HAVE_CONFIG_H
-   int32_t i;
-   uint32_t uf;
-   uint32_t f;
-   float ff;
-   i = EXTRACT_32BITS(p);
-   uf = EXTRACT_32BITS(p + 4);
-   ff = uf;
-   if (ff < 0.0)           /* some compilers are buggy */
-     ff += FMAXINT;
-   ff = ff / FMAXINT;      /* shift radix point by 32 bits */
-   f = ff * 1000000000.0;  /* treat fraction as parts per billion */
-   ND_PRINT((ndo, "%u.%09d", i, f));
++#include <config.h>
 +#endif
 +
 +#include <netdissect-stdinc.h>
 +
 +#include "netdissect.h"
 +
 +#include "extract.h"
 +
 +/* From wireshark packet-zep.c:
 + *
 + ***********************************************************************
 + *
 + * ZEP Packets must be received in the following format:
 + *
 + * |UDP Header|  ZEP Header |IEEE 802.15.4 Packet|
 + * | 8 bytes  | 16/32 bytes |    <= 127 bytes    |
 + *
 + ***********************************************************************
 + *
 + * ZEP v1 Header will have the following format:
 + *
 + * |Preamble|Version|Channel ID|Device ID|CRC/LQI Mode|LQI Val|Reserved|Length|
 + * |2 bytes |1 byte |  1 byte  | 2 bytes |   1 byte   |1 byte |7 bytes |1 byte|
 + *
 + * ZEP v2 Header will have the following format (if type=1/Data):
 + * |Prmbl|Ver  |Type |ChnlID|DevID|C/L Mode|LQI|NTP TS|Seq#|Res |Len|
 + * | 2   | 1   | 1   | 1    | 2   | 1      | 1 | 8    | 4  | 10 | 1 |
 + *
 + * ZEP v2 Header will have the following format (if type=2/Ack):
 + * |Preamble|Version| Type |Sequence#|
 + * |2 bytes |1 byte |1 byte| 4 bytes |
 + *------------------------------------------------------------
 + */
 +
 +#define     FMAXINT (4294967296.0)  /* floating point rep. of MAXINT */
 +#define     JAN_1970        2208988800U
 +
 +/* Print timestamp */
 +static void zep_print_ts(netdissect_options *ndo, const u_char *p)
 +{
-   /*
-    * print the time in human-readable format.
-    */
-   if (i) {
-     time_t seconds = i - JAN_1970;
-     struct tm *tm;
-     char time_buf[128];
-     tm = localtime(&seconds);
-     strftime(time_buf, sizeof (time_buf), "%Y/%m/%d %H:%M:%S", tm);
-     ND_PRINT((ndo, " (%s)", time_buf));
-   }
++      int32_t i;
++      uint32_t uf;
++      uint32_t f;
++      float ff;
++      
++      i = EXTRACT_BE_U_4(p);
++      uf = EXTRACT_BE_U_4(p + 4);
++      ff = uf;
++      if (ff < 0.0)           /* some compilers are buggy */
++              ff += FMAXINT;
++      ff = ff / FMAXINT;      /* shift radix point by 32 bits */
++      f = ff * 1000000000.0;  /* treat fraction as parts per billion */
++      ND_PRINT("%u.%09d", i, f);
++      
 +#ifdef HAVE_STRFTIME
-  
++      /*
++       * print the time in human-readable format.
++       */
++      if (i) {
++              time_t seconds = i - JAN_1970;
++              struct tm *tm;
++              char time_buf[128];
++              
++              tm = localtime(&seconds);
++              strftime(time_buf, sizeof (time_buf), "%Y/%m/%d %H:%M:%S", tm);
++              ND_PRINT(" (%s)", time_buf);
++      }
 +#endif
 +}
 +
 +/*
 + * Main function to print packets.
 + */
-     uint8_t version, inner_len;
-     uint32_t seq_no;
-     
-     ND_PRINT((ndo, "ZEP"));
-     
-     ND_TCHECK2(*bp, 8);
-     if (*bp != 'E' || *(bp+1) != 'X') goto trunc;
-     
-     version = *(bp + 2);
-     ND_PRINT((ndo, "v%d ", version));
-     if (version == 1) {
-       /* ZEP v1 packet. */
-       ND_TCHECK2(*bp, 16);
-       ND_PRINT((ndo, "Channel ID %d, Device ID 0x%04x, ",
-               *(bp + 3), EXTRACT_16BITS(bp + 4)));
-       if (*(bp + 6))
-       ND_PRINT((ndo, "CRC, "));
-       else
-       ND_PRINT((ndo, "LQI %d, ", *(bp + 7)));
-       inner_len = *(bp + 15);
-       ND_PRINT((ndo, "inner len = %d", inner_len));
++
 +void
 +zep_print(netdissect_options *ndo,
 +        const u_char *bp, u_int len)
 +{
-       bp += 16;
-       len -= 16;
-     } else {
-       /* ZEP v2 packet. */
-       if (*(bp + 3) == 2) {
-       /* ZEP v2 ack. */
-       seq_no = EXTRACT_32BITS(bp + 4);
-       ND_PRINT((ndo, "ACK, seq# = %d", seq_no));
-       inner_len = 0;
-       bp += 8;
-       len -= 8;
-       } else {
-       /* ZEP v2 data, or some other. */
-       ND_TCHECK2(*bp, 32);
++      uint8_t version, inner_len;
++      uint32_t seq_no;
++      
++      ndo->ndo_protocol ="ZEP";
 +
-       ND_PRINT((ndo, "Type %d, Channel ID %d, Device ID 0x%04x, ",
-                 *(bp + 3), *(bp + 4), EXTRACT_16BITS(bp + 5)));
-       if (*(bp + 7))
-         ND_PRINT((ndo, "CRC, "));
-       else
-         ND_PRINT((ndo, "LQI %d, ", *(bp + 8)));
++      ND_PRINT("ZEP");
 +      
-       zep_print_ts(ndo, bp + 9);
-       seq_no = EXTRACT_32BITS(bp + 17);
-       inner_len = *(bp + 31);
-       ND_PRINT((ndo, ", seq# = %d, inner len = %d", seq_no, inner_len));
-       bp += 32;
-       len -= 32;
-       }
-     }
-     if (inner_len != 0) {
-       /* Call 802.15.4 dissector. */
-       ND_PRINT((ndo, "\n\t"));
-       if (ieee802_15_4_print(ndo, bp, inner_len)) {
-       bp += len;
-       len = 0;
-       }
-     }
-     
-     if (!ndo->ndo_suppress_default_print)
-       ND_DEFAULTPRINT(bp, len);
-     
-     return;    
++      ND_TCHECK_LEN(bp, 8);
 +      
-     ND_PRINT((ndo, " [|ZEP]"));
++      if (EXTRACT_U_1(bp) != 'E' || EXTRACT_U_1(bp + 1) != 'X')
++              goto trunc;
++      
++      version = EXTRACT_U_1(bp + 2);
++      ND_PRINT("v%d ", version);
++      
++      if (version == 1) {
++              /* ZEP v1 packet. */
++              ND_TCHECK_LEN(bp, 16);
++              ND_PRINT("Channel ID %d, Device ID 0x%04x, ",
++                       EXTRACT_U_1(bp + 3), EXTRACT_BE_U_2(bp + 4));
++              if (EXTRACT_U_1(bp + 6))
++                      ND_PRINT("CRC, ");
++              else
++                      ND_PRINT("LQI %d, ", EXTRACT_U_1(bp + 7));
++              inner_len = EXTRACT_U_1(bp + 15);
++              ND_PRINT("inner len = %d", inner_len);
++              
++              bp += 16;
++              len -= 16;
++      } else {
++              /* ZEP v2 packet. */
++              if (EXTRACT_U_1(bp + 3) == 2) {
++                      /* ZEP v2 ack. */
++                      seq_no = EXTRACT_BE_U_4(bp + 4);
++                      ND_PRINT("ACK, seq# = %d", seq_no);
++                      inner_len = 0;
++                      bp += 8;
++                      len -= 8;
++              } else {
++                      /* ZEP v2 data, or some other. */
++                      ND_TCHECK_LEN(bp, 32);
++                      
++                      ND_PRINT("Type %d, Channel ID %d, Device ID 0x%04x, ",
++                               EXTRACT_U_1(bp + 3), EXTRACT_U_1(bp + 4),
++                               EXTRACT_BE_U_2(bp + 5));
++                      if (EXTRACT_U_1(bp + 7))
++                              ND_PRINT("CRC, ");
++                      else
++                              ND_PRINT("LQI %d, ", EXTRACT_U_1(bp + 8));
++                      
++                      zep_print_ts(ndo, bp + 9);
++                      seq_no = EXTRACT_BE_U_4(bp + 17);
++                      inner_len = EXTRACT_U_1(bp + 31);
++                      ND_PRINT(", seq# = %d, inner len = %d",
++                               seq_no, inner_len);
++                      bp += 32;
++                      len -= 32;
++              }
++      }
++      
++      if (inner_len != 0) {
++              /* Call 802.15.4 dissector. */
++              ND_PRINT("\n\t");
++              if (ieee802_15_4_print(ndo, bp, inner_len)) {
++                      bp += len;
++                      len = 0;
++              }
++      }
++      
++      if (!ndo->ndo_suppress_default_print)
++              ND_DEFAULTPRINT(bp, len);
++      
++      return;    
 + trunc:
++      ND_PRINT(" [|ZEP]");
 +}
++
++/*
++ * Local Variables:
++ * c-style: whitesmith
++ * c-basic-offset: 8
++ * End:
++ */
index 0000000000000000000000000000000000000000,5ac448589c597f989c352bb32f78d41809a42586..54c530e21de10b6a10ec6510874830eb94804c7e
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,1 +1,1 @@@
 -    1  04:15:33.623120 IEEE 802.15.4 Data packet seq 01 ab4d:10:05:00:81:00:01:00:01 <  [|802.15.4]
++    1  04:15:33.623120 IEEE 802.15.4 Data packet v2 AR, seq 01 ab4d:10:05:00:81:00:01:00:01 < -:[ERROR: Truncated before dst_addr]
index 0000000000000000000000000000000000000000,011eb19e8397a32900c7479dbfb6ded7315b0222..31edabe96d5b900fe9b43c2340786fec58ee7d19
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,1 +1,1 @@@
 -    1  11:30:55.515816 IEEE 802.15.4 Beacon packet seq cd  [|802.15.4]
++    1  11:30:55.515816 IEEE 802.15.4 Beacon packet v2 Sequence Number Suppression, IE present, seq suppressed abcd:[ERROR: Truncated before dst_addr]
index 0000000000000000000000000000000000000000,9a213d022b2b7e4eaa6062f11fd655c813dcc63f..9eb6aa99dd23ae2cfbe08604e815bcc0dfd17ded
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,1 +1,1 @@@
 -    1  03:07:17.623120 IEEE 802.15.4 Data packet seq 01  [|802.15.4]
++    1  03:07:17.623120 IEEE 802.15.4 Data packet v2 AR, seq 01 [ERROR: Truncated before dst_pan]
index 0000000000000000000000000000000000000000,5919f261452517a312d521d2b0a2e55b2acd0b92..c7d1f832b404a7346e37940b57bb4bc369d641a8
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,1 +1,1 @@@
 -    1  11:30:55.515816 IEEE 802.15.4 Beacon packet seq cd ffab:cdff <  [|802.15.4]
++    1  11:30:55.515816 IEEE 802.15.4 Beacon packet v2 Sequence Number Suppression, IE present, seq suppressed abcd:ffff < -:[ERROR: Truncated before dst_addr]
diff --cc udp.h
Simple merge