/*
* Frame Control subfields.
*/
- #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)
-
- #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)
- static u_int
- ieee802_15_4_print(netdissect_options *ndo,
- const u_char *p, u_int caplen)
+ #define FC_ADDRESSING_MODE_NONE 0x00
+ #define FC_ADDRESSING_MODE_RESERVED 0x01
+ #define FC_ADDRESSING_MODE_SHORT 0x02
+ #define FC_ADDRESSING_MODE_LONG 0x03
+
+ /*
+ * 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,
+ u_int data_len)
{
- u_int hdrlen;
- uint16_t fc;
- uint8_t seq;
- uint16_t panid = 0;
+ uint16_t crc;
+ u_char x, y;
-
+
- ndo->ndo_protocol = "802.15.4";
- if (caplen < 3) {
- nd_print_trunc(ndo);
- return caplen;
+ 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);
}
- hdrlen = 3;
+ /* 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;
+ }
- 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;
+ /*
+ * 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;
+ }
+
+ /*
+ * 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,
+ u_int data_len)
+ {
+ uint32_t crc, byte;
+ 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;
}
- if (ndo->ndo_vflag)
- ND_PRINT("none ");
+ }
+ /* Reverse bits on output */
+ crc = ieee802_15_4_reverse32(crc);
+ return crc;
+ }
+
+ /*
+ * 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 FC_ADDRESSING_MODE_NONE: /* None. */
+ return 0;
break;
- case FC_ADDRESSING_MODE_RESERVED:
- if (ndo->ndo_vflag)
- ND_PRINT("reserved destination addressing mode");
- return hdrlen;
- case FC_ADDRESSING_MODE_SHORT:
+ 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("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("\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,
+ u_int data_len)
+ {
+ uint8_t gts_spec, gts_cnt;
+ u_int len;
+ int 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 int16_t
+ ieee802_15_4_print_pending_addresses(netdissect_options *ndo,
+ const u_char *p,
+ u_int data_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("[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 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, ulen;
+ int16_t len;
+ int 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;
+ }
-
++
+ ulen = EXTRACT_LE_U_2(p + ptr + 2);
+ ND_PRINT("SD Index = %d, Bitmap len = %d, ",
+ EXTRACT_LE_U_2(p + ptr), ulen);
+ ptr += 4;
+ if (ie_len < ptr + ulen) {
+ ND_PRINT(" [ERROR: Truncated in SD bitmap]");
+ break;
+ }
+ ND_PRINT(" SD Bitmap = ");
+ for(i = 0; i < ulen; i++) {
+ ND_PRINT("%02x ", EXTRACT_U_1(p + ptr + i));
+ }
+ ptr += ulen;
-
++
+ if (ie_len < ptr + 5) {
+ ND_PRINT(" [ERROR: Truncated before Channel hopping specification]");
+ break;
+ }
-
++
+ ulen = 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),
+ ulen);
+ ptr += 5;
+ if (ie_len < ptr + ulen) {
+ ND_PRINT(" [ERROR: Truncated in Channel offset bitmap]");
+ break;
+ }
+ ND_PRINT(" Channel offset bitmap = ");
+ for(i = 0; i < ulen; i++) {
+ ND_PRINT("%02x ", EXTRACT_U_1(p + ptr + i));
+ }
+ ptr += ulen;
+ if (hopping_present) {
+ if (ie_len < ptr + 1) {
+ ND_PRINT(" [ERROR: Truncated in Hopping Sequence length]");
+ break;
+ }
+ ulen = EXTRACT_U_1(p + ptr);
+ ptr++;
+ ND_PRINT("Hopping Seq length = %d [ ", ulen);
-
++
+ /* The specification is not clear how the
+ hopping sequence is encoded, I assume two
+ octet unsigned integers for each channel. */
-
++
+ if (ie_len < ptr + ulen * 2) {
+ ND_PRINT(" [ERROR: Truncated in Channel offset bitmap]");
+ break;
+ }
+ for(i = 0; i < ulen; i++) {
+ ND_PRINT("%02x ", EXTRACT_LE_U_2(p + ptr + i * 2));
+ }
+ ND_PRINT("]");
+ ptr += ulen * 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;
+ }
+ }
+
+ /*
+ * 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,
+ u_int caplen,
+ int *payload_ie_present)
+ {
+ int len, ie, element_id, i;
+ uint16_t ie_len;
-
++
+ *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] ");
}
- panid = EXTRACT_LE_U_2(p);
+ /* 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;
+ }
+ /* 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;
+ uint16_t 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 {
+ uint16_t 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;
+ }
+ }
+
+ /*
+ * 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_id, i, type;
+ uint16_t sub_ie_len;
-
++
+ 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;
+
+ data_start = 0;
+ 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 FC_ADDRESSING_MODE_LONG:
+ 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;
+ }
+
+ ND_PRINT("Upper layer data = ");
+ for(i = data_start; i < ie_len; i++) {
+ ND_PRINT("%02x ", EXTRACT_U_1(p + i));
+ }
+ }
+
+ /*
+ * 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,
+ u_int caplen)
+ {
+ int len, ie, group_id, i;
+ uint16_t ie_len;
-
++
+ 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 {
+ 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 {
++ } 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,
+ u_int caplen,
+ int *security_level)
+ {
+ 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("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 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 FC_ADDRESSING_MODE_RESERVED:
+ 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;
+ uint32_t fcs, crc_check;
+ const u_char *mic_start = NULL;
-
++
+ payload_ie_present = 0;
+
+ crc_check = 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("reserved source addressing mode");
+ 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("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;
+ 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("[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;
+ }
+ #endif /* BROKEN_6TISCH_PAN_ID_COMPRESSION */
+ }
+ }
++
+ /* 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;
- 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("-:");
+ }
+ 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. */
+ 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;
+ } else {
+ 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 (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);
+ }
+ }
-
++
+ /* 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]);
+ }
+ 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;
+ 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;
+ crc_check = 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;
}
- panid = EXTRACT_LE_U_2(p);
+ }
+ }
-
++
+ 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 hdrlen;
+ 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;
+ }
+
+ /*
+ * 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;
-
++
+ ndo->ndo_protocol ="802.15.4";
+
+ 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)
{
- 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);
}
+/* For DLT_IEEE802_15_4_TAP */
+/* https://github.com/jkcko/ieee802.15.4-tap */
+u_int
+ieee802_15_4_tap_if_print(netdissect_options *ndo,
+ const struct pcap_pkthdr *h, const u_char *p)
+{
+ uint8_t version;
+ uint16_t length;
+
+ ndo->ndo_protocol = "802.15.4_tap";
+ if (h->caplen < 4) {
+ nd_print_trunc(ndo);
+ return h->caplen;
+ }
+
+ version = EXTRACT_U_1(p);
+ length = EXTRACT_LE_U_2(p+2);
+ if (version != 0 || length < 4) {
+ nd_print_invalid(ndo);
+ return 0;
+ }
+
+ if (h->caplen < length) {
+ nd_print_trunc(ndo);
+ return h->caplen;
+ }
+
+ return ieee802_15_4_print(ndo, p+length, h->caplen-length) + length;
+}
++
+ /*
+ * Local Variables:
+ * c-style: whitesmith
+ * c-basic-offset: 8
+ * End:
+ */
++